//-----------------------------------------------------------------------------
// Velmi jednoduchy prohlizec souboru typu PLT upraveny pro pouziti se soubory
// urcenymi pro plotter HP 7475
//
// Autor: Pavel Tisnovsky
//
//-----------------------------------------------------------------------------
#ifdef __BORLANDC__
#include <windows.h>
#endif
#include <GL/glut.h> // hlavickovy soubor funkci GLUTu a OpenGL
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#define WINDOW_TITLE "simple HPGL viewer" // titulek okna
#define WINDOW_WIDTH 800 // pocatecni velikost okna
#define WINDOW_HEIGHT 600
// typ prikazu
typedef enum {
PEN_UP, // zvednuti kresliciho pera
PEN_DOWN, // spusteni kresliciho pera
MOVE_TO, // presun kresliciho pera
SELECT_PEN // vyber kresliciho pera ~ vyber barvy
} Command;
// jeden zaznam ziskany ze souboru HPGL
typedef struct Item {
Command cmd; // prikaz - (PEN_UP, PEN_DOWN, MOVE_TO, SELECT_PEN)
double x; // souradnice
double y;
int pen; // barva pera
struct Item *next; // vazba v linearnim seznamu
} Item;
double scale=1.0;
double xpos=0.0;
double ypos=0.0;
int redraw=1;
Item *p_first; // ukazatele v linearnim seznamu
Item *p_last;
// informace o okne
struct {
int width;
int height;
} window={WINDOW_WIDTH, WINDOW_HEIGHT};
// informace o mysi
struct {
int status;
int xtran0, xtran1, xtran2;
int ytran0, ytran1, ytran2;
int ztran0, ztran1, ztran2;
} mouse={0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
//-----------------------------------------------------------------------------
// Inicializace linearniho seznamu
//-----------------------------------------------------------------------------
void initItem(void)
{
p_first=NULL;
p_last=NULL;
}
//-----------------------------------------------------------------------------
// Vlozeni polozky do linearniho seznamu
//-----------------------------------------------------------------------------
void addItem(Command cmd, double x, double y, int pen)
{
Item *item=(Item*)malloc(sizeof(Item));
item->cmd=cmd;
item->x=x;
item->y=y;
item->pen=pen;
item->next=NULL; // prvek bude umisten na konci seznamu
// seznam je prazdny
if (p_first==NULL) {
p_first=item; // prvni i posledni prvek
p_last=item; // seznamu jsou shodne
}
// pridani polozky do neprazdneho seznamu
else {
p_last->next=item; // zretezeni prvku na konec seznamu
p_last=item; // aktualizace ukazatele na posledni prvek
/*
Item *p=p_first;
while (p->next !=NULL)
p=p->next;
p->next=item;
*/
}
}
//-----------------------------------------------------------------------------
// Prescteni HPGL souboru urceneho pro HP7475
//-----------------------------------------------------------------------------
int readItems(char *fileName)
{
FILE *fin=fopen(fileName, "rt");
int c;
char s[100];
if (!fin) return 0;
// smycka, ve ktere se zanalyzuje cely soubor HPGL
do {
int i;
// nacteni jednoho prikazu (oddelovacem je vetsinou strednik)
for (i=0; (c=fgetc(fin))!=';' && c!=EOF; i++) {
// tato podminka je nutna pro ovladace,
// ktere generuji kod ve stylu 'PUPA10,10'
// misto 'PU;PA10,10
if (i==2 && isalpha(c)) {
ungetc(c, fin);
break;
}
// prevod znaku na velka pismena (pro jistotu)
s[i]=(c>='a' && c<='z') ? c-'a'+'A':c;
}
s[i]=0; // ukonceni retezce
if (!strcmp(s, "PU")) {
addItem(PEN_UP, 0, 0, 0);
}
if (!strcmp(s, "PD")) {
addItem(PEN_DOWN, 0, 0, 0);
}
if (!strncmp(s, "SP", 2)) { // prikaz SP
int pen=strtol(s+2, NULL, 10); // = nacteme barvu pera
addItem(SELECT_PEN, 0, 0, pen);
}
if (!strncmp(s, "PA", 2)) { // prikaz PA
double x, y; // = musime nacist obe souradnice
for (i=0; s[i]!='-' && s[i]!='+' && !isdigit(s[i]); i++)
;
x=strtod(s+i, NULL);
i++;
for (; s[i]!='-' && s[i]!='+' && s[i]!=','; i++)
;
i++;
y=strtod(s+i, NULL);
addItem(MOVE_TO, x, y, 0);
}
} while (c!=EOF); // cteni az do konce souboru
fclose(fin);
return 1;
}
//-----------------------------------------------------------------------------
// Prekresleni vektorove kresby
//-----------------------------------------------------------------------------
void redrawDrawing(double scale, // meritko obrazce
double xpos, // posun obrazce
double ypos)
{
Item *item=p_first;
double x1=0, y1=0, x2=0, y2=0; // souradnice pro vypocet usecek
float r=1.0, g=1.0, b=1.0; // barva kresliciho pera
float scale2=mouse.ztran0/100.0+1.0; // zmena meritka zadana mysi
Command pen=PEN_DOWN;
// posun a zmena meritka kresby
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(xpos, ypos, 0); // posun zadany klavesnici
glTranslatef(mouse.xtran0, -mouse.ytran0, 0); // posun zadany mysi
// posunuti pocatku (pro zmenu meritka vuci stredu okna
// je nutna mala programova uprava)
glTranslatef(window.width/2, window.height/2, 0);
glScalef(scale, scale, scale); // zmena meritka zadana klavesnici
glScalef(scale2, scale2, scale2); // zmena meritka zadana mysi
glScalef(0.1, 0.1, 0.1);
glTranslatef(-window.width/2, -window.height/2, 0);
// projit celym seznamem a aplikovat v nem ulozene prikazy
while (item!=NULL) {
Command cmd=item->cmd; // nacist prikaz
double x=item->x; // nacist souradnice
double y=item->y;
int pencolor=item->pen; // nacist barvu pera
item=item->next; // prechod na dalsi polozku
switch (cmd) {
case PEN_UP: // zvednuti kresliciho pera
pen=PEN_UP;
break;
case PEN_DOWN: // polozeni kresliciho pera
pen=PEN_DOWN;
break;
case MOVE_TO: // zmena pozice kresliciho pera
if (pen==PEN_UP) { // PEN_UP - presun bez kresleni
x1=x;
y1=y;
}
else { // PEN_DOWN - kreslime
x2=x;
y2=y;
glColor3f(r, g, b); // nastavit barvu
glBegin(GL_LINES); // a vykreslit usecku
glVertex2d(x1, y1);
glVertex2d(x2, y2);
glEnd();
x1=x; // zapamatovat si pozici
y1=y; // pro dalsi MOVE_TO
}
break;
case SELECT_PEN: // zmena barvy pera
{
static float palette[][3]={ // static=alokace 1x za behu
{0.0, 0.0, 1.0},
{0.0, 1.0, 0.0},
{0.0, 1.0, 1.0},
{1.0, 0.0, 0.0},
{1.0, 0.0, 1.0},
{1.0, 1.0, 0.0},
{1.0, 1.0, 1.0},
{0.5, 0.5, 0.5},
};
if (pencolor>=0 && pencolor<=7) { // HP7475 ma osm per
r=palette[pencolor][0];
g=palette[pencolor][1];
b=palette[pencolor][2];
}
else { // kazdy jiny index=bila barva
r=1.0;
g=1.0;
b=1.0;
}
}
break;
default: // ostatni prikazy ignorujeme
break;
}
}
}
//-----------------------------------------------------------------------------
// Funkce volana pro inicializaci vykreslovani
//-----------------------------------------------------------------------------
void onInit(void)
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // barva pozadi
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // mod ulozeni pixelu
glPointSize(1.0f);
glLineWidth(1.0f);
glEnable(GL_POINT_SMOOTH);
glEnable(GL_LINE_SMOOTH);
}
//-----------------------------------------------------------------------------
// Nastaveni souradneho systemu v zavislosti na velikosti okna
//-----------------------------------------------------------------------------
void onResize(int w, int h) // argumenty w a h reprezentuji novou velikost okna
{
glViewport(0, 0, w, h); // viditelna oblast pres cele okno
glMatrixMode(GL_PROJECTION); // zacatek modifikace projekcni matice
glLoadIdentity(); // vymazani projekcni matice (=identita)
glOrtho(0, w, 0, h, -1, 1); // mapovani abstraktnich souradnic do souradnic okna
window.width=w;
window.height=h;
}
//-----------------------------------------------------------------------------
// Tato callback funkce je zavolana pri kazdem prekresleni okna
//-----------------------------------------------------------------------------
void onDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT); // vymazani vsech bitovych rovin barvoveho bufferu
glDrawBuffer(GL_BACK); // pixmapa se bude kreslit do zadniho barvoveho bufferu
redrawDrawing(scale, xpos, ypos);
glFlush(); // provedeni a vykresleni vsech zmen
glutSwapBuffers();
}
//-----------------------------------------------------------------------------
// Tato callback funkce je zavolana pri stlaceni ASCII klavesy
//-----------------------------------------------------------------------------
#ifdef __BORLANDC__
#pragma option -w-par
#endif
void onKeyboard(unsigned char key, int x, int y)
{
key=(key>='A' && key<='Z') ? key-'A'+'a': key;
if (key>='0' && key<='9') { glutPostRedisplay(); } // nastaveni barvove palety
switch (key) {
case 27: // pokud byla stlacena klavesa ESC, konec programu
case 'q': exit(0); break; // totez co klavesa ESC
default: break;
}
}
#ifdef __BORLANDC__
#pragma option -w+par
#endif
//-----------------------------------------------------------------------------
// Tato callback funkce je zavolana pri stlaceni non-ASCII klavesy
//-----------------------------------------------------------------------------
#ifdef __BORLANDC__
#pragma option -w-par
#endif
void onSpecial(int key, int x, int y)
{
// posun kresby a zmena meritka
switch (key) {
case GLUT_KEY_LEFT: xpos-=25; redraw=1; glutPostRedisplay(); break;
case GLUT_KEY_RIGHT: xpos+=25; redraw=1; glutPostRedisplay(); break;
case GLUT_KEY_UP: ypos+=25; redraw=1; glutPostRedisplay(); break;
case GLUT_KEY_DOWN: ypos-=25; redraw=1; glutPostRedisplay(); break;
case GLUT_KEY_PAGE_UP: scale*=1.1; redraw=1; glutPostRedisplay(); break;
case GLUT_KEY_PAGE_DOWN: scale/=1.1; redraw=1; glutPostRedisplay(); break;
default: break;
}
}
#ifdef __BORLANDC__
#pragma option -w+par
#endif
//-----------------------------------------------------------------------------
// Tato callback funkce je zavolana pri stlaceni ci pusteni tlacitka mysi
//-----------------------------------------------------------------------------
void onMouse(int button, int state, int x, int y)
{
switch (button) {
case GLUT_LEFT_BUTTON: // posun kresby
if (state==GLUT_DOWN) {
mouse.status=1;
mouse.xtran1=x;
mouse.ytran1=y;
}
else {
mouse.status=0;
mouse.xtran2=mouse.xtran0;
mouse.ytran2=mouse.ytran0;
}
break;
case GLUT_RIGHT_BUTTON: // zmena meritka kresby
if (state==GLUT_DOWN) {
mouse.status=2;
mouse.ztran1=y;
}
else {
mouse.status=0;
mouse.ztran2=mouse.ztran0;
}
break;
default:
break;
}
}
//-----------------------------------------------------------------------------
// Tato callback funkce je zavolana pri posunu kurzoru mysi
//-----------------------------------------------------------------------------
void onMouseMotion(int x, int y)
{
switch (mouse.status) {
case 1: // posun kresby
mouse.xtran0=mouse.xtran2+x-mouse.xtran1;
mouse.ytran0=mouse.ytran2+y-mouse.ytran1;
glutPostRedisplay();
break;
case 2: // zmena meritka kresby
mouse.ztran0=mouse.ztran2+y-mouse.ztran1;
glutPostRedisplay();
break;
default:
break;
}
}
//-----------------------------------------------------------------------------
// Hlavni funkce konzolove aplikace
//-----------------------------------------------------------------------------
int main(int argc, char **argv)
{
glutInit(&argc, argv); // inicializace knihovny GLUT
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutCreateWindow(WINDOW_TITLE); // vytvoreni okna pro kresleni
glutReshapeWindow(WINDOW_WIDTH, WINDOW_HEIGHT);// zmena velikosti okna
glutPositionWindow(100, 100); // pozice leveho horniho rohu okna
glutDisplayFunc(onDisplay); // registrace funkce volane pri prekreslovani okna
glutReshapeFunc(onResize); // registrace funkce volane pri zmene velikosti okna
glutKeyboardFunc(onKeyboard); // registrace funkce volane pri stlaceni klavesy
glutSpecialFunc(onSpecial); // registrace funkce volane pri stlaceni specialni klavesy
glutMouseFunc(onMouse); // funkce volana pri stlaceni tlacitka mysi
glutMotionFunc(onMouseMotion); // funkce volana pri posunu mysi
onInit(); // inicializace vykreslovani
if (!readItems(argv[1])) return 0; // nacteni celeho souboru s kresbou
glutMainLoop(); // nekonecna smycka, kde se volaji zaregistrovane funkce
return 0; // navratova hodnota vracena operacnimu systemu
}
//-----------------------------------------------------------------------------
// finito
//-----------------------------------------------------------------------------