//-----------------------------------------------------------------------------
// Velmi jednoduchy prohlizec souboru typu DXF upraveny pro zobrazeni
// zakladnich 2D entit
//
// 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 DXF 2D viewer"  // titulek okna
#define WINDOW_WIDTH    800                     // pocatecni velikost okna
#define WINDOW_HEIGHT   600

#define MAX_LINE_LENGTH         1024
#define MAX_TEXT_LENGTH         256

void callback_begin_header(char *input);
void callback_end_header(char *input);
void callback_begin_blocks(char *input);
void callback_end_blocks(char *input);
void callback_begin_entities(char *input);
void callback_end_entities(char *input);

void callback_line_setcolor(char *input);
void callback_line_setlayer(char *input);
void callback_line_set_x1(char *input);
void callback_line_set_y1(char *input);
void callback_line_set_x2(char *input);
void callback_line_set_y2(char *input);
void callback_line_color(char *input);
void callback_line_layer(char *input);
void callback_line_x1(char *input);
void callback_line_y1(char *input);
void callback_line_x2(char *input);
void callback_line_y2(char *input);
void callback_line_store(char *input);

void callback_circle_setcolor(char *input);
void callback_circle_setlayer(char *input);
void callback_circle_set_x(char *input);
void callback_circle_set_y(char *input);
void callback_circle_set_r(char *input);
void callback_circle_color(char *input);
void callback_circle_layer(char *input);
void callback_circle_x(char *input);
void callback_circle_y(char *input);
void callback_circle_r(char *input);
void callback_circle_store(char *input);

void callback_arc_setcolor(char *input);
void callback_arc_setlayer(char *input);
void callback_arc_set_x(char *input);
void callback_arc_set_y(char *input);
void callback_arc_set_r(char *input);
void callback_arc_set_u1(char *input);
void callback_arc_set_u2(char *input);
void callback_arc_color(char *input);
void callback_arc_layer(char *input);
void callback_arc_x(char *input);
void callback_arc_y(char *input);
void callback_arc_r(char *input);
void callback_arc_u1(char *input);
void callback_arc_u2(char *input);
void callback_arc_store(char *input);

void callback_text_setcolor(char *input);
void callback_text_setlayer(char *input);
void callback_text_set_x(char *input);
void callback_text_set_y(char *input);
void callback_text_set_text(char *input);
void callback_text_color(char *input);
void callback_text_layer(char *input);
void callback_text_x(char *input);
void callback_text_y(char *input);
void callback_text_text(char *input);
void callback_text_store(char *input);

// graficke entity {{{

typedef struct GfxPoint {
    int     color;
    int     layer;
    double  x;
    double  y;
    double  angle;
} GfxPoint;

typedef struct GfxLine {
    int     color;
    int     layer;
    double  x1;
    double  y1;
    double  x2;
    double  y2;
} GfxLine;

typedef struct GfxCircle {
    int     color;
    int     layer;
    double  x;
    double  y;
    double  r;
} GfxCircle;

typedef struct GfxArc {
    int     color;
    int     layer;
    double  x;
    double  y;
    double  r;
    double  u1;
    double  u2;
} GfxArc;

typedef struct GfxText {
    int     color;
    int     layer;
    double  x;
    double  y;
    char    str[MAX_TEXT_LENGTH];
} GfxText;

// }}}
// typ grafickych entit {{{

typedef enum Type {
    T_POINT,
    T_LINE,
    T_CIRCLE,
    T_ARC,
    T_TEXT
} Type;

// }}}
// linearni seznam s entitami {{{

typedef struct Item {
    Type    type;
    void   *entity;
    struct Item *next;          // vazba v linearnim seznamu
} Item;

// }}}

// stav KA {{{

typedef enum t_dxf_status {
    Unknown,
    Delimiter,
    Section,
    SecName,
    Header,
    Blocks,
    Entities,
    Line,
    LineLayer,
    LineColor,
    LineX1,
    LineY1,
    LineX2,
    LineY2,
    Circle,
    CircleLayer,
    CircleColor,
    CircleX,
    CircleY,
    CircleR,
    ArcEntity,
    ArcLayer,
    ArcColor,
    ArcX,
    ArcY,
    ArcR,
    ArcU1,
    ArcU2,
    TextEntity,
    TextLayer,
    TextColor,
    TextX,
    TextY,
    TextText,
    End
} t_dxf_status;

