]> git.saurik.com Git - wxWidgets.git/blobdiff - samples/opengl/penguin/dxfrenderer.cpp
Applied patch [ 1355355 ] Replace GPLed code in penguin sample and add features
[wxWidgets.git] / samples / opengl / penguin / dxfrenderer.cpp
diff --git a/samples/opengl/penguin/dxfrenderer.cpp b/samples/opengl/penguin/dxfrenderer.cpp
new file mode 100644 (file)
index 0000000..5d18667
--- /dev/null
@@ -0,0 +1,680 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        dxfrenderer.cpp
+// Purpose:     DXF reader and renderer
+// Author:      Sandro Sigala
+// Modified by:
+// Created:     2005-11-10
+// RCS-ID:      $Id$
+// Copyright:   (c) Sandro Sigala
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+// For compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#include "wx/wx.h"
+#endif
+
+#include "wx/wfstream.h"
+#include "wx/txtstrm.h"
+
+#if !wxUSE_GLCANVAS
+    #error "OpenGL required: set wxUSE_GLCANVAS to 1 and rebuild the library"
+#endif
+
+#ifdef __WXMAC__
+#  ifdef __DARWIN__
+#    include <OpenGL/glu.h>
+#  else
+#    include <glu.h>
+#  endif
+#else
+#  include <GL/glu.h>
+#endif
+
+#include "dxfrenderer.h"
+
+#include <wx/listimpl.cpp>
+WX_DEFINE_LIST(DXFEntityList);
+WX_DEFINE_LIST(DXFLayerList);
+
+// Conversion table from AutoCAD ACI colours to RGB values
+static const struct { unsigned char r, g, b; } aci_to_rgb[256] = {
+/*   0 */ 255, 255, 255,
+/*   1 */ 255,   0,   0,
+/*   2 */ 255, 255,   0,
+/*   3 */   0, 255,   0,
+/*   4 */   0, 255, 255,
+/*   5 */   0,   0, 255,
+/*   6 */ 255,   0, 255,
+/*   7 */ 255, 255, 255,
+/*   8 */ 128, 128, 128,
+/*   9 */ 192, 192, 192,
+/*  10 */ 255,   0,   0,
+/*  11 */ 255, 127, 127,
+/*  12 */ 204,   0,   0,
+/*  13 */ 204, 102, 102,
+/*  14 */ 153,   0,   0,
+/*  15 */ 153,  76,  76,
+/*  16 */ 127,   0,   0,
+/*  17 */ 127,  63,  63,
+/*  18 */  76,   0,   0,
+/*  19 */  76,  38,  38,
+/*  20 */ 255,  63,   0,
+/*  21 */ 255, 159, 127,
+/*  22 */ 204,  51,   0,
+/*  23 */ 204, 127, 102,
+/*  24 */ 153,  38,   0,
+/*  25 */ 153,  95,  76,
+/*  26 */ 127,  31,   0,
+/*  27 */ 127,  79,  63,
+/*  28 */  76,  19,   0,
+/*  29 */  76,  47,  38,
+/*  30 */ 255, 127,   0,
+/*  31 */ 255, 191, 127,
+/*  32 */ 204, 102,   0,
+/*  33 */ 204, 153, 102,
+/*  34 */ 153,  76,   0,
+/*  35 */ 153, 114,  76,
+/*  36 */ 127,  63,   0,
+/*  37 */ 127,  95,  63,
+/*  38 */  76,  38,   0,
+/*  39 */  76,  57,  38,
+/*  40 */ 255, 191,   0,
+/*  41 */ 255, 223, 127,
+/*  42 */ 204, 153,   0,
+/*  43 */ 204, 178, 102,
+/*  44 */ 153, 114,   0,
+/*  45 */ 153, 133,  76,
+/*  46 */ 127,  95,   0,
+/*  47 */ 127, 111,  63,
+/*  48 */  76,  57,   0,
+/*  49 */  76,  66,  38,
+/*  50 */ 255, 255,   0,
+/*  51 */ 255, 255, 127,
+/*  52 */ 204, 204,   0,
+/*  53 */ 204, 204, 102,
+/*  54 */ 153, 153,   0,
+/*  55 */ 153, 153,  76,
+/*  56 */ 127, 127,   0,
+/*  57 */ 127, 127,  63,
+/*  58 */  76,  76,   0,
+/*  59 */  76,  76,  38,
+/*  60 */ 191, 255,   0,
+/*  61 */ 223, 255, 127,
+/*  62 */ 153, 204,   0,
+/*  63 */ 178, 204, 102,
+/*  64 */ 114, 153,   0,
+/*  65 */ 133, 153,  76,
+/*  66 */  95, 127,   0,
+/*  67 */ 111, 127,  63,
+/*  68 */  57,  76,   0,
+/*  69 */  66,  76,  38,
+/*  70 */ 127, 255,   0,
+/*  71 */ 191, 255, 127,
+/*  72 */ 102, 204,   0,
+/*  73 */ 153, 204, 102,
+/*  74 */  76, 153,   0,
+/*  75 */ 114, 153,  76,
+/*  76 */  63, 127,   0,
+/*  77 */  95, 127,  63,
+/*  78 */  38,  76,   0,
+/*  79 */  57,  76,  38,
+/*  80 */  63, 255,   0,
+/*  81 */ 159, 255, 127,
+/*  82 */  51, 204,   0,
+/*  83 */ 127, 204, 102,
+/*  84 */  38, 153,   0,
+/*  85 */  95, 153,  76,
+/*  86 */  31, 127,   0,
+/*  87 */  79, 127,  63,
+/*  88 */  19,  76,   0,
+/*  89 */  47,  76,  38,
+/*  90 */   0, 255,   0,
+/*  91 */ 127, 255, 127,
+/*  92 */   0, 204,   0,
+/*  93 */ 102, 204, 102,
+/*  94 */   0, 153,   0,
+/*  95 */  76, 153,  76,
+/*  96 */   0, 127,   0,
+/*  97 */  63, 127,  63,
+/*  98 */   0,  76,   0,
+/*  99 */  38,  76,  38,
+/* 100 */   0, 255,  63,
+/* 101 */ 127, 255, 159,
+/* 102 */   0, 204,  51,
+/* 103 */ 102, 204, 127,
+/* 104 */   0, 153,  38,
+/* 105 */  76, 153,  95,
+/* 106 */   0, 127,  31,
+/* 107 */  63, 127,  79,
+/* 108 */   0,  76,  19,
+/* 109 */  38,  76,  47,
+/* 110 */   0, 255, 127,
+/* 111 */ 127, 255, 191,
+/* 112 */   0, 204, 102,
+/* 113 */ 102, 204, 153,
+/* 114 */   0, 153,  76,
+/* 115 */  76, 153, 114,
+/* 116 */   0, 127,  63,
+/* 117 */  63, 127,  95,
+/* 118 */   0,  76,  38,
+/* 119 */  38,  76,  57,
+/* 120 */   0, 255, 191,
+/* 121 */ 127, 255, 223,
+/* 122 */   0, 204, 153,
+/* 123 */ 102, 204, 178,
+/* 124 */   0, 153, 114,
+/* 125 */  76, 153, 133,
+/* 126 */   0, 127,  95,
+/* 127 */  63, 127, 111,
+/* 128 */   0,  76,  57,
+/* 129 */  38,  76,  66,
+/* 130 */   0, 255, 255,
+/* 131 */ 127, 255, 255,
+/* 132 */   0, 204, 204,
+/* 133 */ 102, 204, 204,
+/* 134 */   0, 153, 153,
+/* 135 */  76, 153, 153,
+/* 136 */   0, 127, 127,
+/* 137 */  63, 127, 127,
+/* 138 */   0,  76,  76,
+/* 139 */  38,  76,  76,
+/* 140 */   0, 191, 255,
+/* 141 */ 127, 223, 255,
+/* 142 */   0, 153, 204,
+/* 143 */ 102, 178, 204,
+/* 144 */   0, 114, 153,
+/* 145 */  76, 133, 153,
+/* 146 */   0,  95, 127,
+/* 147 */  63, 111, 127,
+/* 148 */   0,  57,  76,
+/* 149 */  38,  66,  76,
+/* 150 */   0, 127, 255,
+/* 151 */ 127, 191, 255,
+/* 152 */   0, 102, 204,
+/* 153 */ 102, 153, 204,
+/* 154 */   0,  76, 153,
+/* 155 */  76, 114, 153,
+/* 156 */   0,  63, 127,
+/* 157 */  63,  95, 127,
+/* 158 */   0,  38,  76,
+/* 159 */  38,  57,  76,
+/* 160 */   0,  63, 255,
+/* 161 */ 127, 159, 255,
+/* 162 */   0,  51, 204,
+/* 163 */ 102, 127, 204,
+/* 164 */   0,  38, 153,
+/* 165 */  76,  95, 153,
+/* 166 */   0,  31, 127,
+/* 167 */  63,  79, 127,
+/* 168 */   0,  19,  76,
+/* 169 */  38,  47,  76,
+/* 170 */   0,   0, 255,
+/* 171 */ 127, 127, 255,
+/* 172 */   0,   0, 204,
+/* 173 */ 102, 102, 204,
+/* 174 */   0,   0, 153,
+/* 175 */  76,  76, 153,
+/* 176 */   0,   0, 127,
+/* 177 */  63,  63, 127,
+/* 178 */   0,   0,  76,
+/* 179 */  38,  38,  76,
+/* 180 */  63,   0, 255,
+/* 181 */ 159, 127, 255,
+/* 182 */  51,   0, 204,
+/* 183 */ 127, 102, 204,
+/* 184 */  38,   0, 153,
+/* 185 */  95,  76, 153,
+/* 186 */  31,   0, 127,
+/* 187 */  79,  63, 127,
+/* 188 */  19,   0,  76,
+/* 189 */  47,  38,  76,
+/* 190 */ 127,   0, 255,
+/* 191 */ 191, 127, 255,
+/* 192 */ 102,   0, 204,
+/* 193 */ 153, 102, 204,
+/* 194 */  76,   0, 153,
+/* 195 */ 114,  76, 153,
+/* 196 */  63,   0, 127,
+/* 197 */  95,  63, 127,
+/* 198 */  38,   0,  76,
+/* 199 */  57,  38,  76,
+/* 200 */ 191,   0, 255,
+/* 201 */ 223, 127, 255,
+/* 202 */ 153,   0, 204,
+/* 203 */ 178, 102, 204,
+/* 204 */ 114,   0, 153,
+/* 205 */ 133,  76, 153,
+/* 206 */  95,   0, 127,
+/* 207 */ 111,  63, 127,
+/* 208 */  57,   0,  76,
+/* 209 */  66,  38,  76,
+/* 210 */ 255,   0, 255,
+/* 211 */ 255, 127, 255,
+/* 212 */ 204,   0, 204,
+/* 213 */ 204, 102, 204,
+/* 214 */ 153,   0, 153,
+/* 215 */ 153,  76, 153,
+/* 216 */ 127,   0, 127,
+/* 217 */ 127,  63, 127,
+/* 218 */  76,   0,  76,
+/* 219 */  76,  38,  76,
+/* 220 */ 255,   0, 191,
+/* 221 */ 255, 127, 223,
+/* 222 */ 204,   0, 153,
+/* 223 */ 204, 102, 178,
+/* 224 */ 153,   0, 114,
+/* 225 */ 153,  76, 133,
+/* 226 */ 127,   0,  95,
+/* 227 */ 127,  63, 111,
+/* 228 */  76,   0,  57,
+/* 229 */  76,  38,  66,
+/* 230 */ 255,   0, 127,
+/* 231 */ 255, 127, 191,
+/* 232 */ 204,   0, 102,
+/* 233 */ 204, 102, 153,
+/* 234 */ 153,   0,  76,
+/* 235 */ 153,  76, 114,
+/* 236 */ 127,   0,  63,
+/* 237 */ 127,  63,  95,
+/* 238 */  76,   0,  38,
+/* 239 */  76,  38,  57,
+/* 240 */ 255,   0,  63,
+/* 241 */ 255, 127, 159,
+/* 242 */ 204,   0,  51,
+/* 243 */ 204, 102, 127,
+/* 244 */ 153,   0,  38,
+/* 245 */ 153,  76,  95,
+/* 246 */ 127,   0,  31,
+/* 247 */ 127,  63,  79,
+/* 248 */  76,   0,  19,
+/* 249 */  76,  38,  47,
+/* 250 */  51,  51,  51,
+/* 251 */  91,  91,  91,
+/* 252 */ 132, 132, 132,
+/* 253 */ 173, 173, 173,
+/* 254 */ 214, 214, 214,
+/* 255 */ 255, 255, 255,
+};
+
+inline DXFVector Cross(const DXFVector& v1, const DXFVector& v2)
+{
+    return DXFVector(v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x);
+}
+
+void DXFFace::CalculateNormal()
+{
+    DXFVector v01, v02;
+    v01.x = v0.x - v1.x;
+    v01.y = v0.y - v1.y;
+    v01.z = v0.z - v1.z;
+    v02.x = v0.x - v2.x;
+    v02.y = v0.y - v2.y;
+    v02.z = v0.z - v2.z;
+    n = Cross(v01, v02);
+    float mod = sqrt(n.x*n.x + n.y*n.y + n.z*n.z);
+    n.x /= mod;
+    n.y /= mod;
+    n.z /= mod;
+}
+
+// convert an AutoCAD ACI colour to wxWidgets RGB colour
+inline wxColour ACIColourToRGB(int col)
+{
+    wxASSERT(col >= 0 && col <= 255);
+    return wxColour(aci_to_rgb[col].r, aci_to_rgb[col].g, aci_to_rgb[col].b);
+}
+
+// DXFReader constructor
+DXFRenderer::DXFRenderer()
+{
+    m_loaded = false;
+}
+
+// DXFReader destructor
+DXFRenderer::~DXFRenderer()
+{
+    Clear();
+}
+
+// deallocate all the dynamic data
+void DXFRenderer::Clear()
+{
+    m_loaded = false;
+    {
+        for (DXFLayerList::Node *node = m_layers.GetFirst(); node; node = node->GetNext())
+        {
+            DXFLayer *current = node->GetData();
+            delete current;
+        }
+    }
+    m_layers.Clear();
+    {
+        for (DXFEntityList::Node *node = m_entities.GetFirst(); node; node = node->GetNext())
+        {
+            DXFEntity *current = node->GetData();
+            delete current;
+        }
+        m_entities.Clear();
+    }
+}
+
+int DXFRenderer::GetLayerColour(const wxString& layer) const
+{
+    for (DXFLayerList::Node *node = m_layers.GetFirst(); node; node = node->GetNext())
+    {
+        DXFLayer *current = node->GetData();
+        if (current->name == layer)
+            return current->colour;
+    }
+    return 7;   // white
+}
+
+// read two sequential lines
+inline void GetLines(wxTextInputStream& text, wxString& line1, wxString& line2)
+{
+    line1 = text.ReadLine().Trim().Trim(false);
+    line2 = text.ReadLine().Trim().Trim(false);
+}
+
+// parse header section: just skip everything
+bool DXFRenderer::ParseHeader(wxInputStream& stream)
+{
+    wxTextInputStream text(stream);
+    wxString line1, line2;
+    while (stream.CanRead())
+    {
+        GetLines(text, line1, line2);
+        if (line1 == wxT("0") && line2 == wxT("ENDSEC"))
+            return true;
+    }
+    return false;
+}
+
+// parse tables section: save layers name and colour
+bool DXFRenderer::ParseTables(wxInputStream& stream)
+{
+    wxTextInputStream text(stream);
+    wxString line1, line2;
+    bool inlayer=false;
+    DXFLayer layer;
+    while (stream.CanRead())
+    {
+        GetLines(text, line1, line2);
+        if (line1 == wxT("0") && inlayer)
+        {
+            // flush layer
+            if (!layer.name.IsEmpty() && layer.colour != -1)
+            {
+                DXFLayer *p = new DXFLayer;
+                p->name = layer.name;
+                p->colour = layer.colour;
+                m_layers.Append(p);
+            }
+            layer = DXFLayer();
+            inlayer = false;
+        }
+        if (line1 == wxT("0") && line2 == wxT("ENDSEC"))
+            return true;
+        else if (line1 == wxT("0") && line2 == wxT("LAYER"))
+            inlayer = true;
+        else if (inlayer)
+        {
+            if (line1 == wxT("2")) // layer name
+                layer.name = line2;
+            else if (line1 == wxT("62")) // ACI colour
+            {
+                long l;
+                line2.ToLong(&l);
+                layer.colour = l;
+            }
+        }
+    }
+    return false;
+}
+
+// parse entities section: save 3DFACE and LINE entities
+bool DXFRenderer::ParseEntities(wxInputStream& stream)
+{
+    wxTextInputStream text(stream);
+    wxString line1, line2;
+    int state = 0;  // 0: none, 1: 3DFACE, 2: LINE
+    DXFVector v[4];
+    int colour = -1;
+    wxString layer;
+    while (stream.CanRead())
+    {
+        GetLines(text, line1, line2);
+        if (line1 == wxT("0") && state > 0)
+        {
+            // flush entity
+            if (state == 1) // 3DFACE
+            {
+                DXFFace *p = new DXFFace;
+                p->v0 = v[0];
+                p->v1 = v[1];
+                p->v2 = v[2];
+                p->v3 = v[3];
+                p->CalculateNormal();
+                if (colour != -1)
+                    p->colour = colour;
+                else
+                    p->colour = GetLayerColour(layer);
+                m_entities.Append(p);
+                colour = -1; layer = wxEmptyString;
+                v[0] = v[1] = v[2] = v[3] = DXFVector();
+                state = 0;
+            }
+            else if (state == 2) // LINE
+            {
+                DXFLine *p = new DXFLine;
+                p->v0 = v[0];
+                p->v1 = v[1];
+                if (colour != -1)
+                    p->colour = colour;
+                else
+                    p->colour = GetLayerColour(layer);
+                m_entities.Append(p);
+                colour = -1; layer = wxEmptyString;
+                v[0] = v[1] = v[2] = v[3] = DXFVector();
+                state = 0;
+            }
+        }
+        if (line1 == wxT("0") && line2 == wxT("ENDSEC"))
+            return true;
+        else if (line1 == wxT("0") && line2 == wxT("3DFACE"))
+            state = 1;
+        else if (line1 == wxT("0") && line2 == wxT("LINE"))
+            state = 2;
+        else if (state > 0)
+        {
+            double d;
+            line2.ToDouble(&d);
+            if (line1 == wxT("10"))
+                v[0].x = d;
+            else if (line1 == wxT("20"))
+                v[0].y = d;
+            else if (line1 == wxT("30"))
+                v[0].z = d;
+            else if (line1 == wxT("11"))
+                v[1].x = d;
+            else if (line1 == wxT("21"))
+                v[1].y = d;
+            else if (line1 == wxT("31"))
+                v[1].z = d;
+            else if (line1 == wxT("12"))
+                v[2].x = d;
+            else if (line1 == wxT("22"))
+                v[2].y = d;
+            else if (line1 == wxT("32"))
+                v[2].z = d;
+            else if (line1 == wxT("13"))
+                v[3].x = d;
+            else if (line1 == wxT("23"))
+                v[3].y = d;
+            else if (line1 == wxT("33"))
+                v[3].z = d;
+            else if (line1 == wxT("8"))  // layer
+                layer = line2;
+            else if (line1 == wxT("62")) // colour
+            {
+                long l;
+                line2.ToLong(&l);
+                colour = l;
+            }
+        }
+    }
+    return false;
+}
+
+// parse and load a DXF file
+// currently pretty limited, but knows enought do handle 3DFACEs and LINEs
+bool DXFRenderer::Load(wxInputStream& stream)
+{
+    Clear();
+    wxTextInputStream text(stream);
+
+    wxString line1, line2;
+    while (stream.CanRead())
+    {
+        GetLines(text, line1, line2);
+        if (line1 == wxT("999")) // comment
+            continue;
+        else if (line1 == wxT("0") && line2 == wxT("SECTION"))
+        {
+            GetLines(text, line1, line2);
+            if (line1 == wxT("2"))
+            {
+                if (line2 == wxT("HEADER"))
+                {
+                    if (!ParseHeader(stream))
+                        return false;
+                }
+                else if (line2 == wxT("TABLES"))
+                { 
+                    if (!ParseTables(stream))
+                        return false;
+                }
+                else if (line2 == wxT("ENTITIES"))
+                {
+                    if (!ParseEntities(stream))
+                        return false;
+                }
+            }
+        }
+    }
+
+    NormalizeEntities();
+    m_loaded = true;
+    return true;
+}
+
+inline float mymin(float x, float y) { return x < y ? x : y; }
+inline float mymax(float x, float y) { return x > y ? x : y; }
+
+// Scale object boundings to [-5,5]
+void DXFRenderer::NormalizeEntities()
+{
+    // calculate current min and max boundings of object
+    DXFVector minv(10e20f, 10e20f, 10e20f);
+    DXFVector maxv(-10e20f, -10e20f, -10e20f);
+    for (DXFEntityList::Node *node = m_entities.GetFirst(); node; node = node->GetNext())
+    {
+        DXFEntity *p = node->GetData();
+        if (p->type == DXFEntity::Line)
+        {
+            DXFLine *line = (DXFLine *)p;
+            const DXFVector *v[2] = { &line->v0, &line->v1 };
+            for (int i = 0; i < 2; ++i)
+            {
+                minv.x = mymin(v[i]->x, minv.x);
+                minv.y = mymin(v[i]->y, minv.y);
+                minv.z = mymin(v[i]->z, minv.z);
+                maxv.x = mymax(v[i]->x, maxv.x);
+                maxv.y = mymax(v[i]->y, maxv.y);
+                maxv.z = mymax(v[i]->z, maxv.z);
+            }
+        } else if (p->type == DXFEntity::Face)
+        {
+            DXFFace *face = (DXFFace *)p;
+            const DXFVector *v[4] = { &face->v0, &face->v1, &face->v2, &face->v3 };
+            for (int i = 0; i < 4; ++i)
+            {
+                minv.x = mymin(v[i]->x, minv.x);
+                minv.y = mymin(v[i]->y, minv.y);
+                minv.z = mymin(v[i]->z, minv.z);
+                maxv.x = mymax(v[i]->x, maxv.x);
+                maxv.y = mymax(v[i]->y, maxv.y);
+                maxv.z = mymax(v[i]->z, maxv.z);
+            }
+       }
+    }
+
+    // rescale object down to [-5,5]
+    DXFVector span(maxv.x - minv.x, maxv.y - minv.y, maxv.z - minv.z);
+    float factor = mymin(mymin(10.0f / span.x, 10.0f / span.y), 10.0f / span.z);
+    for (DXFEntityList::Node *node2 = m_entities.GetFirst(); node2; node2 = node2->GetNext())
+    {
+        DXFEntity *p = node2->GetData();
+        if (p->type == DXFEntity::Line)
+        {
+            DXFLine *line = (DXFLine *)p;
+            DXFVector *v[2] = { &line->v0, &line->v1 };
+            for (int i = 0; i < 2; ++i)
+            {
+                v[i]->x -= minv.x + span.x/2; v[i]->x *= factor;
+                v[i]->y -= minv.y + span.y/2; v[i]->y *= factor;
+                v[i]->z -= minv.z + span.z/2; v[i]->z *= factor;
+            }
+        } else if (p->type == DXFEntity::Face)
+        {
+            DXFFace *face = (DXFFace *)p;
+            DXFVector *v[4] = { &face->v0, &face->v1, &face->v2, &face->v3 };
+            for (int i = 0; i < 4; ++i)
+            {
+                v[i]->x -= minv.x + span.x/2; v[i]->x *= factor;
+                v[i]->y -= minv.y + span.y/2; v[i]->y *= factor;
+                v[i]->z -= minv.z + span.z/2; v[i]->z *= factor;
+            }
+       }
+    }
+}
+
+// OpenGL renderer for DXF entities
+void DXFRenderer::Render() const
+{
+    if (!m_loaded)
+        return;
+
+    for (DXFEntityList::Node *node = m_entities.GetFirst(); node; node = node->GetNext())
+    {
+        DXFEntity *p = node->GetData();
+        wxColour c = ACIColourToRGB(p->colour);
+        if (p->type == DXFEntity::Line)
+        {
+            DXFLine *line = (DXFLine *)p;
+            glBegin(GL_LINES);
+            glColor3f(c.Red()/255.0,c.Green()/255.0,c.Blue()/255.0);
+            glVertex3f(line->v0.x, line->v0.y, line->v0.z);
+            glVertex3f(line->v1.x, line->v1.y, line->v1.z);
+            glEnd();
+        }
+        else if (p->type == DXFEntity::Face)
+        {
+            DXFFace *face = (DXFFace *)p;
+            glBegin(GL_TRIANGLES);
+            glColor3f(c.Red()/255.0,c.Green()/255.0,c.Blue()/255.0);
+            glNormal3f(face->n.x, face->n.y, face->n.z);
+            glVertex3f(face->v0.x, face->v0.y, face->v0.z);
+            glVertex3f(face->v1.x, face->v1.y, face->v1.z);
+            glVertex3f(face->v2.x, face->v2.y, face->v2.z);
+            glEnd();
+        }
+    }
+}