curvedraw

view src/curvefile.cc @ 16:7f795f7fecd6

readme and COPYING
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 20 Dec 2015 10:55:57 +0200
parents 37ab3a4c02f8
children
line source
1 /*
2 curvedraw - a simple program to draw curves
3 Copyright (C) 2015 John Tsiombikas <nuclear@member.fsf.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include <stdlib.h>
19 #include <ctype.h>
20 #include <string>
21 #include "curvefile.h"
23 static bool save_curve(FILE *fp, const Curve *curve);
25 bool save_curves(const char *fname, const Curve * const *curves, int count)
26 {
27 FILE *fp = fopen(fname, "wb");
28 if(!fp) return false;
30 bool res = save_curves(fp, curves, count);
31 fclose(fp);
32 return res;
33 }
35 bool save_curves(FILE *fp, const Curve * const *curves, int count)
36 {
37 fprintf(fp, "GCURVES\n");
39 for(int i=0; i<count; i++) {
40 if(!save_curve(fp, curves[i])) {
41 return false;
42 }
43 }
44 return true;
45 }
47 static const char *curve_type_str(CurveType type)
48 {
49 switch(type) {
50 case CURVE_LINEAR:
51 return "polyline";
52 case CURVE_HERMITE:
53 return "hermite";
54 case CURVE_BSPLINE:
55 return "bspline";
56 }
57 abort();
58 }
60 static bool save_curve(FILE *fp, const Curve *curve)
61 {
62 fprintf(fp, "curve {\n");
63 fprintf(fp, " type %s\n", curve_type_str(curve->get_type()));
64 fprintf(fp, " cpcount %d\n", curve->size());
65 for(int i=0; i<curve->size(); i++) {
66 Vector4 cp = curve->get_point(i);
67 fprintf(fp, " cp %g %g %g %g\n", cp.x, cp.y, cp.z, cp.w);
68 }
69 fprintf(fp, "}\n");
70 return true;
71 }
73 std::list<Curve*> load_curves(const char *fname)
74 {
75 std::list<Curve*> res;
76 FILE *fp = fopen(fname, "r");
77 if(!fp) return res;
79 res = load_curves(fp);
80 fclose(fp);
81 return res;
82 }
84 static std::string next_token(FILE *fp)
85 {
86 std::string s;
87 int c;
88 while((c = fgetc(fp)) != -1) {
89 if(!isspace(c)) {
90 ungetc(c, fp);
91 break;
92 }
93 }
95 if(feof(fp)) return s;
96 while((c = fgetc(fp)) != -1) {
97 if(isspace(c)) {
98 ungetc(c, fp);
99 break;
100 }
101 s.push_back(c);
102 }
103 return s;
104 }
106 static bool expect_str(FILE *fp, const char *s)
107 {
108 std::string tok = next_token(fp);
109 if(tok != std::string(s)) {
110 if(tok.empty() && feof(fp)) {
111 fprintf(stderr, "expected: %s\n", s);
112 }
113 return false;
114 }
115 return true;
116 }
118 static bool expect_float(FILE *fp, float *ret)
119 {
120 std::string tok = next_token(fp);
121 const char *cs = tok.c_str();
122 char *endp;
123 *ret = strtod(cs, &endp);
124 if(endp != cs + tok.length()) {
125 if(!(tok.empty() && feof(fp))) {
126 fprintf(stderr, "number expected\n");
127 }
128 return false;
129 }
130 return true;
131 }
133 static bool expect_int(FILE *fp, int *ret)
134 {
135 std::string tok = next_token(fp);
136 const char *cs = tok.c_str();
137 char *endp;
138 *ret = strtol(cs, &endp, 0);
139 if(endp != cs + tok.length()) {
140 if(!(tok.empty() && feof(fp))) {
141 fprintf(stderr, "integer expected\n");
142 }
143 return false;
144 }
145 return true;
146 }
148 static Curve *curve_block(FILE *fp)
149 {
150 if(!expect_str(fp, "curve") || !expect_str(fp, "{")) {
151 return 0;
152 }
154 Curve *curve = new Curve;
155 int cpcount = -1;
156 std::string tok;
157 while(!(tok = next_token(fp)).empty() && tok != "}") {
158 if(tok == "cpcount") {
159 if(cpcount != -1 || !expect_int(fp, &cpcount) || cpcount <= 0) {
160 goto err;
161 }
162 } else if(tok == "type") {
163 tok = next_token(fp);
164 if(tok == "polyline") {
165 curve->set_type(CURVE_LINEAR);
166 } else if(tok == "hermite") {
167 curve->set_type(CURVE_HERMITE);
168 } else if(tok == "bspline") {
169 curve->set_type(CURVE_BSPLINE);
170 } else {
171 goto err;
172 }
173 } else {
174 if(tok != "cp") {
175 goto err;
176 }
177 Vector4 cp;
178 for(int i=0; i<4; i++) {
179 if(!expect_float(fp, &cp[i])) {
180 goto err;
181 }
182 }
183 curve->add_point(Vector3(cp.x, cp.y, cp.z), cp.w);
184 }
185 }
187 if(curve->size() != cpcount) {
188 fprintf(stderr, "warning: curve cpcount was %d, but read %d control points\n", cpcount, curve->size());
189 }
191 return curve;
192 err:
193 fprintf(stderr, "failed to parse curve block\n");
194 delete curve;
195 return 0;
196 }
198 std::list<Curve*> load_curves(FILE *fp)
199 {
200 std::list<Curve*> curves;
201 if(!expect_str(fp, "GCURVES")) {
202 fprintf(stderr, "load_curves: failed to load, invalid file format\n");
203 return curves;
204 }
206 Curve *curve;
207 while((curve = curve_block(fp))) {
208 curves.push_back(curve);
209 }
211 if(!feof(fp)) {
212 std::list<Curve*>::iterator it = curves.begin();
213 while(it != curves.end()) {
214 delete *it++;
215 }
216 return curves;
217 }
219 return curves;
220 }