// }}}
// prechod mezi stavy KA {{{

typedef struct t_transition {
    t_dxf_status status;
    char         *input;
    t_dxf_status newStatus;
    void     (*fce)(char *input);
} t_transition;

// }}}
// vlastni konfigurace KA {{{

static const t_transition transitions[]={
    {Unknown,    "  0",         Delimiter,     NULL},
    {Delimiter,  "SECTION",     Section,       NULL},
    {Section,    "  2",         SecName,       NULL},
    {SecName,    "HEADER",      Header,        callback_begin_header},
    {SecName,    "BLOCKS",      Blocks,        callback_begin_blocks},
    {SecName,    "ENTITIES",    Entities,      callback_begin_entities},
    {Header,     "  0",         Header,        NULL},
    {Header,     "ENDSEC",      Unknown,       callback_end_header},
    {Blocks,     "  0",         Blocks,        NULL},
    {Blocks,     "ENDSEC",      Unknown,       callback_end_blocks},
    {Entities,   "  0",         Entities,      NULL},
    {Entities,   "ENDSEC",      Unknown,       callback_end_entities},

    {Entities,   "LINE",        Line,          NULL},
    {Line,       "  8",         LineLayer,     callback_line_layer},
    {Line,       " 62",         LineColor,     callback_line_color},
    {Line,       " 10",         LineX1,        callback_line_x1},
    {Line,       " 20",         LineY1,        callback_line_y1},
    {Line,       " 11",         LineX2,        callback_line_x2},
    {Line,       " 21",         LineY2,        callback_line_y2},
    {Line,       "  0",         Entities,      callback_line_store},

    {Entities,   "CIRCLE",      Circle,        NULL},
    {Circle,     "  8",         CircleLayer,   callback_circle_layer},
    {Circle,     " 62",         CircleColor,   callback_circle_color},
    {Circle,     " 10",         CircleX,       callback_circle_x},
    {Circle,     " 20",         CircleY,       callback_circle_y},
    {Circle,     " 40",         CircleR,       callback_circle_r},
    {Circle,     "  0",         Entities,      callback_circle_store},

    {Entities,   "ARC",         ArcEntity,     NULL},
    {ArcEntity,  "  8",         ArcLayer,      callback_arc_layer},
    {ArcEntity,  " 62",         ArcColor,      callback_arc_color},
    {ArcEntity,  " 10",         ArcX,          callback_arc_x},
    {ArcEntity,  " 20",         ArcY,          callback_arc_y},
    {ArcEntity,  " 40",         ArcR,          callback_arc_r},
    {ArcEntity,  " 50",         ArcU1,         callback_arc_u1},
    {ArcEntity,  " 51",         ArcU2,         callback_arc_u2},
    {ArcEntity,  "  0",         Entities,      callback_arc_store},

    {Entities,   "TEXT",        TextEntity,    NULL},
    {TextEntity, "  8",         TextLayer,     callback_text_layer},
    {TextEntity, " 62",         TextColor,     callback_text_color},
    {TextEntity, " 10",         TextX,         callback_text_x},
    {TextEntity, " 20",         TextY,         callback_text_y},
    {TextEntity, "  1",         TextText,      callback_text_text},
    {TextEntity, "  0",         Entities,      callback_text_store},

    {End,        "",            End,           NULL} // jen ukonceni pro pruchod stavy KA
};

// }}}

// 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};

// }}}

// globalni promenne {{{

double scale=1.0;
double xpos=0.0;
double ypos=0.0;
int    redraw=1;
void   (*special_callback)(char *input)=NULL;
t_dxf_status    status=Unknown; // inicializace KA

Item *p_first;                  // ukazatele v linearnim seznamu
Item *p_last;
GfxLine   g_line;               // pomocne entity pro postupne naplnovani
GfxCircle g_circle;
GfxArc    g_arc;
GfxText   g_text;
int       colorStyle=1;



// }}}
// initItem() {{{



//-----------------------------------------------------------------------------
// Inicializace linearniho seznamu
//-----------------------------------------------------------------------------
void initItem(void)
{
    p_first=NULL;
    p_last=NULL;
}



// }}}
// addItem() {{{



//-----------------------------------------------------------------------------
// Vlozeni polozky do linearniho seznamu
//-----------------------------------------------------------------------------
void addItem(Type type, void *entity)
{
    Item *item=(Item*)malloc(sizeof(Item));
    item->type=type;
    item->entity=entity;
    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;
        */
    }
}



