]> Shamusworld >> Repos - ttedit/blob - src/glyphpoints.cpp
Added some functions to GlyphPoints to reduce redundancy in glyph
[ttedit] / src / glyphpoints.cpp
1 //
2 // GLYPHPOINTS.CPP
3 //
4 // Class implementation. Nothing too inexplicable going on here. Fairly
5 // straightforward stuff.
6 //
7 // by James L. Hammons
8 // (C) 2004 Underground Software
9 //
10 // JLH = James L. Hammons <jlhamm@acm.org>
11 //
12 // Who  When        What
13 // ---  ----------  ------------------------------------------------------------
14 // JLH  ??/??/200?  Created this file
15 // JLH  05/18/2004  Added pure point adding, inserting, better polygon handling
16 //
17
18 // Uncomment this for debugging...
19 #define DEBUG
20
21 #include "glyphpoints.h"
22 #ifdef DEBUG
23 #include "debug.h"
24 #endif
25
26 /*GlyphPoints::GlyphPoints(void)
27 {
28         GlyphPoints(0, 0, NULL, NULL, NULL, NULL);
29 }*/
30
31 GlyphPoints::GlyphPoints(int nPts/*=0*/, int nPlys/*=0*/, int * xa/*=null*/, int * ya/*=null*/,
32         bool * oca/*=null*/, uint16 * pa/*=null*/): x(NULL), y(NULL), onCurve(NULL), polyEnd(NULL)
33 //GlyphPoints::GlyphPoints(int nPts, int nPlys/*=0*/, int * xa/*=null*/, int * ya/*=null*/,
34 //      bool * oca/*=null*/, uint16 * pa/*=null*/): x(NULL), y(NULL), onCurve(NULL), polyEnd(NULL)
35 {
36         AllocateAndCopy(nPts, nPlys, xa, ya, oca, pa);
37
38         if (nPlys == 0)
39         {
40                 numPolys = 1;
41                 polyEnd = new uint16[numPolys];
42                 polyEnd[0] = numPoints - 1;
43         }
44 #ifdef DEBUG
45 WriteLogMsg("GlyphPoints: Default constructor. %u points, %u polys.\n", numPoints, numPolys);
46 #endif
47 }
48
49 GlyphPoints::GlyphPoints(int xx, int yy, bool oc)
50 {
51 //Hmm. What to do with this...?
52         AllocateAndCopy(1, 0, &xx, &yy, &oc, NULL);
53 #ifdef DEBUG
54 WriteLogMsg("GlyphPoints: Single point constructor. %u points, %u polys.\n", numPoints, numPolys);
55 #endif
56 }
57
58 // Copy constructor (needed for deep copying)
59
60 //GlyphPoints::GlyphPoints(GlyphPoints &c): x(NULL), y(NULL), onCurve(NULL), polyEnd(NULL)
61 GlyphPoints::GlyphPoints(const GlyphPoints &c): x(NULL), y(NULL), onCurve(NULL), polyEnd(NULL)
62 {
63         *this = c;                                                                      // Use overloaded operator=
64 #ifdef DEBUG
65 WriteLogMsg("GlyphPoints: Copy constructor. %u points, %u polys.\n", numPoints, numPolys);
66 #endif
67 }
68
69 GlyphPoints::~GlyphPoints()
70 {
71         if (x)
72                 delete[] x;
73
74         if (y)
75                 delete[] y;
76
77         if (onCurve)
78                 delete[] onCurve;
79
80         if (polyEnd)
81                 delete[] polyEnd;
82 }
83
84 void GlyphPoints::AllocateAndCopy(int nPts, int nPlys, int * xa, int * ya, bool * oca, uint16 * pa)
85 {
86         numPoints = nPts, numPolys = nPlys;
87
88         if (nPts)
89         {
90                 x = new int[numPoints];
91                 y = new int[numPoints];
92                 onCurve = new bool[numPoints];
93
94                 if (xa)                                                                 // Copy points in if they're passed in...
95                         for(int i=0; i<nPts; i++)
96                                 x[i] = xa[i];
97
98                 if (ya)
99                         for(int i=0; i<nPts; i++)
100                                 y[i] = ya[i];
101
102                 if (oca)
103                         for(int i=0; i<nPts; i++)
104                                 onCurve[i] = oca[i];
105         }
106
107         if (numPolys)
108         {
109                 polyEnd = new uint16[numPolys];
110
111                 if (pa)                                                                 // Copy poly ends in if they're passed in...
112                         for(int i=0; i<nPlys; i++)
113                                 polyEnd[i] = pa[i];
114         }
115 }
116
117 GlyphPoints& GlyphPoints::operator=(const GlyphPoints &c)
118 {
119         if (this == &c)
120                 return *this;                                                   // Take care of self-assignment
121
122         if (x)
123                 delete[] x;
124
125         if (y)
126                 delete[] y;
127
128         if (onCurve)
129                 delete[] onCurve;
130
131         if (polyEnd)
132                 delete[] polyEnd;
133
134         AllocateAndCopy(c.numPoints, c.numPolys, c.x, c.y, c.onCurve, c.polyEnd);
135
136         return *this;
137 }
138
139 // Add another GlyphPoints' points to this one...
140
141 GlyphPoints GlyphPoints::operator+(const GlyphPoints &c)
142 {
143         int totPoints = numPoints + c.numPoints, totPolys = numPolys + c.numPolys;
144
145         int * totX = new int[totPoints];
146         int * totY = new int[totPoints];
147         bool * totOnCurve = new bool[totPoints];
148         uint16 * totPolyEnd = new uint16[totPolys];
149
150         for(int i=0; i<numPoints; i++)
151         {
152                 totX[i] = x[i];
153                 totY[i] = y[i];
154                 totOnCurve[i] = onCurve[i];
155         }
156
157         for(int i=0; i<numPolys; i++)
158                 totPolyEnd[i] = polyEnd[i];
159
160         for(int i=0; i<c.numPoints; i++)
161         {
162                 totX[numPoints+i] = c.x[i];
163                 totY[numPoints+i] = c.y[i];
164                 totOnCurve[numPoints+i] = c.onCurve[i];
165         }
166
167         for(int i=0; i<c.numPolys; i++)
168                 totPolyEnd[numPolys+i] = numPoints + c.polyEnd[i];  // Need to adjust the "added in"
169                                                         // poly's end points...
170
171         GlyphPoints retVal(totPoints, totPolys, totX, totY, totOnCurve, totPolyEnd);
172         delete[] totX;
173         delete[] totY;
174         delete[] totOnCurve;
175         delete[] totPolyEnd;
176
177         return retVal;
178 }
179
180 // Add a point to this GlyphPoints...
181
182 GlyphPoints GlyphPoints::operator+(const IPoint &c)
183 {
184 //This is kinda silly. We can do better than this! !!! FIX !!!
185         int * totX = new int[numPoints + 1];
186         int * totY = new int[numPoints + 1];
187         bool * totOnCurve = new bool[numPoints + 1];
188         uint16 * totPolyEnd = new uint16[numPolys];
189
190         for(int i=0; i<numPoints; i++)
191                 totX[i] = x[i], totY[i] = y[i], totOnCurve[i] = onCurve[i];
192
193         totX[numPoints] = c.x, totY[numPoints] = c.y, totOnCurve[numPoints] = c.onCurve;
194
195         for(int i=0; i<numPolys; i++)
196                 totPolyEnd[i] = polyEnd[i];
197
198         totPolyEnd[numPolys - 1]++;                                     // Bump polygon's end point
199         GlyphPoints retVal(numPoints + 1, numPolys, totX, totY, totOnCurve, totPolyEnd);
200
201         delete[] totX;
202         delete[] totY;
203         delete[] totOnCurve;
204
205         return retVal;
206 }
207
208 GlyphPoints& GlyphPoints::operator+=(const IPoint &p)
209 {
210         InsertPoint(numPoints, p.x, p.y, p.onCurve);
211
212         return *this;
213 }
214
215 void GlyphPoints::InsertPoint(uint16 pt, int xx, int yy, bool oc)
216 {
217         if (pt > numPoints)                                                     // > because we can insert at end...!
218                 throw GP_OUT_OF_RANGE;
219
220 //This is kinda silly. We can do better than this! !!! FIX !!!
221         int * totX = new int[numPoints + 1];
222         int * totY = new int[numPoints + 1];
223         bool * totOnCurve = new bool[numPoints + 1];
224
225         for(int i=0; i<pt; i++)
226                 totX[i] = x[i], totY[i] = y[i], totOnCurve[i] = onCurve[i];
227
228         for(int i=pt; i<numPoints; i++)
229                 totX[i + 1] = x[i], totY[i + 1] = y[i], totOnCurve[i + 1] = onCurve[i];
230
231         totX[pt] = xx, totY[pt] = yy, totOnCurve[pt] = oc;
232
233 //A way to fix the kludge in GetPoly() would be to put a check here to see if
234 //we're adding to the end of the structure: [DONE, below]
235         int polyInsert = (pt == numPoints ? numPolys - 1 : GetPoly(pt));
236         for(int i=polyInsert; i<numPolys; i++)
237 //      for(int i=GetPoly(pt); i<numPolys; i++)
238                 polyEnd[i]++;                                                   // Bump polygons' end point
239
240         numPoints++;
241
242         delete[] x;
243         delete[] y;
244         delete[] onCurve;
245
246         x = totX, y = totY, onCurve = totOnCurve;
247 }
248
249 void GlyphPoints::InsertPoint(uint16 pt, const IPoint &p)
250 {
251         InsertPoint(pt, p.x, p.y, p.onCurve);
252 }
253
254 //
255 // Delete a point from the glyph
256 // Note that we don't bother to reallocate anything here, just bump the
257 // size counters down as needed. In the future, we'll keep track so we
258 // don't have to reallocate *every* damn time a point is added...
259 //
260 void GlyphPoints::DeletePoint(uint16 pt)
261 {
262         // Adjust polygon ends appropriately
263         uint16 poly = GetPoly(pt);
264
265         for(int i=poly; i<numPolys; i++)
266                 polyEnd[i]--;
267
268 //Need to check here if we're deleting the last point in the glyph or not.
269 //!!! FIX !!! [DONE]
270         if (GetNumPoints(poly) == 0 && numPoints > 0)
271         {
272                 numPolys--;
273
274                 for(int i=poly; i<numPolys; i++)
275                         polyEnd[i] = polyEnd[i + 1];
276         }
277
278 //This causes a crash becuz GetPoly() uses numPoints... !!! FIX !!! [DONE by switching poly delete & point delete]
279         // Close up the gap left by the current point
280         numPoints--;
281
282         for(int i=pt; i<numPoints; i++)
283                 x[i] = x[i + 1], y[i] = y[i + 1], onCurve[i] = onCurve[i + 1];
284 }
285
286 uint16 GlyphPoints::GetNumPoints(void)
287 {
288         return numPoints;
289 }
290
291 uint16 GlyphPoints::GetNumPoints(uint16 poly)
292 {
293         if (poly >= numPolys)
294 #ifdef DEBUG
295 {
296 WriteLogMsg("Exception: GetNumPoints(uint16). poly=%u, numPolys=%u\xD\xA", poly, numPolys);
297 #endif
298                 throw GP_OUT_OF_RANGE;
299 #ifdef DEBUG
300 }
301 #endif
302
303         return polyEnd[poly] - (poly == 0 ? -1 : polyEnd[poly - 1]);
304 }
305
306 uint16 GlyphPoints::GetNumPolys(void)
307 {
308         return numPolys;
309 }
310
311 int GlyphPoints::GetX(uint16 pt)
312 {
313         if (pt >= numPoints)
314 #ifdef DEBUG
315 {
316 WriteLogMsg("Exception: GetX(uint16). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
317 #endif
318                 throw GP_OUT_OF_RANGE;
319 #ifdef DEBUG
320 }
321 #endif
322
323         return x[pt];
324 }
325
326 int GlyphPoints::GetY(uint16 pt)
327 {
328         if (pt >= numPoints)
329 #ifdef DEBUG
330 {
331 WriteLogMsg("Exception: GetY(uint16). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
332 #endif
333                 throw GP_OUT_OF_RANGE;
334 #ifdef DEBUG
335 }
336 #endif
337
338         return y[pt];
339 }
340
341 bool GlyphPoints::GetOnCurve(uint16 pt)
342 {
343         if (pt >= numPoints)
344 #ifdef DEBUG
345 {
346 WriteLogMsg("Exception: GetOnCurve(uint16). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
347 #endif
348                 throw GP_OUT_OF_RANGE;
349 #ifdef DEBUG
350 }
351 #endif
352
353         return onCurve[pt];
354 }
355
356 int GlyphPoints::GetX(uint16 poly, uint16 pt)
357 {
358         if (pt >= GetNumPoints(poly))
359 #ifdef DEBUG
360 {
361 WriteLogMsg("Exception: GetX(uint16, uint16). poly= %u, pt=%u, numPoints=%u\xD\xA", poly, pt, numPoints);
362 #endif
363                 throw GP_OUT_OF_RANGE;
364 #ifdef DEBUG
365 }
366 #endif
367
368         return x[pt + (poly == 0 ? 0 : polyEnd[poly - 1] + 1)];
369 }
370
371 int GlyphPoints::GetNextX(uint16 poly, uint16 pt)
372 {
373         return GetX(poly, GetNext(poly, pt));
374 }
375
376 int GlyphPoints::GetY(uint16 poly, uint16 pt)
377 {
378         if (pt >= GetNumPoints(poly))
379 #ifdef DEBUG
380 {
381 WriteLogMsg("Exception: GetY(uint16, uint16). poly= %u, pt=%u, numPoints=%u\xD\xA", poly, pt, numPoints);
382 #endif
383                 throw GP_OUT_OF_RANGE;
384 #ifdef DEBUG
385 }
386 #endif
387
388         return y[pt + (poly == 0 ? 0 : polyEnd[poly - 1] + 1)];
389 }
390
391 int GlyphPoints::GetNextY(uint16 poly, uint16 pt)
392 {
393         return GetY(poly, GetNext(poly, pt));
394 }
395
396 IPoint GlyphPoints::GetPoint(uint16 poly, uint16 pt)
397 {
398         return IPoint(GetX(poly, pt), GetY(poly, pt));
399 }
400
401 bool GlyphPoints::GetOnCurve(uint16 poly, uint16 pt)
402 {
403         if (pt >= GetNumPoints(poly))
404 #ifdef DEBUG
405 {
406 WriteLogMsg("Exception: GetOnCurve(uint16, uint16). poly= %u, pt=%u, numPoints=%u\xD\xA", poly, pt, numPoints);
407 #endif
408                 throw GP_OUT_OF_RANGE;
409 #ifdef DEBUG
410 }
411 #endif
412
413         return onCurve[pt + (poly == 0 ? 0 : polyEnd[poly - 1] + 1)];
414 }
415
416 bool GlyphPoints::GetPrevOnCurve(uint16 poly, uint16 pt)
417 {
418         return GetOnCurve(poly, GetPrev(poly, pt));
419 }
420
421 bool GlyphPoints::GetNextOnCurve(uint16 poly, uint16 pt)
422 {
423         return GetOnCurve(poly, GetNext(poly, pt));
424 }
425
426 uint16 GlyphPoints::GetPolyEnd(uint16 poly)
427 {
428         if (poly >= numPolys)
429 #ifdef DEBUG
430 {
431 WriteLogMsg("Exception: GetPolyEnd(uint16). poly=%u, numPolys=%u\xD\xA", poly, numPolys);
432 #endif
433                 throw GP_OUT_OF_RANGE;
434 #ifdef DEBUG
435 }
436 #endif
437
438         return polyEnd[poly];
439 }
440
441 void GlyphPoints::OffsetPoints(int xOff, int yOff)
442 {
443         for(int i=0; i<numPoints; i++)
444                 x[i] += xOff, y[i] += yOff;
445 }
446
447 //
448 // Offset only a specific polygon in the glyph
449 //
450 void GlyphPoints::OffsetPoly(uint16 poly, int32 xOff, int32 yOff)
451 {
452         if (poly >= numPolys)
453 #ifdef DEBUG
454 {
455 WriteLogMsg("Exception: GetPolyEnd(uint16). poly=%u, numPolys=%u\xD\xA", poly, numPolys);
456 #endif
457                 throw GP_OUT_OF_RANGE;
458 #ifdef DEBUG
459 }
460 #endif
461
462         uint16 polyStart = (poly == 0 ? 0 : polyEnd[poly - 1] + 1);
463
464         for(int i=0; i<GetNumPoints(poly); i++)
465                 x[polyStart + i] += xOff, y[polyStart + i] += yOff;
466 }
467
468 void GlyphPoints::ScalePoints(float sc)
469 {
470         for(int i=0; i<numPoints; i++)
471                 x[i] = (int)(((float)x[i] * sc) + 0.5f),
472                 y[i] = (int)(((float)y[i] * sc) + 0.5f);
473 }
474
475 void GlyphPoints::SetXY(uint16 pt, int xx, int yy)
476 {
477         if (pt >= numPoints)
478 #ifdef DEBUG
479 {
480 WriteLogMsg("Exception: SetXY(uint16, int, int). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
481 #endif
482                 throw GP_OUT_OF_RANGE;
483 #ifdef DEBUG
484 }
485 #endif
486
487         x[pt] = xx, y[pt] = yy;
488 }
489
490 void GlyphPoints::SetOnCurve(uint16 pt, bool oc)
491 {
492         if (pt >= numPoints)
493 #ifdef DEBUG
494 {
495 WriteLogMsg("Exception: SetOnCurve(uint16, bool). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
496 #endif
497                 throw GP_OUT_OF_RANGE;
498 #ifdef DEBUG
499 }
500 #endif
501
502         onCurve[pt] = oc;
503 }
504
505 uint16 GlyphPoints::GetPrev(uint16 pt)
506 {
507 // pt = 7, polyEnd = 4, 9, 15
508         uint16 min = 0, max = numPoints - 1;
509
510         for(int i=0; i<numPolys; i++)
511         {
512                 if (pt <= polyEnd[i])
513                 {
514                         if (i > 0)
515                                 min = polyEnd[i - 1] + 1;
516
517                         max = polyEnd[i];
518                         break;
519                 }
520         }
521
522         uint16 retVal = pt - 1;
523
524         if (pt == min)
525                 retVal = max;
526
527         return retVal;
528 }
529
530 uint16 GlyphPoints::GetNext(uint16 pt)
531 {
532         uint16 min = 0, max = numPoints - 1;
533
534         for(int i=0; i<numPolys; i++)
535         {
536                 if (pt <= polyEnd[i])
537                 {
538                         if (i > 0)
539                                 min = polyEnd[i - 1] + 1;
540
541                         max = polyEnd[i];
542                         break;
543                 }
544         }
545
546         uint16 retVal = pt + 1;
547
548         if (pt == max)
549                 retVal = min;
550
551         return retVal;
552 }
553
554 //
555 // Get previous point for this polygon using wraparound.
556 // Note that pt is a zero-based index!
557 //
558 uint16 GlyphPoints::GetPrev(uint16 poly, uint16 pt)
559 {
560         return (pt == 0 ? GetNumPoints(poly) - 1 : pt - 1);
561 }
562
563 //
564 // Get next point for this polygon using wraparound.
565 // Note that pt is a zero-based index!
566 //
567 uint16 GlyphPoints::GetNext(uint16 poly, uint16 pt)
568 {
569         return (pt == GetNumPoints(poly) - 1 ? 0 : pt + 1);
570 }
571
572 uint16 GlyphPoints::GetPoly(uint16 pt)
573 {
574         if (pt >= numPoints)
575 #ifdef DEBUG
576 {
577 WriteLogMsg("Exception: GetPoly(uint16). pt=%u, numPoints=%u\xD\xA", pt, numPoints);
578 #endif
579                 throw GP_OUT_OF_RANGE;
580 #ifdef DEBUG
581 }
582 #endif
583
584         for(int i=0; i<numPolys; i++)
585                 if (pt <= polyEnd[i])
586                         return i;
587
588         return (uint16)-1;
589 }
590
591 void GlyphPoints::AddNewPolyAtEnd(void)
592 {
593         if (numPoints == 0)                                                     // By default, we already *have* a poly
594                 return;
595
596         uint16 * newPolyEnd = new uint16[numPolys + 1];
597
598         for(uint16 i=0; i<numPolys; i++)
599                 newPolyEnd[i] = polyEnd[i];
600
601         newPolyEnd[numPolys] = newPolyEnd[numPolys - 1];
602         numPolys++;
603         delete[] polyEnd;
604         polyEnd = newPolyEnd;
605 }
606
607 IPoint GlyphPoints::GetMidpointToPrev(uint16 poly, uint16 pt)
608 {
609         uint16 prev = GetPrev(poly, pt);
610
611         int32 x1 = GetX(poly, pt), y1 = GetY(poly, pt);
612         int32 x2 = GetX(poly, prev), y2 = GetY(poly, prev);
613
614         return IPoint((x1 + x2) / 2.0f, (y1 + y2) / 2.0f);
615 }
616
617 IPoint GlyphPoints::GetMidpointToNext(uint16 poly, uint16 pt)
618 {
619         uint16 next = GetNext(poly, pt);
620
621         int32 x1 = GetX(poly, pt), y1 = GetY(poly, pt);
622         int32 x2 = GetX(poly, next), y2 = GetY(poly, next);
623
624         return IPoint((x1 + x2) / 2.0f, (y1 + y2) / 2.0f);
625 }
626
627 IPoint GlyphPoints::GetPrevPoint(uint16 poly, uint16 pt)
628 {
629         uint16 prevPt = GetPrev(poly, pt);
630
631         return IPoint(GetX(poly, prevPt), GetY(poly, prevPt));
632 }
633
634 IPoint GlyphPoints::GetNextPoint(uint16 poly, uint16 pt)
635 {
636         uint16 nextPt = GetNext(poly, pt);
637
638         return IPoint(GetX(poly, nextPt), GetY(poly, nextPt));
639 }