Document domain parameter of wxTranslations::GetTranslatedString().
[wxWidgets.git] / samples / opengl / penguin / dxfrenderer.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: dxfrenderer.cpp
3 // Purpose: DXF reader and renderer
4 // Author: Sandro Sigala
5 // Modified by:
6 // Created: 2005-11-10
7 // Copyright: (c) Sandro Sigala
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // For compilers that support precompilation, includes "wx/wx.h".
12 #include "wx/wxprec.h"
13
14 #ifdef __BORLANDC__
15 #pragma hdrstop
16 #endif
17
18 #ifndef WX_PRECOMP
19 #include "wx/wx.h"
20 #endif
21
22 #include "wx/wfstream.h"
23 #include "wx/txtstrm.h"
24
25 #if !wxUSE_GLCANVAS
26 #error "OpenGL required: set wxUSE_GLCANVAS to 1 and rebuild the library"
27 #endif
28
29 #ifdef __DARWIN__
30 #include <OpenGL/glu.h>
31 #else
32 #include <GL/glu.h>
33 #endif
34
35 #include <sstream>
36
37 #include "dxfrenderer.h"
38
39 #include "wx/listimpl.cpp"
40 WX_DEFINE_LIST(DXFEntityList)
41 WX_DEFINE_LIST(DXFLayerList)
42
43 // Conversion table from AutoCAD ACI colours to RGB values
44 static const struct { unsigned char r, g, b; } aci_to_rgb[256] = {
45 /* 0 */ {255, 255, 255},
46 /* 1 */ {255, 0, 0},
47 /* 2 */ {255, 255, 0},
48 /* 3 */ { 0, 255, 0},
49 /* 4 */ { 0, 255, 255},
50 /* 5 */ { 0, 0, 255},
51 /* 6 */ {255, 0, 255},
52 /* 7 */ {255, 255, 255},
53 /* 8 */ {128, 128, 128},
54 /* 9 */ {192, 192, 192},
55 /* 10 */ {255, 0, 0},
56 /* 11 */ {255, 127, 127},
57 /* 12 */ {204, 0, 0},
58 /* 13 */ {204, 102, 102},
59 /* 14 */ {153, 0, 0},
60 /* 15 */ {153, 76, 76},
61 /* 16 */ {127, 0, 0},
62 /* 17 */ {127, 63, 63},
63 /* 18 */ { 76, 0, 0},
64 /* 19 */ { 76, 38, 38},
65 /* 20 */ {255, 63, 0},
66 /* 21 */ {255, 159, 127},
67 /* 22 */ {204, 51, 0},
68 /* 23 */ {204, 127, 102},
69 /* 24 */ {153, 38, 0},
70 /* 25 */ {153, 95, 76},
71 /* 26 */ {127, 31, 0},
72 /* 27 */ {127, 79, 63},
73 /* 28 */ { 76, 19, 0},
74 /* 29 */ { 76, 47, 38},
75 /* 30 */ {255, 127, 0},
76 /* 31 */ {255, 191, 127},
77 /* 32 */ {204, 102, 0},
78 /* 33 */ {204, 153, 102},
79 /* 34 */ {153, 76, 0},
80 /* 35 */ {153, 114, 76},
81 /* 36 */ {127, 63, 0},
82 /* 37 */ {127, 95, 63},
83 /* 38 */ { 76, 38, 0},
84 /* 39 */ { 76, 57, 38},
85 /* 40 */ {255, 191, 0},
86 /* 41 */ {255, 223, 127},
87 /* 42 */ {204, 153, 0},
88 /* 43 */ {204, 178, 102},
89 /* 44 */ {153, 114, 0},
90 /* 45 */ {153, 133, 76},
91 /* 46 */ {127, 95, 0},
92 /* 47 */ {127, 111, 63},
93 /* 48 */ { 76, 57, 0},
94 /* 49 */ { 76, 66, 38},
95 /* 50 */ {255, 255, 0},
96 /* 51 */ {255, 255, 127},
97 /* 52 */ {204, 204, 0},
98 /* 53 */ {204, 204, 102},
99 /* 54 */ {153, 153, 0},
100 /* 55 */ {153, 153, 76},
101 /* 56 */ {127, 127, 0},
102 /* 57 */ {127, 127, 63},
103 /* 58 */ { 76, 76, 0},
104 /* 59 */ { 76, 76, 38},
105 /* 60 */ {191, 255, 0},
106 /* 61 */ {223, 255, 127},
107 /* 62 */ {153, 204, 0},
108 /* 63 */ {178, 204, 102},
109 /* 64 */ {114, 153, 0},
110 /* 65 */ {133, 153, 76},
111 /* 66 */ { 95, 127, 0},
112 /* 67 */ {111, 127, 63},
113 /* 68 */ { 57, 76, 0},
114 /* 69 */ { 66, 76, 38},
115 /* 70 */ {127, 255, 0},
116 /* 71 */ {191, 255, 127},
117 /* 72 */ {102, 204, 0},
118 /* 73 */ {153, 204, 102},
119 /* 74 */ { 76, 153, 0},
120 /* 75 */ {114, 153, 76},
121 /* 76 */ { 63, 127, 0},
122 /* 77 */ { 95, 127, 63},
123 /* 78 */ { 38, 76, 0},
124 /* 79 */ { 57, 76, 38},
125 /* 80 */ { 63, 255, 0},
126 /* 81 */ {159, 255, 127},
127 /* 82 */ { 51, 204, 0},
128 /* 83 */ {127, 204, 102},
129 /* 84 */ { 38, 153, 0},
130 /* 85 */ { 95, 153, 76},
131 /* 86 */ { 31, 127, 0},
132 /* 87 */ { 79, 127, 63},
133 /* 88 */ { 19, 76, 0},
134 /* 89 */ { 47, 76, 38},
135 /* 90 */ { 0, 255, 0},
136 /* 91 */ {127, 255, 127},
137 /* 92 */ { 0, 204, 0},
138 /* 93 */ {102, 204, 102},
139 /* 94 */ { 0, 153, 0},
140 /* 95 */ { 76, 153, 76},
141 /* 96 */ { 0, 127, 0},
142 /* 97 */ { 63, 127, 63},
143 /* 98 */ { 0, 76, 0},
144 /* 99 */ { 38, 76, 38},
145 /* 100 */ { 0, 255, 63},
146 /* 101 */ {127, 255, 159},
147 /* 102 */ { 0, 204, 51},
148 /* 103 */ {102, 204, 127},
149 /* 104 */ { 0, 153, 38},
150 /* 105 */ { 76, 153, 95},
151 /* 106 */ { 0, 127, 31},
152 /* 107 */ { 63, 127, 79},
153 /* 108 */ { 0, 76, 19},
154 /* 109 */ { 38, 76, 47},
155 /* 110 */ { 0, 255, 127},
156 /* 111 */ {127, 255, 191},
157 /* 112 */ { 0, 204, 102},
158 /* 113 */ {102, 204, 153},
159 /* 114 */ { 0, 153, 76},
160 /* 115 */ { 76, 153, 114},
161 /* 116 */ { 0, 127, 63},
162 /* 117 */ { 63, 127, 95},
163 /* 118 */ { 0, 76, 38},
164 /* 119 */ { 38, 76, 57},
165 /* 120 */ { 0, 255, 191},
166 /* 121 */ {127, 255, 223},
167 /* 122 */ { 0, 204, 153},
168 /* 123 */ {102, 204, 178},
169 /* 124 */ { 0, 153, 114},
170 /* 125 */ { 76, 153, 133},
171 /* 126 */ { 0, 127, 95},
172 /* 127 */ { 63, 127, 111},
173 /* 128 */ { 0, 76, 57},
174 /* 129 */ { 38, 76, 66},
175 /* 130 */ { 0, 255, 255},
176 /* 131 */ {127, 255, 255},
177 /* 132 */ { 0, 204, 204},
178 /* 133 */ {102, 204, 204},
179 /* 134 */ { 0, 153, 153},
180 /* 135 */ { 76, 153, 153},
181 /* 136 */ { 0, 127, 127},
182 /* 137 */ { 63, 127, 127},
183 /* 138 */ { 0, 76, 76},
184 /* 139 */ { 38, 76, 76},
185 /* 140 */ { 0, 191, 255},
186 /* 141 */ {127, 223, 255},
187 /* 142 */ { 0, 153, 204},
188 /* 143 */ {102, 178, 204},
189 /* 144 */ { 0, 114, 153},
190 /* 145 */ { 76, 133, 153},
191 /* 146 */ { 0, 95, 127},
192 /* 147 */ { 63, 111, 127},
193 /* 148 */ { 0, 57, 76},
194 /* 149 */ { 38, 66, 76},
195 /* 150 */ { 0, 127, 255},
196 /* 151 */ {127, 191, 255},
197 /* 152 */ { 0, 102, 204},
198 /* 153 */ {102, 153, 204},
199 /* 154 */ { 0, 76, 153},
200 /* 155 */ { 76, 114, 153},
201 /* 156 */ { 0, 63, 127},
202 /* 157 */ { 63, 95, 127},
203 /* 158 */ { 0, 38, 76},
204 /* 159 */ { 38, 57, 76},
205 /* 160 */ { 0, 63, 255},
206 /* 161 */ {127, 159, 255},
207 /* 162 */ { 0, 51, 204},
208 /* 163 */ {102, 127, 204},
209 /* 164 */ { 0, 38, 153},
210 /* 165 */ { 76, 95, 153},
211 /* 166 */ { 0, 31, 127},
212 /* 167 */ { 63, 79, 127},
213 /* 168 */ { 0, 19, 76},
214 /* 169 */ { 38, 47, 76},
215 /* 170 */ { 0, 0, 255},
216 /* 171 */ {127, 127, 255},
217 /* 172 */ { 0, 0, 204},
218 /* 173 */ {102, 102, 204},
219 /* 174 */ { 0, 0, 153},
220 /* 175 */ { 76, 76, 153},
221 /* 176 */ { 0, 0, 127},
222 /* 177 */ { 63, 63, 127},
223 /* 178 */ { 0, 0, 76},
224 /* 179 */ { 38, 38, 76},
225 /* 180 */ { 63, 0, 255},
226 /* 181 */ {159, 127, 255},
227 /* 182 */ { 51, 0, 204},
228 /* 183 */ {127, 102, 204},
229 /* 184 */ { 38, 0, 153},
230 /* 185 */ { 95, 76, 153},
231 /* 186 */ { 31, 0, 127},
232 /* 187 */ { 79, 63, 127},
233 /* 188 */ { 19, 0, 76},
234 /* 189 */ { 47, 38, 76},
235 /* 190 */ {127, 0, 255},
236 /* 191 */ {191, 127, 255},
237 /* 192 */ {102, 0, 204},
238 /* 193 */ {153, 102, 204},
239 /* 194 */ { 76, 0, 153},
240 /* 195 */ {114, 76, 153},
241 /* 196 */ { 63, 0, 127},
242 /* 197 */ { 95, 63, 127},
243 /* 198 */ { 38, 0, 76},
244 /* 199 */ { 57, 38, 76},
245 /* 200 */ {191, 0, 255},
246 /* 201 */ {223, 127, 255},
247 /* 202 */ {153, 0, 204},
248 /* 203 */ {178, 102, 204},
249 /* 204 */ {114, 0, 153},
250 /* 205 */ {133, 76, 153},
251 /* 206 */ { 95, 0, 127},
252 /* 207 */ {111, 63, 127},
253 /* 208 */ { 57, 0, 76},
254 /* 209 */ { 66, 38, 76},
255 /* 210 */ {255, 0, 255},
256 /* 211 */ {255, 127, 255},
257 /* 212 */ {204, 0, 204},
258 /* 213 */ {204, 102, 204},
259 /* 214 */ {153, 0, 153},
260 /* 215 */ {153, 76, 153},
261 /* 216 */ {127, 0, 127},
262 /* 217 */ {127, 63, 127},
263 /* 218 */ { 76, 0, 76},
264 /* 219 */ { 76, 38, 76},
265 /* 220 */ {255, 0, 191},
266 /* 221 */ {255, 127, 223},
267 /* 222 */ {204, 0, 153},
268 /* 223 */ {204, 102, 178},
269 /* 224 */ {153, 0, 114},
270 /* 225 */ {153, 76, 133},
271 /* 226 */ {127, 0, 95},
272 /* 227 */ {127, 63, 111},
273 /* 228 */ { 76, 0, 57},
274 /* 229 */ { 76, 38, 66},
275 /* 230 */ {255, 0, 127},
276 /* 231 */ {255, 127, 191},
277 /* 232 */ {204, 0, 102},
278 /* 233 */ {204, 102, 153},
279 /* 234 */ {153, 0, 76},
280 /* 235 */ {153, 76, 114},
281 /* 236 */ {127, 0, 63},
282 /* 237 */ {127, 63, 95},
283 /* 238 */ { 76, 0, 38},
284 /* 239 */ { 76, 38, 57},
285 /* 240 */ {255, 0, 63},
286 /* 241 */ {255, 127, 159},
287 /* 242 */ {204, 0, 51},
288 /* 243 */ {204, 102, 127},
289 /* 244 */ {153, 0, 38},
290 /* 245 */ {153, 76, 95},
291 /* 246 */ {127, 0, 31},
292 /* 247 */ {127, 63, 79},
293 /* 248 */ { 76, 0, 19},
294 /* 249 */ { 76, 38, 47},
295 /* 250 */ { 51, 51, 51},
296 /* 251 */ { 91, 91, 91},
297 /* 252 */ {132, 132, 132},
298 /* 253 */ {173, 173, 173},
299 /* 254 */ {214, 214, 214},
300 /* 255 */ {255, 255, 255}
301 };
302
303 inline DXFVector Cross(const DXFVector& v1, const DXFVector& v2)
304 {
305 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);
306 }
307
308 void DXFFace::CalculateNormal()
309 {
310 DXFVector v01, v02;
311 v01.x = v0.x - v1.x;
312 v01.y = v0.y - v1.y;
313 v01.z = v0.z - v1.z;
314 v02.x = v0.x - v2.x;
315 v02.y = v0.y - v2.y;
316 v02.z = v0.z - v2.z;
317 n = Cross(v01, v02);
318 float mod = sqrt(n.x*n.x + n.y*n.y + n.z*n.z);
319 n.x /= mod;
320 n.y /= mod;
321 n.z /= mod;
322 }
323
324 // convert an AutoCAD ACI colour to wxWidgets RGB colour
325 inline wxColour ACIColourToRGB(int col)
326 {
327 wxASSERT(col >= 0 && col <= 255);
328 return wxColour(aci_to_rgb[col].r, aci_to_rgb[col].g, aci_to_rgb[col].b);
329 }
330
331 // DXFReader constructor
332 DXFRenderer::DXFRenderer()
333 {
334 m_loaded = false;
335 }
336
337 // DXFReader destructor
338 DXFRenderer::~DXFRenderer()
339 {
340 Clear();
341 }
342
343 // deallocate all the dynamic data
344 void DXFRenderer::Clear()
345 {
346 m_loaded = false;
347 {
348 for (DXFLayerList::compatibility_iterator node = m_layers.GetFirst(); node; node = node->GetNext())
349 {
350 DXFLayer *current = node->GetData();
351 delete current;
352 }
353 }
354 m_layers.Clear();
355 {
356 for (DXFEntityList::compatibility_iterator node = m_entities.GetFirst(); node; node = node->GetNext())
357 {
358 DXFEntity *current = node->GetData();
359 delete current;
360 }
361 m_entities.Clear();
362 }
363 }
364
365 int DXFRenderer::GetLayerColour(const wxString& layer) const
366 {
367 for (DXFLayerList::compatibility_iterator node = m_layers.GetFirst(); node; node = node->GetNext())
368 {
369 DXFLayer *current = node->GetData();
370 if (current->name == layer)
371 return current->colour;
372 }
373 return 7; // white
374 }
375
376 // read two sequential lines
377 inline void GetLines(wxTextInputStream& text, wxString& line1, wxString& line2)
378 {
379 line1 = text.ReadLine().Trim().Trim(false);
380 line2 = text.ReadLine().Trim().Trim(false);
381 }
382
383 // parse header section: just skip everything
384 bool DXFRenderer::ParseHeader(wxInputStream& stream)
385 {
386 wxTextInputStream text(stream);
387 wxString line1, line2;
388 while (stream.CanRead())
389 {
390 GetLines(text, line1, line2);
391 if (line1 == wxT("0") && line2 == wxT("ENDSEC"))
392 return true;
393 }
394 return false;
395 }
396
397 // parse tables section: save layers name and colour
398 bool DXFRenderer::ParseTables(wxInputStream& stream)
399 {
400 wxTextInputStream text(stream);
401 wxString line1, line2;
402 bool inlayer=false;
403 DXFLayer layer;
404 while (stream.CanRead())
405 {
406 GetLines(text, line1, line2);
407 if (line1 == wxT("0") && inlayer)
408 {
409 // flush layer
410 if (!layer.name.IsEmpty() && layer.colour != -1)
411 {
412 DXFLayer *p = new DXFLayer;
413 p->name = layer.name;
414 p->colour = layer.colour;
415 m_layers.Append(p);
416 }
417 layer = DXFLayer();
418 inlayer = false;
419 }
420 if (line1 == wxT("0") && line2 == wxT("ENDSEC"))
421 return true;
422 else if (line1 == wxT("0") && line2 == wxT("LAYER"))
423 inlayer = true;
424 else if (inlayer)
425 {
426 if (line1 == wxT("2")) // layer name
427 layer.name = line2;
428 else if (line1 == wxT("62")) // ACI colour
429 {
430 long l;
431 line2.ToLong(&l);
432 layer.colour = l;
433 }
434 }
435 }
436 return false;
437 }
438
439 // This method is used instead of numStr.ToDouble(d) because the latter
440 // (wxString::ToDouble()) takes the systems proper locale into account,
441 // whereas the implementation below works with the default locale.
442 // (Converting numbers that are formatted in the default locale can fail
443 // with system locales that use e.g. the comma as the decimal separator.)
444 static double ToDouble(const wxString& numStr)
445 {
446 double d;
447 std::string numStr_(numStr.c_str());
448 std::istringstream iss(numStr_);
449
450 iss >> d;
451
452 return d;
453 }
454
455 // parse entities section: save 3DFACE and LINE entities
456 bool DXFRenderer::ParseEntities(wxInputStream& stream)
457 {
458 wxTextInputStream text(stream);
459 wxString line1, line2;
460 int state = 0; // 0: none, 1: 3DFACE, 2: LINE
461 DXFVector v[4];
462 int colour = -1;
463 wxString layer;
464 while (stream.CanRead())
465 {
466 GetLines(text, line1, line2);
467 if (line1 == wxT("0") && state > 0)
468 {
469 // flush entity
470 if (state == 1) // 3DFACE
471 {
472 DXFFace *p = new DXFFace;
473 p->v0 = v[0];
474 p->v1 = v[1];
475 p->v2 = v[2];
476 p->v3 = v[3];
477 p->CalculateNormal();
478 if (colour != -1)
479 p->colour = colour;
480 else
481 p->colour = GetLayerColour(layer);
482 m_entities.Append(p);
483 colour = -1; layer = wxEmptyString;
484 v[0] = v[1] = v[2] = v[3] = DXFVector();
485 state = 0;
486 }
487 else if (state == 2) // LINE
488 {
489 DXFLine *p = new DXFLine;
490 p->v0 = v[0];
491 p->v1 = v[1];
492 if (colour != -1)
493 p->colour = colour;
494 else
495 p->colour = GetLayerColour(layer);
496 m_entities.Append(p);
497 colour = -1; layer = wxEmptyString;
498 v[0] = v[1] = v[2] = v[3] = DXFVector();
499 state = 0;
500 }
501 }
502 if (line1 == wxT("0") && line2 == wxT("ENDSEC"))
503 return true;
504 else if (line1 == wxT("0") && line2 == wxT("3DFACE"))
505 state = 1;
506 else if (line1 == wxT("0") && line2 == wxT("LINE"))
507 state = 2;
508 else if (state > 0)
509 {
510 const double d=ToDouble(line2);
511
512 if (line1 == wxT("10"))
513 v[0].x = d;
514 else if (line1 == wxT("20"))
515 v[0].y = d;
516 else if (line1 == wxT("30"))
517 v[0].z = d;
518 else if (line1 == wxT("11"))
519 v[1].x = d;
520 else if (line1 == wxT("21"))
521 v[1].y = d;
522 else if (line1 == wxT("31"))
523 v[1].z = d;
524 else if (line1 == wxT("12"))
525 v[2].x = d;
526 else if (line1 == wxT("22"))
527 v[2].y = d;
528 else if (line1 == wxT("32"))
529 v[2].z = d;
530 else if (line1 == wxT("13"))
531 v[3].x = d;
532 else if (line1 == wxT("23"))
533 v[3].y = d;
534 else if (line1 == wxT("33"))
535 v[3].z = d;
536 else if (line1 == wxT("8")) // layer
537 layer = line2;
538 else if (line1 == wxT("62")) // colour
539 {
540 long l;
541 line2.ToLong(&l);
542 colour = l;
543 }
544 }
545 }
546 return false;
547 }
548
549 // parse and load a DXF file
550 // currently pretty limited, but knows enought do handle 3DFACEs and LINEs
551 bool DXFRenderer::Load(wxInputStream& stream)
552 {
553 Clear();
554 wxTextInputStream text(stream);
555
556 wxString line1, line2;
557 while (stream.CanRead())
558 {
559 GetLines(text, line1, line2);
560 if (line1 == wxT("999")) // comment
561 continue;
562 else if (line1 == wxT("0") && line2 == wxT("SECTION"))
563 {
564 GetLines(text, line1, line2);
565 if (line1 == wxT("2"))
566 {
567 if (line2 == wxT("HEADER"))
568 {
569 if (!ParseHeader(stream))
570 return false;
571 }
572 else if (line2 == wxT("TABLES"))
573 {
574 if (!ParseTables(stream))
575 return false;
576 }
577 else if (line2 == wxT("ENTITIES"))
578 {
579 if (!ParseEntities(stream))
580 return false;
581 }
582 }
583 }
584 }
585
586 NormalizeEntities();
587 m_loaded = true;
588 return true;
589 }
590
591 inline float mymin(float x, float y) { return x < y ? x : y; }
592 inline float mymax(float x, float y) { return x > y ? x : y; }
593
594 // Scale object boundings to [-5,5]
595 void DXFRenderer::NormalizeEntities()
596 {
597 // calculate current min and max boundings of object
598 DXFVector minv(10e20f, 10e20f, 10e20f);
599 DXFVector maxv(-10e20f, -10e20f, -10e20f);
600 for (DXFEntityList::compatibility_iterator node = m_entities.GetFirst(); node; node = node->GetNext())
601 {
602 DXFEntity *p = node->GetData();
603 if (p->type == DXFEntity::Line)
604 {
605 DXFLine *line = (DXFLine *)p;
606 const DXFVector *v[2] = { &line->v0, &line->v1 };
607 for (int i = 0; i < 2; ++i)
608 {
609 minv.x = mymin(v[i]->x, minv.x);
610 minv.y = mymin(v[i]->y, minv.y);
611 minv.z = mymin(v[i]->z, minv.z);
612 maxv.x = mymax(v[i]->x, maxv.x);
613 maxv.y = mymax(v[i]->y, maxv.y);
614 maxv.z = mymax(v[i]->z, maxv.z);
615 }
616 } else if (p->type == DXFEntity::Face)
617 {
618 DXFFace *face = (DXFFace *)p;
619 const DXFVector *v[4] = { &face->v0, &face->v1, &face->v2, &face->v3 };
620 for (int i = 0; i < 4; ++i)
621 {
622 minv.x = mymin(v[i]->x, minv.x);
623 minv.y = mymin(v[i]->y, minv.y);
624 minv.z = mymin(v[i]->z, minv.z);
625 maxv.x = mymax(v[i]->x, maxv.x);
626 maxv.y = mymax(v[i]->y, maxv.y);
627 maxv.z = mymax(v[i]->z, maxv.z);
628 }
629 }
630 }
631
632 // rescale object down to [-5,5]
633 DXFVector span(maxv.x - minv.x, maxv.y - minv.y, maxv.z - minv.z);
634 float factor = mymin(mymin(10.0f / span.x, 10.0f / span.y), 10.0f / span.z);
635 for (DXFEntityList::compatibility_iterator node2 = m_entities.GetFirst(); node2; node2 = node2->GetNext())
636 {
637 DXFEntity *p = node2->GetData();
638 if (p->type == DXFEntity::Line)
639 {
640 DXFLine *line = (DXFLine *)p;
641 DXFVector *v[2] = { &line->v0, &line->v1 };
642 for (int i = 0; i < 2; ++i)
643 {
644 v[i]->x -= minv.x + span.x/2; v[i]->x *= factor;
645 v[i]->y -= minv.y + span.y/2; v[i]->y *= factor;
646 v[i]->z -= minv.z + span.z/2; v[i]->z *= factor;
647 }
648 } else if (p->type == DXFEntity::Face)
649 {
650 DXFFace *face = (DXFFace *)p;
651 DXFVector *v[4] = { &face->v0, &face->v1, &face->v2, &face->v3 };
652 for (int i = 0; i < 4; ++i)
653 {
654 v[i]->x -= minv.x + span.x/2; v[i]->x *= factor;
655 v[i]->y -= minv.y + span.y/2; v[i]->y *= factor;
656 v[i]->z -= minv.z + span.z/2; v[i]->z *= factor;
657 }
658 }
659 }
660 }
661
662 // OpenGL renderer for DXF entities
663 void DXFRenderer::Render() const
664 {
665 if (!m_loaded)
666 return;
667
668 for (DXFEntityList::compatibility_iterator node = m_entities.GetFirst(); node; node = node->GetNext())
669 {
670 DXFEntity *p = node->GetData();
671 wxColour c = ACIColourToRGB(p->colour);
672 if (p->type == DXFEntity::Line)
673 {
674 DXFLine *line = (DXFLine *)p;
675 glBegin(GL_LINES);
676 glColor3f(c.Red()/255.0,c.Green()/255.0,c.Blue()/255.0);
677 glVertex3f(line->v0.x, line->v0.y, line->v0.z);
678 glVertex3f(line->v1.x, line->v1.y, line->v1.z);
679 glEnd();
680 }
681 else if (p->type == DXFEntity::Face)
682 {
683 DXFFace *face = (DXFFace *)p;
684 glBegin(GL_TRIANGLES);
685 glColor3f(c.Red()/255.0,c.Green()/255.0,c.Blue()/255.0);
686 glNormal3f(face->n.x, face->n.y, face->n.z);
687 glVertex3f(face->v0.x, face->v0.y, face->v0.z);
688 glVertex3f(face->v1.x, face->v1.y, face->v1.z);
689 glVertex3f(face->v2.x, face->v2.y, face->v2.z);
690 glEnd();
691 }
692 }
693 }