// }}}

// callback_begin_header() {{{



void callback_begin_header(char *input)
{
    puts("    begin header");
}



// }}}
// callback_end_header() {{{



void callback_end_header(char *input)
{
    puts("    end header");
}



// }}}
// callback_begin_blocks() {{{



void callback_begin_blocks(char *input)
{
    puts("    begin blocks");
}



// }}}
// callback_end_blocks() {{{



void callback_end_blocks(char *input)
{
    puts("    end blocks");
}



// }}}
// callback_begin_entities() {{{



void callback_begin_entities(char *input)
{
    puts("    begin entities");
}



// }}}
// callback_end_entities() {{{



void callback_end_entities(char *input)
{
    puts("    end entities");
}



// }}}

// callback_line_setcolor() {{{



void callback_line_setcolor(char *input)
{
    g_line.color=atoi(input);
    special_callback=NULL;
    status=Line;
}



// }}}
// callback_line_setlayer() {{{



void callback_line_setlayer(char *input)
{
    int i, j;
    // velmi primitivni vypocet hashe
    for (i=0, j=0; input[i]; i++)
        j+=input[i];
    g_line.layer=j;
    special_callback=NULL;
    status=Line;
}



// }}}
// callback_line_set_x1() {{{



void callback_line_set_x1(char *input)
{
    g_line.x1=atof(input);
    special_callback=NULL;
    status=Line;
}



// }}}
// callback_line_set_y1() {{{



void callback_line_set_y1(char *input)
{
    g_line.y1=atof(input);
    special_callback=NULL;
    status=Line;
}



// }}}
// callback_line_set_x2() {{{



void callback_line_set_x2(char *input)
{
    g_line.x2=atof(input);
    special_callback=NULL;
    status=Line;
}



// }}}
// callback_line_set_y2() {{{



void callback_line_set_y2(char *input)
{
    g_line.y2=atof(input);
    special_callback=NULL;
    status=Line;
}



// }}}
// callback_line_color() {{{



void callback_line_color(char *input)
{
    special_callback=callback_line_setcolor;
}



// }}}
// callback_line_layer() {{{



void callback_line_layer(char *input)
{
    special_callback=callback_line_setlayer;
}



// }}}
// callback_line_x1() {{{



void callback_line_x1(char *input)
{
    special_callback=callback_line_set_x1;
}



// }}}
// callback_line_y1() {{{



void callback_line_y1(char *input)
{
    special_callback=callback_line_set_y1;
}



// }}}
// callback_line_x2() {{{



void callback_line_x2(char *input)
{
    special_callback=callback_line_set_x2;
}



// }}}
// callback_line_y2() {{{



void callback_line_y2(char *input)
{
    special_callback=callback_line_set_y2;
}



// }}}
// callback_line_store() {{{



void callback_line_store(char *input)
{
    GfxLine *l=(GfxLine *)malloc(sizeof(GfxLine));
    l->x1=g_line.x1;
    l->y1=g_line.y1;
    l->x2=g_line.x2;
    l->y2=g_line.y2;
    l->color=g_line.color;
    l->layer=g_line.layer;
    addItem(T_LINE, l);
}



// }}}

// callback_circle_setcolor() {{{



void callback_circle_setcolor(char *input)
{
    g_circle.color=atoi(input);
    special_callback=NULL;
    status=Circle;
}



// }}}
// callback_circle_setlayer() {{{



void callback_circle_setlayer(char *input)
{
    int i, j;
    // velmi primitivni vypocet hashe
    for (i=0, j=0; input[i]; i++)
        j+=input[i];
    g_circle.layer=j;
    special_callback=NULL;
    status=Circle;
}



// }}}
// callback_circle_set_x() {{{



void callback_circle_set_x(char *input)
{
    g_circle.x=atof(input);
    special_callback=NULL;
    status=Circle;
}



// }}}
// callback_circle_set_y() {{{



void callback_circle_set_y(char *input)
{
    g_circle.y=atof(input);
    special_callback=NULL;
    status=Circle;
}



// }}}
// callback_circle_set_r() {{{



void callback_circle_set_r(char *input)
{
    g_circle.r=atof(input);
    special_callback=NULL;
    status=Circle;
}



// }}}
// callback_circle_color() {{{



void callback_circle_color(char *input)
{
    special_callback=callback_circle_setcolor;
}



