//-----------------------------------------------------------------------------
// Velmi jednoduchy prohlizec souboru typu SLD (Slide)
//
// 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 SVG viewer" // titulek okna
#define WINDOW_WIDTH 800 // pocatecni velikost okna
#define WINDOW_HEIGHT 600
// typ prikazu
typedef enum {
ABSOLUTE_VECTOR,
OFFSET_VECTOR,
SOLID_FILL,
END_POINT,
NEW_COLOR
} Command;
typedef struct AbsoluteVector {
short int x1;
short int y1;
short int x2;
short int y2;
} AbsoluteVector;
typedef struct OffsetVector {
signed char x1;
signed char y1;
signed char x2;
signed char y2;
} OffsetVector;
typedef struct SolidFill {
} SolidFill;
typedef struct EndPoint {
signed char x;
signed char y;
} EndPoint;
typedef struct NewColor {
unsigned char color;
} NewColor;
// jeden zaznam ziskany ze souboru HPGL
typedef struct Item {
Command cmd; // prikaz
struct Item *next; // vazba v linearnim seznamu
union { // anonymni unie
AbsoluteVector *absoluteVector;
OffsetVector *offsetVector;
SolidFill *solidFill;
EndPoint *endPoint;
NewColor *newColor;
};
} 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 addAbsoluteVector(AbsoluteVector *absoluteVector)
{
Item *item=(Item*)malloc(sizeof(Item));
item->cmd=ABSOLUTE_VECTOR;
item->next=NULL; // prvek bude umisten na konci seznamu
item->absoluteVector=absoluteVector;
// 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
}
}
//-----------------------------------------------------------------------------
// Vlozeni polozky do linearniho seznamu
//-----------------------------------------------------------------------------
void addOffsetVector(OffsetVector *offsetVector)
{
Item *item=(Item*)malloc(sizeof(Item));
item->cmd=OFFSET_VECTOR;
item->next=NULL; // prvek bude umisten na konci seznamu
item->offsetVector=offsetVector;
// 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
}
}
//-----------------------------------------------------------------------------
// Vlozeni polozky do linearniho seznamu
//-----------------------------------------------------------------------------
void addSolidFill(SolidFill *solidFill)
{
Item *item=(Item*)malloc(sizeof(Item));
item->cmd=SOLID_FILL;
item->next=NULL; // prvek bude umisten na konci seznamu
item->solidFill=solidFill;
// 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
}
}
//-----------------------------------------------------------------------------
// Vlozeni polozky do linearniho seznamu
//-----------------------------------------------------------------------------
void addEndPoint(EndPoint *endPoint)
{
Item *item=(Item*)malloc(sizeof(Item));
item->cmd=END_POINT;
item->next=NULL; // prvek bude umisten na konci seznamu
item->endPoint=endPoint;
// 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
}
}
//-----------------------------------------------------------------------------
// Vlozeni polozky do linearniho seznamu
//-----------------------------------------------------------------------------
void addNewColor(NewColor *newColor)
{
Item *item=(Item*)malloc(sizeof(Item));
item->cmd=NEW_COLOR;
item->next=NULL; // prvek bude umisten na konci seznamu
item->newColor=newColor;
// 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
}
}
//-----------------------------------------------------------------------------
// Precteni SLD souboru
//-----------------------------------------------------------------------------
int readItems(char *fileName)
{
char header[31];
FILE *fin=fopen(fileName, "rb");
if (!fin) return 0;
// nacteni hlavicky
//printf("%d\n", ftell(fin));
fread(header, 31, 1, fin);
//printf("%d\n", ftell(fin));
puts(header);
// smycka, ve ktere se zanalyzuje cely soubor typu SLD
while(1) {
int b1;
int b2;
b1=fgetc(fin);
b2=fgetc(fin);
// test na ukonceni smycky -> konec souboru
if (b1==EOF || b2==EOF)
break;
printf("(%6d) %02x %02x\t", ftell(fin), b1, b2);
if (b2>=0x00 && b2<=0x7f) {
unsigned char array[6];
AbsoluteVector *a=(AbsoluteVector*)malloc(sizeof(AbsoluteVector));
puts("absolute vector");
fread(array, 6, 1, fin);
a->x1=(b2<<8)+b1;
a->y1=array[0]+(array[1]<<8);
a->x2=array[2]+(array[3]<<8);
a->y2=array[4]+(array[5]<<8);
addAbsoluteVector(a);
}
else {
switch (b2) {
case 0xfb: // offset vektor
puts("offset");
signed char array[3];
OffsetVector *o=(OffsetVector*)malloc(sizeof(OffsetVector));
fread(array, 3, 1, fin);
o->x1=b1;
o->y1=array[0];
o->x2=array[1];
o->y2=array[2];
addOffsetVector(o);
break;
case 0xfc: // konec souboru
puts("end of file");
break;
case 0xfd: // vypln - neimplementovano
puts("solid fill");
fread(header, 4, 1, fin);
break;
case 0xfe: // koncovy bod vektoru (relativni)
puts("endpoint vector");
signed char y=fgetc(fin);
EndPoint *e=(EndPoint*)malloc(sizeof(EndPoint));
e->x=b1;
e->y=y;
addEndPoint(e);
break;
case 0xff:
puts("new color");
NewColor *c=(NewColor*)malloc(sizeof(NewColor));
c->color=b1;
addNewColor(c);
break;
default:
puts("undefined");
break;
}
}
}
fclose(fin);
return 1;
}
//-----------------------------------------------------------------------------
// Prekresleni vektorove kresby
//-----------------------------------------------------------------------------
void redrawDrawing(double scale, // meritko obrazce
double xpos, // posun obrazce
double ypos)
{
// velmi zjednodusena paleta
static float palette[][3]={
{1.0, 1.0, 1.0},
{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},
{0.5, 0.5, 0.5},
};
Item *item=p_first;
int x1=0, y1=0, x2=0, y2=0;
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
unsigned char c;
// 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);
glColor3f(1.0, 1.0, 1.0);
// projit celym seznamem a aplikovat v nem ulozene prikazy
while (item!=NULL) {
Command cmd=item->cmd; // nacist prikaz
switch (cmd) {
case ABSOLUTE_VECTOR: // absolutni vektor - dva body
x1=item->absoluteVector->x1;
y1=item->absoluteVector->y1;
x2=item->absoluteVector->x2;
y2=item->absoluteVector->y2;
glBegin(GL_LINES);
glVertex2i((int)x1, (int)y1);
glVertex2i((int)x2, (int)y2);
glEnd();
break;
case OFFSET_VECTOR: // relativni vektor - dva body
x2=x1+item->offsetVector->x1;
y2=y1+item->offsetVector->y1;
x1=x1+item->offsetVector->x1;
y1=y1+item->offsetVector->y1;
glBegin(GL_LINES);
glVertex2i((int)x1, (int)y1);
glVertex2i((int)x2, (int)y2);
glEnd();
break;
case END_POINT: // koncovy bod vektoru
x2=x1+item->endPoint->x;
y2=y1+item->endPoint->y;
glBegin(GL_LINES);
glVertex2i((int)x1, (int)y1);
glVertex2i((int)x2, (int)y2);
glEnd();
x1=x2;
y1=y2;
break;
case SOLID_FILL: // neimplementovano
break;
case NEW_COLOR: // nastaveni barvy
c=item->newColor->color;
r=palette[c & 0x07][0];
g=palette[c & 0x07][1];
b=palette[c & 0x07][2];
glColor3f(r, g, b);
break;
default: // ostatni prikazy ignorujeme
break;
}
item=item->next; // prechod na dalsi polozku
}
}
//-----------------------------------------------------------------------------
// 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-=5; redraw=1; glutPostRedisplay(); break;
case GLUT_KEY_RIGHT: xpos+=5; redraw=1; glutPostRedisplay(); break;
case GLUT_KEY_UP: ypos+=5; redraw=1; glutPostRedisplay(); break;
case GLUT_KEY_DOWN: ypos-=5; 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
//-----------------------------------------------------------------------------