├── COPYING
├── Makefile
├── README.md
└── main.c
/COPYING:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | OSTYPE=$(shell uname)
2 |
3 | LIBS = sdl ftgl fontconfig
4 | CFLAGS = -O$(OPTIMIZE) -std=c99 -Wall `pkg-config --cflags $(LIBS)`
5 | LDFLAGS = `pkg-config --libs $(LIBS)` -lm
6 |
7 | ifeq ($(OSTYPE),Darwin)
8 | LIBS += freetype2
9 | LDFLAGS += -framework OpenGL
10 | else
11 | LIBS += gl
12 | endif
13 |
14 | EXECUTABLE = gcodeview
15 |
16 | OPTIMIZE = 2
17 |
18 | SOURCES = main.c
19 | OBJECTS = $(SOURCES:.c=.o)
20 |
21 | .PHONY: all clean
22 |
23 | all: $(SOURCES) $(EXECUTABLE)
24 |
25 | $(EXECUTABLE): $(OBJECTS)
26 | $(CC) $(OBJECTS) $(LDFLAGS) -o $@
27 | @echo Building for [$(OSTYPE)].
28 |
29 | %.o: %.c
30 | $(CC) $(CFLAGS) -std=c99 -c $< -o $@
31 |
32 | clean:
33 | rm $(OBJECTS) $(EXECUTABLE)
34 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | GCodeView
2 | =========
3 |
4 | Purpose
5 | -------
6 |
7 | A *FAST* gcode viewer.
8 |
9 | Nothing fancy, nothing else.
10 |
11 | Usage
12 | -----
13 |
14 | `gcodeview `
15 |
16 | Controls
17 | --------
18 |
19 | * __Scroll up/down__
20 |
21 | zoom in and out
22 |
23 | * __PgUp / PgDn / shift + Scroll__
24 |
25 | go up and down layers
26 |
27 | * __left click + drag__
28 |
29 | pan view
30 |
31 | * __r__
32 |
33 | reset viewing window
34 |
35 | * __q / ESC__
36 |
37 | exit
38 |
39 | Platforms
40 | ---------
41 |
42 | * works on linux
43 | * should work on mac, with some massaging of the Makefile (pull requests please!)
44 | * no idea about windows, pull requests welcome
45 |
46 | Dependencies
47 | ------------
48 |
49 | 1. SDL
50 | 2. OpenGL
51 | 3. FTGL
52 | 4. fontconfig (linux/mac, windows probably can give me the path to a font some other way)
53 |
54 | Mac OS X (Lion)
55 | ---------------
56 | Install deps with homebrew
57 | 1. brew install sdl
58 | 2. brew install ftgl
59 | 3. brew install fontconfig
60 |
61 |
--------------------------------------------------------------------------------
/main.c:
--------------------------------------------------------------------------------
1 | /***************************************************************************\
2 | * *
3 | * Copyright 2012 Michael Moon *
4 | * *
5 | * *
6 | * This program is free software: you can redistribute it and/or modify *
7 | * it under the terms of the GNU General Public License as published by *
8 | * the Free Software Foundation, either version 3 of the License, or *
9 | * (at your option) any later version. *
10 | * *
11 | * This program is distributed in the hope that it will be useful, *
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 | * GNU General Public License for more details. *
15 | * *
16 | * You should have received a copy of the GNU General Public License *
17 | * along with this program. If not, see . *
18 | * *
19 | * *
20 | * This program lives at http://github.com/triffid/gcodeview and Author can *
21 | * be contacted via that site *
22 | * *
23 | \***************************************************************************/
24 |
25 |
26 | #ifndef _GNU_SOURCE
27 | #define _GNU_SOURCE
28 | #endif
29 |
30 | #ifdef __linux__
31 | #include
32 | #endif
33 |
34 | #include
35 | #include
36 | #include
37 |
38 | #include
39 | #include
40 | #include
41 |
42 | #include
43 | #include
44 | #include
45 | #include
46 | #include
47 |
48 | #include
49 | #include
50 |
51 | #include
52 |
53 | #define bool uint8_t
54 | #define true 255
55 | #define false 0
56 |
57 | #define OPENGL
58 |
59 | #ifdef OPENGL
60 | #include
61 | float transX, transY;
62 | #else
63 | #include
64 | float viewPortL, viewPortR, viewPortT, viewPortB;
65 | #endif
66 |
67 | #ifndef SDL_NOEVENT
68 | #define SDL_NOEVENT 0
69 | #endif
70 |
71 | // main loop fall-through flag
72 | bool Running;
73 |
74 | // whether or not to do cacheing of each layer
75 | bool cache;
76 |
77 | // drawing stuff
78 | #define SHADOW_LAYERS 3
79 | #define SHADOW_ALPHA 0.2
80 | int shadow_layers = 3;
81 | float shadow_alpha = 0.2;
82 |
83 | // busy flags
84 | #define BUSY_SCANFILE 1
85 | #define BUSY_RENDER 2
86 | int busy;
87 |
88 | // getopt stuff
89 | static const char *optString = "l:w:nh?";
90 | static const struct option longOpts[] = {
91 | { "layer", required_argument, NULL, 'l' },
92 | { "width", required_argument, NULL, 'w' },
93 | { "no-cache", no_argument, NULL, 'n' },
94 | { 0 , 0 , 0 , 0 }
95 | };
96 |
97 | // GCODE file related stuff
98 | int filesz;
99 | char* gcodefile;
100 | char* gcodefile_end;
101 | float extrusionWidth = 0.3;
102 | int layerCount;
103 | size_t layerSize;
104 | float linewords[26];
105 |
106 | // for tracking hop/z-lift moves
107 | int ZstackIndex = 0;
108 | typedef struct {
109 | char *start;
110 | float E, X, Y, Z;
111 | } ZstackItem;
112 | ZstackItem Zstack[8];
113 |
114 | // file scan stuff
115 | #define LMASK(l) (1<<((l & ~0x20) - 'A'))
116 | #define SEEN(c) ((seen & LMASK(c)) != 0)
117 | #define LW(c) linewords[c -'A']
118 |
119 | // layer data
120 | #define LD_LISTGENERATED 1
121 | typedef struct {
122 | char* index;
123 | int size;
124 | float height;
125 | uint8_t flags;
126 | int glList;
127 | float startX;
128 | float startY;
129 | float startE;
130 | float endX;
131 | float endY;
132 | float endE;
133 | } layerData;
134 | layerData* layer;
135 |
136 | // FTGL stuff for drawing text
137 | FTGLfont* font = NULL;
138 | char *msgbuf;
139 |
140 | // SDL window and GL Viewport
141 | SDL_Surface* Surf_Display;
142 | int Surf_width;
143 | int Surf_height;
144 |
145 | // Current View settings
146 | int layerVelocity;
147 | int currentLayer;
148 | float zoomFactor;
149 |
150 | // SDL Events Interface
151 | #define KMM_LSHIFT 1
152 | #define KMM_RSHIFT 2
153 | #define KMM_CTRL 4
154 | #define KMM_ALT 8
155 | int keymodifiermask;
156 |
157 | #define TIMER_KEYREPEAT 1
158 | #define TIMER_DRAGRENDER 2
159 | #define TIMER_IDLE 3
160 | SDL_TimerID timerKeyRepeat = NULL;
161 | SDL_TimerID timerDragRender = NULL;
162 | SDL_TimerID timerIdle = NULL;
163 |
164 | float gXmouseDown = 0.0, gYmouseDown = 0.0;
165 |
166 | /***************************************************************************\
167 | * *
168 | * Utility Functions *
169 | * *
170 | \***************************************************************************/
171 |
172 | void display_usage() {
173 | printf("\n");
174 | printf("USAGE: gcodeview [-w|--width width] [-l|--layer layer] [-n|--no-cache] \n");
175 | printf("\n");
176 | printf("\twidth: Extrusion Width used to draw lines\n");
177 | printf("\tlayer: Render this layer first\n");
178 | printf("\tno-cache: Don't cache layers (large files)\n");
179 | printf("\n");
180 | printf("Color Key:\n");
181 | printf("\n");
182 | printf("\tBlack: Extrusion move at current layer height\n");
183 | printf("\tGreen: Travel move at current layer height\n");
184 | printf("\tRed: Travel move at higher layer height (ie hop/z-lift)\n");
185 | printf("\tMagenta: Travel move at lower layer height (ie cutting/etching)\n");
186 | printf("\n");
187 | exit(0);
188 | }
189 |
190 | float minf(float a, float b) {
191 | if (a < b)
192 | return a;
193 | return b;
194 | }
195 |
196 | float maxf(float a, float b) {
197 | if (a > b)
198 | return a;
199 | return b;
200 | }
201 |
202 | float linint(float value, float oldmin, float oldmax, float newmin, float newmax) {
203 | return (value - oldmin) * (newmax - newmin) / (oldmax - oldmin) + newmin;
204 | }
205 |
206 | void die(char* call, char* data) {
207 | int errsv = errno;
208 | fprintf(stderr, "%s%s failed: %s\n", call, data, strerror(errsv));
209 | exit(1);
210 | }
211 |
212 | Uint32 timerCallback(Uint32 interval, void* param) {
213 | SDL_Event e;
214 | e.type = SDL_USEREVENT;
215 | e.user.code = (int) param;
216 | e.user.data1 = 0;
217 | e.user.data2 = 0;
218 |
219 | SDL_PushEvent(&e);
220 |
221 | return 0;
222 | }
223 |
224 | void dumpZstack() {
225 | printf("Zstack has %d entries:\n", ZstackIndex);
226 | for (int i = 0; i < ZstackIndex; i++) {
227 | printf("Zstack %d:\n", i);
228 | printf("\tstart: %d\n", Zstack[i].start - gcodefile);
229 | printf("\tX: %g\n\tY: %g\n\tZ: %g\n", Zstack[i].X, Zstack[i].Y, Zstack[i].Z);
230 | }
231 | }
232 |
233 | /***************************************************************************\
234 | * *
235 | * Read a single line of GCODE, extracting which words are present and their *
236 | * values *
237 | * *
238 | \***************************************************************************/
239 |
240 | void findEndFloat(char *c, char **end) {
241 | while ((*c >= '0' && *c <= '9') || (*c == '.') || (*c == 'e') || (*c == '-') || (*c == '+'))
242 | c++;
243 | *end = c;
244 | }
245 |
246 | uint32_t scanline(char *line, int length, float *words, char **end, uint32_t interest_mask) {
247 | int i = 0;
248 | uint32_t seen = 0;
249 |
250 | #define COMMENT_SEMICOLON 1
251 | #define COMMENT_PARENTHESIS 2
252 | int comment = 0;
253 | while (i < length) {
254 | char c = line[i];
255 | if (c == 13 || c == 10) {
256 | *end = &line[i + 1];
257 | return seen;
258 | }
259 | if ((comment & COMMENT_SEMICOLON) == 0) {
260 | if (c == ';')
261 | comment |= COMMENT_SEMICOLON;
262 | else if (c == '(')
263 | comment |= COMMENT_PARENTHESIS;
264 | else if (c == ')')
265 | comment &= ~COMMENT_PARENTHESIS;
266 |
267 | else if (comment == 0) {
268 | if (c >= 'a' && c <= 'z')
269 | c &= ~0x20;
270 | if (c >= 'A' && c <= 'Z') {
271 | char *e;
272 | if (LMASK(c) & interest_mask) {
273 | float v = strtof(&line[i + 1], &e);
274 | if (e > &line[i + 1]) {
275 | seen |= LMASK(c);
276 | words[c - 'A'] = v;
277 | i = e - line - 1;
278 | }
279 | }
280 | else {
281 | seen |= LMASK(c);
282 | findEndFloat(&line[i + 1], &e);
283 | i = e - line - 1;
284 | }
285 | }
286 | }
287 | }
288 | i++;
289 | }
290 | *end = &line[i];
291 | return seen;
292 | }
293 |
294 | /***************************************************************************\
295 | * *
296 | * Draw a thick line (QUAD) given gcode coordinates, width and RGBA *
297 | * *
298 | \***************************************************************************/
299 |
300 | void gline(float x1, float y1, float x2, float y2, float width, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
301 | #ifdef OPENGL
302 | glColor4f(((float) r) / 255.0, ((float) g) / 255.0, ((float) b) / 255.0, ((float) a) / 255.0);
303 | // c1x,c1y
304 | // 0,0......
305 | // c4x,c4y ........ c2x,c2y
306 | // ........ px,py
307 | // c3x,c3y
308 | float c1x, c1y, c1l, c2x, c2y, c2l, c3x, c3y, c3l, c4x, c4y, c4l;
309 |
310 | float px = x2 - x1;
311 | float py = y2 - y1;
312 |
313 | c1x = -py;
314 | c1y = px;
315 | c1l = hypotf(c1x, c1y);
316 | c1x = (c1x * width / c1l / 2.0) + x1;
317 | c1y = (c1y * width / c1l / 2.0) + y1;
318 |
319 | c2x = -py;
320 | c2y = px;
321 | c2l = hypotf(c2x, c2y);
322 | c2x = (c2x * width / c2l / 2.0) + px + x1;
323 | c2y = (c2y * width / c2l / 2.0) + py + y1;
324 |
325 | c3x = py;
326 | c3y = -px;
327 | c3l = hypotf(c3x, c3y);
328 | c3x = (c3x * width / c3l / 2.0) + px + x1;
329 | c3y = (c3y * width / c3l / 2.0) + py + y1;
330 |
331 | c4x = py;
332 | c4y = -px;
333 | c4l = hypotf(c4x, c4y);
334 | c4x = (c4x * width / c4l / 2.0) + x1;
335 | c4y = (c4y * width / c4l / 2.0) + y1;
336 |
337 | if (width == 4.0)
338 | printf("LINE: [%3.0f,%3.0f]->[%3.0f,%3.0f]->[%3.0f,%3.0f]->[%3.0f,%3.0f]\n", c1x, c1y, c2x, c2y, c3x, c3y, c4x, c4y);
339 |
340 | glVertex2f(c1x, c1y);
341 | glVertex2f(c2x, c2y);
342 | glVertex2f(c3x, c3y);
343 | glVertex2f(c4x, c4y);
344 | #else
345 | thickLineRGBA(Surf_Display,
346 | (x1 - viewPortL) * zoomFactor,
347 | (viewPortB - y1) * zoomFactor,
348 | (x2 - viewPortL) * zoomFactor,
349 | (viewPortB - y2) * zoomFactor,
350 | mind(maxd(width * zoomFactor, 1), 2),
351 | r, g, b, a
352 | );
353 | #endif
354 | }
355 |
356 | /***************************************************************************\
357 | * *
358 | * create the quads for a layer, no wrappers *
359 | * *
360 | \***************************************************************************/
361 |
362 | void render_layer(int clayer, float alpha) {
363 | char *s = layer[clayer].index;
364 | char *e = layer[clayer].index + layer[clayer].size;
365 | float G = NAN, X = NAN, Y = NAN, E = NAN, Z = NAN, lastX = NAN, lastY = NAN, lastE = NAN;
366 | uint32_t seen = 0;
367 |
368 | for (X = 0; X < 201.0; X += 10.0) {
369 | gline(X, 0, X, 200, ((((int) X) % 50) == 0)?1:0.2, 0, 0, 0, 16);
370 | gline(0, X, 200, X, ((((int) X) % 50) == 0)?1:0.2, 0, 0, 0, 16);
371 | }
372 |
373 | //printf("render layer %d (%g)\n", clayer + 1, alpha);
374 |
375 | lastX = layer[clayer].startX;
376 | lastY = layer[clayer].startY;
377 | Z = layer[clayer].height;
378 | lastE = layer[clayer].startE;
379 |
380 | while (s < e) {
381 | seen = scanline(s, e - s, linewords, &s, LMASK('G') | LMASK('X') | LMASK('Y') | LMASK('Z') | LMASK('E'));
382 | if (SEEN('G') && (LW('G') == 0.0 || LW('G') == 1.0)) {
383 | G = LW('G');
384 | if (SEEN('X'))
385 | X = LW('X');
386 | if (SEEN('Y'))
387 | Y = LW('Y');
388 | if (SEEN('Z'))
389 | Z = LW('Z');
390 | if (SEEN('E'))
391 | E = LW('E');
392 | //if (clayer == 2)
393 | // printf("SEEN %c%c%c%c X%g Y%g Z%g E%g\n", SEEN('X')?'X':' ', SEEN('Y')?'Y':' ', SEEN('Z')?'Z':' ', SEEN('E')?'E':' ', X, Y, Z, E);
394 | if (SEEN('X') || SEEN('Y')) {
395 | // draw
396 | uint8_t r = 0, g = 0, b = 0, a = 160;
397 | if (SEEN('E')) {
398 | r = 0;
399 | g = 0;
400 | b = 0;
401 | a = 224;
402 | }
403 | else if (Z > layer[clayer].height) {
404 | r = 224;
405 | g = 64;
406 | b = 64;
407 | a = 160;
408 | }
409 | else if (Z < layer[clayer].height) {
410 | r = 128;
411 | g = 0;
412 | b = 128;
413 | a = 160;
414 | }
415 | else {
416 | r = 0;
417 | g = 128;
418 | b = 64;
419 | a = 160;
420 | }
421 | if ((lastX != X || lastY != Y) && !isnan(X) && !isnan(Y) && lastX <= 200.0)
422 | gline(lastX, lastY, X, Y, extrusionWidth, r, g, b, a * alpha);
423 | }
424 | if (SEEN('X'))
425 | lastX = X;
426 | if (SEEN('Y'))
427 | lastY = Y;
428 | if (SEEN('E'))
429 | lastE = E;
430 | }
431 | }
432 | }
433 |
434 | /***************************************************************************\
435 | * *
436 | * Update the OpenGL display with the current layer *
437 | * *
438 | \***************************************************************************/
439 |
440 | void render() {
441 | #ifdef OPENGL
442 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
443 | glLoadIdentity();
444 | glPushMatrix();
445 | glScalef(zoomFactor, zoomFactor, 0.0);
446 | glTranslatef(-transX, -transY, 0.0);
447 | if (layer[currentLayer].glList) {
448 | glCallList(layer[currentLayer].glList);
449 | }
450 | else {
451 | layer[currentLayer].glList = glGenLists(1);
452 | glNewList(layer[currentLayer].glList, GL_COMPILE_AND_EXECUTE);
453 | glBegin(GL_QUADS);
454 | #else
455 | uint32_t yellow;
456 |
457 | yellow = SDL_MapRGB(Surf_Display->format, 224, 224, 128);
458 |
459 | SDL_LockSurface(Surf_Display);
460 | SDL_FillRect(Surf_Display, NULL, yellow);
461 | int lines = 0;
462 | #endif
463 |
464 | for (int i = shadow_layers; i >= 1; i--) {
465 | if (currentLayer - i > 0)
466 | render_layer(currentLayer - i, shadow_alpha - (i - 1) * (shadow_alpha / ((float) shadow_layers)));
467 | }
468 | render_layer(currentLayer, 1.0);
469 |
470 | #ifdef OPENGL
471 | glEnd();
472 | glEndList();
473 | }
474 | glPopMatrix();
475 | glPushMatrix();
476 | glTranslatef(0.0, 200.0 - (20.0 * 0.3), 0.0);
477 | glScalef(0.3, 0.3, 1.0);
478 | ftglSetFontFaceSize(font, 20, 20);
479 | ftglRenderFont(font, msgbuf, FTGL_RENDER_ALL);
480 | glPopMatrix();
481 | glFlush();
482 | glFinish();
483 | SDL_GL_SwapBuffers();
484 | glFinish();
485 | #else
486 | SDL_UnlockSurface(Surf_Display);
487 |
488 | SDL_Flip(Surf_Display);
489 | #endif
490 | }
491 |
492 | /***************************************************************************\
493 | * *
494 | * Resize the display *
495 | * *
496 | * Includes refreshing the OpenGL Context *
497 | * *
498 | \***************************************************************************/
499 |
500 | void resize(int w, int h) {
501 | Surf_width = w;
502 | Surf_height = h;
503 | #ifdef OPENGL
504 | int dim;
505 | if (w > h)
506 | dim = h;
507 | else
508 | dim = w;
509 |
510 | for (int i = 0; i < layerCount; i++) {
511 | if (layer[i].glList)
512 | glDeleteLists(layer[i].glList, 1);
513 | layer[i].glList = 0;
514 | layer[i].flags = 0;
515 | };
516 |
517 | SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
518 |
519 | Surf_Display = SDL_SetVideoMode(Surf_width, Surf_height, 0, SDL_HWSURFACE | SDL_RESIZABLE | SDL_OPENGL);
520 |
521 | w = Surf_Display->w; h = Surf_Display->h;
522 | glViewport(0, 0, w, h);
523 | glClearColor(0.8, 0.8, 0.5, 0.5);
524 | glClearDepth(1.0f);
525 | glShadeModel(GL_SMOOTH);
526 | glEnable(GL_BLEND);
527 | glEnable(GL_POLYGON_SMOOTH);
528 | glEnable(GL_LINE_SMOOTH);
529 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
530 | glMatrixMode(GL_PROJECTION);
531 | glLoadIdentity();
532 | glOrtho(0, 200 * w / dim, 0, 200 * h / dim, 0, 1);
533 | glDisable(GL_DEPTH_TEST);
534 | glMatrixMode(GL_MODELVIEW);
535 | glLoadIdentity();
536 | busy |= BUSY_RENDER;
537 | #else
538 | Surf_Display = SDL_SetVideoMode(Surf_width, Surf_height, 32, SDL_HWSURFACE | SDL_floatBUF | SDL_RESIZABLE);
539 | #endif
540 | if (Surf_Display == NULL) {
541 | SDL_FreeSurface(Surf_Display);
542 | SDL_Quit();
543 | die("SDL resize", "");
544 | }
545 | render(); // redraw whole window
546 | }
547 |
548 | /***************************************************************************\
549 | * *
550 | * Simple function to change current layer *
551 | * *
552 | \***************************************************************************/
553 |
554 | void drawLayer(int layerNum) {
555 | if (layerNum > layerCount)
556 | layerNum = layerCount;
557 | snprintf(msgbuf, 256, "Layer %3d: %gmm", layerNum + 1, layer[layerNum].height);
558 | // printf("Drawing layer %3d (%5.2f)\n", layerNum, layer[layerNum].height);
559 | if ((currentLayer != layerNum) && (cache == false)) {
560 | glDeleteLists(layer[currentLayer].glList, 1);
561 | layer[currentLayer].glList = 0;
562 | }
563 | currentLayer = layerNum;
564 | render();
565 | }
566 |
567 | /***************************************************************************\
568 | * *
569 | * Read lines from GCODE input file *
570 | * Earmark the start of each layer in the file so we can find it quickly *
571 | * *
572 | \***************************************************************************/
573 |
574 | void scanLine() {
575 | static char* l = NULL;
576 | static float lastX = 0.0, lastY = 0.0, lastE = 0.0;
577 |
578 | if (l == NULL)
579 | l = gcodefile;
580 | char* end;
581 | uint32_t seen;
582 |
583 | if (l < gcodefile_end) {
584 | //printf("\t-\n");
585 | seen = scanline(l, gcodefile_end - l, linewords, &end, LMASK('G') | LMASK('X') | LMASK('Y') | LMASK('Z') | LMASK('E'));
586 |
587 | if (SEEN('G')) {
588 | if (LW('G') == 0.0 || LW('G') == 1.0) {
589 | if (layer[layerCount].index == NULL) {
590 | layer[layerCount].index = l;
591 | layer[layerCount].startX = lastX;
592 | layer[layerCount].startY = lastY;
593 | layer[layerCount].startE = lastE;
594 | }
595 | if (SEEN('Z')) {
596 | //dumpZstack();
597 | //printf("%d: Z%g\n", l - gcodefile, LW('Z'));
598 | if (layer[layerCount].height == NAN)
599 | layer[layerCount].height = LW('Z');
600 | else {
601 | int i;
602 | //dumpZstack();
603 | for (i = 0; i < ZstackIndex; i++) {
604 | //printf("Check %d: got %g vs found %g\n", i, Zstack[i].Z, LW('Z'));
605 | if (Zstack[i].Z == LW('Z')) {
606 | //printf("found end of hop\n");
607 | // end of hop
608 | ZstackIndex = i + 1;
609 | break;
610 | }
611 | }
612 | //printf("ZS %d i %d\n", ZstackIndex, i);
613 | if (i >= ZstackIndex || ZstackIndex == 0) {
614 | //printf("found start of hop\n");
615 | // start of hop or new layer
616 | Zstack[ZstackIndex].start = l;
617 | Zstack[ZstackIndex].X = lastX;
618 | Zstack[ZstackIndex].Y = lastY;
619 | Zstack[ZstackIndex].Z = LW('Z');
620 | Zstack[ZstackIndex].E = lastE;
621 | ZstackIndex++;
622 | if (ZstackIndex >= 8)
623 | die("Zstack overflow!","");
624 | }
625 | }
626 | }
627 | if (SEEN('E')) {
628 | // extrusion, collapse Z stack
629 | int i = ZstackIndex - 1;
630 | if (Zstack[i].Z != layer[layerCount].height) {
631 | //printf("E word at Z=%g\n", LW('Z'));
632 | //dumpZstack();
633 | //printf("new layer!\n");
634 | // finish previous layer
635 | layer[layerCount].size = Zstack[i].start - layer[layerCount].index;
636 | layer[layerCount].flags = 0;
637 | layer[layerCount].glList = 0;
638 | layer[layerCount].endX = Zstack[i].X;
639 | layer[layerCount].endY = Zstack[i].Y;
640 | layer[layerCount].endE = Zstack[i].E;
641 |
642 | // start new layer
643 | layerCount++;
644 | //printf("NEW LAYER: %d\n", layerCount);
645 | if (layerCount * sizeof(layerData) >= layerSize) {
646 | layerSize += sizeof(layerData) * 128;
647 | layer = realloc(layer, layerSize);
648 | if (layer == NULL)
649 | die("Scan: realloc layer","");
650 | }
651 | //printf("START LAYER %d\n", layerCount);
652 | // initialise
653 | layer[layerCount].index = Zstack[i].start;
654 | layer[layerCount].startX = Zstack[i].X;
655 | layer[layerCount].startY = Zstack[i].Y;
656 | layer[layerCount].height = Zstack[i].Z;
657 | layer[layerCount].startE = Zstack[i].E;
658 | // flush Z stack
659 | memcpy(Zstack, &Zstack[i], sizeof(ZstackItem));
660 | ZstackIndex = 1;
661 | //dumpZstack();
662 | }
663 | }
664 | }
665 | if (SEEN('X'))
666 | lastX = LW('X');
667 | if (SEEN('Y'))
668 | lastY = LW('Y');
669 | if (SEEN('E'))
670 | lastE = LW('E');
671 | }
672 | l = end;
673 | }
674 | if (l >= gcodefile_end) {
675 | layer[layerCount].size = l - layer[layerCount].index;
676 | layer[layerCount].flags = 0;
677 | layer[layerCount].glList = 0;
678 | layer[layerCount].endX = lastX;
679 | layer[layerCount].endY = lastY;
680 | layer[layerCount].endE = lastE;
681 | layerCount++;
682 |
683 | printf("Found %d layers\n", layerCount);
684 |
685 | if (0)
686 | for (int i = 0; i < layerCount; i++) {
687 | printf("Layer %d at %d+%d=%d\n", i, layer[i].index - gcodefile, layer[i].size, layer[i].index - gcodefile + layer[i].size);
688 | printf("\tHeight: %g\n", layer[i].height);
689 | printf("\tStarts at [%g,%g:%g]\n", layer[i].startX, layer[i].startY, layer[i].startE);
690 | printf("\tEnds at [%g,%g:%g]\n", layer[i].endX, layer[i].endY, layer[i].endE);
691 | }
692 |
693 | busy &= ~BUSY_SCANFILE;
694 | }
695 | }
696 |
697 | // quickly finds user-specified layer before first render
698 | void scanLines() {
699 | printf("Indexing lines...\n");
700 |
701 | layerCount = 0;
702 | // preallocate for 128 layers, we double the size later if it's not enough
703 | layerSize = (128 * sizeof(layerData));
704 | layer = malloc(layerSize);
705 |
706 | layer[0].startX = NAN;
707 | layer[0].startY = NAN;
708 | layer[0].index = NULL;
709 |
710 | ZstackIndex = 0;
711 |
712 | while ((busy & BUSY_SCANFILE) && ((layerCount - 2) <= currentLayer)) {
713 | scanLine();
714 | }
715 |
716 | printf("found layer %d\n", currentLayer);
717 | }
718 |
719 | /***************************************************************************\
720 | * *
721 | * SDL Event Handlers *
722 | * *
723 | \***************************************************************************/
724 |
725 | void handle_mousedown(SDL_MouseButtonEvent button) {
726 | //printf("SDL Mousebutton down event: mouse %d, button %d, state %d, %dx%d\n", Event.button.which, Event.button.button, Event.button.state, Event.button.x, Event.button.y);
727 | switch (button.button) {
728 | case 1: // left mouse
729 | {
730 | float mousex = button.x;
731 | float mousey = Surf_Display->h - button.y;
732 | float w = Surf_Display->w;
733 | float h = Surf_Display->h;
734 | float dim = minf(w, h);
735 | gXmouseDown = transX + (mousex / w) * 200.0 * w / dim / zoomFactor;
736 | gYmouseDown = transY + (mousey / h) * 200.0 * h / dim / zoomFactor;
737 | if (timerDragRender)
738 | SDL_RemoveTimer(timerDragRender);
739 | timerDragRender = SDL_AddTimer(50, &timerCallback, (void *) TIMER_DRAGRENDER);
740 | }
741 | break;
742 | case 2: // middle mouse
743 | break;
744 | case 3: // right mouse
745 | break;
746 | case 4: // wheel up
747 | if ((keymodifiermask & (KMM_LSHIFT | KMM_RSHIFT)) == 0) {
748 | #ifdef OPENGL
749 | float mousex = button.x;
750 | float mousey = Surf_Display->h - button.y;
751 | float w = Surf_Display->w;
752 | float h = Surf_Display->h;
753 | float dim = minf(w, h);
754 | float gX = transX + (mousex / w) * 200.0 * w / dim / zoomFactor;
755 | float gY = transY + (mousey / h) * 200.0 * h / dim / zoomFactor;
756 | //printf("%d,%d->%d,%d\n", (int) transX, (int) transY, (int) gX, (int) gY);
757 | zoomFactor *= 1.1;
758 | transX = gX - (mousex / w) * 200.0 * w / dim / zoomFactor;
759 | transY = gY - (mousey / h) * 200.0 * h / dim/ zoomFactor;
760 | #else
761 | //float viewX = (gX - viewPortL) * zoomFactor,
762 | float gX = ((float) button.x) / zoomFactor + viewPortL;
763 | // float viewY = (viewPortB - gY) * zoomFactor,
764 | float gY = viewPortB - ((float) button.y) / zoomFactor;
765 | zoomFactor *= 1.1;
766 | //printf("Zoom %g\n", zoomFactor);
767 | viewPortL = gX - ((float) button.x) / zoomFactor;
768 | viewPortB = ((float) button.y) / zoomFactor + gY;
769 | #endif
770 | render();
771 | }
772 | else if (currentLayer > 0)
773 | drawLayer(--currentLayer);
774 | break;
775 | case 5: // wheel down
776 | if ((keymodifiermask & (KMM_LSHIFT | KMM_RSHIFT)) == 0) {
777 | #ifdef OPENGL
778 | float mousex = button.x;
779 | float mousey = Surf_Display->h - button.y;
780 | float w = Surf_Display->w;
781 | float h = Surf_Display->h;
782 | float dim = minf(w, h);
783 | float gX = transX + (mousex / w) * 200.0 * w / dim / zoomFactor;
784 | float gY = transY + (mousey / h) * 200.0 * h / dim / zoomFactor;
785 | //printf("%d,%d->%d,%d\n", (int) transX, (int) transY, (int) gX, (int) gY);
786 | zoomFactor /= 1.1;
787 | transX = gX - (mousex / w) * 200.0 * w / dim / zoomFactor;
788 | transY = gY - (mousey / h) * 200.0 * h / dim / zoomFactor;
789 | #else
790 | //float viewX = (gX - viewPortL) * zoomFactor,
791 | float gX = ((float) button.x) / zoomFactor + viewPortL;
792 | // float viewY = (viewPortB - gY) * zoomFactor,
793 | float gY = viewPortB - ((float) button.y) / zoomFactor;
794 | zoomFactor /= 1.1;
795 | //printf("Zoom %g\n", zoomFactor);
796 | viewPortL = gX - ((float) button.x) / zoomFactor;
797 | viewPortB = ((float) button.y) / zoomFactor + gY;
798 | #endif
799 | render();
800 | }
801 | else if (currentLayer < layerCount - 1)
802 | drawLayer(++currentLayer);
803 | break;
804 | }
805 | }
806 | void handle_mousemove(SDL_MouseMotionEvent motion) {
807 | if (motion.state & 1) { // left-drag
808 | float mousex = motion.x;
809 | float mousey = Surf_Display->h - motion.y;
810 | float w = Surf_Display->w;
811 | float h = Surf_Display->h;
812 | float dim = minf(w, h);
813 | transX = gXmouseDown - (mousex / w) * 200.0 * w / dim / zoomFactor;
814 | transY = gYmouseDown - (mousey / h) * 200.0 * h / dim / zoomFactor;
815 | }
816 | }
817 | void handle_mouseup(SDL_MouseButtonEvent button) {
818 | switch (button.button) {
819 | case 1: // left mouse
820 | if (timerDragRender) {
821 | SDL_RemoveTimer(timerDragRender);
822 | timerDragRender = NULL;
823 | }
824 | break;
825 | }
826 | }
827 |
828 | void handle_keydown(SDL_KeyboardEvent key) {
829 | switch(key.keysym.sym) {
830 | case SDLK_q:
831 | case SDLK_ESCAPE:
832 | printf("Exiting\n");
833 | Running = false;
834 | break;
835 | case SDLK_r:
836 | printf("Resetting position\n");
837 | zoomFactor = 3;
838 | #ifdef OPENGL
839 | transX = transY = 0.0;
840 | #else
841 | viewPortL = 0.0;
842 | viewPortB = 200.0;
843 | #endif
844 | resize(600, 600);
845 | render();
846 | break;
847 | case SDLK_PAGEUP:
848 | layerVelocity = 1;
849 | if (timerKeyRepeat)
850 | SDL_RemoveTimer(timerKeyRepeat);
851 | else if (currentLayer < layerCount - 1)
852 | drawLayer(++currentLayer);
853 | timerKeyRepeat = SDL_AddTimer(500, &timerCallback, (void *) TIMER_KEYREPEAT);
854 | break;
855 | case SDLK_PAGEDOWN:
856 | layerVelocity = -1;
857 | if (timerKeyRepeat)
858 | SDL_RemoveTimer(timerKeyRepeat);
859 | else if (currentLayer > 0)
860 | drawLayer(--currentLayer);
861 | timerKeyRepeat = SDL_AddTimer(500, &timerCallback, (void *) TIMER_KEYREPEAT);
862 | break;
863 | case SDLK_LSHIFT:
864 | keymodifiermask |= KMM_LSHIFT;
865 | break;
866 | case SDLK_RSHIFT:
867 | keymodifiermask |= KMM_RSHIFT;
868 | break;
869 | default:
870 | printf("key %d pressed (%c)\n", key.keysym.sym, key.keysym.sym);
871 | break;
872 | }
873 | }
874 |
875 | void handle_keyup(SDL_KeyboardEvent key) {
876 | switch(key.keysym.sym) {
877 | case SDLK_PAGEUP:
878 | layerVelocity = 0;
879 | if (timerKeyRepeat) {
880 | SDL_RemoveTimer(timerKeyRepeat);
881 | timerKeyRepeat = NULL;
882 | }
883 | break;
884 | case SDLK_PAGEDOWN:
885 | layerVelocity = 0;
886 | if (timerKeyRepeat) {
887 | SDL_RemoveTimer(timerKeyRepeat);
888 | timerKeyRepeat = NULL;
889 | }
890 | break;
891 | case SDLK_LSHIFT:
892 | keymodifiermask &= ~KMM_LSHIFT;
893 | break;
894 | case SDLK_RSHIFT:
895 | keymodifiermask &= ~KMM_RSHIFT;
896 | break;
897 | default:
898 | break;
899 | }
900 | }
901 |
902 | void handle_userevent(SDL_UserEvent user) {
903 | switch (user.code) {
904 | case TIMER_KEYREPEAT:
905 | SDL_RemoveTimer(timerKeyRepeat);
906 | if (layerVelocity > 0) {
907 | if (currentLayer < layerCount - 1)
908 | drawLayer(++currentLayer);
909 | else
910 | break;
911 | }
912 | else if (layerVelocity < 0) {
913 | if (currentLayer > 0)
914 | drawLayer(--currentLayer);
915 | else
916 | break;
917 | }
918 | timerKeyRepeat = SDL_AddTimer(20, &timerCallback, (void *) TIMER_KEYREPEAT);
919 | break;
920 | case TIMER_DRAGRENDER:
921 | SDL_RemoveTimer(timerDragRender);
922 | render();
923 | timerDragRender = SDL_AddTimer(50, &timerCallback, (void *) TIMER_DRAGRENDER);
924 | break;
925 | }
926 | }
927 |
928 | /***************************************************************************\
929 | * *
930 | * Main *
931 | * *
932 | * Read GCODE, Initialise SDL window and OpenGL surface, Start FTGL, run SDL *
933 | * Event loop *
934 | * *
935 | \***************************************************************************/
936 |
937 | int main(int argc, char* argv[]) {
938 | msgbuf = malloc(256);
939 | msgbuf[0] = 0;
940 |
941 | currentLayer = 0;
942 | cache = true;
943 |
944 | int longIndex;
945 | int opt;
946 | do {
947 | opt = getopt_long(argc, argv, optString, longOpts, &longIndex);
948 | if (opt != -1) {
949 | switch( opt ) {
950 | case 'l':
951 | currentLayer = strtol(optarg, NULL, 10);
952 | break;
953 |
954 | case 'w':
955 | extrusionWidth = strtof(optarg, NULL);
956 | break;
957 |
958 | case 'n':
959 | printf("DISABLING CACHE\n");
960 | cache = false;
961 | break;
962 |
963 | case 'h': /* fall-through is intentional */
964 | case '?':
965 | display_usage();
966 | break;
967 |
968 | case 0: /* long option without a short arg */
969 | //if( strcmp( "randomize", longOpts[longIndex].name ) == 0 ) {
970 | // globalArgs.randomized = 1;
971 | //}
972 | break;
973 |
974 | default:
975 | /* You won't actually get here. */
976 | break;
977 | }
978 | }
979 | }
980 | while (opt != -1);
981 |
982 | if (optind >= argc)
983 | display_usage();
984 |
985 | int fd = open(argv[optind], 0);
986 | if (fd == -1)
987 | die("Open ", argv[optind]);
988 |
989 | struct stat filestats;
990 | if (fstat(fd, &filestats) == -1)
991 | die("fstat ", argv[optind]);
992 |
993 | filesz = filestats.st_size;
994 |
995 | printf("File is %d long\n", filesz);
996 |
997 | #ifdef __linux__
998 | gcodefile = mmap(NULL, filesz, PROT_READ, MAP_PRIVATE | MAP_POPULATE, fd, 0);
999 | #elif defined __APPLE__
1000 | gcodefile = mmap(NULL, filesz, PROT_READ, MAP_PRIVATE, fd, 0);
1001 | #else
1002 | #error "don't know how to mmap on this system!"
1003 | #endif
1004 |
1005 | if (gcodefile == MAP_FAILED)
1006 | die("mmap ", argv[optind]);
1007 | gcodefile_end = &gcodefile[filesz];
1008 |
1009 | busy = BUSY_SCANFILE;
1010 |
1011 | scanLines();
1012 |
1013 | if (currentLayer >= layerCount)
1014 | currentLayer = layerCount - 1;
1015 |
1016 | //for (int i = 0; i < layerCount; i++)
1017 | // printf("Layer %3d starts at %7d and is %7d bytes long\n", i, layer[i].index - gcodefile, layer[i].size);
1018 |
1019 | Running = true;
1020 | Surf_Display = NULL;
1021 |
1022 | if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
1023 | die("SDL_init", "");
1024 |
1025 | if (FcInitLoadConfigAndFonts() == ((void *) FcTrue))
1026 | die("FontConfig Init","");
1027 |
1028 | // from http://www.spinics.net/lists/font-config/msg03050.html
1029 | FcPattern *pat, *match;
1030 | FcResult result;
1031 | char *file;
1032 | int index;
1033 | pat = FcPatternCreate();
1034 | FcPatternAddString(pat, FC_FAMILY, (FcChar8 *) "Mono");
1035 | FcConfigSubstitute(NULL, pat, FcMatchPattern);
1036 | FcDefaultSubstitute(pat);
1037 | match = FcFontMatch(NULL, pat, &result);
1038 | FcPatternGetString(match, FC_FILE, 0, (FcChar8 **) &file);
1039 | FcPatternGetInteger(match, FC_INDEX, 0, &index);
1040 |
1041 |
1042 | font = ftglCreateExtrudeFont(file);
1043 | if (!font)
1044 | die("FTGL createFont", "");
1045 |
1046 | FcPatternDestroy (match);
1047 | FcPatternDestroy (pat);
1048 |
1049 | #ifdef OPENGL
1050 | transX = transY = 0.0;
1051 | zoomFactor = 1.0;
1052 |
1053 | resize(600, 600);
1054 | #else
1055 | viewPortL = viewPortT = 0.0;
1056 | viewPortR = viewPortB = 200.0;
1057 | zoomFactor = 3.0;
1058 | resize(viewPortR * zoomFactor, viewPortB * zoomFactor);
1059 | #endif
1060 |
1061 | SDL_WM_SetCaption("gcodeview", 0);
1062 |
1063 | drawLayer(currentLayer);
1064 |
1065 | layerVelocity = 0;
1066 |
1067 | timerIdle = SDL_AddTimer(20, &timerCallback, (void *) TIMER_IDLE);
1068 |
1069 | SDL_Event Event;
1070 | while(Running != false) {
1071 | if (busy) {
1072 | Event.type = SDL_NOEVENT;
1073 | SDL_PollEvent(&Event);
1074 | }
1075 | else {
1076 | if (SDL_WaitEvent(&Event) == 0)
1077 | die("SDL_WaitEvent", "");
1078 | }
1079 | //SDL_RemoveTimer(timerIdle);
1080 | switch (Event.type) {
1081 | case SDL_NOEVENT:
1082 | if (busy & BUSY_SCANFILE) {
1083 | // TODO: scan next layer
1084 | scanLine();
1085 | if ((busy & BUSY_SCANFILE) == 0) {
1086 | if (cache) {
1087 | printf("File scanned, rendering...\n");
1088 | busy = BUSY_RENDER;
1089 | }
1090 | else {
1091 | printf("File scanned.\n");
1092 | busy = 0;
1093 | }
1094 | }
1095 | }
1096 | else if ((busy & BUSY_RENDER) && cache) {
1097 | bool allRendered = true;
1098 | int i;
1099 | // TODO: render next layer in background
1100 | for (i = 0; i < layerCount; i++) {
1101 | if (layer[i].glList == 0) {
1102 | layer[i].glList = glGenLists(1);
1103 | glNewList(layer[i].glList, GL_COMPILE);
1104 | glBegin(GL_QUADS);
1105 | for (int j = SHADOW_LAYERS; j >= 1; j--) {
1106 | if (i - j > 0)
1107 | render_layer(i - j, SHADOW_ALPHA - (j - 1) * (SHADOW_ALPHA / SHADOW_LAYERS));
1108 | }
1109 | render_layer(i, 1.0);
1110 | glEnd();
1111 | glEndList();
1112 | layer[i].flags |= LD_LISTGENERATED;
1113 | allRendered = false;
1114 | break;
1115 | }
1116 | }
1117 | if (allRendered) {
1118 | printf("All %d layers rendered\n", i);
1119 | busy &= ~BUSY_RENDER;
1120 | }
1121 | }
1122 | break;
1123 | case SDL_QUIT:
1124 | Running = false;
1125 | break;
1126 | case SDL_VIDEORESIZE:
1127 | resize(Event.resize.w, Event.resize.h);
1128 | break;
1129 | case SDL_VIDEOEXPOSE:
1130 | render();
1131 | break;
1132 | case SDL_MOUSEBUTTONDOWN:
1133 | handle_mousedown(Event.button);
1134 | break;
1135 | case SDL_MOUSEBUTTONUP:
1136 | handle_mouseup(Event.button);
1137 | break;
1138 | case SDL_MOUSEMOTION:
1139 | handle_mousemove(Event.motion);
1140 | break;
1141 | case SDL_ACTIVEEVENT: // lose or gain focus
1142 | break;
1143 | case SDL_KEYDOWN:
1144 | handle_keydown(Event.key);
1145 | break;
1146 | case SDL_KEYUP:
1147 | handle_keyup(Event.key);
1148 | break;
1149 | case SDL_USEREVENT:
1150 | handle_userevent(Event.user);
1151 | break;
1152 | default:
1153 | printf("SDL Event %d\n", Event.type);
1154 | break;
1155 | }
1156 | //idle code
1157 | //if (busy)
1158 | // timerIdle = SDL_AddTimer(20, &timerCallback, (void *) TIMER_IDLE);
1159 | }
1160 | if (timerKeyRepeat)
1161 | SDL_RemoveTimer(timerKeyRepeat);
1162 | if (timerDragRender)
1163 | SDL_RemoveTimer(timerDragRender);
1164 | free(layer);
1165 | SDL_FreeSurface(Surf_Display);
1166 | SDL_Quit();
1167 | return 0;
1168 | }
1169 |
--------------------------------------------------------------------------------