// }}}
// callback_circle_layer() {{{



void callback_circle_layer(char *input)
{
    special_callback=callback_circle_setlayer;
}



// }}}
// callback_circle_x() {{{



void callback_circle_x(char *input)
{
    special_callback=callback_circle_set_x;
}



// }}}
// callback_circle_y() {{{



void callback_circle_y(char *input)
{
    special_callback=callback_circle_set_y;
}



// }}}
// callback_circle_r() {{{



void callback_circle_r(char *input)
{
    special_callback=callback_circle_set_r;
}



// }}}
// callback_circle_store() {{{



void callback_circle_store(char *input)
{
    GfxCircle *c=(GfxCircle *)malloc(sizeof(GfxCircle));
    c->x=g_circle.x;
    c->y=g_circle.y;
    c->r=g_circle.r;
    c->color=g_circle.color;
    c->layer=g_circle.layer;
    addItem(T_CIRCLE, c);
}



// }}}

// callback_arc_setcolor() {{{



void callback_arc_setcolor(char *input)
{
    g_arc.color=atoi(input);
    special_callback=NULL;
    status=ArcEntity;
}



// }}}
// callback_arc_setlayer() {{{



void callback_arc_setlayer(char *input)
{
    int i, j;
    // velmi primitivni vypocet hashe
    for (i=0, j=0; input[i]; i++)
        j+=input[i];
    g_arc.layer=j;
    special_callback=NULL;
    status=ArcEntity;
}



// }}}
// callback_arc_set_x() {{{



void callback_arc_set_x(char *input)
{
    g_arc.x=atof(input);
    special_callback=NULL;
    status=ArcEntity;
}



// }}}
// callback_arc_set_y() {{{



void callback_arc_set_y(char *input)
{
    g_arc.y=atof(input);
    special_callback=NULL;
    status=ArcEntity;
}



// }}}
// callback_arc_set_r() {{{



void callback_arc_set_r(char *input)
{
    g_arc.r=atof(input);
    special_callback=NULL;
    status=ArcEntity;
}



// }}}
// callback_arc_set_u1() {{{



void callback_arc_set_u1(char *input)
{
    g_arc.u1=atof(input);
    special_callback=NULL;
    status=ArcEntity;
}



// }}}
// callback_arc_set_u2() {{{



void callback_arc_set_u2(char *input)
{
    g_arc.u2=atof(input);
    special_callback=NULL;
    status=ArcEntity;
}



// }}}
// callback_arc_color() {{{



void callback_arc_color(char *input)
{
    special_callback=callback_arc_setcolor;
}



// }}}
// callback_arc_layer() {{{



void callback_arc_layer(char *input)
{
    special_callback=callback_arc_setlayer;
}



// }}}
// callback_arc_x() {{{



void callback_arc_x(char *input)
{
    special_callback=callback_arc_set_x;
}



// }}}
// callback_arc_y() {{{



void callback_arc_y(char *input)
{
    special_callback=callback_arc_set_y;
}



// }}}
// callback_arc_r() {{{



void callback_arc_r(char *input)
{
    special_callback=callback_arc_set_r;
}



// }}}
// callback_arc_u1() {{{



void callback_arc_u1(char *input)
{
    special_callback=callback_arc_set_u1;
}



// }}}
// callback_arc_u2() {{{



void callback_arc_u2(char *input)
{
    special_callback=callback_arc_set_u2;
}



// }}}
// callback_arc_store() {{{



void callback_arc_store(char *input)
{
    GfxArc *c=(GfxArc *)malloc(sizeof(GfxArc));
    c->x=g_arc.x;
    c->y=g_arc.y;
    c->r=g_arc.r;
    c->u1=g_arc.u1;
    c->u2=g_arc.u2;
    c->color=g_arc.color;
    c->layer=g_arc.layer;
    addItem(T_ARC, c);
}



// }}}

// callback_text_setcolor() {{{



void callback_text_setcolor(char *input)
{
    g_text.color=atoi(input);
    special_callback=NULL;
    status=TextEntity;
}



// }}}
// callback_text_setlayer() {{{



void callback_text_setlayer(char *input)
{
    int i, j;
    // velmi primitivni vypocet hashe
    for (i=0, j=0; input[i]; i++)
        j+=input[i];
    g_text.layer=j;
    special_callback=NULL;
    status=TextEntity;
}



