Introduction..
Since the earliest day of DOS-based PC's , programmers enjoyed a simple graphics programming platform that changed little over the years. Over time, many "hackish" techniques were developed to achive speed and quality in rendered graphics that eventually became standard practice for most programmers. In the last few years, the emerging dominance of 32-bit multitasking operating systems rendered the "old" ways of doing things obsolete. The ability to directly access the graphics hardware was gone, along with the ability to directly address the large amounts of memory needed for graphics programming. All graphics applications now needed to be performed via the API provided by the operating system. In many cases, just getting to the point where one could plot a single pixel was a major effort that turned a graphics programmer, into a systems programmer, forced to interface to the operating system with programming API's that were often slow, difficult or simply too cumbersome to use for small projects.
Last September, I began experimenting with the OpenGL graphics api on Windows NT. It didn't take long for me to realize that, despite the large number of graphics functions it offers , it has an underlying simplicity that struck me as being the "right" approach to graphics rendering. Since so many people come to #C with questions about rendering basic graphics to the screen , I though that It might be a "good thing" (TM, 1998 by OGL ) to share some of the things I learned from my experiments with this incredible graphics API.
The program is called 2D4NT, a script-reading , two-dimensional graphics rendering engine. It was written for Windows NT /Win95 on Borland C++ V5.01 and MSVC v 5.0.
What this is about...
Presented here is a "plain-brown-wrapper" version of the basics of two dimensional graphics rendering using OpenGL. This article is not about windows coding, it's not even about OpenGL programming, and it's not about animation, or 3-d effects. It's simply about rendering basic graphics "primitives" on the screen in the simplest and easiest way possible. If you want to draw a line on the screen of your Windows box, and don't want to make a major production out of it, this article is for YOU.
Let us begin.....
We will be using the OpenGL api via the GLaux functions. This library allows graphics to be rendered in console mode, with a minimum of code dedicated to dealing with windowing and interfacing to the operating system. GLaux handles all that for you, so you are free to write graphics code. Some of you may wish to adapt this code to GLut, which is newer and better supported than GLaux.
Setting up a graphics window...
The code for setting up a simple , resizable graphics window appears below. When using console mode with GLaux, two windows will appear. The graphics window, where all of the rendered stuff appears, and a text console window, where console I/O will appear.
PROGRAM BEGINS
#include<windows.h> #include<gl\gl.h> #include<gl\glaux.h> #include<conio.h> #include<math.h> /* Called by GLaux to render scene */ void CALLBACK RenderScene(void) { /* Local variables, OpenGL code, and miscellaneous code goes here. */ } void main(void) { /* setup the window */ auxInitDisplayMode(AUX_SINGLE | AUX_RGBA); auxInitPosition(100,100,250,250); auxInitWindow("Blah, blah, blah..."); /* Do all of your non-graphics stuff here */ /* The function to call when updating the window */ auxMainLoop(RenderScene); }
PROGRAM ENDS
The above code works, but renders nothing but a blank screen. to exit the graphics screen, press ESC. We will be adding code to this later.
Primitives.... The basis for every possible shape.
All of the possible shapes that can be drawn on a two-dimensional screen can be broken down into "Primitives", shapes that can be used in combinations with other shapes.
For our purposes, these shapes are:
1) A single Pixel
2) A straight line
3) A box (A square or rectangle)
4) A triangle
5) A circle
Furthermore, primitives can be rendered as lines, or they can be rendered as "solids", that is, primitive shapes that have their interiors filled with the same color as the line.
This give us three more shapes to render:
1) A Solid Box
2) A Solid Circle (a disc)
3) A Solid Triangle
Using a combination of these basic shapes, it is possible to render any concievable two-dimensional shape. It's a fact, try it and see.
Rendering the basic shapes..
OpenGL provides commands to render all of our shapes except a circle and a solid circle. This means we have to come up with a way of rendering these objects so we can accomplish this (Actually, GLut does provide a way of doing this, but we aren't using it here).
Rendering a single pixel...
CODE BEGINS
/* set a pixel */ glBegin(GL_POINTS); glVertex2d(PointX,PointY); glEnd();
CODE ENDS
Rendering a line...
CODE BEGINS
/* Draw a filled rectangle with the current color */ glRectf(100.0f,150.0f,150.0f,100.0f);
CODE ENDS
Rendering a triangle using lines...
CODE BEGINS
/* draw a triangle using lines */ glBegin(GL_LINES); glVertex2d(TriangleX1,TriangleY1); glVertex2d(TriangleX2,TriangleY2); glVertex2d(TriangleX2,TriangleY2); glVertex2d(TriangleX3,TriangleY3); glVertex2d(TriangleX3,TriangleY3); glVertex2d(TriangleX1,TriangleY1); glEnd();
CODE ENDS
Rendering a solid triangle...
CODE BEGINS
/* draw a filled triangle */ glBegin(GL_TRIANGLES); glVertex2d(TriangleX1,TriangleY1); glVertex2d(TriangleX2,TriangleY2); glVertex2d(TriangleX3,TriangleY3); glEnd();
CODE ENDS
Rendering a rectangle with lines...
CODE BEGINS
/* Render a rectangle by drawing four connected lines */
glBegin(GL_LINES); glVertex2d(RectangleX1,RectangleY1); glVertex2d(RectangleX1,RectangleY2); glVertex2d(RectangleX2,RectangleY1); glVertex2d(RectangleX2,RectangleY2); glVertex2d(RectangleX1,RectangleY1); glVertex2d(RectangleX2,RectangleY1); glVertex2d(RectangleX1,RectangleY2); glVertex2d(RectangleX2,RectangleY2); glEnd();
CODE ENDS
Rendering a solid rectangle...
CODE BEGINS
/* Draw a filled rectangle with the current color */
glRectf(RectangleX1,RectangleY1,RectangleX2,RectangleY2);
CODE ENDS
Rendering a simple circle...
The solution for drawing a circle is simple: draw a series of connected lines of tangency, around the radius of the circle. If you use really short lines, and lots of them, it looks exactly like a "real " circle. The trick is, to use just enough lines to make a nice , round circle.. If you use too many lines , the rendering is slow. Use too few lines, and the rendering is faster, but the circle looks pixelated, or turns into an obvious polygon.
Here is how it's done...
CODE BEGINS
/* draw a circle from a bunch of short lines */ vectorY1=originY+radius; vectorX1=originX; glBegin(GL_LINE_STRIP); for(angle=0.0f;angle<=(2.0f*3.14159);angle+=0.01f) { vectorX=originX+(radius*(float)sin((double)angle)); vectorY=originY+(radius*(float)cos((double)angle)); glVertex2d(vectorX1,vectorY1); vectorY1=vectorY; vectorX1=vectorX; } glEnd();
CODE ENDS
Rendering a solid circle...
Now, a similar problem occurs when trying to render a solid circle. We could just render a bunch of lines from the center of the circle to it's edge to create a solid disc, but that would be way too slow. The faster way to do it, is to render the circle as a bunch of solid triangles sharing a common vertex at the center of the circle. Once again, the more triangles you use, the better the quality of the circle gets, and the fewer you use , the faster it will render.
Here is the code for a solid circle..
CODE BEGINS
/* draw a solid disc from a bunch of triangles */ vectorY1=originY; vectorX1=originX; glBegin(GL_TRIANGLES); for(i=0;i<=360;i++) { angle=(float)(((double)i)/57.29577957795135); vectorX=originX+(radius*(float)sin((double)angle)); vectorY=originY+(radius*(float)cos((double)angle)); glVertex2d(originX,originY); glVertex2d(vectorX1,vectorY1); glVertex2d(vectorX,vectorY); vectorY1=vectorY; vectorX1=vectorX; } glEnd();
CODE ENDS
Making it all work....
Below, is the source for a program that uses all of the primitives I've discussed in a script-reading rendering engine.
The source for this program is available at : ftp://www.night-flyer.com/freeware/2d4nt.c
Alternatively, a fully compiled version of this program, with documentation, and a sample script can be downloaded at: ftp://www.night-flyer.com/freeware/2d4nt75.zip
PROGRAM BEGINS /* 2D4NT.C by Glen E. Gardner, Jr. */ /* Copyright 1998 by Glen E. Gardner, Jr. */ /* Released as freeware. Use this program freely and enjoy! */ /* Please include this original unaltered source code in all distributions */ #include<windows.h> #include<gl\gl.h> #include<gl\glaux.h> #include<conio.h> #include<math.h> #include<stdio.h> #include<math.h> #include<ctype.h> #include<string.h> #include<sys\types.h> #include<sys\stat.h> char * ParseFile(char*,char*); void StoreTokens(int); char * GetToken(char *,char*); int CheckList(char*); int Evaluate(int,char*); char* Perform(int,int,char *,char*,char *); void CALLBACK RenderScene(void); FILE *filein; int blah=0; char *data; char *temp2; char *tokens; char *temp; /* Program Begins */ int main(int argc,char **argv) { char *ptr; int commandnum; int numargs; int status=0; int i; int filesize; struct stat buf; /* setup the window */ auxInitDisplayMode(AUX_SINGLE | AUX_RGBA); auxInitPosition(100,100,250,250); auxInitWindow("2D4NT Version 0.75 Alpha. Copyright 1998 by Glen E. Gardner, Jr."); if(argc <2){cprintf("Use: parser source.txt\n");exit(1);} if(stat(argv[1],&buf)) printf( "file not found\n" ); else {filesize=buf.st_size;} if ((ptr = (char *) malloc(64)) == NULL) { cprintf("Out of Memory\n"); exit(0); /* terminate program if out of memory */ } if ((data = (char *) malloc(filesize*2)) == NULL) { cprintf("Out of Memory\n"); exit(0); /* terminate program if out of memory */ } if ((tokens = (char *) malloc(filesize*2)) == NULL) { cprintf("Out of Memory\n"); exit(0); /* terminate program if out of memory */ } temp2=data; temp=tokens; ParseFile(argv[1],tokens); i=0; commandnum=0; tokens=temp; while(strlen(tokens)>31) { if(!ptr){cprintf("Run Complete..\n");exit(0);} while((commandnum=CheckList((ptr=GetToken(tokens,ptr))))==0)tokens=(tokens+strlen(ptr)+1); numargs=Evaluate(commandnum,ptr=GetToken(tokens,ptr)); tokens=(tokens+strlen(ptr)+1); ptr=Perform(numargs,commandnum,tokens,ptr,data); tokens=(tokens+strlen(ptr)+1); } data=temp2; /* The function to call when updating the window */ auxMainLoop(RenderScene); data=temp2; return(0); } /* Functions Begin */ char * ParseFile(char *filename,char *stack1) { FILE *filein; char *temp; int data=0; int size=1; int flag=0; int olddata=0; temp=stack1; filein=fopen(filename,"rt"); while((data=fgetc(filein))!=EOF) { if((iscntrl(data)==0)&&(isspace(data)==0)) { if((isalpha(data))&&(isalpha(olddata))){sprintf(stack1,"%c",data);stack1++;} if((isalpha(data))&&(!isalpha(olddata))){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((isdigit(data))&&(isdigit(olddata))){sprintf(stack1,"%c",data);stack1++;} if((isdigit(data))&&(!isdigit(olddata))){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((ispunct(data))&&(!ispunct(olddata))){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((ispunct(data))&&(ispunct(olddata))) { if((data=='!')&&(olddata=='!')){sprintf(stack1,"%c",data);stack1++;} if((data=='!')&&(olddata!='!')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((data=='@')&&(olddata=='@')){sprintf(stack1,"%c",data);stack1++;} if((data=='@')&&(olddata!='@')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((data=='#')&&(olddata=='#')){sprintf(stack1,"%c",data);stack1++;} if((data=='#')&&(olddata!='#')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((data=='$')&&(olddata=='$')){sprintf(stack1,"%c",data);stack1++;} if((data=='$')&&(olddata!='$')){sprintf(stack1,"%c",'\n');stack1++; sprintf(stack1,"%c",data);size++;stack1++;} if((data=='%')&&(olddata=='%')){sprintf(stack1,"%c",data);stack1++;} if((data=='%')&&(olddata!='%')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((data=='^')&&(olddata=='^')){sprintf(stack1,"%c",data);stack1++;} if((data=='^')&&(olddata!='^')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((data=='&')&&(olddata=='&')){sprintf(stack1,"%c",data);stack1++;} if((data=='&')&&(olddata!='&')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((data=='*')&&(olddata=='*')){sprintf(stack1,"%c",data);stack1++;} if((data=='*')&&(olddata!='*')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((data=='(')&&(olddata=='(')){sprintf(stack1,"%c",data);stack1++;} if((data=='(')&&(olddata!='(')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((data==')')&&(olddata==')')){sprintf(stack1,"%c",data);stack1++;} if((data==')')&&(olddata!=')')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((data=='-')&&(olddata=='-')){sprintf(stack1,"%c",data);stack1++;} if((data=='-')&&(olddata!='-')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((data=='_')&&(olddata=='_')){sprintf(stack1,"%c",data);stack1++;} if((data=='_')&&(olddata!='_')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((data=='+')&&(olddata=='+')){sprintf(stack1,"%c",data);stack1++;} if((data=='+')&&(olddata!='+')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((data=='=')&&(olddata=='=')){sprintf(stack1,"%c",data);stack1++;} if((data=='=')&&(olddata!='=')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;} if((data=='[')&&(olddata=='[')){sprintf(stack1,"%c",data);stack1++;} if((data=='[')&&(olddata!='[')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((data==']')&&(olddata==']')){sprintf(stack1,"%c",data);stack1++;} if((data==']')&&(olddata!=']')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((data=='{')&&(olddata=='{')){sprintf(stack1,"%c",data);stack1++;} if((data=='{')&&(olddata!='{')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((data=='}')&&(olddata=='}')){sprintf(stack1,"%c",data);stack1++;} if((data=='}')&&(olddata!='}')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((data=='\\')&&(olddata=='\\')){sprintf(stack1,"%c",data);stack1++;} if((data=='\\')&&(olddata!='\\')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((data==';')&&(olddata==';')){sprintf(stack1,"%c",data);stack1++;} if((data==';')&&(olddata!=';')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((data==':')&&(olddata==':')){sprintf(stack1,"%c",data);stack1++;} if((data==':')&&(olddata!=':')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((data=='\"')&&(olddata=='\"')){sprintf(stack1,"%c",data);stack1++;} if((data=='\"')&&(olddata!='\"')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((data=='\'')&&(olddata=='\'')){sprintf(stack1,"%c",data);stack1++;} if((data=='\'')&&(olddata!='\'')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((data==',')&&(olddata==',')){sprintf(stack1,"%c",data);stack1++;} if((data==',')&&(olddata!=',')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((data=='.')&&(olddata=='.')){sprintf(stack1,"%c",data);stack1++;} if((data=='.')&&(olddata!='.')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((data=='>')&&(olddata=='>')){sprintf(stack1,"%c",data);stack1++;} if((data=='>')&&(olddata!='>')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((data=='<')&&(olddata=='<')){sprintf(stack1,"%c",data);stack1++;} if((data=='<')&&(olddata!='<')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((data=='/')&&(olddata=='/')){sprintf(stack1,"%c",data);stack1++;} if((data=='/')&&(olddata!='/')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} if((data=='?')&&(olddata=='?')){sprintf(stack1,"%c",data);stack1++;} if((data=='?')&&(olddata!='?')){sprintf(stack1,"%c",'\n');stack1++;sprintf(stack1,"%c",data);size++;stack1++;} } } olddata=data; } fclose(filein); return(stack1); } char * GetToken(char *tokens, char *token) { if(sscanf(tokens,"%s",token)==EOF){return(NULL);} return(token); } int CheckList(char*token) { if(token==NULL){return((int)NULL);} if(!strcmp(token,"SetBackgroundColor")){return(1);} if(!strcmp(token,"SetDrawColor")){return(2);} if(!strcmp(token,"SetPixel")){return(3);} if(!strcmp(token,"UnsetPixel")){return(4);} if(!strcmp(token,"DrawLine")){return(5);} if(!strcmp(token,"DrawCircle")){return(6);} if(!strcmp(token,"DrawSquare")){return(7);} if(!strcmp(token,"DrawTriangle")){return(8);} return(0); } int Evaluate(int command,char*token) { int numargs; if(token==NULL){return((int)NULL);} if(command==0){cprintf("ERROR! \'%s\' not recognized.\n",token);return(0);} if(command==1){numargs=3;} if(command==2){numargs=3;} if(command==3){numargs=2;} if(command==4){numargs=2;} if(command==5){numargs=4;} if(command==6){numargs=4;} if(command==7){numargs=5;} if(command==8){numargs=7;} return(numargs); } char* Perform(int num,int command,char *tokens,char*token,char * datam) { int i; sprintf(data,"%s\n",itoa(command,data,10)); data++; data++; sprintf(data,"%s\n",itoa(num,data,10)); data++; data++; for(i=1;i!=(num+3+num);i++) { token=GetToken(tokens,token); if(token==NULL){return(NULL);} tokens=tokens+strlen(token)+1; if((i==1)&&(strcmp(token,"("))){cprintf("Error...\'(\' missing. %s found.\n",token);return(token);} if((i==((2*num)+3+1))&&(strcmp(token,")"))){cprintf("Error...\'(\' missing. %s found.\n",token);return(token);} if((i>1)&&(i<((2*num)+1))&&(strcmp(token,","))){strcat(data,token);strcat(data,"\n");data=data+strlen(token)+1;} } if(strcmp(token,";")){cprintf("Error...\';\' missing. %s found.\n",token);} return(token); } /* Called by GLaux to render scene */ void CALLBACK RenderScene(void) { float LineX1=0; float LineX2=0; float LineY1=0; float LineY2=0; float CircleRadius=0; float OriginX=0; float OriginY=0; float RED=1; float GREEN=1; float BLUE=1; float BackgroundRED=0; float BackgroundGREEN=0; float BackgroundBLUE=0; float TriangleX1=0; float TriangleX2=0; float TriangleX3=0; float TriangleY1=0; float TriangleY2=0; float TriangleY3=0; float RectangleX1=0; float RectangleX2=0; float RectangleY1=0; float RectangleY2=0; float PointX; float PointY; float radius; float vectorX; float vectorY; float vectorY1; float vectorX1; float originX; float originY; float angle; float mode; int i; int num; int command; char temp[256]; char esc; /* Set Clear Color to Black */ glClearColor(BackgroundRED,BackgroundGREEN,BackgroundBLUE,1.0f); /* Clear the window with the clear color */ glClear(GL_COLOR_BUFFER_BIT); /* Set the current drawing color */ glColor3f(RED,GREEN,BLUE); while(esc!=EOF) { esc=sscanf(data,"%s",temp); command=atoi(temp); data=data+strlen(temp)+1; esc=sscanf(data,"%s",temp); num=atoi(temp); data=data+strlen(temp)+1; if(command==2) { esc=sscanf(data,"%s",temp); RED=(float)atof(temp); data=data+strlen(temp)+1; esc=sscanf(data,"%s",temp); GREEN=(float)atof(temp); data=data+strlen(temp)+1; esc=sscanf(data,"%s",temp); BLUE=(float)atof(temp); data=data+strlen(temp)+1; RED=RED/1000; GREEN=GREEN/1000; BLUE=BLUE/1000; } if(command==1) { esc=sscanf(data,"%s",temp); BackgroundRED=(float)atof(temp); data=data+strlen(temp)+1; esc=sscanf(data,"%s",temp); BackgroundGREEN=(float)atof(temp); data=data+strlen(temp)+1; esc=sscanf(data,"%s",temp); BackgroundBLUE=(float)atof(temp); data=data+strlen(temp)+1; BackgroundRED=BackgroundRED/1000; BackgroundGREEN=BackgroundGREEN/1000; BackgroundBLUE=BackgroundBLUE/1000; /* Set Clear Color to Black */ glClearColor(BackgroundRED,BackgroundGREEN,BackgroundBLUE,1.0f); /* Clear the window with the clear color */ glClear(GL_COLOR_BUFFER_BIT); } if(command==7) { esc=sscanf(data,"%s",temp); RectangleX1=(float)atof(temp); data=data+strlen(temp)+1; esc=sscanf(data,"%s",temp); RectangleY1=(float)atof(temp); data=data+strlen(temp)+1; esc=sscanf(data,"%s",temp); RectangleX2=(float)atof(temp); data=data+strlen(temp)+1; esc=sscanf(data,"%s",temp); RectangleY2=(float)atof(temp); data=data+strlen(temp)+1; esc=sscanf(data,"%s",temp); mode=(float)atof(temp); data=data+strlen(temp)+1; /* Set the current drawing color */ glColor3f(RED,GREEN,BLUE); if(mode==1) { /* Draw a filled rectangle with the current color */ glRectf(RectangleX1,RectangleY1,RectangleX2,RectangleY2); } if(mode==0) { /* draw a line */ glBegin(GL_LINES); glVertex2d(RectangleX1,RectangleY1); glVertex2d(RectangleX1,RectangleY2); glVertex2d(RectangleX2,RectangleY1); glVertex2d(RectangleX2,RectangleY2); glVertex2d(RectangleX1,RectangleY1); glVertex2d(RectangleX2,RectangleY1); glVertex2d(RectangleX1,RectangleY2); glVertex2d(RectangleX2,RectangleY2); glEnd(); } } if(command==3) { esc=sscanf(data,"%s",temp); PointX=(float)atof(temp); data=data+strlen(temp)+1; esc=sscanf(data,"%s",temp); PointY=(float)atof(temp); data=data+strlen(temp)+1; /* Set the current drawing color */ glColor3f(RED,GREEN,BLUE); /* set a pixel */ glBegin(GL_POINTS); glVertex2d(PointX,PointY); glEnd(); } if(command==5) { esc=sscanf(data,"%s",temp); LineX1=(float)atof(temp); data=data+strlen(temp)+1; esc=sscanf(data,"%s",temp); LineY1=(float)atof(temp); data=data+strlen(temp)+1; esc=sscanf(data,"%s",temp); LineX2=(float)atof(temp); data=data+strlen(temp)+1; esc=sscanf(data,"%s",temp); LineY2=(float)atof(temp); data=data+strlen(temp)+1; /* Set the current drawing color */ glColor3f(RED,GREEN,BLUE); /* draw a line */ glBegin(GL_LINES); glVertex2d(LineX1,LineY1); glVertex2d(LineX2,LineY2); glEnd(); } if(command==8) { esc=sscanf(data,"%s",temp); TriangleX1=(float)atof(temp); data=data+strlen(temp)+1; esc=sscanf(data,"%s",temp); TriangleY1=(float)atof(temp); data=data+strlen(temp)+1; esc=sscanf(data,"%s",temp); TriangleX2=(float)atof(temp); data=data+strlen(temp)+1; esc=sscanf(data,"%s",temp); TriangleY2=(float)atof(temp); data=data+strlen(temp)+1; esc=sscanf(data,"%s",temp); TriangleX3=(float)atof(temp); data=data+strlen(temp)+1; esc=sscanf(data,"%s",temp); TriangleY3=(float)atof(temp); data=data+strlen(temp)+1; esc=sscanf(data,"%s",temp); mode=(float)atof(temp); data=data+strlen(temp)+1; /* Set the current drawing color */ glColor3f(RED,GREEN,BLUE); if(mode==1) { /* draw a filled triangle */ glBegin(GL_TRIANGLES); glVertex2d(TriangleX1,TriangleY1); glVertex2d(TriangleX2,TriangleY2); glVertex2d(TriangleX3,TriangleY3); glEnd(); } if(mode==0) { /* draw a line */ glBegin(GL_LINES); glVertex2d(TriangleX1,TriangleY1); glVertex2d(TriangleX2,TriangleY2); glVertex2d(TriangleX2,TriangleY2); glVertex2d(TriangleX3,TriangleY3); glVertex2d(TriangleX3,TriangleY3); glVertex2d(TriangleX1,TriangleY1); glEnd(); } } if(command==6) { esc=sscanf(data,"%s",temp); originX=(float)atof(temp); data=data+strlen(temp)+1; esc=sscanf(data,"%s",temp); originY=(float)atof(temp); data=data+strlen(temp)+1; esc=sscanf(data,"%s",temp); radius=(float)atof(temp); data=data+strlen(temp)+1; esc=sscanf(data,"%s",temp); mode=(float)atof(temp); data=data+strlen(temp)+1; /* Set the current drawing color */ glColor3f(RED,GREEN,BLUE); if(mode==1) { /* draw a solid disc from a bunch of triangles */ vectorY1=originY; vectorX1=originX; glBegin(GL_TRIANGLES); for(i=0;i<=360;i++) { angle=(float)(((double)i)/57.29577957795135); vectorX=originX+(radius*(float)sin((double)angle)); vectorY=originY+(radius*(float)cos((double)angle)); glVertex2d(originX,originY); glVertex2d(vectorX1,vectorY1); glVertex2d(vectorX,vectorY); vectorY1=vectorY; vectorX1=vectorX; } glEnd(); } if(mode==0) { /* draw a circle from a bunch of short lines */ vectorY1=originY+radius; vectorX1=originX; glBegin(GL_LINE_STRIP); for(angle=0.0f;angle<=(2.0f*3.14159);angle+=0.01f) { vectorX=originX+(radius*(float)sin((double)angle)); vectorY=originY+(radius*(float)cos((double)angle)); glVertex2d(vectorX1,vectorY1); vectorY1=vectorY; vectorX1=vectorX; } glEnd(); } } } /*flush the command queue */ glFlush(); data=temp2; } PROGRAM ENDS