// }}}
// callback_text_set_x() {{{



void callback_text_set_x(char *input)
{
    g_text.x=atof(input);
    special_callback=NULL;
    status=TextEntity;
}



// }}}
// callback_text_set_y() {{{



void callback_text_set_y(char *input)
{
    g_text.y=atof(input);
    special_callback=NULL;
    status=TextEntity;
}



// }}}
// callback_text_set_text() {{{



void callback_text_set_text(char *input)
{
    strncpy(g_text.str, input, MAX_TEXT_LENGTH-1);
    special_callback=NULL;
    status=TextEntity;
}



// }}}
// callback_text_color() {{{



void callback_text_color(char *input)
{
    special_callback=callback_text_setcolor;
}



// }}}
// callback_text_layer() {{{



void callback_text_layer(char *input)
{
    special_callback=callback_text_setlayer;
}



// }}}
// callback_text_x() {{{



void callback_text_x(char *input)
{
    special_callback=callback_text_set_x;
}



// }}}
// callback_text_y() {{{



void callback_text_y(char *input)
{
    special_callback=callback_text_set_y;
}



// }}}
// callback_text_text() {{{



void callback_text_text(char *input)
{
    special_callback=callback_text_set_text;
}



// }}}
// callback_text_store() {{{



void callback_text_store(char *input)
{
    GfxText *t=(GfxText *)malloc(sizeof(GfxText));
    t->x=g_text.x;
    t->y=g_text.y;
    t->color=g_text.color;
    t->layer=g_text.layer;
    strcpy(t->str, g_text.str);
    addItem(T_TEXT, t);
}



// }}}

// doConvert() {{{



// ---------------------------------------------------------------------
// Nacteni obsahu souboru DXF a konverze do internich datovych struktur
// ---------------------------------------------------------------------
int doConvert(char *fileName)
{
    FILE *fin;
    char line[MAX_LINE_LENGTH];
    int  lines=0;
    int  t;

    fin=fopen(fileName, "rt");                  // otevreni vstupniho souboru
    if (!fin) return 0;
    while (fgets(line, MAX_LINE_LENGTH, fin)) { // projit vsechny radky
        lines++;
        line[strlen(line)-1]=0;                 // oriznout <CR>
        if (special_callback!=NULL) {           // specialni callback funkce -> nacteni atributu
            special_callback(line);
        }
        else {                                  // normalni callback funkce -> prechod KA
            for (t=0; transitions[t].status!=End; t++) {
                if ((status==transitions[t].status) && (!strcmp(transitions[t].input, line))) {
                    if (transitions[t].fce!=NULL) transitions[t].fce(line);
                    status=transitions[t].newStatus;
                    break;
                }
            }
        }
    }
    printf("done %d lines\n", lines);
    fclose(fin);
    return 1;
}



// }}}

// setColor() {{{



//-----------------------------------------------------------------------------
// nastaveni barvy vykreslovani
//-----------------------------------------------------------------------------
void setColor(int color)
{
    // 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},
    };
    float r, g, b;
    r=palette[color & 0x07][0];
    g=palette[color & 0x07][1];
    b=palette[color & 0x07][2];
    glColor3f(r, g, b);
}



// }}}
// drawPoint() {{{



//-----------------------------------------------------------------------------
// vykresleni bodu
//-----------------------------------------------------------------------------
void drawPoint(void *entity)
{
    GfxPoint *p=(GfxPoint*)entity;
    if (colorStyle)
        setColor(p->color);
    else
        setColor(p->layer);
    glBegin(GL_POINTS);
    glVertex2d(p->x, p->y);
    glEnd();
}



// }}}
// drawLine() {{{



//-----------------------------------------------------------------------------
// vykresleni usecky
//-----------------------------------------------------------------------------
void drawLine(void *entity)
{
    GfxLine *l=(GfxLine*)entity;
    if (colorStyle)
        setColor(l->color);
    else
        setColor(l->layer);
    glBegin(GL_LINES);
    glVertex2d(l->x1, l->y1);
    glVertex2d(l->x2, l->y2);
    glEnd();
}



// }}}
// drawCircle() {{{



//-----------------------------------------------------------------------------
// vykresleni kruznice
//-----------------------------------------------------------------------------
void drawCircle(void *entity)
{
#define SEGMENTS 100
    int i;
    GfxCircle *c=(GfxCircle*)entity;
    if (colorStyle)
        setColor(c->color);
    else
        setColor(c->layer);
    glBegin(GL_LINE_LOOP);
    for (i=0; i<SEGMENTS; i++)
        glVertex2d(c->x+c->r*cos(i*6.28/SEGMENTS), c->y+c->r*sin(i*6.28/SEGMENTS));
    glEnd();
}



// }}}
// drawArc() {{{



//-----------------------------------------------------------------------------
// vykresleni oblouku
//-----------------------------------------------------------------------------
void drawArc(void *entity)
{
#define SEGMENTS_A 50
#ifndef M_PI
#define M_PI 3.1415927
#endif
    float u;
    float a, b;
    GfxArc *arc=(GfxArc*)entity;
    if (colorStyle)
        setColor(arc->color);
    else
        setColor(arc->layer);

    if (arc->u1 > arc->u2) {
        a=(arc->u2)*M_PI/180.0+M_PI;
        b=(arc->u1)*M_PI/180.0+M_PI;
    }
    else {
        a=(arc->u1)*M_PI/180.0;
        b=(arc->u2)*M_PI/180.0;
    }
    glBegin(GL_LINE_STRIP);
        for (u=a; u<=b; u+=(b-a)/SEGMENTS_A) {
            glVertex2d(arc->x+arc->r*cos(u), arc->y+arc->r*sin(u));
        }
    glEnd();
}



// }}}
// drawText() {{{



//-----------------------------------------------------------------------------
// vykresleni textu
//-----------------------------------------------------------------------------
void drawText(void *entity)
{
    char *c;
    GfxText *t=(GfxText*)entity;
    if (colorStyle)
        setColor(t->color);
    else
        setColor(t->layer);
    glPushMatrix();
    glTranslatef(t->x, t->y, 0);
    glScalef(0.01, 0.01, 0.01);
    for (c=t->str; *c!=0; c++) {
        glutStrokeCharacter(GLUT_STROKE_ROMAN, *c);
    }
    glPopMatrix();
}



// }}}
// redrawDrawing() {{{



//-----------------------------------------------------------------------------
// Prekresleni vektorove kresby
//-----------------------------------------------------------------------------
void redrawDrawing(double scale,                    // meritko obrazce
                   double xpos,                     // posun obrazce
                   double ypos)
{
    Item *item=p_first;
    float  scale2=mouse.ztran0/100.0+1.0;           // zmena meritka zadana mysi

    // 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) {
        Type type=item->type;
        switch (type) {
            case T_POINT:  drawPoint(item->entity);  break;
            case T_LINE:   drawLine(item->entity);   break;
            case T_CIRCLE: drawCircle(item->entity); break;
            case T_ARC:    drawArc(item->entity);    break;
            case T_TEXT:   drawText(item->entity);   break;
            default: break;
        }
        item=item->next;
    }
}



// }}}

// onInit() {{{



//-----------------------------------------------------------------------------
// 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);
}



// }}}
// onResize() {{{



//-----------------------------------------------------------------------------
// 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;
}



// }}}
// onDisplay() {{{



//-----------------------------------------------------------------------------
// 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();
}



// }}}
// onKeyboard() {{{



//-----------------------------------------------------------------------------
// 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
        case 'l': colorStyle=0; glutPostRedisplay(); break; // barvy podle hashe hladiny
        case 'c': colorStyle=1; glutPostRedisplay(); break; // barvy podle informaci z DXF
        default:           break;
    }
}
#ifdef __BORLANDC__
#pragma option -w+par
#endif



// }}}
// onSpecial() {{{



//-----------------------------------------------------------------------------
// 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



// }}}
// onMouse() {{{



//-----------------------------------------------------------------------------
// 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;
    }
}



// }}}
// onMouseMotion() {{{



//-----------------------------------------------------------------------------
// 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;
    }
}



// }}}

// main() {{{



//-----------------------------------------------------------------------------
// 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 (!doConvert(argv[1])) {                  // nacteni celeho souboru s kresbou
        puts("Nacteni souboru selhalo!\nUkonceni prohlizece...\n");
        return 0;
    }
    glutMainLoop();                             // nekonecna smycka, kde se volaji zaregistrovane funkce
    return 0;                                   // navratova hodnota vracena operacnimu systemu
}



// }}}

//-----------------------------------------------------------------------------
// finito
//-----------------------------------------------------------------------------

// vim: foldmethod=marker