diff --git a/simgear/canvas/ShaderVG/COPYING b/simgear/canvas/ShaderVG/COPYING new file mode 100644 index 00000000..5ab7695a --- /dev/null +++ b/simgear/canvas/ShaderVG/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/simgear/canvas/ShaderVG/README.md b/simgear/canvas/ShaderVG/README.md new file mode 100644 index 00000000..32698d46 --- /dev/null +++ b/simgear/canvas/ShaderVG/README.md @@ -0,0 +1,223 @@ +# ShaderVG + + + +_**Note:** This project is based on https://github.com/tqm-dev/ShivaVG-2_ + +## Main Features + +- Working on Shader-Based OpenGL +- API extensions for GLSL shader integrated to vector/image rendering + +## Getting Started + +### Prerequisites + +- OpenGL development libraries and headers should be installed. +- freeglut must be installed for rendering on window system. +- jpeglib needs to be installed for example programs that use images. + +### Compiling + +Clone and enter the repository: +``` +$ git clone https://github.com/tqm-dev/ShaderVG +$ cd ShaderVG +``` + +Under UNIX systems, execute configure and make: +``` +$ sh autogen.sh +$ ./configure LIBS="-lGL -lglut -ljpeg" +$ make +``` + +### Testing + +Move to examples directory, execute tests: +``` +$ cd examples +$ ./test_tiger_shader +``` +#### test_tiger_shader + Well known svg tiger meets GLSL vertex/fragment shading. + +#### test_vgu + Constructs some path primitives using the VGU API. + +#### test_tiger + The most simple performance test. It draws the well known svg + tiger using just simple stroke and fill of solid colors. It + consists of 240 paths. + +#### test_dash + Shows different stroke dashing modes. + +#### test_linear + A rectangle drawn using 3-color linear gradient fill paint + +#### test_radial + A rectangle drawn using 3-color radial gradient fill paint + +#### test_interpolate + Interpolates between two paths - an apple and a pear. + +#### test_image + Images are drawn using VG_DRAW_IMAGE_MULTIPLY image mode to be + multiplied with radial gradient fill paint. + +#### test_pattern + An image is drawn in multiply mode with an image pattern fill + paint. + +## Implementation status + +#### General +API | status +----------------------- | --------------------- +vgGetError | FULLY implemented +vgFlush | FULLY implemented +vgFinish | FULLY implemented + +#### Getters and setters +API | status +----------------------- | --------------------- +vgSet | FULLY implemented +vgSeti | FULLY implemented +vgSetfv | FULLY implemented +vgSetiv | FULLY implemented +vgGetf | FULLY implemented +vgGeti | FULLY implemented +vgGetVectorSize | FULLY implemented +vgGetfv | FULLY implemented +vgGetiv | FULLY implemented +vgSetParameterf | FULLY implemented +vgSetParameteri | FULLY implemented +vgSetParameterfv | FULLY implemented +vgSetParameteriv | FULLY implemented +vgGetParameterf | FULLY implemented +vgGetParameteri | FULLY implemented +vgGetParameterVectorSize| FULLY implemented +vgGetParameterfv | FULLY implemented +vgGetParameteriv | FULLY implemented + +#### Matrix Manipulation +API | status +----------------------- | --------------------- +vgLoadIdentity | FULLY implemented +vgLoadMatrix | FULLY implemented +vgGetMatrix | FULLY implemented +vgMultMatrix | FULLY implemented +vgTranslate | FULLY implemented +vgScale | FULLY implemented +vgShear | FULLY implemented +vgRotate | FULLY implemented + +#### Masking and Clearing +API | status +----------------------- | --------------------- +vgMask | NOT implemented +vgClear | FULLY implemented + +#### Paths +API | status +----------------------- | --------------------- +vgCreatePath | FULLY implemented +vgClearPath | FULLY implemented +vgDestroyPath | FULLY implemented +vgRemovePathCapabilities| FULLY implemented +vgGetPathCapabilities | FULLY implemented +vgAppendPath | FULLY implemented +vgAppendPathData | FULLY implemented +vgModifyPathCoords | FULLY implemented +vgTransformPath | FULLY implemented +vgInterpolatePath | FULLY implemented +vgPathLength | NOT implemented +vgPointAlongPath | NOT implemented +vgPathBounds | FULLY implemented +vgPathTransformedBounds | FULLY implemented +vgDrawPath | PARTIALLY implemented + +#### Paint +API | status +----------------------- | --------------------- +vgCreatePaint | FULLY implemented +vgDestroyPaint | FULLY implemented +vgSetPaint | FULLY implemented +vgGetPaint | FULLY implemented +vgSetColor | FULLY implemented +vgGetColor | FULLY implemented +vgPaintPattern | FULLY implemented + +#### Images +API | status +----------------------- | --------------------- +vgCreateImage | PARTIALLY implemented +vgDestroyImage | FULLY implemented +vgClearImage | FULLY implemented +vgImageSubData | PARTIALLY implemented +vgGetImageSubData | PARTIALLY implemented +vgChildImage | NOT implemented +vgGetParent | NOT implemented +vgCopyImage | FULLY implemented +vgDrawImage | PARTIALLY implemented +vgSetPixels | NOT implemented yet +vgWritePixels | NOT implemented yet +vgGetPixels | FULLY implemented +vgReadPixels | FULLY implemented +vgCopyPixels | NOT implemented yet + +#### Image Filters +API | status +----------------------- | --------------------- +vgColorMatrix | NOT implemented +vgConvolve | NOT implemented +vgSeparableConvolve | NOT implemented +vgGaussianBlur | NOT implemented +vgLookup | NOT implemented +vgLookupSingle | NOT implemented + +#### Queries +API | status +----------------------- | --------------------- +vgHardwareQuery | NOT implemented +vgGetString | FULLY implemented + +#### VGU +API | status +----------------------- | --------------------- +vguLine | FULLY implemented +vguPolygon | FULLY implemented +vguRect | FULLY implemented +vguRoundRect | FULLY implemented +vguEllipse | FULLY implemented +vguArc | FULLY implemented +vguComputeWarpQuadToSquare | NOT implemented +vguComputeWarpSquareToQuad | NOT implemented +vguComputeWarpQuadToQuad | NOT implemented + +## Extensions + +### Manipulate the OpenVG context as a temporary replacement for EGL: + +- VGboolean vgCreateContextSH(VGint width, VGint height) + + Creates an OpenVG context on top of an existing OpenGL context + that should have been manually initialized by the user of the + library. Width and height specify the size of the rendering + surface. No multi-threading support has been implemented yet. + The context is created once per process. + +- void vgResizeSurfaceSH(VGint width, VGint height) + + Should be called whenever the size of the surface changes (e.g. + the owner window of the OpenGL context is resized). + +- void vgDestroyContextSH() + + Destroys the OpenVG context associated with the calling process. + +## License + +This project is licensed under the GNU Lesser General Public License v2.1 - see the [LICENSE](https://github.com/tqm-dev/ShaderVG/blob/master/COPYING) file for details + diff --git a/simgear/canvas/ShaderVG/include/vg/openvg.h b/simgear/canvas/ShaderVG/include/vg/openvg.h new file mode 100644 index 00000000..c5723f1f --- /dev/null +++ b/simgear/canvas/ShaderVG/include/vg/openvg.h @@ -0,0 +1,676 @@ +/* + * Copyright (c) 2007 Ivan Leben + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _OPENVG_H +#define _OPENVG_H + +#define OPENVG_VERSION_1_0_1 1 + +/* Type definitions */ +/* TODO: we can't use config.h in this header so there + must be some other technique to assert the proper + size of the basic types */ + +typedef float VGfloat; +typedef char VGbyte; +typedef unsigned char VGubyte; +typedef short VGshort; +typedef int VGint; +typedef unsigned int VGuint; +typedef unsigned int VGbitfield; + +typedef enum { + VG_FALSE = 0, + VG_TRUE = 1 +} VGboolean; + +#define VG_MAXSHORT ((VGshort)((~((unsigned)0)) >> 1)) +#define VG_MAXINT ((VGint)((~((unsigned)0)) >> 1)) + +/* Define handle to be of same length as any pointer */ + +typedef void * VGHandle; +#define VG_INVALID_HANDLE ((VGHandle)NULL) + +/* Enumerations */ + +typedef enum { + VG_NO_ERROR = 0, + VG_BAD_HANDLE_ERROR = 0x1000, + VG_ILLEGAL_ARGUMENT_ERROR = 0x1001, + VG_OUT_OF_MEMORY_ERROR = 0x1002, + VG_PATH_CAPABILITY_ERROR = 0x1003, + VG_UNSUPPORTED_IMAGE_FORMAT_ERROR = 0x1004, + VG_UNSUPPORTED_PATH_FORMAT_ERROR = 0x1005, + VG_IMAGE_IN_USE_ERROR = 0x1006, + VG_NO_CONTEXT_ERROR = 0x1007 +} VGErrorCode; + +typedef enum { + /* Mode settings */ + VG_MATRIX_MODE = 0x1100, + VG_FILL_RULE = 0x1101, + VG_IMAGE_QUALITY = 0x1102, + VG_RENDERING_QUALITY = 0x1103, + VG_BLEND_MODE = 0x1104, + VG_IMAGE_MODE = 0x1105, + + /* Scissoring rectangles */ + VG_SCISSOR_RECTS = 0x1106, + + /* Stroke parameters */ + VG_STROKE_LINE_WIDTH = 0x1110, + VG_STROKE_CAP_STYLE = 0x1111, + VG_STROKE_JOIN_STYLE = 0x1112, + VG_STROKE_MITER_LIMIT = 0x1113, + VG_STROKE_DASH_PATTERN = 0x1114, + VG_STROKE_DASH_PHASE = 0x1115, + VG_STROKE_DASH_PHASE_RESET = 0x1116, + + /* Edge fill color for VG_TILE_FILL tiling mode */ + VG_TILE_FILL_COLOR = 0x1120, + + /* Color for vgClear */ + VG_CLEAR_COLOR = 0x1121, + + /* Enable/disable alpha masking and scissoring */ + VG_MASKING = 0x1130, + VG_SCISSORING = 0x1131, + + /* Pixel layout information */ + VG_PIXEL_LAYOUT = 0x1140, + VG_SCREEN_LAYOUT = 0x1141, + + /* Source format selection for image filters */ + VG_FILTER_FORMAT_LINEAR = 0x1150, + VG_FILTER_FORMAT_PREMULTIPLIED = 0x1151, + + /* Destination write enable mask for image filters */ + VG_FILTER_CHANNEL_MASK = 0x1152, + + /* Implementation limits (read-only) */ + VG_MAX_SCISSOR_RECTS = 0x1160, + VG_MAX_DASH_COUNT = 0x1161, + VG_MAX_KERNEL_SIZE = 0x1162, + VG_MAX_SEPARABLE_KERNEL_SIZE = 0x1163, + VG_MAX_COLOR_RAMP_STOPS = 0x1164, + VG_MAX_IMAGE_WIDTH = 0x1165, + VG_MAX_IMAGE_HEIGHT = 0x1166, + VG_MAX_IMAGE_PIXELS = 0x1167, + VG_MAX_IMAGE_BYTES = 0x1168, + VG_MAX_FLOAT = 0x1169, + VG_MAX_GAUSSIAN_STD_DEVIATION = 0x116A +} VGParamType; + +typedef enum { + VG_RENDERING_QUALITY_NONANTIALIASED = 0x1200, + VG_RENDERING_QUALITY_FASTER = 0x1201, + VG_RENDERING_QUALITY_BETTER = 0x1202 /* Default */ +} VGRenderingQuality; + +typedef enum { + VG_PIXEL_LAYOUT_UNKNOWN = 0x1300, + VG_PIXEL_LAYOUT_RGB_VERTICAL = 0x1301, + VG_PIXEL_LAYOUT_BGR_VERTICAL = 0x1302, + VG_PIXEL_LAYOUT_RGB_HORIZONTAL = 0x1303, + VG_PIXEL_LAYOUT_BGR_HORIZONTAL = 0x1304 +} VGPixelLayout; + +typedef enum { + VG_MATRIX_PATH_USER_TO_SURFACE = 0x1400, + VG_MATRIX_IMAGE_USER_TO_SURFACE = 0x1401, + VG_MATRIX_FILL_PAINT_TO_USER = 0x1402, + VG_MATRIX_STROKE_PAINT_TO_USER = 0x1403 +} VGMatrixMode; + +typedef enum { + VG_CLEAR_MASK = 0x1500, + VG_FILL_MASK = 0x1501, + VG_SET_MASK = 0x1502, + VG_UNION_MASK = 0x1503, + VG_INTERSECT_MASK = 0x1504, + VG_SUBTRACT_MASK = 0x1505 +} VGMaskOperation; + +#define VG_PATH_FORMAT_STANDARD 0 + +typedef enum { + VG_PATH_DATATYPE_S_8 = 0, + VG_PATH_DATATYPE_S_16 = 1, + VG_PATH_DATATYPE_S_32 = 2, + VG_PATH_DATATYPE_F = 3 +} VGPathDatatype; + +typedef enum { + VG_ABSOLUTE = 0, + VG_RELATIVE = 1 +} VGPathAbsRel; + +typedef enum { + VG_CLOSE_PATH = ( 0 << 1), + VG_MOVE_TO = ( 1 << 1), + VG_LINE_TO = ( 2 << 1), + VG_HLINE_TO = ( 3 << 1), + VG_VLINE_TO = ( 4 << 1), + VG_QUAD_TO = ( 5 << 1), + VG_CUBIC_TO = ( 6 << 1), + VG_SQUAD_TO = ( 7 << 1), + VG_SCUBIC_TO = ( 8 << 1), + VG_SCCWARC_TO = ( 9 << 1), + VG_SCWARC_TO = (10 << 1), + VG_LCCWARC_TO = (11 << 1), + VG_LCWARC_TO = (12 << 1) +} VGPathSegment; + +typedef enum { + VG_MOVE_TO_ABS = VG_MOVE_TO | VG_ABSOLUTE, + VG_MOVE_TO_REL = VG_MOVE_TO | VG_RELATIVE, + VG_LINE_TO_ABS = VG_LINE_TO | VG_ABSOLUTE, + VG_LINE_TO_REL = VG_LINE_TO | VG_RELATIVE, + VG_HLINE_TO_ABS = VG_HLINE_TO | VG_ABSOLUTE, + VG_HLINE_TO_REL = VG_HLINE_TO | VG_RELATIVE, + VG_VLINE_TO_ABS = VG_VLINE_TO | VG_ABSOLUTE, + VG_VLINE_TO_REL = VG_VLINE_TO | VG_RELATIVE, + VG_QUAD_TO_ABS = VG_QUAD_TO | VG_ABSOLUTE, + VG_QUAD_TO_REL = VG_QUAD_TO | VG_RELATIVE, + VG_CUBIC_TO_ABS = VG_CUBIC_TO | VG_ABSOLUTE, + VG_CUBIC_TO_REL = VG_CUBIC_TO | VG_RELATIVE, + VG_SQUAD_TO_ABS = VG_SQUAD_TO | VG_ABSOLUTE, + VG_SQUAD_TO_REL = VG_SQUAD_TO | VG_RELATIVE, + VG_SCUBIC_TO_ABS = VG_SCUBIC_TO | VG_ABSOLUTE, + VG_SCUBIC_TO_REL = VG_SCUBIC_TO | VG_RELATIVE, + VG_SCCWARC_TO_ABS = VG_SCCWARC_TO | VG_ABSOLUTE, + VG_SCCWARC_TO_REL = VG_SCCWARC_TO | VG_RELATIVE, + VG_SCWARC_TO_ABS = VG_SCWARC_TO | VG_ABSOLUTE, + VG_SCWARC_TO_REL = VG_SCWARC_TO | VG_RELATIVE, + VG_LCCWARC_TO_ABS = VG_LCCWARC_TO | VG_ABSOLUTE, + VG_LCCWARC_TO_REL = VG_LCCWARC_TO | VG_RELATIVE, + VG_LCWARC_TO_ABS = VG_LCWARC_TO | VG_ABSOLUTE, + VG_LCWARC_TO_REL = VG_LCWARC_TO | VG_RELATIVE +} VGPathCommand; + +typedef VGHandle VGPath; + +typedef enum { + VG_PATH_CAPABILITY_APPEND_FROM = (1 << 0), + VG_PATH_CAPABILITY_APPEND_TO = (1 << 1), + VG_PATH_CAPABILITY_MODIFY = (1 << 2), + VG_PATH_CAPABILITY_TRANSFORM_FROM = (1 << 3), + VG_PATH_CAPABILITY_TRANSFORM_TO = (1 << 4), + VG_PATH_CAPABILITY_INTERPOLATE_FROM = (1 << 5), + VG_PATH_CAPABILITY_INTERPOLATE_TO = (1 << 6), + VG_PATH_CAPABILITY_PATH_LENGTH = (1 << 7), + VG_PATH_CAPABILITY_POINT_ALONG_PATH = (1 << 8), + VG_PATH_CAPABILITY_TANGENT_ALONG_PATH = (1 << 9), + VG_PATH_CAPABILITY_PATH_BOUNDS = (1 << 10), + VG_PATH_CAPABILITY_PATH_TRANSFORMED_BOUNDS = (1 << 11), + VG_PATH_CAPABILITY_ALL = (1 << 12) - 1 +} VGPathCapabilities; + +typedef enum { + VG_PATH_FORMAT = 0x1600, + VG_PATH_DATATYPE = 0x1601, + VG_PATH_SCALE = 0x1602, + VG_PATH_BIAS = 0x1603, + VG_PATH_NUM_SEGMENTS = 0x1604, + VG_PATH_NUM_COORDS = 0x1605 +} VGPathParamType; + +typedef enum { + VG_CAP_BUTT = 0x1700, + VG_CAP_ROUND = 0x1701, + VG_CAP_SQUARE = 0x1702 +} VGCapStyle; + +typedef enum { + VG_JOIN_MITER = 0x1800, + VG_JOIN_ROUND = 0x1801, + VG_JOIN_BEVEL = 0x1802 +} VGJoinStyle; + +typedef enum { + VG_EVEN_ODD = 0x1900, + VG_NON_ZERO = 0x1901 +} VGFillRule; + +typedef enum { + VG_STROKE_PATH = (1 << 0), + VG_FILL_PATH = (1 << 1) +} VGPaintMode; + +typedef VGHandle VGPaint; + +typedef enum { + /* Color paint parameters */ + VG_PAINT_TYPE = 0x1A00, + VG_PAINT_COLOR = 0x1A01, + VG_PAINT_COLOR_RAMP_SPREAD_MODE = 0x1A02, + VG_PAINT_COLOR_RAMP_PREMULTIPLIED = 0x1A07, + VG_PAINT_COLOR_RAMP_STOPS = 0x1A03, + + /* Linear gradient paint parameters */ + VG_PAINT_LINEAR_GRADIENT = 0x1A04, + + /* Radial gradient paint parameters */ + VG_PAINT_RADIAL_GRADIENT = 0x1A05, + + /* Pattern paint parameters */ + VG_PAINT_PATTERN_TILING_MODE = 0x1A06 +} VGPaintParamType; + +typedef enum { + VG_PAINT_TYPE_COLOR = 0x1B00, + VG_PAINT_TYPE_LINEAR_GRADIENT = 0x1B01, + VG_PAINT_TYPE_RADIAL_GRADIENT = 0x1B02, + VG_PAINT_TYPE_PATTERN = 0x1B03 +} VGPaintType; + +typedef enum { + VG_COLOR_RAMP_SPREAD_PAD = 0x1C00, + VG_COLOR_RAMP_SPREAD_REPEAT = 0x1C01, + VG_COLOR_RAMP_SPREAD_REFLECT = 0x1C02 +} VGColorRampSpreadMode; + +typedef enum { + VG_TILE_FILL = 0x1D00, + VG_TILE_PAD = 0x1D01, + VG_TILE_REPEAT = 0x1D02, + VG_TILE_REFLECT = 0x1D03 +} VGTilingMode; + +typedef enum { + /* RGB{A,X} channel ordering */ + VG_sRGBX_8888 = 0, + VG_sRGBA_8888 = 1, + VG_sRGBA_8888_PRE = 2, + VG_sRGB_565 = 3, + VG_sRGBA_5551 = 4, + VG_sRGBA_4444 = 5, + VG_sL_8 = 6, + VG_lRGBX_8888 = 7, + VG_lRGBA_8888 = 8, + VG_lRGBA_8888_PRE = 9, + VG_lL_8 = 10, + VG_A_8 = 11, + VG_BW_1 = 12, + + /* {A,X}RGB channel ordering */ + VG_sXRGB_8888 = 0 | (1 << 6), + VG_sARGB_8888 = 1 | (1 << 6), + VG_sARGB_8888_PRE = 2 | (1 << 6), + VG_sARGB_1555 = 4 | (1 << 6), + VG_sARGB_4444 = 5 | (1 << 6), + VG_lXRGB_8888 = 7 | (1 << 6), + VG_lARGB_8888 = 8 | (1 << 6), + VG_lARGB_8888_PRE = 9 | (1 << 6), + + /* BGR{A,X} channel ordering */ + VG_sBGRX_8888 = 0 | (1 << 7), + VG_sBGRA_8888 = 1 | (1 << 7), + VG_sBGRA_8888_PRE = 2 | (1 << 7), + VG_sBGR_565 = 3 | (1 << 7), + VG_sBGRA_5551 = 4 | (1 << 7), + VG_sBGRA_4444 = 5 | (1 << 7), + VG_lBGRX_8888 = 7 | (1 << 7), + VG_lBGRA_8888 = 8 | (1 << 7), + VG_lBGRA_8888_PRE = 9 | (1 << 7), + + /* {A,X}BGR channel ordering */ + VG_sXBGR_8888 = 0 | (1 << 6) | (1 << 7), + VG_sABGR_8888 = 1 | (1 << 6) | (1 << 7), + VG_sABGR_8888_PRE = 2 | (1 << 6) | (1 << 7), + VG_sABGR_1555 = 4 | (1 << 6) | (1 << 7), + VG_sABGR_4444 = 5 | (1 << 6) | (1 << 7), + VG_lXBGR_8888 = 7 | (1 << 6) | (1 << 7), + VG_lABGR_8888 = 8 | (1 << 6) | (1 << 7), + VG_lABGR_8888_PRE = 9 | (1 << 6) | (1 << 7) +} VGImageFormat; + +typedef VGHandle VGImage; + +typedef enum { + VG_IMAGE_QUALITY_NONANTIALIASED = (1 << 0), + VG_IMAGE_QUALITY_FASTER = (1 << 1), + VG_IMAGE_QUALITY_BETTER = (1 << 2) +} VGImageQuality; + +typedef enum { + VG_IMAGE_FORMAT = 0x1E00, + VG_IMAGE_WIDTH = 0x1E01, + VG_IMAGE_HEIGHT = 0x1E02 +} VGImageParamType; + +typedef enum { + VG_DRAW_IMAGE_NORMAL = 0x1F00, + VG_DRAW_IMAGE_MULTIPLY = 0x1F01, + VG_DRAW_IMAGE_STENCIL = 0x1F02 +} VGImageMode; + +typedef enum { + VG_RED = (1 << 3), + VG_GREEN = (1 << 2), + VG_BLUE = (1 << 1), + VG_ALPHA = (1 << 0) +} VGImageChannel; + +typedef enum { + VG_BLEND_SRC = 0x2000, + VG_BLEND_SRC_OVER = 0x2001, + VG_BLEND_DST_OVER = 0x2002, + VG_BLEND_SRC_IN = 0x2003, + VG_BLEND_DST_IN = 0x2004, + VG_BLEND_MULTIPLY = 0x2005, + VG_BLEND_SCREEN = 0x2006, + VG_BLEND_DARKEN = 0x2007, + VG_BLEND_LIGHTEN = 0x2008, + VG_BLEND_ADDITIVE = 0x2009, + VG_BLEND_SRC_OUT_SH = 0x200A, + VG_BLEND_DST_OUT_SH = 0x200B, + VG_BLEND_SRC_ATOP_SH = 0x200C, + VG_BLEND_DST_ATOP_SH = 0x200D +} VGBlendMode; + +typedef enum { + VG_IMAGE_FORMAT_QUERY = 0x2100, + VG_PATH_DATATYPE_QUERY = 0x2101 +} VGHardwareQueryType; + +typedef enum { + VG_HARDWARE_ACCELERATED = 0x2200, + VG_HARDWARE_UNACCELERATED = 0x2201 +} VGHardwareQueryResult; + +typedef enum { + VG_VENDOR = 0x2300, + VG_RENDERER = 0x2301, + VG_VERSION = 0x2302, + VG_EXTENSIONS = 0x2303 +} VGStringID; + +/* Function Prototypes */ + +#if 0 // We are including ShivaVG directly into libSimGearScene and only using + // inside the library so there is no need for any dll import/export stuff +#if defined(_WIN32) || defined(__VC32__) +# if defined(VG_API_EXPORT) +# define VG_API_CALL __declspec(dllexport) +# else +# define VG_API_CALL __declspec(dllimport) +# endif +#else +# define VG_API_CALL extern +#endif +#else +# define VG_API_CALL +#endif + +#if defined (__cplusplus) +extern "C" { +#endif + +VG_API_CALL VGErrorCode vgGetError(void); + +VG_API_CALL void vgFlush(void); +VG_API_CALL void vgFinish(void); + +/* Getters and Setters */ +VG_API_CALL void vgSetf (VGParamType type, VGfloat value); +VG_API_CALL void vgSeti (VGParamType type, VGint value); +VG_API_CALL void vgSetfv(VGParamType type, VGint count, + const VGfloat * values); +VG_API_CALL void vgSetiv(VGParamType type, VGint count, + const VGint * values); + +VG_API_CALL VGfloat vgGetf(VGParamType type); +VG_API_CALL VGint vgGeti(VGParamType type); +VG_API_CALL VGint vgGetVectorSize(VGParamType type); +VG_API_CALL void vgGetfv(VGParamType type, VGint count, VGfloat * values); +VG_API_CALL void vgGetiv(VGParamType type, VGint count, VGint * values); + +VG_API_CALL void vgSetParameterf(VGHandle object, + VGint paramType, + VGfloat value); +VG_API_CALL void vgSetParameteri(VGHandle object, + VGint paramType, + VGint value); +VG_API_CALL void vgSetParameterfv(VGHandle object, + VGint paramType, + VGint count, const VGfloat * values); +VG_API_CALL void vgSetParameteriv(VGHandle object, + VGint paramType, + VGint count, const VGint * values); + +VG_API_CALL VGfloat vgGetParameterf(VGHandle object, + VGint paramType); +VG_API_CALL VGint vgGetParameteri(VGHandle object, + VGint paramType); +VG_API_CALL VGint vgGetParameterVectorSize(VGHandle object, + VGint paramType); +VG_API_CALL void vgGetParameterfv(VGHandle object, + VGint paramType, + VGint count, VGfloat * values); +VG_API_CALL void vgGetParameteriv(VGHandle object, + VGint paramType, + VGint count, VGint * values); + +/* Matrix Manipulation */ +VG_API_CALL void vgLoadIdentity(void); +VG_API_CALL void vgLoadMatrix(const VGfloat * m); +VG_API_CALL void vgGetMatrix(VGfloat * m); +VG_API_CALL void vgMultMatrix(const VGfloat * m); +VG_API_CALL void vgTranslate(VGfloat tx, VGfloat ty); +VG_API_CALL void vgScale(VGfloat sx, VGfloat sy); +VG_API_CALL void vgShear(VGfloat shx, VGfloat shy); +VG_API_CALL void vgRotate(VGfloat angle); + +/* Masking and Clearing */ +VG_API_CALL void vgMask(VGImage mask, VGMaskOperation operation, + VGint x, VGint y, VGint width, VGint height); +VG_API_CALL void vgClear(VGint x, VGint y, VGint width, VGint height); + +/* Paths */ +VG_API_CALL VGPath vgCreatePath(VGint pathFormat, + VGPathDatatype datatype, + VGfloat scale, VGfloat bias, + VGint segmentCapacityHint, + VGint coordCapacityHint, + VGbitfield capabilities); +VG_API_CALL void vgClearPath(VGPath path, VGbitfield capabilities); +VG_API_CALL void vgDestroyPath(VGPath path); +VG_API_CALL void vgRemovePathCapabilities(VGPath path, + VGbitfield capabilities); +VG_API_CALL VGbitfield vgGetPathCapabilities(VGPath path); +VG_API_CALL void vgAppendPath(VGPath dstPath, VGPath srcPath); +VG_API_CALL void vgAppendPathData(VGPath dstPath, + VGint numSegments, + const VGubyte * pathSegments, + const void * pathData); +VG_API_CALL void vgModifyPathCoords(VGPath dstPath, VGint startIndex, + VGint numSegments, + const void * pathData); +VG_API_CALL void vgTransformPath(VGPath dstPath, VGPath srcPath); +VG_API_CALL VGboolean vgInterpolatePath(VGPath dstPath, + VGPath startPath, + VGPath endPath, + VGfloat amount); +VG_API_CALL VGfloat vgPathLength(VGPath path, + VGint startSegment, VGint numSegments); +VG_API_CALL void vgPointAlongPath(VGPath path, + VGint startSegment, VGint numSegments, + VGfloat distance, + VGfloat * x, VGfloat * y, + VGfloat * tangentX, VGfloat * tangentY); +VG_API_CALL void vgPathBounds(VGPath path, + VGfloat * minX, VGfloat * minY, + VGfloat * width, VGfloat * height); +VG_API_CALL void vgPathTransformedBounds(VGPath path, + VGfloat * minX, VGfloat * minY, + VGfloat * width, VGfloat * height); +VG_API_CALL void vgDrawPath(VGPath path, VGbitfield paintModes); + +/* Paint */ +VG_API_CALL VGPaint vgCreatePaint(void); +VG_API_CALL void vgDestroyPaint(VGPaint paint); +VG_API_CALL void vgSetPaint(VGPaint paint, VGbitfield paintModes); +VG_API_CALL VGPaint vgGetPaint(VGPaintMode paintMode); +VG_API_CALL void vgSetColor(VGPaint paint, VGuint rgba); +VG_API_CALL VGuint vgGetColor(VGPaint paint); +VG_API_CALL void vgPaintPattern(VGPaint paint, VGImage pattern); + +/* Images */ +VG_API_CALL VGImage vgCreateImage(VGImageFormat format, + VGint width, VGint height, + VGbitfield allowedQuality); +VG_API_CALL void vgDestroyImage(VGImage image); +VG_API_CALL void vgClearImage(VGImage image, + VGint x, VGint y, VGint width, VGint height); +VG_API_CALL void vgImageSubData(VGImage image, + const void * data, VGint dataStride, + VGImageFormat dataFormat, + VGint x, VGint y, VGint width, VGint height); +VG_API_CALL void vgGetImageSubData(VGImage image, + void * data, VGint dataStride, + VGImageFormat dataFormat, + VGint x, VGint y, + VGint width, VGint height); +VG_API_CALL VGImage vgChildImage(VGImage parent, + VGint x, VGint y, VGint width, VGint height); +VG_API_CALL VGImage vgGetParent(VGImage image); +VG_API_CALL void vgCopyImage(VGImage dst, VGint dx, VGint dy, + VGImage src, VGint sx, VGint sy, + VGint width, VGint height, + VGboolean dither); +VG_API_CALL void vgDrawImage(VGImage image); +VG_API_CALL void vgSetPixels(VGint dx, VGint dy, + VGImage src, VGint sx, VGint sy, + VGint width, VGint height); +VG_API_CALL void vgWritePixels(const void * data, VGint dataStride, + VGImageFormat dataFormat, + VGint dx, VGint dy, + VGint width, VGint height); +VG_API_CALL void vgGetPixels(VGImage dst, VGint dx, VGint dy, + VGint sx, VGint sy, + VGint width, VGint height); +VG_API_CALL void vgReadPixels(void * data, VGint dataStride, + VGImageFormat dataFormat, + VGint sx, VGint sy, + VGint width, VGint height); +VG_API_CALL void vgCopyPixels(VGint dx, VGint dy, + VGint sx, VGint sy, + VGint width, VGint height); + +/* Image Filters */ +VG_API_CALL void vgColorMatrix(VGImage dst, VGImage src, + const VGfloat * matrix); +VG_API_CALL void vgConvolve(VGImage dst, VGImage src, + VGint kernelWidth, VGint kernelHeight, + VGint shiftX, VGint shiftY, + const VGshort * kernel, + VGfloat scale, + VGfloat bias, + VGTilingMode tilingMode); +VG_API_CALL void vgSeparableConvolve(VGImage dst, VGImage src, + VGint kernelWidth, + VGint kernelHeight, + VGint shiftX, VGint shiftY, + const VGshort * kernelX, + const VGshort * kernelY, + VGfloat scale, + VGfloat bias, + VGTilingMode tilingMode); +VG_API_CALL void vgGaussianBlur(VGImage dst, VGImage src, + VGfloat stdDeviationX, + VGfloat stdDeviationY, + VGTilingMode tilingMode); +VG_API_CALL void vgLookup(VGImage dst, VGImage src, + const VGubyte * redLUT, + const VGubyte * greenLUT, + const VGubyte * blueLUT, + const VGubyte * alphaLUT, + VGboolean outputLinear, + VGboolean outputPremultiplied); +VG_API_CALL void vgLookupSingle(VGImage dst, VGImage src, + const VGuint * lookupTable, + VGImageChannel sourceChannel, + VGboolean outputLinear, + VGboolean outputPremultiplied); + +/* Hardware Queries */ +VG_API_CALL VGHardwareQueryResult vgHardwareQuery(VGHardwareQueryType key, + VGint setting); + +/* Renderer and Extension Information */ +VG_API_CALL const VGubyte * vgGetString(VGStringID name); + +/* Extensions */ + +#define OVG_SH_blend_src_out 1 +#define OVG_SH_blend_dst_out 1 +#define OVG_SH_blend_src_atop 1 +#define OVG_SH_blend_dst_atop 1 + +VG_API_CALL VGboolean vgCreateContextSH(VGint width, VGint height); +VG_API_CALL VGboolean vgHasContextSH(); +VG_API_CALL void vgResizeSurfaceSH(VGint width, VGint height); +VG_API_CALL void vgDestroyContextSH(void); + +/* Extensions for ShaderVG */ +#define VG_FRAGMENT_SHADER_SH 0 +#define VG_VERTEX_SHADER_SH 1 + +#define VG_IMAGE_UNIT_OFFSET_SH 2 + +typedef enum { + VG_IMAGE_UNIT_0_SH = VG_IMAGE_UNIT_OFFSET_SH, + VG_IMAGE_UNIT_1_SH, + VG_IMAGE_UNIT_2_SH, + VG_IMAGE_UNIT_3_SH, + VG_IMAGE_UNIT_4_SH +} VGImageUnitSH; + +VG_API_CALL void vgShaderSourceSH(VGuint shadertype, const VGbyte* string); +VG_API_CALL void vgCompileShaderSH(void); +VG_API_CALL void vgUniform1fSH(VGint location, VGfloat v0); +VG_API_CALL void vgUniform2fSH(VGint location, VGfloat v0, VGfloat v1); +VG_API_CALL void vgUniform3fSH(VGint location, VGfloat v0, VGfloat v1, VGfloat v2); +VG_API_CALL void vgUniform4fSH(VGint location, VGfloat v0, VGfloat v1, VGfloat v2, VGfloat v3); +VG_API_CALL void vgUniform1fvSH(VGint location, VGint count, const VGfloat *value); +VG_API_CALL void vgUniform2fvSH(VGint location, VGint count, const VGfloat *value); +VG_API_CALL void vgUniform3fvSH(VGint location, VGint count, const VGfloat *value); +VG_API_CALL void vgUniform4fvSH(VGint location, VGint count, const VGfloat *value); +VG_API_CALL void vgUniform1iSH(VGint location, VGint v0); +VG_API_CALL void vgUniform2iSH(VGint location, VGint v0, VGint v1); +VG_API_CALL void vgUniform3iSH(VGint location, VGint v0, VGint v1, VGint v2); +VG_API_CALL void vgUniform4iSH(VGint location, VGint v0, VGint v1, VGint v2, VGint v3); +VG_API_CALL void vgUniform1ivSH(VGint location, VGint count, const VGint *value); +VG_API_CALL void vgUniform2ivSH(VGint location, VGint count, const VGint *value); +VG_API_CALL void vgUniform3ivSH(VGint location, VGint count, const VGint *value); +VG_API_CALL void vgUniform4ivSH(VGint location, VGint count, const VGint *value); +VG_API_CALL void vgUniformMatrix2fvSH (VGint location, VGint count, VGboolean transpose, const VGfloat *value); +VG_API_CALL void vgUniformMatrix3fvSH (VGint location, VGint count, VGboolean transpose, const VGfloat *value); +VG_API_CALL void vgUniformMatrix4fvSH (VGint location, VGint count, VGboolean transpose, const VGfloat *value); +VG_API_CALL void vgBindImageSH(VGImage image, VGImageUnitSH unit); +VG_API_CALL VGint vgGetUniformLocationSH(const VGbyte *name); +VG_API_CALL void vgGetUniformfvSH(VGint location, VGfloat *params); + +#if defined (__cplusplus) +} /* extern "C" */ +#endif +#endif /* _OPENVG_H */ diff --git a/simgear/canvas/ShaderVG/include/vg/vgu.h b/simgear/canvas/ShaderVG/include/vg/vgu.h new file mode 100644 index 00000000..ee7fe6e1 --- /dev/null +++ b/simgear/canvas/ShaderVG/include/vg/vgu.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2007 Ivan Leben + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _VGU_H +#define _VGU_H + +#include "openvg.h" + +#define VGU_VERSION_1_0 1 +#define VGU_VERSION_1_0_1 1 + +#ifndef VGU_API_CALL +#define VGU_API_CALL VG_API_CALL +#endif + +typedef enum { + VGU_NO_ERROR = 0, + VGU_BAD_HANDLE_ERROR = 0xF000, + VGU_ILLEGAL_ARGUMENT_ERROR = 0xF001, + VGU_OUT_OF_MEMORY_ERROR = 0xF002, + VGU_PATH_CAPABILITY_ERROR = 0xF003, + VGU_BAD_WARP_ERROR = 0xF004 +} VGUErrorCode; + +typedef enum { + VGU_ARC_OPEN = 0xF100, + VGU_ARC_CHORD = 0xF101, + VGU_ARC_PIE = 0xF102 +} VGUArcType; + +#ifdef __cplusplus +extern "C" { +#endif + +VGU_API_CALL VGUErrorCode vguLine(VGPath path, + VGfloat x0, VGfloat y0, + VGfloat x1, VGfloat y1); + +VGU_API_CALL VGUErrorCode vguPolygon(VGPath path, + const VGfloat * points, VGint count, + VGboolean closed); + +VGU_API_CALL VGUErrorCode vguRect(VGPath path, + VGfloat x, VGfloat y, + VGfloat width, VGfloat height); + +VGU_API_CALL VGUErrorCode vguRoundRect(VGPath path, + VGfloat x, VGfloat y, + VGfloat width, VGfloat height, + VGfloat arcWidth, VGfloat arcHeight); + +VGU_API_CALL VGUErrorCode vguEllipse(VGPath path, + VGfloat cx, VGfloat cy, + VGfloat width, VGfloat height); + +VGU_API_CALL VGUErrorCode vguArc(VGPath path, + VGfloat x, VGfloat y, + VGfloat width, VGfloat height, + VGfloat startAngle, VGfloat angleExtent, + VGUArcType arcType); + +VGU_API_CALL VGUErrorCode vguComputeWarpQuadToSquare(VGfloat sx0, VGfloat sy0, + VGfloat sx1, VGfloat sy1, + VGfloat sx2, VGfloat sy2, + VGfloat sx3, VGfloat sy3, + VGfloat * matrix); + +VGU_API_CALL VGUErrorCode vguComputeWarpSquareToQuad(VGfloat dx0, VGfloat dy0, + VGfloat dx1, VGfloat dy1, + VGfloat dx2, VGfloat dy2, + VGfloat dx3, VGfloat dy3, + VGfloat * matrix); + +VGU_API_CALL VGUErrorCode vguComputeWarpQuadToQuad(VGfloat dx0, VGfloat dy0, + VGfloat dx1, VGfloat dy1, + VGfloat dx2, VGfloat dy2, + VGfloat dx3, VGfloat dy3, + VGfloat sx0, VGfloat sy0, + VGfloat sx1, VGfloat sy1, + VGfloat sx2, VGfloat sy2, + VGfloat sx3, VGfloat sy3, + VGfloat * matrix); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* #ifndef _VGU_H */ diff --git a/simgear/canvas/ShaderVG/src/CMakeLists.txt b/simgear/canvas/ShaderVG/src/CMakeLists.txt new file mode 100644 index 00000000..bee4c920 --- /dev/null +++ b/simgear/canvas/ShaderVG/src/CMakeLists.txt @@ -0,0 +1,23 @@ +include(SimGearComponent) + +set(HEADERS + ../include/vg/openvg.h + ../include/vg/vgu.h +) + +set(SOURCES + shaders.c + shArrays.c + shContext.c + shExtensions.c + shGeometry.c + shImage.c + shPaint.c + shParams.c + shPath.c + shPipeline.c + shVectors.c + shVgu.c +) + +simgear_scene_component(ShivaVG canvas/ShivaVG "${SOURCES}" "${HEADERS}") diff --git a/simgear/canvas/ShaderVG/src/Makefile.am b/simgear/canvas/ShaderVG/src/Makefile.am new file mode 100644 index 00000000..88cb47ea --- /dev/null +++ b/simgear/canvas/ShaderVG/src/Makefile.am @@ -0,0 +1,31 @@ +lib_LTLIBRARIES = libOpenVG.la +libOpenVG_la_CFLAGS = -pedantic -I$(top_builddir)/include/vg +libOpenVG_la_SOURCES =\ + shDefs.h\ + shExtensions.h\ + shArrayBase.h\ + shArrays.h\ + shVectors.h\ + shPath.h\ + shImage.h\ + shPaint.h\ + shGeometry.h\ + shContext.h\ + shaders.h\ + shExtensions.c\ + shArrays.c\ + shVectors.c\ + shPath.c\ + shImage.c\ + shPaint.c\ + shGeometry.c\ + shPipeline.c\ + shParams.c\ + shContext.c\ + shaders.c\ + shVgu.c + +VG_includedir = $(includedir)/vg +VG_include_HEADERS =\ + $(top_builddir)/include/vg/openvg.h\ + $(top_builddir)/include/vg/vgu.h diff --git a/simgear/canvas/ShaderVG/src/shArrayBase.h b/simgear/canvas/ShaderVG/src/shArrayBase.h new file mode 100644 index 00000000..1083af4d --- /dev/null +++ b/simgear/canvas/ShaderVG/src/shArrayBase.h @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2007 Ivan Leben + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +/*------------------------------------------------------------ + * The base for any type of array. According to appropriate + * macro definitions, specific array types will be generated + * and their manipulation functions respectively. + * + * This code assumes the following are defined: + * _ITEM_T: the type of the items in the array + * _ARRAY_T: the name of the structure + * _FUNC_T: the prefix to prepend to each function + * + * And at least one of these: + * _ARRAY_DECLARE: generate structure declaration + * _ARRAY_DEFINE: generate function definitions + *-----------------------------------------------------------*/ + +#ifndef __SHARRAYBASE_H +#define __SHARRAYBASE_H + +#include "shDefs.h" + +#define VAL(x,y) x ## y +#define JN(x,y) VAL(x,y) + +#endif + +/*-------------------------------------------- + * The rest is not #ifndef protected to allow + * for various array type definitions. + *--------------------------------------------*/ + + +#ifdef _ARRAY_DECLARE +typedef struct +{ + _ITEM_T *items; + SHint32 capacity; + SHint32 size; + SHint outofmemory; + +} _ARRAY_T; +#endif + + +void JN(_ARRAY_T,_ctor) (_ARRAY_T *a) +#ifdef _ARRAY_DEFINE +{ + a->items = (_ITEM_T*)malloc(sizeof(_ITEM_T)); + + if (!a->items) { + a->outofmemory = 1; + a->capacity = 0; + a->size = 0; + return; + } + + a->outofmemory = 0; + a->capacity = 1; + a->size = 0; +} +#else +; +#endif + + +void JN(_ARRAY_T,_dtor) (_ARRAY_T *a) +#ifdef _ARRAY_DEFINE +{ + if (a->items) { + free(a->items); + a->items = NULL; + } +} +#else +; +#endif + +void JN(_FUNC_T,Clear) (_ARRAY_T *a) +#ifdef _ARRAY_DEFINE +{ + a->size = 0; +} +#else +; +#endif + + +/*-------------------------------------------------------- + * Set the capacity of the array. In case of reallocation + * the items are not preserved. + *--------------------------------------------------------*/ + +int JN(_FUNC_T,Realloc) (_ARRAY_T *a, SHint newsize) +#ifdef _ARRAY_DEFINE +{ + _ITEM_T *newitems = 0; + + SH_ASSERT(newsize > 0); + if (newsize == a->capacity) + return 1; + + newitems = (_ITEM_T*)malloc(newsize * sizeof(_ITEM_T)); + + if (!newitems) { + a->outofmemory = 1; + return 0; + } + + if (a->items) + free(a->items); + + a->outofmemory = 0; + a->items = newitems; + a->capacity = newsize; + a->size = 0; + return 1; +} +#else +; +#endif + + +/*------------------------------------------------------ + * Asserts the capacity is at least [newsize]. In case + * of reallocation items are not preserved. + *------------------------------------------------------*/ + +int JN(_FUNC_T,Reserve) (_ARRAY_T *a, SHint newsize) +#ifdef _ARRAY_DEFINE +{ + _ITEM_T *newitems = 0; + + SH_ASSERT(newsize >= 0); + if (newsize <= a->capacity) + return 1; + + newitems = (_ITEM_T*)malloc(newsize * sizeof(_ITEM_T)); + + if (!newitems) { + a->outofmemory = 1; + return 0; + } + + if (a->items) + free(a->items); + + a->outofmemory = 0; + a->items = newitems; + a->capacity = newsize; + a->size = 0; + return 1; +} +#else +; +#endif + +/*------------------------------------------------------ + * Asserts the capacity is at least [newsize]. In case + * of reallocation items are copied. + *------------------------------------------------------*/ + +int JN(_FUNC_T,ReserveAndCopy) (_ARRAY_T *a, SHint newsize) +#ifdef _ARRAY_DEFINE +{ + _ITEM_T *newitems = 0; + + SH_ASSERT(newsize >= 0); + if (newsize <= a->capacity) + return 1; + + newitems = (_ITEM_T*)realloc(a->items, newsize * sizeof(_ITEM_T)); + + if (!newitems) { + a->outofmemory = 1; + return 0; + } + + a->outofmemory = 0; + a->items = newitems; + a->capacity = newsize; + return 1; +} +#else +; +#endif + + +int JN(_FUNC_T,PushBack) (_ARRAY_T *a, _ITEM_T item) +#ifdef _ARRAY_DEFINE +{ + if (a->capacity == 0) { + JN(_FUNC_T,Realloc)(a, 1); + if (a->outofmemory) + return 0; + } + + if (a->size + 1 > a->capacity) + JN(_FUNC_T,ReserveAndCopy)(a, a->capacity*2); + + if (a->outofmemory) + return 0; + + a->items[a->size++] = item; + return 1; +} +#else +; +#endif + + +int JN(_FUNC_T,PushBackP) (_ARRAY_T *a, _ITEM_T *item) +#ifdef _ARRAY_DEFINE +{ + if (a->capacity == 0) { + JN(_FUNC_T,Realloc)(a, 1); + if (a->outofmemory) + return 0; + } + + if (a->size + 1 > a->capacity) + JN(_FUNC_T,ReserveAndCopy)(a, a->capacity*2); + + if (a->outofmemory) + return 0; + + a->items[a->size++] = *item; + return 1; +} +#else +; +#endif + + +void JN(_FUNC_T,PopBack) (_ARRAY_T *a) +#ifdef _ARRAY_DEFINE +{ + SH_ASSERT(a->size); + --a->size; +} +#else +; +#endif + + +_ITEM_T JN(_FUNC_T,Front) (_ARRAY_T *a) +#ifdef _ARRAY_DEFINE +{ + SH_ASSERT(a->size); + return a->items[0]; +} +#else +; +#endif + + +_ITEM_T* JN(_FUNC_T,FrontP) (_ARRAY_T *a) +#ifdef _ARRAY_DEFINE +{ + SH_ASSERT(a->size); + return &a->items[0]; +} +#else +; +#endif + + +_ITEM_T JN(_FUNC_T,Back) (_ARRAY_T *a) +#ifdef _ARRAY_DEFINE +{ + SH_ASSERT(a->size); + return a->items[a->size - 1]; +} +#else +; +#endif + + +_ITEM_T* JN(_FUNC_T,BackP) (_ARRAY_T *a) +#ifdef _ARRAY_DEFINE +{ + SH_ASSERT(a->size); + return &a->items[a->size - 1]; +} +#else +; +#endif + + +_ITEM_T JN(_FUNC_T,At) (_ARRAY_T *a, SHint index) +#ifdef _ARRAY_DEFINE +{ + SH_ASSERT(index >= 0); + SH_ASSERT(index < a->size); + return a->items[index]; +} +#else +; +#endif + + +_ITEM_T* JN(_FUNC_T,AtP) (_ARRAY_T *a, SHint index) +#ifdef _ARRAY_DEFINE +{ + SH_ASSERT(index >= 0); + SH_ASSERT(index < a->size); + return &a->items[index]; +} +#else +; +#endif + +SHint JN(_FUNC_T,Find) (_ARRAY_T *a, _ITEM_T item) +#ifdef _ARRAY_DEFINE +{ + int i; + for (i=0; isize; ++i) { + #ifdef _COMPARE_T + if (_COMPARE_T(a->items[i], item)) + return i; + #else + if (a->items[i] == item) + return i; + #endif + } + + return -1; +} +#else +; +#endif + +void JN(_FUNC_T,RemoveAt) (_ARRAY_T *a, SHint index) +#ifdef _ARRAY_DEFINE +{ + int i; + SH_ASSERT(index >= 0); + SH_ASSERT(index < a->size); + for (i=index; isize-1; ++i) + a->items[i] = a->items[i+1]; + a->size--; +} +#else +; +#endif + +#undef _ITEM_T +#undef _ARRAY_T +#undef _FUNC_T +#undef _COMPARE_T +#undef _ARRAY_DEFINE +#undef _ARRAY_DECLARE diff --git a/simgear/canvas/ShaderVG/src/shArrays.c b/simgear/canvas/ShaderVG/src/shArrays.c new file mode 100644 index 00000000..2f149bfb --- /dev/null +++ b/simgear/canvas/ShaderVG/src/shArrays.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2007 Ivan Leben + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +/*-------------------------------------------- + * Definitions of all the arrays used + *--------------------------------------------*/ + +#include "shArrays.h" + +#define _ITEM_T SHint +#define _ARRAY_T SHIntArray +#define _FUNC_T shIntArray +#define _ARRAY_DEFINE +#include "shArrayBase.h" + +#define _ITEM_T SHuint8 +#define _ARRAY_T SHUint8Array +#define _FUNC_T shUint8Array +#define _ARRAY_DEFINE +#include "shArrayBase.h" + +#define _ITEM_T SHfloat +#define _ARRAY_T SHFloatArray +#define _FUNC_T shFloatArray +#define _ARRAY_DEFINE +#include "shArrayBase.h" + +#define _ITEM_T SHRectangle +#define _ARRAY_T SHRectArray +#define _FUNC_T shRectArray +#define _COMPARE_T(x,y) 1 +#define _ARRAY_DEFINE +#include "shArrayBase.h" diff --git a/simgear/canvas/ShaderVG/src/shArrays.h b/simgear/canvas/ShaderVG/src/shArrays.h new file mode 100644 index 00000000..9a2de00e --- /dev/null +++ b/simgear/canvas/ShaderVG/src/shArrays.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2007 Ivan Leben + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +/*-------------------------------------------- + * Declarations of all the arrays used + *--------------------------------------------*/ + +#ifndef __SHARRAYS_H +#define __SHARRAYS_H + +#include "shVectors.h" + + +#define _ITEM_T SHint +#define _ARRAY_T SHIntArray +#define _FUNC_T shIntArray +#define _ARRAY_DECLARE +#include "shArrayBase.h" + +#define _ITEM_T SHuint8 +#define _ARRAY_T SHUint8Array +#define _FUNC_T shUint8Array +#define _ARRAY_DECLARE +#include "shArrayBase.h" + +#define _ITEM_T SHfloat +#define _ARRAY_T SHFloatArray +#define _FUNC_T shFloatArray +#define _ARRAY_DECLARE +#include "shArrayBase.h" + +#define _ITEM_T SHRectangle +#define _ARRAY_T SHRectArray +#define _FUNC_T shRectArray +#define _ARRAY_DECLARE +#include "shArrayBase.h" + +#endif diff --git a/simgear/canvas/ShaderVG/src/shConfig.h b/simgear/canvas/ShaderVG/src/shConfig.h new file mode 100644 index 00000000..77be46ac --- /dev/null +++ b/simgear/canvas/ShaderVG/src/shConfig.h @@ -0,0 +1,51 @@ + +#ifndef __SHCONFIG_H +#define __SHCONFIG_H + +//////////////////////////////////////////////////////////// +// Identify the operating system +//////////////////////////////////////////////////////////// +#if defined(_WIN32) || defined(__WIN32__) + + // Windows + #define VG_API_WINDOWS + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #endif + #ifndef NOMINMAX + #define NOMINMAX + #endif + +#elif defined(linux) || defined(__linux) + + // Linux + #define VG_API_LINUX + +#elif defined(__APPLE__) || defined(MACOSX) || defined(macintosh) || defined(Macintosh) + + // MacOS + #define VG_API_MACOSX + +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + + // FreeBSD + #define VG_API_FREEBSD + +#elif defined(__OpenBSD__) + + // FreeBSD + #define VG_API_OPENBSD + +#else + + // Unsupported system + #error This operating system is not supported by SFML library + +#endif + +// We currently do not support using images (inside paths). If we were going to +// use it loading and unloading needs to happen within OpenSceneGraph to handle +// synchronization correctly in multithreading mode. +#define SH_NO_IMAGE + +#endif // __SHCONFIG_H diff --git a/simgear/canvas/ShaderVG/src/shContext.c b/simgear/canvas/ShaderVG/src/shContext.c new file mode 100644 index 00000000..4461bdc9 --- /dev/null +++ b/simgear/canvas/ShaderVG/src/shContext.c @@ -0,0 +1,504 @@ +/* + * Copyright (c) 2007 Ivan Leben + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#define VG_API_EXPORT +#include "vg/openvg.h" +#include "shContext.h" +#include "shaders.h" +#include +#include + +/*----------------------------------------------------- + * Simple functions to create a VG context instance + * on top of an existing OpenGL context. + * TODO: There is no mechanics yet to asure the OpenGL + * context exists and to choose which context / window + * to bind to. + *-----------------------------------------------------*/ + +static VGContext *g_context = NULL; + +VG_API_CALL VGboolean vgCreateContextSH(VGint width, VGint height) +{ + /* return if already created */ + if (g_context) return VG_TRUE; + + /* create new context */ + SH_NEWOBJ(VGContext, g_context); + if (!g_context) return VG_FALSE; + + /* init surface info */ + g_context->surfaceWidth = width; + g_context->surfaceHeight = height; + + /* setup GL projection */ + /* We handle viewport and projection ourselves... + glViewport(0,0,width,height); */ + + /* Setup shader for rendering*/ + g_context->userShaderVertex = NULL; + g_context->userShaderFragment = NULL; + shInitPiplelineShaders(); + + /* Setup shaders for making color ramp */ + shInitRampShaders(); + + return VG_TRUE; +} + +VG_API_CALL VGboolean vgHasContextSH() +{ + return g_context != NULL; +} + +VG_API_CALL void vgResizeSurfaceSH(VGint width, VGint height) +{ + VG_GETCONTEXT(VG_NO_RETVAL); + + /* update surface info */ + context->surfaceWidth = width; + context->surfaceHeight = height; + + /* setup GL projection */ + /* We handle viewport and projection ourselves... + glViewport(0,0,width,height); */ + + /* Setup projection matrix */ +//float mat[16]; +//float volume = fmax(width, height) / 2; +//shCalcOrtho2D(mat, 0, width, 0, height, -volume, volume); + glUseProgram(context->progDraw); +//glUniformMatrix4fv(context->locationDraw.projection, 1, GL_FALSE, mat); + GL_CEHCK_ERROR; + + VG_RETURN(VG_NO_RETVAL); +} + +VG_API_CALL void vgDestroyContextSH() +{ + /* return if already released */ + if (!g_context) return; + + /* delete context object */ + SH_DELETEOBJ(VGContext, g_context); + g_context = NULL; +} + +VGContext* shGetContext() +{ + SH_ASSERT(g_context); + return g_context; +} + +/*----------------------------------------------------- + * VGContext constructor + *-----------------------------------------------------*/ + +void shLoadExtensions(void *c); + +void VGContext_ctor(VGContext *c) +{ + /* Surface info */ + c->surfaceWidth = 0; + c->surfaceHeight = 0; + + /* GetString info */ + strncpy(c->vendor, "Takuma Hayashi", sizeof(c->vendor)); + strncpy(c->renderer, "ShaderVG", sizeof(c->renderer)); + strncpy(c->version, "1.0.0", sizeof(c->version)); + strncpy(c->extensions, "", sizeof(c->extensions)); + + /* Mode settings */ + c->matrixMode = VG_MATRIX_PATH_USER_TO_SURFACE; + c->fillRule = VG_EVEN_ODD; + c->imageQuality = VG_IMAGE_QUALITY_FASTER; + c->renderingQuality = VG_RENDERING_QUALITY_BETTER; + c->blendMode = VG_BLEND_SRC_OVER; + c->imageMode = VG_DRAW_IMAGE_NORMAL; + + /* Scissor rectangles */ + SH_INITOBJ(SHRectArray, c->scissor); + c->scissoring = VG_FALSE; + c->masking = VG_FALSE; + + /* Stroke parameters */ + c->strokeLineWidth = 1.0f; + c->strokeCapStyle = VG_CAP_BUTT; + c->strokeJoinStyle = VG_JOIN_MITER; + c->strokeMiterLimit = 4.0f; + c->strokeDashPhase = 0.0f; + c->strokeDashPhaseReset = VG_FALSE; + SH_INITOBJ(SHFloatArray, c->strokeDashPattern); + + /* Edge fill color for vgConvolve and pattern paint */ + CSET(c->tileFillColor, 0,0,0,0); + + /* Color for vgClear */ + CSET(c->clearColor, 0,0,0,0); + + /* Color components layout inside pixel */ + c->pixelLayout = VG_PIXEL_LAYOUT_UNKNOWN; + + /* Source format for image filters */ + c->filterFormatLinear = VG_FALSE; + c->filterFormatPremultiplied = VG_FALSE; + c->filterChannelMask = VG_RED|VG_GREEN|VG_BLUE|VG_ALPHA; + + /* Matrices */ + SH_INITOBJ(SHMatrix3x3, c->pathTransform); + SH_INITOBJ(SHMatrix3x3, c->imageTransform); + SH_INITOBJ(SHMatrix3x3, c->fillTransform); + SH_INITOBJ(SHMatrix3x3, c->strokeTransform); + + /* Paints */ + c->fillPaint = NULL; + c->strokePaint = NULL; + SH_INITOBJ(SHPaint, c->defaultPaint); + + /* Error */ + c->error = VG_NO_ERROR; + + /* Resources */ + SH_INITOBJ(SHPathArray, c->paths); + SH_INITOBJ(SHPaintArray, c->paints); + SH_INITOBJ(SHImageArray, c->images); + + shLoadExtensions(c); +} + +/*----------------------------------------------------- + * VGContext constructor + *-----------------------------------------------------*/ + +void VGContext_dtor(VGContext *c) +{ + int i; + + SH_DEINITOBJ(SHRectArray, c->scissor); + SH_DEINITOBJ(SHFloatArray, c->strokeDashPattern); + + /* Destroy resources */ + for (i=0; ipaths.size; ++i) + SH_DELETEOBJ(SHPath, c->paths.items[i]); + + for (i=0; ipaints.size; ++i) + SH_DELETEOBJ(SHPaint, c->paints.items[i]); + + for (i=0; iimages.size; ++i) + SH_DELETEOBJ(SHImage, c->images.items[i]); +} + +/*-------------------------------------------------- + * Tries to find resources in this context + *--------------------------------------------------*/ + +SHint shIsValidPath(VGContext *c, VGHandle h) +{ + int index = shPathArrayFind(&c->paths, (SHPath*)h); + return (index == -1) ? 0 : 1; +} + +SHint shIsValidPaint(VGContext *c, VGHandle h) +{ + int index = shPaintArrayFind(&c->paints, (SHPaint*)h); + return (index == -1) ? 0 : 1; +} + +SHint shIsValidImage(VGContext *c, VGHandle h) +{ + int index = shImageArrayFind(&c->images, (SHImage*)h); + return (index == -1) ? 0 : 1; +} + +/*-------------------------------------------------- + * Tries to find a resources in this context and + * return its type or invalid flag. + *--------------------------------------------------*/ + +SHResourceType shGetResourceType(VGContext *c, VGHandle h) +{ + if (shIsValidPath(c, h)) + return SH_RESOURCE_PATH; + + else if (shIsValidPaint(c, h)) + return SH_RESOURCE_PAINT; + + else if (shIsValidImage(c, h)) + return SH_RESOURCE_IMAGE; + + else + return SH_RESOURCE_INVALID; +} + +/*----------------------------------------------------- + * Sets the specified error on the given context if + * there is no pending error yet + *-----------------------------------------------------*/ + +void shSetError(VGContext *c, VGErrorCode e) +{ + if (c->error == VG_NO_ERROR) + c->error = e; +} + +/*-------------------------------------------------- + * Returns the oldest error pending on the current + * context and clears its error code + *--------------------------------------------------*/ + +VG_API_CALL VGErrorCode vgGetError(void) +{ + VGErrorCode error; + VG_GETCONTEXT(VG_NO_CONTEXT_ERROR); + error = context->error; + context->error = VG_NO_ERROR; + VG_RETURN(error); +} + +VG_API_CALL void vgFlush(void) +{ + VG_GETCONTEXT(VG_NO_RETVAL); + glFlush(); + VG_RETURN(VG_NO_RETVAL); +} + +VG_API_CALL void vgFinish(void) +{ + VG_GETCONTEXT(VG_NO_RETVAL); + glFinish(); + VG_RETURN(VG_NO_RETVAL); +} + +VG_API_CALL void vgMask(VGImage mask, VGMaskOperation operation, + VGint x, VGint y, VGint width, VGint height) +{ +} + +VG_API_CALL void vgClear(VGint x, VGint y, VGint width, VGint height) +{ + VG_GETCONTEXT(VG_NO_RETVAL); + + /* Clip to window */ + if (x < 0) x = 0; + if (y < 0) y = 0; + if (width > context->surfaceWidth) width = context->surfaceWidth; + if (height > context->surfaceHeight) height = context->surfaceHeight; + + /* Check if scissoring needed */ + if (x > 0 || y > 0 || + width < context->surfaceWidth || + height < context->surfaceHeight) { + + glScissor(x, y, width, height); + glEnable(GL_SCISSOR_TEST); + } + + /* Clear GL color buffer */ + /* TODO: what about stencil and depth? when do we clear that? + we would need some kind of special "begin" function at + beginning of each drawing or clear the planes prior to each + drawing where it takes places */ + glClearColor(context->clearColor.r, + context->clearColor.g, + context->clearColor.b, + context->clearColor.a); + + glClear(GL_COLOR_BUFFER_BIT | + GL_STENCIL_BUFFER_BIT | + GL_DEPTH_BUFFER_BIT); + + glDisable(GL_SCISSOR_TEST); + + VG_RETURN(VG_NO_RETVAL); +} + +/*----------------------------------------------------------- + * Returns the matrix currently selected via VG_MATRIX_MODE + *-----------------------------------------------------------*/ + +SHMatrix3x3* shCurrentMatrix(VGContext *c) +{ + switch(c->matrixMode) { + case VG_MATRIX_PATH_USER_TO_SURFACE: + return &c->pathTransform; + case VG_MATRIX_IMAGE_USER_TO_SURFACE: + return &c->imageTransform; + case VG_MATRIX_FILL_PAINT_TO_USER: + return &c->fillTransform; + default: + return &c->strokeTransform; + } +} + +/*-------------------------------------- + * Sets the current matrix to identity + *--------------------------------------*/ + +VG_API_CALL void vgLoadIdentity(void) +{ + SHMatrix3x3 *m; + VG_GETCONTEXT(VG_NO_RETVAL); + + m = shCurrentMatrix(context); + IDMAT((*m)); + + VG_RETURN(VG_NO_RETVAL); +} + +/*------------------------------------------------------------- + * Loads values into the current matrix from the given array. + * Matrix affinity is preserved if an affine matrix is loaded. + *-------------------------------------------------------------*/ + +VG_API_CALL void vgLoadMatrix(const VGfloat * mm) +{ + SHMatrix3x3 *m; + VG_GETCONTEXT(VG_NO_RETVAL); + + VG_RETURN_ERR_IF(!mm, VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL); + /* TODO: check matrix array alignment */ + + m = shCurrentMatrix(context); + + if (context->matrixMode == VG_MATRIX_IMAGE_USER_TO_SURFACE) { + + SETMAT((*m), + mm[0], mm[3], mm[6], + mm[1], mm[4], mm[7], + mm[2], mm[5], mm[8]); + }else{ + + SETMAT((*m), + mm[0], mm[3], mm[6], + mm[1], mm[4], mm[7], + 0.0f, 0.0f, 1.0f); + } + + VG_RETURN(VG_NO_RETVAL); +} + +/*--------------------------------------------------------------- + * Outputs the values of the current matrix into the given array + *---------------------------------------------------------------*/ + +VG_API_CALL void vgGetMatrix(VGfloat * mm) +{ + SHMatrix3x3 *m; int i,j,k=0; + VG_GETCONTEXT(VG_NO_RETVAL); + + VG_RETURN_ERR_IF(!mm, VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL); + /* TODO: check matrix array alignment */ + + m = shCurrentMatrix(context); + + for (i=0; i<3; ++i) + for (j=0; j<3; ++j) + mm[k++] = m->m[j][i]; + + VG_RETURN(VG_NO_RETVAL); +} + +/*------------------------------------------------------------- + * Right-multiplies the current matrix with the one specified + * in the given array. Matrix affinity is preserved if an + * affine matrix is begin multiplied. + *-------------------------------------------------------------*/ + +VG_API_CALL void vgMultMatrix(const VGfloat * mm) +{ + SHMatrix3x3 *m, mul, temp; + VG_GETCONTEXT(VG_NO_RETVAL); + + VG_RETURN_ERR_IF(!mm, VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL); + /* TODO: check matrix array alignment */ + + m = shCurrentMatrix(context); + + if (context->matrixMode == VG_MATRIX_IMAGE_USER_TO_SURFACE) { + + SETMAT(mul, + mm[0], mm[3], mm[6], + mm[1], mm[4], mm[7], + mm[2], mm[5], mm[8]); + }else{ + + SETMAT(mul, + mm[0], mm[3], mm[6], + mm[1], mm[4], mm[7], + 0.0f, 0.0f, 1.0f); + } + + MULMATMAT((*m), mul, temp); + SETMATMAT((*m), temp); + + VG_RETURN(VG_NO_RETVAL); +} + +VG_API_CALL void vgTranslate(VGfloat tx, VGfloat ty) +{ + SHMatrix3x3 *m; + VG_GETCONTEXT(VG_NO_RETVAL); + + m = shCurrentMatrix(context); + TRANSLATEMATR((*m), tx, ty); + + VG_RETURN(VG_NO_RETVAL); +} + +VG_API_CALL void vgScale(VGfloat sx, VGfloat sy) +{ + SHMatrix3x3 *m; + VG_GETCONTEXT(VG_NO_RETVAL); + + m = shCurrentMatrix(context); + SCALEMATR((*m), sx, sy); + + VG_RETURN(VG_NO_RETVAL); +} + +VG_API_CALL void vgShear(VGfloat shx, VGfloat shy) +{ + SHMatrix3x3 *m; + VG_GETCONTEXT(VG_NO_RETVAL); + + m = shCurrentMatrix(context); + SHEARMATR((*m), shx, shy); + + VG_RETURN(VG_NO_RETVAL); +} + +VG_API_CALL void vgRotate(VGfloat angle) +{ + SHfloat a; + SHMatrix3x3 *m; + VG_GETCONTEXT(VG_NO_RETVAL); + + a = SH_DEG2RAD(angle); + m = shCurrentMatrix(context); + ROTATEMATR((*m), a); + + VG_RETURN(VG_NO_RETVAL); +} + +VG_API_CALL VGHardwareQueryResult vgHardwareQuery(VGHardwareQueryType key, + VGint setting) +{ + return VG_HARDWARE_UNACCELERATED; +} diff --git a/simgear/canvas/ShaderVG/src/shContext.h b/simgear/canvas/ShaderVG/src/shContext.h new file mode 100644 index 00000000..916c9368 --- /dev/null +++ b/simgear/canvas/ShaderVG/src/shContext.h @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2007 Ivan Leben + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __SHCONTEXT_H +#define __SHCONTEXT_H + +#include "shDefs.h" +#include "shVectors.h" +#include "shArrays.h" +#include "shPath.h" +#include "shPaint.h" +#include "shImage.h" + +/*------------------------------------------------ + * VGContext object + *------------------------------------------------*/ + +typedef enum +{ + SH_RESOURCE_INVALID = 0, + SH_RESOURCE_PATH = 1, + SH_RESOURCE_PAINT = 2, + SH_RESOURCE_IMAGE = 3 +} SHResourceType; + +typedef struct +{ + /* Surface info (since no EGL yet) */ + SHint surfaceWidth; + SHint surfaceHeight; + + /* GetString info */ + char vendor[256]; + char renderer[256]; + char version[256]; + char extensions[256]; + + /* Mode settings */ + VGMatrixMode matrixMode; + VGFillRule fillRule; + VGImageQuality imageQuality; + VGRenderingQuality renderingQuality; + VGBlendMode blendMode; + VGImageMode imageMode; + + /* Scissor rectangles */ + SHRectArray scissor; + VGboolean scissoring; + VGboolean masking; + + /* Stroke parameters */ + SHfloat strokeLineWidth; + VGCapStyle strokeCapStyle; + VGJoinStyle strokeJoinStyle; + SHfloat strokeMiterLimit; + SHFloatArray strokeDashPattern; + SHfloat strokeDashPhase; + VGboolean strokeDashPhaseReset; + + /* Edge fill color for vgConvolve and pattern paint */ + SHColor tileFillColor; + + /* Color for vgClear */ + SHColor clearColor; + + /* Color components layout inside pixel */ + VGPixelLayout pixelLayout; + + /* Source format for image filters */ + VGboolean filterFormatLinear; + VGboolean filterFormatPremultiplied; + VGbitfield filterChannelMask; + + /* Matrices */ + SHMatrix3x3 pathTransform; + SHMatrix3x3 imageTransform; + SHMatrix3x3 fillTransform; + SHMatrix3x3 strokeTransform; + + /* Paints */ + SHPaint* fillPaint; + SHPaint* strokePaint; + SHPaint defaultPaint; + + VGErrorCode error; + + /* Resources */ + SHPathArray paths; + SHPaintArray paints; + SHImageArray images; + + /* Pointers to extensions */ + + /* GL locations */ + struct { + GLint pos ; + GLint textureUV ; + GLint model ; + GLint projection ; + GLint paintInverted ; + GLint drawMode ; + GLint imageSampler ; + GLint imageMode ; + GLint paintType ; + GLint rampSampler ; + GLint patternSampler ; + GLint userSampler ; + GLint paintParams ; + GLint paintColor ; + GLint scaleFactorBias; + } locationDraw; + + struct { + GLuint step; + GLuint stepColor; + } locationColorRamp; + + /* GL programs */ + GLuint progDraw; + GLuint progColorRamp; + + /* GL shaders */ + const void* userShaderVertex; + const void* userShaderFragment; + GLint vs; + GLint fs; + +} VGContext; + +void VGContext_ctor(VGContext *c); +void VGContext_dtor(VGContext *c); +void shSetError(VGContext *c, VGErrorCode e); +SHint shIsValidPath(VGContext *c, VGHandle h); +SHint shIsValidPaint(VGContext *c, VGHandle h); +SHint shIsValidImage(VGContext *c, VGHandle h); +SHResourceType shGetResourceType(VGContext *c, VGHandle h); +VGContext* shGetContext(); + +/*---------------------------------------------------- + * TODO: Add mutex locking/unlocking to these macros + * to assure sequentiallity in multithreading. + *----------------------------------------------------*/ + +#define VG_NO_RETVAL + +#define VG_GETCONTEXT(RETVAL) \ + VGContext *context = shGetContext(); \ + if (!context) return RETVAL; + +#define VG_RETURN(RETVAL) \ + { return RETVAL; } + +#define VG_RETURN_ERR(ERRORCODE, RETVAL) \ + { shSetError(context,ERRORCODE); return RETVAL; } + +#define VG_RETURN_ERR_IF(COND, ERRORCODE, RETVAL) \ + { if (COND) {shSetError(context,ERRORCODE); return RETVAL;} } + +/*----------------------------------------------------------- + * Same macros but no mutex handling - used by sub-functions + *-----------------------------------------------------------*/ + +#define SH_NO_RETVAL + +#define SH_GETCONTEXT(RETVAL) \ + VGContext *context = shGetContext(); \ + if (!context) return RETVAL; + +#define SH_RETURN(RETVAL) \ + { return RETVAL; } + +#define SH_RETURN_ERR(ERRORCODE, RETVAL) \ + { shSetError(context,ERRORCODE); return RETVAL; } + +#define SH_RETURN_ERR_IF(COND, ERRORCODE, RETVAL) \ + { if (COND) {shSetError(context,ERRORCODE); return RETVAL;} } + + +#endif /* __SHCONTEXT_H */ diff --git a/simgear/canvas/ShaderVG/src/shDefs.h b/simgear/canvas/ShaderVG/src/shDefs.h new file mode 100644 index 00000000..da42c826 --- /dev/null +++ b/simgear/canvas/ShaderVG/src/shDefs.h @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2007 Ivan Leben + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __SHDEFS_H +#define __SHDEFS_H + +/* Standard headers */ + +#include "shConfig.h" + +#ifdef VG_API_WINDOWS +# include +#endif + +#include +#include +#include +#include + +#if !defined(VG_API_MACOSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__) +# include +#endif + +/* Disable VGHandle-pointer conversion warnings since we + do deal with it by defining VGHandle properly */ + +#if defined(_MSC_VER) +# pragma warning(disable:4311) +# pragma warning(disable:4312) +#endif + +/* Type definitions */ +#if HAVE_INTTYPES_H + + #include + +#else + + #define int8_t char + #define uint8_t unsigned char + #define int16_t short + #define uint16_t unsigned short + #define int32_t int + #define uint32_t unsigned int + #define int64_t long long + #define uint64_t unsigned long long + +#endif + +typedef int8_t SHint8; +typedef uint8_t SHuint8; +typedef int16_t SHint16; +typedef uint16_t SHuint16; +typedef int32_t SHint32; +typedef uint32_t SHuint32; +typedef float SHfloat32; + +#define SHint SHint32 +#define SHuint SHuint32 +#define SHfloat SHfloat32 + +/* Maximum / minimum values */ + +#define SH_MAX_INT (0x7fffffff) +#define SH_MIN_INT (-0x7fffffff-1) + +#define SH_MANTISSA_BITS 23 +#define SH_EXPONENT_BITS 8 + +/* all 1s in exponent yields NaN in IEEE 754 so we take + 1 less then maximum representable with exponent bits */ +#define SH_MAX_EXPONENT ((1 << SH_EXPONENT_BITS) - 2) +/* maximum representable with mantissa bits */ +#define SH_MAX_MANTISSA ((1 << SH_MANTISSA_BITS) - 1) +/* compose into IEEE754 floating point bit value */ +#define SH_MAX_FLOAT_BITS (SH_MAX_EXPONENT << SH_MANTISSA_BITS) | SH_MAX_MANTISSA + +typedef union { + float f; + unsigned int i; +} SHfloatint; + +SHfloat getMaxFloat(); + +/* Portable function definitions */ + +#define SH_SQRT (float)sqrt +#define SH_COS (float)cos +#define SH_SIN (float)sin +#define SH_ACOS (float)acos +#define SH_ASIN (float)asin +#define SH_ATAN (float)atan +#define SH_FLOOR (float)floor +#define SH_CEIL (float)ceil +#define SH_ASSERT assert + +#if defined(__isnan) || (defined(__APPLE__) && (__GNUC__ == 3)) +# define SH_ISNAN __isnan +#elif defined(_isnan) || defined(WIN32) +# define SH_ISNAN _isnan +#else +# define SH_ISNAN isnan +#endif + + +/* Helper macros */ + +#define PI 3.141592654f +#define SH_DEG2RAD(a) (a * PI / 180.0f) +#define SH_RAD2DEG(a) (a * 180.0f / PI) +#define SH_ABS(a) ((a < 0.0f) ? -a : a) +#define SH_MAX(a,b) ((a > b) ? a : b) +#define SH_MIN(a,b) ((a < b) ? a : b) +#define SH_NEARZERO(a) (a >= -0.0001 && a < 0.0001) +#define SH_SWAP(a,b) {SHfloat t=a; a=b; b=t;} +#define SH_CLAMP(a,min,max) {if (amax) a=max; } + +#define SH_NEWOBJ(type,obj) { obj = (type*)malloc(sizeof(type)); if(obj) type ## _ctor(obj); } +#define SH_INITOBJ(type,obj){ type ## _ctor(&obj); } +#define SH_DEINITOBJ(type,obj) { type ## _dtor(&obj); } +#define SH_DELETEOBJ(type,obj) { if(obj) type ## _dtor(obj); free(obj); } + +/* Implementation limits */ + +#define SH_MAX_SCISSOR_RECTS 1 +#define SH_MAX_DASH_COUNT VG_MAXINT +#define SH_MAX_IMAGE_WIDTH VG_MAXINT +#define SH_MAX_IMAGE_HEIGHT VG_MAXINT +#define SH_MAX_IMAGE_PIXELS VG_MAXINT +#define SH_MAX_IMAGE_BYTES VG_MAXINT +#define SH_MAX_COLOR_RAMP_STOPS 256 + +#define SH_MAX_VERTICES 999999999 +#define SH_MAX_RECURSE_DEPTH 16 + +#define SH_GRADIENT_TEX_WIDTH 1024 +#define SH_GRADIENT_TEX_HEIGHT 1 +#define SH_GRADIENT_TEX_COORDSIZE 4096 /* 1024 * RGBA */ + +/* OpenGL headers */ + +#if defined(VG_API_LINUX) || defined(VG_API_FREEBSD) || defined(VG_API_OPENBSD) + #include + #include +#elif defined(VG_API_MACOSX) + #include +#elif defined(VG_API_WINDOWS) + #include +#else + #define GL_GLEXT_LEGACY /* don't include glext.h */ + #include + #include +#endif + +#include "shExtensions.h" + +#define GL_GET_ERROR printf("glGetError() -> %d line:%d file:%s\r\n", glGetError(), __LINE__, __FILE__) +#define GL_CEHCK_ERROR \ + { \ + GLint err = glGetError(); \ + if(err){\ + printf("glGetError() -> %d \r\n", err);\ + assert(0);\ + }\ + } + +// GL_TEXTURE0 :imageSampler +// GL_TEXTURE1 :rampSampler or patternSampler +// GL_TEXTURE2 :User defined +#define SH_TEXTURE_USER_TOP GL_TEXTURE2 + +#endif /* __SHDEFS_H */ diff --git a/simgear/canvas/ShaderVG/src/shExtensions.c b/simgear/canvas/ShaderVG/src/shExtensions.c new file mode 100644 index 00000000..1149a9b2 --- /dev/null +++ b/simgear/canvas/ShaderVG/src/shExtensions.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2007 Ivan Leben + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#define VG_API_EXPORT +#include "shExtensions.h" +#include +#include +#include + +/*----------------------------------------------------- + * OpenGL core profile + *-----------------------------------------------------*/ +#if defined(_WIN32) + PFNGLUNIFORM1IPROC glUniform1i; + PFNGLUNIFORM2FVPROC glUniform2fv; + PFNGLUNIFORMMATRIX3FVPROC glUniformMatrix3fv; + PFNGLUNIFORM2FPROC glUniform2f; + PFNGLUNIFORM4FVPROC glUniform4fv; + PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; + PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; + PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray; + PFNGLUSEPROGRAMPROC glUseProgram; + PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv; + PFNGLCREATESHADERPROC glCreateShader; + PFNGLSHADERSOURCEPROC glShaderSource; + PFNGLCOMPILESHADERPROC glCompileShader; + PFNGLGETSHADERIVPROC glGetShaderiv; + PFNGLATTACHSHADERPROC glAttachShader; + PFNGLLINKPROGRAMPROC glLinkProgram; + PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation; + PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation; + PFNGLDELETESHADERPROC glDeleteShader; + PFNGLDELETEPROGRAMPROC glDeleteProgram; + PFNGLUNIFORM1FPROC glUniform1f; + PFNGLUNIFORM3FPROC glUniform3f; + PFNGLUNIFORM4FPROC glUniform4f; + PFNGLUNIFORM1FVPROC glUniform1fv; + PFNGLUNIFORM3FVPROC glUniform3fv; + PFNGLUNIFORMMATRIX2FVPROC glUniformMatrix2fv; + PFNGLGETUNIFORMFVPROC glGetUniformfv; + PFNGLCREATEPROGRAMPROC glCreateProgram; + PFNGLACTIVETEXTUREPROC glActiveTexture; +#endif + +/*----------------------------------------------------- + * Extensions check + *-----------------------------------------------------*/ +static int checkExtension(const char *extensions, const char *name) +{ + int nlen = (int)strlen(name); + int elen = (int)strlen(extensions); + const char *e = extensions; + if(nlen <= 0) return 0; + + while (1) { + + /* Try to find sub-string */ + e = strstr(e, name); + if (e == NULL) return 0; + /* Check if last */ + if (e == extensions + elen - nlen) + return 1; + /* Check if space follows (avoid same names with a suffix) */ + if (*(e + nlen) == ' ') + return 1; + + e += nlen; + } + + return 0; +} + +typedef void (*PFVOID)(); + +PFVOID shGetProcAddress(const char *name) +{ + #if defined(_WIN32) + return (PFVOID)wglGetProcAddress(name); + #else + return (PFVOID)NULL; + #endif +} + +void shLoadExtensions(void *c) +{ + if(shGetProcAddress == NULL) return; + + #if defined(_WIN32) + glUniform1i = shGetProcAddress("glUniform1i"); + glUniform2fv = shGetProcAddress("glUniform2fv"); + glUniformMatrix3fv = shGetProcAddress("glUniformMatrix3fv"); + glUniform2f = shGetProcAddress("glUniform2f"); + glUniform4fv = shGetProcAddress("glUniform4fv"); + glEnableVertexAttribArray = shGetProcAddress("glEnableVertexAttribArray"); + glVertexAttribPointer = shGetProcAddress("glVertexAttribPointer"); + glDisableVertexAttribArray = shGetProcAddress("glDisableVertexAttribArray"); + glUseProgram = shGetProcAddress("glUseProgram"); + glUniformMatrix4fv = shGetProcAddress("glUniformMatrix4fv"); + glCreateShader = shGetProcAddress("glCreateShader"); + glShaderSource = shGetProcAddress("glShaderSource"); + glCompileShader = shGetProcAddress("glCompileShader"); + glGetShaderiv = shGetProcAddress("glGetShaderiv"); + glAttachShader = shGetProcAddress("glAttachShader"); + glLinkProgram = shGetProcAddress("glLinkProgram"); + glGetAttribLocation = shGetProcAddress("glGetAttribLocation"); + glGetUniformLocation = shGetProcAddress("glGetUniformLocation"); + glDeleteShader = shGetProcAddress("glDeleteShader"); + glDeleteProgram = shGetProcAddress("glDeleteProgram"); + glUniform1f = shGetProcAddress("glUniform1f"); + glUniform3f = shGetProcAddress("glUniform3f"); + glUniform4f = shGetProcAddress("glUniform4f"); + glUniform1fv = shGetProcAddress("glUniform1fv"); + glUniform3fv = shGetProcAddress("glUniform3fv"); + glUniformMatrix2fv = shGetProcAddress("glUniformMatrix2fv"); + glGetUniformfv = shGetProcAddress("glGetUniformfv"); + glCreateProgram = shGetProcAddress("glCreateProgram"); + glActiveTexture = shGetProcAddress("glActiveTexture"); + #endif +} diff --git a/simgear/canvas/ShaderVG/src/shExtensions.h b/simgear/canvas/ShaderVG/src/shExtensions.h new file mode 100644 index 00000000..3f9ef827 --- /dev/null +++ b/simgear/canvas/ShaderVG/src/shExtensions.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2007 Ivan Leben + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __SHEXTENSIONS_H +#define __SHEXTENSIONS_H + + +#endif diff --git a/simgear/canvas/ShaderVG/src/shGeometry.c b/simgear/canvas/ShaderVG/src/shGeometry.c new file mode 100644 index 00000000..40725c6e --- /dev/null +++ b/simgear/canvas/ShaderVG/src/shGeometry.c @@ -0,0 +1,937 @@ +/* + * Copyright (c) 2007 Ivan Leben + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#define VG_API_EXPORT +#include "vg/openvg.h" +#include "shContext.h" +#include "shGeometry.h" + + +static int shAddVertex(SHPath *p, SHVertex *v, SHint *contourStart) +{ + /* Assert contour was open */ + SH_ASSERT((*contourStart) >= 0); + + /* Check vertex limit */ + if (p->vertices.size >= SH_MAX_VERTICES) return 0; + + /* Add vertex to subdivision */ + shVertexArrayPushBackP(&p->vertices, v); + + /* Increment contour size. Its stored in + the flags of first contour vertex */ + p->vertices.items[*contourStart].flags++; + + return 1; +} + +static void shSubrecurseQuad(SHPath *p, SHQuad *quad, SHint *contourStart) +{ + SHVertex v; + SHVector2 mid, dif, c1, c2, c3; + SHQuad quads[SH_MAX_RECURSE_DEPTH]; + SHQuad *q, *qleft, *qright; + SHint qindex=0; + quads[0] = *quad; + + while (qindex >= 0) { + + q = &quads[qindex]; + + /* Calculate distance of control point from its + counterpart on the line between end points */ + SET2V(mid, q->p1); ADD2V(mid, q->p3); DIV2(mid, 2); + SET2V(dif, q->p2); SUB2V(dif, mid); ABS2(dif); + + /* Cancel if the curve is flat enough */ + if (dif.x + dif.y <= 1.0f || qindex == SH_MAX_RECURSE_DEPTH-1) { + + /* Add subdivision point */ + v.point = q->p3; v.flags = 0; + if (qindex == 0) return; /* Skip last point */ + if (!shAddVertex(p, &v, contourStart)) return; + --qindex; + + }else{ + + /* Left recursion goes on top of stack! */ + qright = q; qleft = &quads[++qindex]; + + /* Subdivide into 2 sub-curves */ + SET2V(c1, q->p1); ADD2V(c1, q->p2); DIV2(c1, 2); + SET2V(c3, q->p2); ADD2V(c3, q->p3); DIV2(c3, 2); + SET2V(c2, c1); ADD2V(c2, c3); DIV2(c2, 2); + + /* Add left recursion onto stack */ + qleft->p1 = q->p1; + qleft->p2 = c1; + qleft->p3 = c2; + + /* Add right recursion onto stack */ + qright->p1 = c2; + qright->p2 = c3; + qright->p3 = q->p3; + } + } +} + +static void shSubrecurseCubic(SHPath *p, SHCubic *cubic, SHint *contourStart) +{ + SHVertex v; + SHfloat dx1, dy1, dx2, dy2; + SHVector2 mm, c1, c2, c3, c4, c5; + SHCubic cubics[SH_MAX_RECURSE_DEPTH]; + SHCubic *c, *cleft, *cright; + SHint cindex = 0; + cubics[0] = *cubic; + + while (cindex >= 0) { + + c = &cubics[cindex]; + + /* Calculate distance of control points from their + counterparts on the line between end points */ + dx1 = 3.0f*c->p2.x - 2.0f*c->p1.x - c->p4.x; dx1 *= dx1; + dy1 = 3.0f*c->p2.y - 2.0f*c->p1.y - c->p4.y; dy1 *= dy1; + dx2 = 3.0f*c->p3.x - 2.0f*c->p4.x - c->p1.x; dx2 *= dx2; + dy2 = 3.0f*c->p3.y - 2.0f*c->p4.y - c->p1.y; dy2 *= dy2; + if (dx1 < dx2) dx1 = dx2; + if (dy1 < dy2) dy1 = dy2; + + /* Cancel if the curve is flat enough */ + if (dx1+dy1 <= 1.0 || cindex == SH_MAX_RECURSE_DEPTH-1) { + + /* Add subdivision point */ + v.point = c->p4; v.flags = 0; + if (cindex == 0) return; /* Skip last point */ + if (!shAddVertex(p, &v, contourStart)) return; + --cindex; + + }else{ + + /* Left recursion goes on top of stack! */ + cright = c; cleft = &cubics[++cindex]; + + /* Subdivide into 2 sub-curves */ + SET2V(c1, c->p1); ADD2V(c1, c->p2); DIV2(c1, 2); + SET2V(mm, c->p2); ADD2V(mm, c->p3); DIV2(mm, 2); + SET2V(c5, c->p3); ADD2V(c5, c->p4); DIV2(c5, 2); + + SET2V(c2, c1); ADD2V(c2, mm); DIV2(c2, 2); + SET2V(c4, mm); ADD2V(c4, c5); DIV2(c4, 2); + + SET2V(c3, c2); ADD2V(c3, c4); DIV2(c3, 2); + + /* Add left recursion to stack */ + cleft->p1 = c->p1; + cleft->p2 = c1; + cleft->p3 = c2; + cleft->p4 = c3; + + /* Add right recursion to stack */ + cright->p1 = c3; + cright->p2 = c4; + cright->p3 = c5; + cright->p4 = c->p4; + } + } +} + +static void shSubrecurseArc(SHPath *p, SHArc *arc, + SHVector2 *c,SHVector2 *ux, SHVector2 *uy, + SHint *contourStart) +{ + SHVertex v; + SHfloat am, cosa, sina, dx, dy; + SHVector2 uux, uuy, c1, m; + SHArc arcs[SH_MAX_RECURSE_DEPTH]; + SHArc *a, *aleft, *aright; + SHint aindex=0; + arcs[0] = *arc; + + while (aindex >= 0) { + + a = &arcs[aindex]; + + /* Middle angle and its cos/sin */ + am = (a->a1 + a->a2)/2; + cosa = SH_COS(am); + sina = SH_SIN(am); + + /* New point */ + SET2V(uux, (*ux)); MUL2(uux, cosa); + SET2V(uuy, (*uy)); MUL2(uuy, sina); + SET2V(c1, (*c)); ADD2V(c1, uux); ADD2V(c1, uuy); + + /* Check distance from linear midpoint */ + SET2V(m, a->p1); ADD2V(m, a->p2); DIV2(m, 2); + dx = c1.x - m.x; dy = c1.y - m.y; + if (dx < 0.0f) dx = -dx; + if (dy < 0.0f) dy = -dy; + + /* Stop if flat enough */ + if (dx+dy <= 1.0f || aindex == SH_MAX_RECURSE_DEPTH-1) { + + /* Add middle subdivision point */ + v.point = c1; v.flags = 0; + if (!shAddVertex(p, &v, contourStart)) return; + if (aindex == 0) return; /* Skip very last point */ + + /* Add end subdivision point */ + v.point = a->p2; v.flags = 0; + if (!shAddVertex(p, &v, contourStart)) return; + --aindex; + + }else{ + + /* Left subdivision goes on top of stack! */ + aright = a; aleft = &arcs[++aindex]; + + /* Add left recursion to stack */ + aleft->p1 = a->p1; + aleft->a1 = a->a1; + aleft->p2 = c1; + aleft->a2 = am; + + /* Add right recursion to stack */ + aright->p1 = c1; + aright->a1 = am; + aright->p2 = a->p2; + aright->a2 = a->a2; + } + } +} + +static void shSubdivideSegment(SHPath *p, VGPathSegment segment, + VGPathCommand originalCommand, + SHfloat *data, void *userData) +{ + SHVertex v; + SHint *contourStart = ((SHint**)userData)[0]; + SHint *surfaceSpace = ((SHint**)userData)[1]; + SHQuad quad; SHCubic cubic; SHArc arc; + SHVector2 c, ux, uy; + VG_GETCONTEXT(VG_NO_RETVAL); + + switch (segment) + { + case VG_MOVE_TO: + + /* Set contour start here */ + (*contourStart) = p->vertices.size; + + /* First contour vertex */ + v.point.x = data[2]; + v.point.y = data[3]; + v.flags = 0; + if (*surfaceSpace) + TRANSFORM2(v.point, context->pathTransform); + break; + + case VG_CLOSE_PATH: + + /* Last contour vertex */ + v.point.x = data[2]; + v.point.y = data[3]; + v.flags = SH_VERTEX_FLAG_SEGEND | SH_VERTEX_FLAG_CLOSE; + if (*surfaceSpace) + TRANSFORM2(v.point, context->pathTransform); + break; + + case VG_LINE_TO: + + /* Last segment vertex */ + v.point.x = data[2]; + v.point.y = data[3]; + v.flags = SH_VERTEX_FLAG_SEGEND; + if (*surfaceSpace) + TRANSFORM2(v.point, context->pathTransform); + break; + + case VG_QUAD_TO: + + /* Recurse subdivision */ + SET2(quad.p1, data[0], data[1]); + SET2(quad.p2, data[2], data[3]); + SET2(quad.p3, data[4], data[5]); + if (*surfaceSpace) { + TRANSFORM2(quad.p1, context->pathTransform); + TRANSFORM2(quad.p2, context->pathTransform); + TRANSFORM2(quad.p3, context->pathTransform); } + shSubrecurseQuad(p, &quad, contourStart); + + /* Last segment vertex */ + v.point.x = data[4]; + v.point.y = data[5]; + v.flags = SH_VERTEX_FLAG_SEGEND; + if (*surfaceSpace) + TRANSFORM2(v.point, context->pathTransform); + break; + + case VG_CUBIC_TO: + + /* Recurse subdivision */ + SET2(cubic.p1, data[0], data[1]); + SET2(cubic.p2, data[2], data[3]); + SET2(cubic.p3, data[4], data[5]); + SET2(cubic.p4, data[6], data[7]); + if (*surfaceSpace) { + TRANSFORM2(cubic.p1, context->pathTransform); + TRANSFORM2(cubic.p2, context->pathTransform); + TRANSFORM2(cubic.p3, context->pathTransform); + TRANSFORM2(cubic.p4, context->pathTransform); } + shSubrecurseCubic(p, &cubic, contourStart); + + /* Last segment vertex */ + v.point.x = data[6]; + v.point.y = data[7]; + v.flags = SH_VERTEX_FLAG_SEGEND; + if (*surfaceSpace) + TRANSFORM2(v.point, context->pathTransform); + break; + + default: + + SH_ASSERT(segment==VG_SCWARC_TO || segment==VG_SCCWARC_TO || + segment==VG_LCWARC_TO || segment==VG_LCCWARC_TO); + + /* Recurse subdivision */ + SET2(arc.p1, data[0], data[1]); + SET2(arc.p2, data[10], data[11]); + arc.a1 = data[8]; arc.a2 = data[9]; + SET2(c, data[2], data[3]); + SET2(ux, data[4], data[5]); + SET2(uy, data[6], data[7]); + if (*surfaceSpace) { + TRANSFORM2(arc.p1, context->pathTransform); + TRANSFORM2(arc.p2, context->pathTransform); + TRANSFORM2(c, context->pathTransform); + TRANSFORM2DIR(ux, context->pathTransform); + TRANSFORM2DIR(uy, context->pathTransform); } + shSubrecurseArc(p, &arc, &c, &ux, &uy, contourStart); + + /* Last segment vertex */ + v.point.x = data[10]; + v.point.y = data[11]; + v.flags = SH_VERTEX_FLAG_SEGEND; + if (*surfaceSpace) { + TRANSFORM2(v.point, context->pathTransform); } + break; + } + + /* Add subdivision vertex */ + shAddVertex(p, &v, contourStart); +} + +/*-------------------------------------------------- + * Processes path data by simplfying it and sending + * each segment to subdivision callback function + *--------------------------------------------------*/ + +void shFlattenPath(SHPath *p, SHint surfaceSpace) +{ + SHint contourStart = -1; +//SHint surfSpace = surfaceSpace; + SHint *userData[2]; + SHint processFlags = + SH_PROCESS_SIMPLIFY_LINES | + SH_PROCESS_SIMPLIFY_CURVES | + SH_PROCESS_CENTRALIZE_ARCS | + SH_PROCESS_REPAIR_ENDS; + + userData[0] = &contourStart; + userData[1] = &surfaceSpace; + + shVertexArrayClear(&p->vertices); + shProcessPathData(p, processFlags, shSubdivideSegment, userData); +} + +/*------------------------------------------- + * Adds a rectangle to the path's stroke. + *-------------------------------------------*/ + +static void shPushStrokeQuad(SHPath *p, SHVector2 *p1, SHVector2 *p2, + SHVector2 *p3, SHVector2 *p4) +{ + shVector2ArrayPushBackP(&p->stroke, p1); + shVector2ArrayPushBackP(&p->stroke, p2); + shVector2ArrayPushBackP(&p->stroke, p3); + shVector2ArrayPushBackP(&p->stroke, p3); + shVector2ArrayPushBackP(&p->stroke, p4); + shVector2ArrayPushBackP(&p->stroke, p1); +} + +/*------------------------------------------- + * Adds a triangle to the path's stroke. + *-------------------------------------------*/ + +static void shPushStrokeTri(SHPath *p, SHVector2 *p1, + SHVector2 *p2, SHVector2 *p3) +{ + shVector2ArrayPushBackP(&p->stroke, p1); + shVector2ArrayPushBackP(&p->stroke, p2); + shVector2ArrayPushBackP(&p->stroke, p3); +} + +/*----------------------------------------------------------- + * Adds a miter join to the path's stroke at the given + * turn point [c], with the end of the previous segment + * outset [o1] and the beginning of the next segment + * outset [o2], transiting from tangent [d1] to [d2]. + *-----------------------------------------------------------*/ + +static void shStrokeJoinMiter(SHPath *p, SHVector2 *c, + SHVector2 *o1, SHVector2 *d1, + SHVector2 *o2, SHVector2 *d2) +{ + /* Init miter top to first point in case lines are colinear */ + SHVector2 x; SET2V(x,(*o1)); + + /* Find intersection of two outer turn edges + (lines defined by origin and direction) */ + shLineLineXsection(o1, d1, o2, d2, &x); + + /* Add a "diamond" quad with top on intersected point + and bottom on center of turn (on the line) */ + shPushStrokeQuad(p, &x, o1, c, o2); +} + +/*----------------------------------------------------------- + * Adds a round join to the path's stroke at the given + * turn point [c], with the end of the previous segment + * outset [pstart] and the beginning of the next segment + * outset [pend], transiting from perpendicular vector + * [tstart] to [tend]. + *-----------------------------------------------------------*/ + +static void shStrokeJoinRound(SHPath *p, SHVector2 *c, + SHVector2 *pstart, SHVector2 *tstart, + SHVector2 *pend, SHVector2 *tend) +{ + SHVector2 p1, p2; + SHfloat a, ang, cosa, sina; + + /* Find angle between lines */ + ang = ANGLE2((*tstart),(*tend)); + + /* Begin with start point */ + SET2V(p1,(*pstart)); + for (a=0.0f; ax*cosa - tstart->y*sina, + tstart->x*sina + tstart->y*cosa); + ADD2V(p2, (*c)); + + /* Add triangle, save previous */ + shPushStrokeTri(p, &p1, &p2, c); + SET2V(p1, p2); + } + + /* Add last triangle */ + shPushStrokeTri(p, &p1, pend, c); +} + +static void shStrokeCapRound(SHPath *p, SHVector2 *c, SHVector2 *t, SHint start) +{ + SHint a; + SHfloat ang, cosa, sina; + SHVector2 p1, p2; + SHint steps = 12; + SHVector2 tt; + + /* Revert perpendicular vector if start cap */ + SET2V(tt, (*t)); + if (start) MUL2(tt, -1); + + /* Find start point */ + SET2V(p1, (*c)); + ADD2V(p1, tt); + + for (a = 1; a<=steps; ++a) { + + /* Rotate perpendicular vector around and + find next offset point from center */ + ang = (SHfloat)a * PI / steps; + cosa = SH_COS(-ang); + sina = SH_SIN(-ang); + SET2(p2, tt.x*cosa - tt.y*sina, + tt.x*sina + tt.y*cosa); + ADD2V(p2, (*c)); + + /* Add triangle, save previous */ + shPushStrokeTri(p, &p1, &p2, c); + SET2V(p1, p2); + } +} + +static void shStrokeCapSquare(SHPath *p, SHVector2 *c, SHVector2 *t, SHint start) +{ + SHVector2 tt, p1, p2, p3, p4; + + /* Revert perpendicular vector if start cap */ + SET2V(tt, (*t)); + if (start) MUL2(tt, -1); + + /* Find four corners of the quad */ + SET2V(p1, (*c)); + ADD2V(p1, tt); + + SET2V(p2, p1); + ADD2(p2, tt.y, -tt.x); + + SET2V(p3, p2); + ADD2(p3, -2*tt.x, -2*tt.y); + + SET2V(p4, p3); + ADD2(p4, -tt.y, tt.x); + + shPushStrokeQuad(p, &p1, &p2, &p3, &p4); +} + +/*----------------------------------------------------------- + * Generates stroke of a path according to VGContext state. + * Produces quads for every linear subdivision segment or + * dash "on" segment, handles line caps and joins. + *-----------------------------------------------------------*/ + +void shStrokePath(VGContext* c, SHPath *p) +{ + /* Line width and vertex count */ + SHfloat w = c->strokeLineWidth / 2; + SHfloat mlimit = c->strokeMiterLimit; + SHint vertsize = p->vertices.size; + + /* Contour state */ + SHint contourStart = 0; + SHint contourLength = 0; + SHint start = 0; + SHint end = 0; + SHint loop = 0; + SHint close = 0; + SHint segend = 0; + + /* Current vertices */ + SHint i1=0, i2=0; + SHVertex *v1, *v2; + SHVector2 *p1, *p2; + SHVector2 d, t, dprev, tprev; + SHfloat norm, cross, mlength; + + /* Stroke edge points */ + SHVector2 l1, r1, l2, r2, lprev, rprev; + + /* Dash state */ + SHint dashIndex = 0; + SHfloat dashLength = 0.0f, strokeLength = 0.0f; + SHint dashSize = c->strokeDashPattern.size; + SHfloat *dashPattern = c->strokeDashPattern.items; + SHint dashOn = 1; + + /* Dash edge points */ + SHVector2 dash1, dash2; + SHVector2 dashL1, dashR1; + SHVector2 dashL2, dashR2; + SHfloat nextDashLength, dashOffset; + + /* Discard odd dash segment */ + dashSize -= dashSize % 2; + + /* Init previous so compiler doesn't warn + for uninitialized usage */ + SET2(tprev, 0,0); SET2(dprev, 0,0); + SET2(lprev, 0,0); SET2(rprev, 0,0); + + + /* Walk over subdivision vertices */ + for (i1=0; i1vertices.items[i1].flags; + start = 1; + } + + if (contourLength <= 1) { + /* Discard empty contours. */ + contourStart = i1 + 1; + loop = 1; + continue; + } + + v1 = &p->vertices.items[i1]; + v2 = &p->vertices.items[i2]; + + if (i2 == contourStart + contourLength-1) { + /* Contour has ended. Check close */ + close = v2->flags & SH_VERTEX_FLAG_CLOSE; + end = 1; + } + + if (i1 == contourStart + contourLength-1) { + /* Loop back to first edge. Check close */ + close = v1->flags & SH_VERTEX_FLAG_CLOSE; + i2 = contourStart+1; + contourStart = i1 + 1; + i1 = i2 - 1; + loop = 1; + } + + if (!start && !loop) { + /* We are inside a contour. Check segment end. */ + segend = (v1->flags & SH_VERTEX_FLAG_SEGEND); + } + + if (dashSize > 0 && start && + (contourStart == 0 || c->strokeDashPhaseReset)) { + + /* Reset pattern phase at contour start */ + dashLength = -c->strokeDashPhase; + strokeLength = 0.0f; + dashIndex = 0; + dashOn = 1; + + if (dashLength < 0.0f) { + /* Consume dash segments forward to reach stroke start */ + while (dashLength + dashPattern[dashIndex] <= 0.0f) { + dashLength += dashPattern[dashIndex]; + dashIndex = (dashIndex + 1) % dashSize; + dashOn = !dashOn; } + + }else if (dashLength > 0.0f) { + /* Consume dash segments backward to return to stroke start */ + dashIndex = dashSize; + while (dashLength > 0.0f) { + dashIndex = dashIndex ? (dashIndex-1) : (dashSize-1); + dashLength -= dashPattern[dashIndex]; + dashOn = !dashOn; } + } + } + + /* Subdiv segment vertices and points */ + v1 = &p->vertices.items[i1]; + v2 = &p->vertices.items[i2]; + p1 = &v1->point; + p2 = &v2->point; + + /* Direction vector */ + SET2(d, p2->x-p1->x, p2->y-p1->y); + norm = NORM2(d); + if (norm == 0.0f) d = dprev; + else DIV2(d, norm); + + /* Perpendicular vector */ + SET2(t, -d.y, d.x); + MUL2(t, w); + cross = CROSS2(t,tprev); + + /* Left and right edge points */ + SET2V(l1, (*p1)); ADD2V(l1, t); + SET2V(r1, (*p1)); SUB2V(r1, t); + SET2V(l2, (*p2)); ADD2V(l2, t); + SET2V(r2, (*p2)); SUB2V(r2, t); + + /* Check if join needed */ + if ((segend || (loop && close)) && dashOn) { + + switch (c->strokeJoinStyle) { + case VG_JOIN_ROUND: + + /* Add a round join to stroke */ + if (cross >= 0.0f) + shStrokeJoinRound(p, p1, &lprev, &tprev, &l1, &t); + else{ + SHVector2 _t, _tprev; + SET2(_t, -t.x, -t.y); + SET2(_tprev, -tprev.x, -tprev.y); + shStrokeJoinRound(p, p1, &r1, &_t, &rprev, &_tprev); + } + + break; + case VG_JOIN_MITER: + + /* Add a miter join to stroke */ + mlength = 1/SH_COS((ANGLE2(t, tprev))/2); + if (mlength <= mlimit) { + if (cross > 0.0f) + shStrokeJoinMiter(p, p1, &lprev, &dprev, &l1, &d); + else if (cross < 0.0f) + shStrokeJoinMiter(p, p1, &rprev, &dprev, &r1, &d); + break; + }/* Else fall down to bevel */ + + case VG_JOIN_BEVEL: + + /* Add a bevel join to stroke */ + if (cross > 0.0f) + shPushStrokeTri(p, &l1, &lprev, p1); + else if (cross < 0.0f) + shPushStrokeTri(p, &r1, &rprev, p1); + + break; + } + }else if (!start && !loop && dashOn) { + + /* Fill gap with previous (= bevel join) */ + if (cross > 0.0f) + shPushStrokeTri(p, &l1, &lprev, p1); + else if (cross < 0.0f) + shPushStrokeTri(p, &r1, &rprev, p1); + } + + + /* Apply cap to start of a non-closed contour or + if we are dashing and dash segment is on */ + if ((dashSize == 0 && loop && !close) || + (dashSize > 0 && start && dashOn)) { + switch (c->strokeCapStyle) { + case VG_CAP_ROUND: + shStrokeCapRound(p, p1, &t, 1); break; + case VG_CAP_SQUARE: + shStrokeCapSquare(p, p1, &t, 1); break; + default: break; + } + } + + if (loop) + continue; + + /* Handle dashing */ + if (dashSize > 0) { + + /* Start with beginning of subdiv segment */ + SET2V(dash1, (*p1)); SET2V(dashL1, l1); SET2V(dashR1, r1); + + do { + /* Interpolate point on the current subdiv segment */ + nextDashLength = dashLength + dashPattern[dashIndex]; + dashOffset = (nextDashLength - strokeLength) / norm; + if (dashOffset > 1.0f) dashOffset = 1; + SET2V(dash2, (*p2)); SUB2V(dash2, (*p1)); + MUL2(dash2, dashOffset); ADD2V(dash2, (*p1)); + + /* Left and right edge points */ + SET2V(dashL2, dash2); ADD2V(dashL2, t); + SET2V(dashR2, dash2); SUB2V(dashR2, t); + + /* Add quad for this dash segment */ + if (dashOn) shPushStrokeQuad(p, &dashL2, &dashL1, &dashR1, &dashR2); + + /* Move to next dash segment if inside this subdiv segment */ + if (nextDashLength <= strokeLength + norm) { + dashIndex = (dashIndex + 1) % dashSize; + dashLength = nextDashLength; + dashOn = !dashOn; + SET2V(dash1, dash2); + SET2V(dashL1, dashL2); + SET2V(dashR1, dashR2); + + /* Apply cap to dash segment */ + switch (c->strokeCapStyle) { + case VG_CAP_ROUND: + shStrokeCapRound(p, &dash1, &t, dashOn); break; + case VG_CAP_SQUARE: + shStrokeCapSquare(p, &dash1, &t, dashOn); break; + default: break; + } + } + + /* Consume dash segments until subdiv end met */ + } while (nextDashLength < strokeLength + norm); + + }else{ + + /* Add quad for this line segment */ + shPushStrokeQuad(p, &l2, &l1, &r1, &r2); + } + + + /* Apply cap to end of a non-closed contour or + if we are dashing and dash segment is on */ + if ((dashSize == 0 && end && !close) || + (dashSize > 0 && end && dashOn)) { + switch (c->strokeCapStyle) { + case VG_CAP_ROUND: + shStrokeCapRound(p, p2, &t, 0); break; + case VG_CAP_SQUARE: + shStrokeCapSquare(p, p2, &t, 0); break; + default: break; + } + } + + /* Save previous edge */ + strokeLength += norm; + SET2V(lprev, l2); + SET2V(rprev, r2); + dprev = d; + tprev = t; + } +} + + +/*------------------------------------------------------------- + * Transforms the tessellation vertices using the given matrix + *-------------------------------------------------------------*/ + +void shTransformVertices(SHMatrix3x3 *m, SHPath *p) +{ + SHVector2 *v; + int i = 0; + + for (i = p->vertices.size-1; i>=0; --i) { + v = (&p->vertices.items[i].point); + TRANSFORM2((*v), (*m)); } +} + +/*-------------------------------------------------------- + * Finds the tight bounding box of path's tesselation + * vertices. Depends on whether the path had been + * tesselated in user or surface space. + *--------------------------------------------------------*/ + +void shFindBoundbox(SHPath *p) +{ + int i; + + if (p->vertices.size == 0) { + SET2(p->min, 0,0); + SET2(p->max, 0,0); + return; + } + + p->min.x = p->max.x = p->vertices.items[0].point.x; + p->min.y = p->max.y = p->vertices.items[0].point.y; + + for (i=0; ivertices.size; ++i) { + + SHVector2 *v = &p->vertices.items[i].point; + if (v->x < p->min.x) p->min.x = v->x; + if (v->x > p->max.x) p->max.x = v->x; + if (v->y < p->min.y) p->min.y = v->y; + if (v->y > p->max.y) p->max.y = v->y; + } +} + +/*-------------------------------------------------------- + * Outputs a tight bounding box of a path in path's own + * coordinate system. + *--------------------------------------------------------*/ + +VG_API_CALL void vgPathBounds(VGPath path, + VGfloat * minX, VGfloat * minY, + VGfloat * width, VGfloat * height) +{ + SHPath *p = NULL; + VG_GETCONTEXT(VG_NO_RETVAL); + + VG_RETURN_ERR_IF(!shIsValidPath(context, path), + VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + VG_RETURN_ERR_IF(minX == NULL || minY == NULL || + width == NULL || height == NULL, + VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL); + + /* TODO: check output pointer alignment */ + + p = (SHPath*)path; + VG_RETURN_ERR_IF(!(p->caps & VG_PATH_CAPABILITY_PATH_BOUNDS), + VG_PATH_CAPABILITY_ERROR, VG_NO_RETVAL); + + /* Update path geometry */ + shFlattenPath(p, 0); + shFindBoundbox(p); + + /* Output bounds */ + *minX = p->min.x; + *minY = p->min.y; + *width = p->max.x - p->min.x; + *height = p->max.y - p->min.y; + + VG_RETURN(VG_NO_RETVAL); +} + +/*------------------------------------------------------------ + * Outputs a bounding box of a path defined by its control + * points that is guaranteed to enclose the path geometry + * after applying the current path-user-to-surface transform + *------------------------------------------------------------*/ + +VG_API_CALL void vgPathTransformedBounds(VGPath path, + VGfloat * minX, VGfloat * minY, + VGfloat * width, VGfloat * height) +{ + SHPath *p = NULL; + VG_GETCONTEXT(VG_NO_RETVAL); + + VG_RETURN_ERR_IF(!shIsValidPath(context, path), + VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + VG_RETURN_ERR_IF(minX == NULL || minY == NULL || + width == NULL || height == NULL, + VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL); + + /* TODO: check output pointer alignment */ + + p = (SHPath*)path; + VG_RETURN_ERR_IF(!(p->caps & VG_PATH_CAPABILITY_PATH_BOUNDS), + VG_PATH_CAPABILITY_ERROR, VG_NO_RETVAL); + + /* Update path geometry */ + shFlattenPath(p, 1); + shFindBoundbox(p); + + /* Output bounds */ + *minX = p->min.x; + *minY = p->min.y; + *width = p->max.x - p->min.x; + *height = p->max.y - p->min.y; + + /* Invalidate subdivision for rendering */ + p->cacheDataValid = VG_FALSE; + + VG_RETURN(VG_NO_RETVAL); +} + +VG_API_CALL VGfloat vgPathLength(VGPath path, + VGint startSegment, VGint numSegments) +{ + return 0.0f; +} + +VG_API_CALL void vgPointAlongPath(VGPath path, + VGint startSegment, VGint numSegments, + VGfloat distance, + VGfloat * x, VGfloat * y, + VGfloat * tangentX, VGfloat * tangentY) +{ +} diff --git a/simgear/canvas/ShaderVG/src/shGeometry.h b/simgear/canvas/ShaderVG/src/shGeometry.h new file mode 100644 index 00000000..ae636cee --- /dev/null +++ b/simgear/canvas/ShaderVG/src/shGeometry.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2007 Ivan Leben + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __SH_GEOMETRY_H + +#include "shDefs.h" +#include "shContext.h" +#include "shVectors.h" +#include "shPath.h" + +void shFlattenPath(SHPath *p, SHint surfaceSpace); +void shStrokePath(VGContext* c, SHPath *p); +void shTransformVertices(SHMatrix3x3 *m, SHPath *p); +void shFindBoundbox(SHPath *p); + +#endif /* __SH_GEOMETRY_H */ diff --git a/simgear/canvas/ShaderVG/src/shImage.c b/simgear/canvas/ShaderVG/src/shImage.c new file mode 100644 index 00000000..eff512e3 --- /dev/null +++ b/simgear/canvas/ShaderVG/src/shImage.c @@ -0,0 +1,1294 @@ +/* + * Copyright (c) 2007 Ivan Leben + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#define VG_API_EXPORT +#include "vg/openvg.h" +#include "shImage.h" +#include "shContext.h" +#include +#include + +#define _ITEM_T SHColor +#define _ARRAY_T SHColorArray +#define _FUNC_T shColorArray +#define _ARRAY_DEFINE +#define _COMPARE_T(c1,c2) 0 +#include "shArrayBase.h" + +#define _ITEM_T SHImage* +#define _ARRAY_T SHImageArray +#define _FUNC_T shImageArray +#define _ARRAY_DEFINE +#include "shArrayBase.h" + +#ifndef SH_NO_IMAGE + +/*----------------------------------------------------------- + * Prepares the proper pixel pack/unpack info for the given + * OpenVG image format. + *-----------------------------------------------------------*/ + +void shSetupImageFormat(VGImageFormat vg, SHImageFormatDesc *f) +{ + SHuint8 abits = 0; + SHuint8 tshift = 0; + SHuint8 tmask = 0; + SHuint32 amsbBit = 0; + SHuint32 bgrBit = 0; + + /* Store VG format name */ + f->vgformat = vg; + + /* Check if alpha on MSB or colors in BGR order */ + amsbBit = ((vg & (1 << 6)) >> 6); + bgrBit = ((vg & (1 << 7)) >> 7); + + /* Find component ordering and size */ + switch(vg & 0x1F) + { + case 0: /* VG_sRGBX_8888 */ + case 7: /* VG_lRGBX_8888 */ + f->bytes = 4; + f->rmask = 0xFF000000; + f->rshift = 24; + f->rmax = 255; + f->gmask = 0x00FF0000; + f->gshift = 16; + f->gmax = 255; + f->bmask = 0x0000FF00; + f->bshift = 8; + f->bmax = 255; + f->amask = 0x0; + f->ashift = 0; + f->amax = 1; + break; + case 1: /* VG_sRGBA_8888 */ + case 2: /* VG_sRGBA_8888_PRE */ + case 8: /* VG_lRGBA_8888 */ + case 9: /* VG_lRGBA_8888_PRE */ + f->bytes = 4; + f->rmask = 0xFF000000; + f->rshift = 24; + f->rmax = 255; + f->gmask = 0x00FF0000; + f->gshift = 16; + f->gmax = 255; + f->bmask = 0x0000FF00; + f->bshift = 8; + f->bmax = 255; + f->amask = 0x000000FF; + f->ashift = 0; + f->amax = 255; + break; + case 3: /* VG_sRGB_565 */ + f->bytes = 2; + f->rmask = 0xF800; + f->rshift = 11; + f->rmax = 31; + f->gmask = 0x07E0; + f->gshift = 5; + f->gmax = 63; + f->bmask = 0x001F; + f->bshift = 0; + f->bmax = 31; + f->amask = 0x0; + f->ashift = 0; + f->amax = 1; + break; + case 4: /* VG_sRGBA_5551 */ + f->bytes = 2; + f->rmask = 0xF800; + f->rshift = 11; + f->rmax = 31; + f->gmask = 0x07C0; + f->gshift = 6; + f->gmax = 31; + f->bmask = 0x003E; + f->bshift = 1; + f->bmax = 31; + f->amask = 0x0001; + f->ashift = 0; + f->amax = 1; + break; + case 5: /* VG_sRGBA_4444 */ + f->bytes = 2; + f->rmask = 0xF000; + f->rshift = 12; + f->rmax = 15; + f->gmask = 0x0F00; + f->gshift = 8; + f->gmax = 15; + f->bmask = 0x00F0; + f->bshift = 4; + f->bmax = 15; + f->amask = 0x000F; + f->ashift = 0; + f->amax = 15; + break; + case 6: /* VG_sL_8 */ + case 10: /* VG_lL_8 */ + f->bytes = 1; + f->rmask = 0xFF; + f->rshift = 0; + f->rmax = 255; + f->gmask = 0xFF; + f->gshift = 0; + f->gmax = 255; + f->bmask = 0xFF; + f->bshift = 0; + f->bmax = 255; + f->amask = 0x0; + f->ashift = 0; + f->amax = 1; + break; + case 11: /* VG_A_8 */ + f->bytes = 1; + f->rmask = 0x0; + f->rshift = 0; + f->rmax = 1; + f->gmask = 0x0; + f->gshift = 0; + f->gmax = 1; + f->bmask = 0x0; + f->bshift = 0; + f->bmax = 1; + f->amask = 0xFF; + f->ashift = 0; + f->amax = 255; + break; + case 12: /* VG_BW_1 */ + f->bytes = 1; + f->rmask = 0x0; + f->rshift = 0; + f->rmax = 1; + f->gmask = 0x0; + f->gshift = 0; + f->gmax = 1; + f->bmask = 0x0; + f->bshift = 0; + f->bmax = 1; + f->amask = 0x0; + f->ashift = 0; + f->amax = 1; + break; + } + + /* Check for A,X at MSB */ + if (amsbBit) { + + abits = f->bshift; + + f->rshift -= abits; + f->gshift -= abits; + f->bshift -= abits; + f->ashift = f->bytes * 8 - abits; + + f->rmask >>= abits; + f->gmask >>= abits; + f->bmask >>= abits; + f->amask <<= f->bytes * 8 - abits; + } + + /* Check for BGR ordering */ + if (bgrBit) { + + tshift = f->bshift; + f->bshift = f->rshift; + f->rshift = tshift; + + tmask = f->bmask; + f->bmask = f->rmask; + f->rmask = tmask; + } + + /* Find proper mapping to OpenGL formats */ + switch(vg & 0x1F) + { + case VG_sRGBX_8888: + case VG_lRGBX_8888: + case VG_sRGBA_8888: + case VG_sRGBA_8888_PRE: + case VG_lRGBA_8888: + case VG_lRGBA_8888_PRE: + + f->glintformat = GL_RGBA; + + if (amsbBit == 0 && bgrBit == 0) { + f->glformat = GL_RGBA; + f->gltype = GL_UNSIGNED_INT_8_8_8_8; + + }else if (amsbBit == 1 && bgrBit == 0) { + f->glformat = GL_BGRA; + f->gltype = GL_UNSIGNED_INT_8_8_8_8_REV; + + }else if (amsbBit == 0 && bgrBit == 1) { + f->glformat = GL_BGRA; + f->gltype = GL_UNSIGNED_INT_8_8_8_8; + + }else if (amsbBit == 1 && bgrBit == 1) { + f->glformat = GL_RGBA; + f->gltype = GL_UNSIGNED_INT_8_8_8_8_REV; + } + + break; + case VG_sRGBA_5551: + + f->glintformat = GL_RGBA; + + if (amsbBit == 0 && bgrBit == 0) { + f->glformat = GL_RGBA; + f->gltype = GL_UNSIGNED_SHORT_5_5_5_1; + + }else if (amsbBit == 1 && bgrBit == 0) { + f->glformat = GL_BGRA; + f->gltype = GL_UNSIGNED_SHORT_1_5_5_5_REV; + + }else if (amsbBit == 0 && bgrBit == 1) { + f->glformat = GL_BGRA; + f->gltype = GL_UNSIGNED_SHORT_5_5_5_1; + + }else if (amsbBit == 1 && bgrBit == 1) { + f->glformat = GL_RGBA; + f->gltype = GL_UNSIGNED_SHORT_1_5_5_5_REV; + } + + break; + case VG_sRGBA_4444: + + f->glintformat = GL_RGBA; + + if (amsbBit == 0 && bgrBit == 0) { + f->glformat = GL_RGBA; + f->gltype = GL_UNSIGNED_SHORT_4_4_4_4; + + }else if (amsbBit == 1 && bgrBit == 0) { + f->glformat = GL_BGRA; + f->gltype = GL_UNSIGNED_SHORT_4_4_4_4_REV; + + }else if (amsbBit == 0 && bgrBit == 1) { + f->glformat = GL_BGRA; + f->gltype = GL_UNSIGNED_SHORT_4_4_4_4; + + }else if (amsbBit == 1 && bgrBit == 1) { + f->glformat = GL_RGBA; + f->gltype = GL_UNSIGNED_SHORT_4_4_4_4_REV; + } + + break; + case VG_sRGB_565: + + f->glintformat = GL_RGB; + + if (bgrBit == 0) { + f->glformat = GL_RGB; + f->gltype = GL_UNSIGNED_SHORT_5_6_5; + + }else if (bgrBit == 1) { + f->glformat = GL_RGB; + f->gltype = GL_UNSIGNED_SHORT_5_6_5; + } + + break; + case VG_sL_8: + case VG_lL_8: + +#if 0 + f->glintformat = GL_LUMINANCE; + f->glformat = GL_LUMINANCE; +#else + /* Not supported yet */ +#endif + f->gltype = GL_UNSIGNED_BYTE; + + break; + case VG_A_8: + + f->glintformat = GL_ALPHA; + f->glformat = GL_ALPHA; + f->gltype = GL_UNSIGNED_BYTE; + + break; + case VG_BW_1: + + f->glintformat = 0; + f->glformat = 0; + f->gltype = 0; + break; + } +} + +/*----------------------------------------------------- + * Returns 1 if the given format is valid according to + * the OpenVG specification, else 0. + *-----------------------------------------------------*/ + +int shIsValidImageFormat(VGImageFormat format) +{ + SHint aOrderBit = (1 << 6); + SHint rgbOrderBit = (1 << 7); + SHint baseFormat = format & 0x1F; + SHint unorderedRgba = format & (~(aOrderBit | rgbOrderBit)); + SHint isRgba = (baseFormat == VG_sRGBX_8888 || + baseFormat == VG_sRGBA_8888 || + baseFormat == VG_sRGBA_8888_PRE || + baseFormat == VG_sRGBA_5551 || + baseFormat == VG_sRGBA_4444 || + baseFormat == VG_lRGBX_8888 || + baseFormat == VG_lRGBA_8888 || + baseFormat == VG_lRGBA_8888_PRE); + + SHint check = isRgba ? unorderedRgba : format; + return check >= VG_sRGBX_8888 && check <= VG_BW_1; +} + +/*----------------------------------------------------- + * Returns 1 if the given format is supported by this + * implementation + *-----------------------------------------------------*/ + +int shIsSupportedImageFormat(VGImageFormat format) +{ + SHuint32 baseFormat = (format & 0x1F); + if (baseFormat == VG_sRGBA_8888_PRE || + baseFormat == VG_lRGBA_8888_PRE || + baseFormat == VG_BW_1) + return 0; + + return 1; +} + +/*-------------------------------------------------------- + * Packs the pixel color components into memory at given + * address according to given format + *--------------------------------------------------------*/ + +void shStoreColor(SHColor *c, void *data, SHImageFormatDesc *f) +{ + /* + TODO: unsupported formats: + - s and l both behave linearly + - 1-bit black & white (BW_1) + */ + + SHfloat l = 0.0f; + SHuint32 out = 0x0; + + if (f->vgformat == VG_lL_8 || f->vgformat == VG_sL_8) { + + /* Grayscale (luminosity) conversion as defined by the spec */ + l = 0.2126f * c->r + 0.7152f * c->g + 0.0722f * c->r; + out = (SHuint32)(l * (SHfloat)f->rmax + 0.5f); + + }else{ + + /* Pack color components */ + out += ( ((SHuint32)(c->r * (SHfloat)f->rmax + 0.5f)) << f->rshift ) & f->rmask; + out += ( ((SHuint32)(c->g * (SHfloat)f->gmax + 0.5f)) << f->gshift ) & f->gmask; + out += ( ((SHuint32)(c->b * (SHfloat)f->bmax + 0.5f)) << f->bshift ) & f->bmask; + out += ( ((SHuint32)(c->a * (SHfloat)f->amax + 0.5f)) << f->ashift ) & f->amask; + } + + /* Store to buffer */ + switch (f->bytes) { + case 4: *((SHuint32*)data) = (SHuint32)(out & 0xFFFFFFFF); break; + case 2: *((SHuint16*)data) = (SHuint16)(out & 0x0000FFFF); break; + case 1: *((SHuint8*)data) = (SHuint8) (out & 0x000000FF); break; + } +} + +/*--------------------------------------------------------- + * Unpacks the pixel color components from memory at given + * address according to the given format + *---------------------------------------------------------*/ + +void shLoadColor(SHColor *c, const void *data, SHImageFormatDesc *f) +{ + /* + TODO: unsupported formats: + - s and l both behave linearly + - 1-bit black & white (BW_1) + */ + + SHuint32 in = 0x0; + + /* Load from buffer */ + switch (f->bytes) { + case 4: in = (SHuint32) *((SHuint32*)data); break; + case 2: in = (SHuint32) *((SHuint16*)data); break; + case 1: in = (SHuint32) *((SHuint8*)data); break; + } + + /* Unpack color components */ + c->r = (SHfloat)((in & f->rmask) >> f->rshift) / (SHfloat) f->rmax; + c->g = (SHfloat)((in & f->gmask) >> f->gshift) / (SHfloat) f->gmax; + c->b = (SHfloat)((in & f->bmask) >> f->bshift) / (SHfloat) f->bmax; + c->a = (SHfloat)((in & f->amask) >> f->ashift) / (SHfloat) f->amax; + + /* Initialize unused components to 1 */ + if (f->amask == 0x0) { c->a = 1.0f; } + if (f->rmask == 0x0) { c->r = 1.0f; c->g = 1.0f; c->b = 1.0f; } +} + +#endif // SH_NO_IMAGE + + +/*---------------------------------------------- + * Color and Image constructors and destructors + *----------------------------------------------*/ + +void SHColor_ctor(SHColor *c) +{ + c->r = 0.0f; + c->g = 0.0f; + c->b = 0.0f; + c->a = 0.0f; +} + +void SHColor_dtor(SHColor *c) { +} + +void SHImage_ctor(SHImage *i) +{ + i->data = NULL; + i->width = 0; + i->height = 0; +#ifdef SH_NO_IMAGE + printf("ShaderVG: images not supported!"); +#else + glGenTextures(1, &i->texture); +#endif +} + +void SHImage_dtor(SHImage *i) +{ + if (i->data != NULL) + free(i->data); + +#ifdef SH_NO_IMAGE + printf("ShaderVG: images not supported!"); +#else + if (glIsTexture(i->texture)) + glDeleteTextures(1, &i->texture); +#endif +} + +#ifndef SH_NO_IMAGE +/*-------------------------------------------------------- + * Finds appropriate OpenGL texture size for the size of + * the given image + *--------------------------------------------------------*/ + +void shUpdateImageTextureSize(SHImage *i) +{ + i->texwidth = i->width; + i->texheight = i->height; + i->texwidthK = 1.0f; + i->texheightK = 1.0f; + + /* Round size to nearest power of 2 */ + /* TODO: might be dropped out if it works without */ + + /*i->texwidth = 1; + while (i->texwidth < i->width) + i->texwidth *= 2; + + i->texheight = 1; + while (i->texheight < i->height) + i->texheight *= 2; + + i->texwidthK = (SHfloat)i->width / i->texwidth; + i->texheightK = (SHfloat)i->height / i->texheight; */ +} + +/*-------------------------------------------------- + * Downloads the image data from OpenVG into + * an OpenGL texture + *--------------------------------------------------*/ + +void shUpdateImageTexture(SHImage *i, VGContext *c) +{ + /* Store pixels to texture */ + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glBindTexture(GL_TEXTURE_2D, i->texture); + glTexImage2D(GL_TEXTURE_2D, 0, i->fd.glintformat, + i->texwidth, i->texheight, 0, + i->fd.glformat, i->fd.gltype, i->data); +} +#endif // SH_NO_IMAGE + +/*---------------------------------------------------------- + * Creates a new image object and returns the handle to it + *----------------------------------------------------------*/ + +VG_API_CALL VGImage vgCreateImage(VGImageFormat format, + VGint width, VGint height, + VGbitfield allowedQuality) +{ +#ifdef SH_NO_IMAGE + printf("ShaderVG: images not supported!"); + return VG_INVALID_HANDLE; +#else + SHImage *i = NULL; + SHImageFormatDesc fd; + VG_GETCONTEXT(VG_INVALID_HANDLE); + + /* Reject invalid formats */ + VG_RETURN_ERR_IF(!shIsValidImageFormat(format), + VG_UNSUPPORTED_IMAGE_FORMAT_ERROR, + VG_INVALID_HANDLE); + + /* Reject unsupported formats */ + VG_RETURN_ERR_IF(!shIsSupportedImageFormat(format), + VG_UNSUPPORTED_IMAGE_FORMAT_ERROR, + VG_INVALID_HANDLE); + + /* Reject invalid sizes */ + VG_RETURN_ERR_IF(width <= 0 || width > SH_MAX_IMAGE_WIDTH || + height <= 0 || height > SH_MAX_IMAGE_HEIGHT || + width * height > SH_MAX_IMAGE_PIXELS, + VG_ILLEGAL_ARGUMENT_ERROR, VG_INVALID_HANDLE); + + /* Check if byte size exceeds SH_MAX_IMAGE_BYTES */ + shSetupImageFormat(format, &fd); + VG_RETURN_ERR_IF(width * height * fd.bytes > SH_MAX_IMAGE_BYTES, + VG_ILLEGAL_ARGUMENT_ERROR, VG_INVALID_HANDLE); + + /* Reject invalid quality bits */ + VG_RETURN_ERR_IF(allowedQuality & + ~(VG_IMAGE_QUALITY_NONANTIALIASED | + VG_IMAGE_QUALITY_FASTER | VG_IMAGE_QUALITY_BETTER), + VG_ILLEGAL_ARGUMENT_ERROR, VG_INVALID_HANDLE); + + /* Create new image object */ + SH_NEWOBJ(SHImage, i); + VG_RETURN_ERR_IF(!i, VG_OUT_OF_MEMORY_ERROR, VG_INVALID_HANDLE); + i->width = width; + i->height = height; + i->fd = fd; + + /* Allocate data memory */ + shUpdateImageTextureSize(i); + i->data = (SHuint8*)malloc( i->texwidth * i->texheight * fd.bytes ); + + if (i->data == NULL) { + SH_DELETEOBJ(SHImage, i); + VG_RETURN_ERR(VG_OUT_OF_MEMORY_ERROR, VG_INVALID_HANDLE); } + + /* Initialize data by zeroing-out */ + memset(i->data, 1, width * height * fd.bytes); + shUpdateImageTexture(i, context); + + /* Add to resource list */ + shImageArrayPushBack(&context->images, i); + + VG_RETURN((VGImage)i); +#endif // SH_NO_IMAGE +} + +VG_API_CALL void vgDestroyImage(VGImage image) +{ +#ifdef SH_NO_IMAGE + printf("ShaderVG: images not supported!"); +#else + SHint index; + VG_GETCONTEXT(VG_NO_RETVAL); + + /* Check if valid resource */ + index = shImageArrayFind(&context->images, (SHImage*)image); + VG_RETURN_ERR_IF(index == -1, VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL); + + /* Delete object and remove resource */ + SH_DELETEOBJ(SHImage, (SHImage*)image); + shImageArrayRemoveAt(&context->images, index); + + VG_RETURN(VG_NO_RETVAL); +#endif // SH_NO_IMAGE +} + +/*--------------------------------------------------- + * Clear given rectangle area in the image data with + * color set via vgSetfv(VG_CLEAR_COLOR, ...) + *---------------------------------------------------*/ + +VG_API_CALL void vgClearImage(VGImage image, + VGint x, VGint y, VGint width, VGint height) +{ +#ifdef SH_NO_IMAGE + printf("ShaderVG: images not supported!"); +#else + SHImage *i; + SHColor clear; + SHuint8 *data; + SHint X,Y, ix, iy, dx, dy, stride; + VG_GETCONTEXT(VG_NO_RETVAL); + + VG_RETURN_ERR_IF(!shIsValidImage(context, image), + VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + /* TODO: check if image current render target */ + + i = (SHImage*)image; + VG_RETURN_ERR_IF(width <= 0 || height <= 0, + VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL); + + /* Nothing to do if target rectangle out of bounds */ + if (x >= i->width || y >= i->height) + VG_RETURN(VG_NO_RETVAL); + if (x + width < 0 || y + height < 0) + VG_RETURN(VG_NO_RETVAL); + + /* Clamp to image bounds */ + ix = SH_MAX(x, 0); dx = ix - x; + iy = SH_MAX(y, 0); dy = iy - y; + width = SH_MIN( width - dx, i->width - ix); + height = SH_MIN( height - dy, i->height - iy); + stride = i->texwidth * i->fd.bytes; + + /* Walk pixels and clear*/ + clear = context->clearColor; + + for (Y=iy; Ydata + ( Y*stride + ix * i->fd.bytes ); + + for (X=ix; Xfd); + data += i->fd.bytes; + }} + + shUpdateImageTexture(i, context); + VG_RETURN(VG_NO_RETVAL); +#endif // SH_NO_IMAGE +} + +#ifndef SH_NO_IMAGE + +/*------------------------------------------------------------ + * Generic function for copying a rectangle area of pixels + * of size (width,height) among two data buffers. The size of + * source (swidth,sheight) and destination (dwidth,dheight) + * images may vary as well as the source coordinates (sx,sy) + * and destination coordinates(dx, dy). + *------------------------------------------------------------*/ + +void shCopyPixels(SHuint8 *dst, VGImageFormat dstFormat, SHint dstStride, + const SHuint8 *src, VGImageFormat srcFormat, SHint srcStride, + SHint dwidth, SHint dheight, SHint swidth, SHint sheight, + SHint dx, SHint dy, SHint sx, SHint sy, + SHint width, SHint height) +{ + SHint dxold, dyold; + SHint SX, SY, DX, DY; + const SHuint8 *SD; + SHuint8 *DD; + SHColor c; + + SHImageFormatDesc dfd; + SHImageFormatDesc sfd; + + /* Setup image format descriptors */ + SH_ASSERT(shIsSupportedImageFormat(dstFormat)); + SH_ASSERT(shIsSupportedImageFormat(srcFormat)); + shSetupImageFormat(dstFormat, &dfd); + shSetupImageFormat(srcFormat, &sfd); + + /* + In order to optimize the copying loop and remove the + if statements from it to check whether target pixel + is in the source and destination surface, we clamp + copy rectangle in advance. This is quite a tedious + task though. Here is a picture of the scene. Note that + (dx,dy) is actually an offset of the copy rectangle + (clamped to src surface) from the (0,0) point on dst + surface. A negative (dx,dy) (as in this picture) also + affects src coords of the copy rectangle which have + to be readjusted again (sx,sy,width,height). + + src + *----------------------* + | (sx,sy) copy rect | + | *-----------* | + | |\(dx, dy) | | dst + | | *------------------------------* + | | |xxxxxxxxx| | | + | | |xxxxxxxxx| | | + | *-----------* | | + | | (width,height) | | + *----------------------* | + | (swidth,sheight) | + *------------------------------* + (dwidth,dheight) + */ + + /* Cancel if copy rect out of src bounds */ + if (sx >= swidth || sy >= sheight) return; + if (sx + width < 0 || sy + height < 0) return; + + /* Clamp copy rectangle to src bounds */ + sx = SH_MAX(sx, 0); + sy = SH_MAX(sy, 0); + width = SH_MIN(width, swidth - sx); + height = SH_MIN(height, sheight - sy); + + /* Cancel if copy rect out of dst bounds */ + if (dx >= dwidth || dy >= dheight) return; + if (dx + width < 0 || dy + height < 0) return; + + /* Clamp copy rectangle to dst bounds */ + dxold = dx; dyold = dy; + dx = SH_MAX(dx, 0); + dy = SH_MAX(dy, 0); + sx += dx - dxold; + sy += dy - dyold; + width -= dx - dxold; + height -= dy - dyold; + width = SH_MIN(width, dwidth - dx); + height = SH_MIN(height, dheight - dy); + + /* Calculate stride from format if not given */ + if (dstStride == -1) dstStride = dwidth * dfd.bytes; + if (srcStride == -1) srcStride = swidth * sfd.bytes; + + if (srcFormat == dstFormat) { + + /* Walk pixels and copy */ + for (SY=sy, DY=dy; SY < sy+height; ++SY, ++DY) { + SD = src + SY * srcStride + sx * sfd.bytes; + DD = dst + DY * dstStride + dx * dfd.bytes; + memcpy(DD, SD, width * sfd.bytes); + } + + }else{ + + /* Walk pixels and copy */ + for (SY=sy, DY=dy; SY < sy+height; ++SY, ++DY) { + SD = src + SY * srcStride + sx * sfd.bytes; + DD = dst + DY * dstStride + dx * dfd.bytes; + + for (SX=sx, DX=dx; SX < sx+width; ++SX, ++DX) { + shLoadColor(&c, SD, &sfd); + shStoreColor(&c, DD, &dfd); + SD += sfd.bytes; DD += dfd.bytes; + }} + } +} + +#endif // SH_NO_IMAGE + +/*--------------------------------------------------------- + * Copies a rectangle area of pixels of size (width,height) + * from given data buffer to image surface at destination + * coordinates (x,y) + *---------------------------------------------------------*/ + +VG_API_CALL void vgImageSubData(VGImage image, + const void * data, VGint dataStride, + VGImageFormat dataFormat, + VGint x, VGint y, VGint width, VGint height) +{ +#ifdef SH_NO_IMAGE + printf("ShaderVG: images not supported!"); +#else + SHImage *i; + VG_GETCONTEXT(VG_NO_RETVAL); + + VG_RETURN_ERR_IF(!shIsValidImage(context, image), + VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + /* TODO: check if image current render target */ + i = (SHImage*)image; + + /* Reject invalid formats */ + VG_RETURN_ERR_IF(!shIsValidImageFormat(dataFormat), + VG_UNSUPPORTED_IMAGE_FORMAT_ERROR, + VG_NO_RETVAL); + + /* Reject unsupported image formats */ + VG_RETURN_ERR_IF(!shIsSupportedImageFormat(dataFormat), + VG_UNSUPPORTED_IMAGE_FORMAT_ERROR, + VG_NO_RETVAL); + + VG_RETURN_ERR_IF(width <= 0 || height <= 0 || !data, + VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL); + + /* TODO: check data array alignment */ + + shCopyPixels(i->data, i->fd.vgformat, i->texwidth * i->fd.bytes, + data, dataFormat,dataStride, + i->width, i->height, width, height, + x, y, 0, 0, width, height); + + shUpdateImageTexture(i, context); + VG_RETURN(VG_NO_RETVAL); +#endif // SH_NO_IMAGE +} + +/*--------------------------------------------------------- + * Copies a rectangle area of pixels of size (width,height) + * from image surface at source coordinates (x,y) to given + * data buffer + *---------------------------------------------------------*/ + +VG_API_CALL void vgGetImageSubData(VGImage image, + void * data, VGint dataStride, + VGImageFormat dataFormat, + VGint x, VGint y, + VGint width, VGint height) +{ +#ifdef SH_NO_IMAGE + printf("ShaderVG: images not supported!"); +#else + SHImage *i; + VG_GETCONTEXT(VG_NO_RETVAL); + + VG_RETURN_ERR_IF(!shIsValidImage(context, image), + VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + /* TODO: check if image current render target */ + i = (SHImage*)image; + + /* Reject invalid formats */ + VG_RETURN_ERR_IF(!shIsValidImageFormat(dataFormat), + VG_UNSUPPORTED_IMAGE_FORMAT_ERROR, + VG_NO_RETVAL); + + /* Reject unsupported formats */ + VG_RETURN_ERR_IF(!shIsSupportedImageFormat(dataFormat), + VG_UNSUPPORTED_IMAGE_FORMAT_ERROR, + VG_NO_RETVAL); + + VG_RETURN_ERR_IF(width <= 0 || height <= 0 || !data, + VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL); + + /* TODO: check data array alignment */ + + shCopyPixels(data, dataFormat, dataStride, + i->data, i->fd.vgformat, i->texwidth * i->fd.bytes, + width, height, i->width, i->height, + 0,0,x,x,width,height); + + VG_RETURN(VG_NO_RETVAL); +#endif // SH_NO_IMAGE +} + +/*---------------------------------------------------------- + * Copies a rectangle area of pixels of size (width,height) + * from src image surface at source coordinates (sx,sy) to + * dst image surface at destination cordinates (dx,dy) + *---------------------------------------------------------*/ + +VG_API_CALL void vgCopyImage(VGImage dst, VGint dx, VGint dy, + VGImage src, VGint sx, VGint sy, + VGint width, VGint height, + VGboolean dither) +{ +#ifdef SH_NO_IMAGE + printf("ShaderVG: images not supported!"); +#else + SHImage *s, *d; + SHuint8 *pixels; + + VG_GETCONTEXT(VG_NO_RETVAL); + + VG_RETURN_ERR_IF(!shIsValidImage(context, src) || + !shIsValidImage(context, dst), + VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + /* TODO: check if images current render target */ + + s = (SHImage*)src; d = (SHImage*)dst; + VG_RETURN_ERR_IF(width <= 0 || height <= 0, + VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL); + + /* In order to perform copying in a cosistent fashion + we first copy to a temporary buffer and only then to + destination image */ + + /* TODO: rather check first if the image is really + the same and whether the regions overlap. if not + we can copy directly */ + + pixels = (SHuint8*)malloc(width * height * s->fd.bytes); + SH_RETURN_ERR_IF(!pixels, VG_OUT_OF_MEMORY_ERROR, SH_NO_RETVAL); + + shCopyPixels(pixels, s->fd.vgformat, s->texwidth * s->fd.bytes, + s->data, s->fd.vgformat, s->texwidth * s->fd.bytes, + width, height, s->width, s->height, + 0, 0, sx, sy, width, height); + + shCopyPixels(d->data, d->fd.vgformat, d->texwidth * d->fd.bytes, + pixels, s->fd.vgformat, s->texwidth * s->fd.bytes, + d->width, d->height, width, height, + dx, dy, 0, 0, width, height); + + free(pixels); + + shUpdateImageTexture(d, context); + VG_RETURN(VG_NO_RETVAL); +#endif // SH_NO_IMAGE +} + +/*--------------------------------------------------------- + * Copies a rectangle area of pixels of size (width,height) + * from src image surface at source coordinates (sx,sy) to + * window surface at destination coordinates (dx,dy) + *---------------------------------------------------------*/ + +VG_API_CALL void vgSetPixels(VGint dx, VGint dy, + VGImage src, VGint sx, VGint sy, + VGint width, VGint height) +{ +#ifdef SH_NO_IMAGE + printf("ShaderVG: images not supported!"); +#else + SHImage *i; + SHuint8 *pixels; + SHImageFormatDesc winfd; + + VG_GETCONTEXT(VG_NO_RETVAL); + + VG_RETURN_ERR_IF(!shIsValidImage(context, src), + VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + /* TODO: check if image current render target (requires EGL) */ + + i = (SHImage*)src; + VG_RETURN_ERR_IF(width <= 0 || height <= 0, + VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL); + + /* Setup window image format descriptor */ + /* TODO: this actually depends on the target framebuffer type + if we really want the copy to be optimized */ + shSetupImageFormat(VG_sRGBA_8888, &winfd); + + /* OpenGL doesn't allow us to use random stride. We have to + manually copy the image data and write from a copy with + normal row length (without power-of-two roundup pixels) */ + + pixels = (SHuint8*)malloc(width * height * winfd.bytes); + SH_RETURN_ERR_IF(!pixels, VG_OUT_OF_MEMORY_ERROR, SH_NO_RETVAL); + + shCopyPixels(pixels, winfd.vgformat, -1, + i->data, i->fd.vgformat, i->texwidth * i->fd.bytes, + width, height, i->width, i->height, + 0,0,sx,sy, width, height); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +#if 0 + glRasterPos2i(dx, dy); + glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + glRasterPos2i(0,0); +#else + /* Not supported yet */ +#endif + + free(pixels); + + VG_RETURN(VG_NO_RETVAL); +#endif // SH_NO_IMAGE +} + +/*--------------------------------------------------------- + * Copies a rectangle area of pixels of size (width,height) + * from given data buffer at source coordinates (sx,sy) to + * window surface at destination coordinates (dx,dy) + *---------------------------------------------------------*/ + +VG_API_CALL void vgWritePixels(const void * data, VGint dataStride, + VGImageFormat dataFormat, + VGint dx, VGint dy, + VGint width, VGint height) +{ +#ifdef SH_NO_IMAGE + printf("ShaderVG: images not supported!"); +#else + SHuint8 *pixels; + SHImageFormatDesc winfd; + + VG_GETCONTEXT(VG_NO_RETVAL); + + /* Reject invalid formats */ + VG_RETURN_ERR_IF(!shIsValidImageFormat(dataFormat), + VG_UNSUPPORTED_IMAGE_FORMAT_ERROR, + VG_NO_RETVAL); + + /* Reject unsupported formats */ + VG_RETURN_ERR_IF(!shIsSupportedImageFormat(dataFormat), + VG_UNSUPPORTED_IMAGE_FORMAT_ERROR, + VG_NO_RETVAL); + + /* TODO: check output data array alignment */ + + VG_RETURN_ERR_IF(width <= 0 || height <= 0 || !data, + VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL); + + /* Setup window image format descriptor */ + /* TODO: this actually depends on the target framebuffer type + if we really want the copy to be optimized */ + shSetupImageFormat(VG_sRGBA_8888, &winfd); + + /* OpenGL doesn't allow us to use random stride. We have to + manually copy the image data and write from a copy with + normal row length */ + + pixels = (SHuint8*)malloc(width * height * winfd.bytes); + SH_RETURN_ERR_IF(!pixels, VG_OUT_OF_MEMORY_ERROR, SH_NO_RETVAL); + + shCopyPixels(pixels, winfd.vgformat, -1, + (SHuint8*)data, dataFormat, dataStride, + width, height, width, height, + 0,0,0,0, width, height); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +#if 0 + glRasterPos2i(dx, dy); + glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + glRasterPos2i(0,0); +#else + /* Not supported yet */ +#endif + + free(pixels); + + VG_RETURN(VG_NO_RETVAL); +#endif // SH_NO_IMAGE +} + +/*----------------------------------------------------------- + * Copies a rectangle area of pixels of size (width, height) + * from window surface at source coordinates (sx, sy) to + * image surface at destination coordinates (dx, dy) + *-----------------------------------------------------------*/ + +VG_API_CALL void vgGetPixels(VGImage dst, VGint dx, VGint dy, + VGint sx, VGint sy, + VGint width, VGint height) +{ +#ifdef SH_NO_IMAGE + printf("ShaderVG: images not supported!"); +#else + SHImage *i; + SHuint8 *pixels; + SHImageFormatDesc winfd; + VG_GETCONTEXT(VG_NO_RETVAL); + + VG_RETURN_ERR_IF(!shIsValidImage(context, dst), + VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + /* TODO: check if image current render target */ + + i = (SHImage*)dst; + VG_RETURN_ERR_IF(width <= 0 || height <= 0, + VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL); + + /* Setup window image format descriptor */ + /* TODO: this actually depends on the target framebuffer type + if we really want the copy to be optimized */ + shSetupImageFormat(VG_sRGBA_8888, &winfd); + + /* OpenGL doesn't allow us to read to random destination + coordinates nor using random stride. We have to + read first and then manually copy to the image data */ + + pixels = (SHuint8*)malloc(width * height * winfd.bytes); + SH_RETURN_ERR_IF(!pixels, VG_OUT_OF_MEMORY_ERROR, SH_NO_RETVAL); + + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glReadPixels(sx, sy, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + + shCopyPixels(i->data, i->fd.vgformat, i->texwidth * i->fd.bytes, + pixels, winfd.vgformat, -1, + i->width, i->height, width, height, + dx, dy, 0, 0, width, height); + + free(pixels); + + shUpdateImageTexture(i, context); + VG_RETURN(VG_NO_RETVAL); +#endif // SH_NO_IMAGE +} + +/*----------------------------------------------------------- + * Copies a rectangle area of pixels of size (width, height) + * from window surface at source coordinates (sx, sy) to + * to given output data buffer. + *-----------------------------------------------------------*/ + +VG_API_CALL void vgReadPixels(void * data, VGint dataStride, + VGImageFormat dataFormat, + VGint sx, VGint sy, + VGint width, VGint height) +{ +#ifdef SH_NO_IMAGE + printf("ShaderVG: images not supported!"); +#else + SHuint8 *pixels; + SHImageFormatDesc winfd; + VG_GETCONTEXT(VG_NO_RETVAL); + + /* Reject invalid formats */ + VG_RETURN_ERR_IF(!shIsValidImageFormat(dataFormat), + VG_UNSUPPORTED_IMAGE_FORMAT_ERROR, + VG_NO_RETVAL); + + /* Reject unsupported image formats */ + VG_RETURN_ERR_IF(!shIsSupportedImageFormat(dataFormat), + VG_UNSUPPORTED_IMAGE_FORMAT_ERROR, + VG_NO_RETVAL); + + /* TODO: check output data array alignment */ + + VG_RETURN_ERR_IF(width <= 0 || height <= 0 || !data, + VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL); + + /* Setup window image format descriptor */ + /* TODO: this actually depends on the target framebuffer type + if we really want the copy to be optimized */ + shSetupImageFormat(VG_sRGBA_8888, &winfd); + + /* OpenGL doesn't allow random data stride. We have to + read first and then manually copy to the output buffer */ + + pixels = (SHuint8*)malloc(width * height * winfd.bytes); + SH_RETURN_ERR_IF(!pixels, VG_OUT_OF_MEMORY_ERROR, SH_NO_RETVAL); + + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glReadPixels(sx, sy, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + + shCopyPixels(data, dataFormat, dataStride, + pixels, winfd.vgformat, -1, + width, height, width, height, + 0, 0, 0, 0, width, height); + + free(pixels); + + VG_RETURN(VG_NO_RETVAL); +#endif // SH_NO_IMAGE +} + +/*---------------------------------------------------------- + * Copies a rectangle area of pixels of size (width,height) + * from window surface at source coordinates (sx,sy) to + * windows surface at destination cordinates (dx,dy) + *---------------------------------------------------------*/ + +VG_API_CALL void vgCopyPixels(VGint dx, VGint dy, + VGint sx, VGint sy, + VGint width, VGint height) +{ + VG_GETCONTEXT(VG_NO_RETVAL); + + VG_RETURN_ERR_IF(width <= 0 || height <= 0, + VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL); + + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +#if 0 + glRasterPos2i(dx, dy); + glCopyPixels(sx, sy, width, height, GL_COLOR); + glRasterPos2i(0, 0); +#else + /* Not supported yet */ +#endif + + VG_RETURN(VG_NO_RETVAL); +} + +VG_API_CALL VGImage vgChildImage(VGImage parent, + VGint x, VGint y, VGint width, VGint height) +{ + return VG_INVALID_HANDLE; +} + +VG_API_CALL VGImage vgGetParent(VGImage image) +{ + return VG_INVALID_HANDLE; +} + +VG_API_CALL void vgColorMatrix(VGImage dst, VGImage src, + const VGfloat * matrix) +{ +} + +VG_API_CALL void vgConvolve(VGImage dst, VGImage src, + VGint kernelWidth, VGint kernelHeight, + VGint shiftX, VGint shiftY, + const VGshort * kernel, + VGfloat scale, + VGfloat bias, + VGTilingMode tilingMode) +{ +} + +VG_API_CALL void vgSeparableConvolve(VGImage dst, VGImage src, + VGint kernelWidth, + VGint kernelHeight, + VGint shiftX, VGint shiftY, + const VGshort * kernelX, + const VGshort * kernelY, + VGfloat scale, + VGfloat bias, + VGTilingMode tilingMode) +{ +} + +VG_API_CALL void vgGaussianBlur(VGImage dst, VGImage src, + VGfloat stdDeviationX, + VGfloat stdDeviationY, + VGTilingMode tilingMode) +{ +} + +VG_API_CALL void vgLookup(VGImage dst, VGImage src, + const VGubyte * redLUT, + const VGubyte * greenLUT, + const VGubyte * blueLUT, + const VGubyte * alphaLUT, + VGboolean outputLinear, + VGboolean outputPremultiplied) +{ +} + +VG_API_CALL void vgLookupSingle(VGImage dst, VGImage src, + const VGuint * lookupTable, + VGImageChannel sourceChannel, + VGboolean outputLinear, + VGboolean outputPremultiplied) +{ +} + +VG_API_CALL void vgBindImageSH(VGImage image, VGImageUnitSH unit){ + + VG_GETCONTEXT(VG_NO_RETVAL); + SH_RETURN_ERR_IF(unit < VG_IMAGE_UNIT_OFFSET_SH, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + SH_RETURN_ERR_IF(image == VG_INVALID_HANDLE, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + SHImage *i = (SHImage*)image; + + glActiveTexture(GL_TEXTURE0 + unit); + + glBindTexture(GL_TEXTURE_2D, i->texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + glEnable(GL_TEXTURE_2D); + GL_CEHCK_ERROR; +} + diff --git a/simgear/canvas/ShaderVG/src/shImage.h b/simgear/canvas/ShaderVG/src/shImage.h new file mode 100644 index 00000000..abd615af --- /dev/null +++ b/simgear/canvas/ShaderVG/src/shImage.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2007 Ivan Leben + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __SHIMAGE_H +#define __SHIMAGE_H + +#include "shDefs.h" + +/*----------------------------------------------------------- + * ColorFormat holds the data necessary to pack/unpack color + * components from a pixel of each supported image format + *-----------------------------------------------------------*/ + +typedef struct +{ + VGImageFormat vgformat; + SHuint8 bytes; + + SHuint32 rmask; + SHuint8 rshift; + SHuint8 rmax; + + SHuint32 gmask; + SHuint8 gshift; + SHuint8 gmax; + + SHuint32 bmask; + SHuint8 bshift; + SHuint8 bmax; + + SHuint32 amask; + SHuint8 ashift; + SHuint8 amax; + + GLenum glintformat; + GLenum glformat; + GLenum gltype; + +} SHImageFormatDesc; + +typedef struct +{ + SHfloat r,g,b,a; + +} SHColor; + +void SHColor_ctor(SHColor *c); +void SHColor_dtor(SHColor *c); + +#define _ITEM_T SHColor +#define _ARRAY_T SHColorArray +#define _FUNC_T shColorArray +#define _ARRAY_DECLARE +#include "shArrayBase.h" + +typedef struct +{ + SHuint8 *data; + SHint width; + SHint height; + SHImageFormatDesc fd; + + SHint texwidth; + SHint texheight; + SHfloat texwidthK; + SHfloat texheightK; + GLuint texture; + +} SHImage; + +void SHImage_ctor(SHImage *i); +void SHImage_dtor(SHImage *i); + +#define _ITEM_T SHImage* +#define _ARRAY_T SHImageArray +#define _FUNC_T shImageArray +#define _ARRAY_DECLARE +#include "shArrayBase.h" + +/*------------------------------------------------------- + * Color operators + *-------------------------------------------------------*/ + +#define CSET(c, rr,gg,bb,aa) { c.r=rr; c.g=gg; c.b=bb; c.a=aa; } +#define CSETC(c1, c2) { c1.r=c2.r; c1.g=c2.g; c1.b=c2.b; c1.a=c2.a; } + +#define CSUB(c1, rr,gg,bb,aa) { c.r-=rr; c.g-=gg; c.b-=bb; c.a-=aa; } +#define CSUBC(c1, c2) { c1.r-=c2.r; c1.g-=c2.g; c1.b-=c2.b; c1.a-=c2.a; } +#define CSUBCTO(c1, c2, c3) { c3.r=c1.r-c2.r; c3.g=c1.g-c2.g; c3.b=c1.b-c2.b; c3.a=c1.a-c2.a; } + +#define CADD(c1, rr,gg,bb,aa) { c.r+=rr; c.g+=gg; c.b+=bb; c.a+=aa; } +#define CADDC(c1, c2) { c1.r+=c2.r; c1.g+=c2.g; c1.b+=c2.b; c1.a+=c2.a; } +#define CADDTO(c1, c2, c3) { c3.r=c1.r+c2.r; c3.g=c1.g+c2.g; c3.b=c1.b+c2.b; c3.a=c1.a+c2.a; } +#define CADDCK(c1, c2, k) { c1.r+=k*c2.r; c1.g+=k*c2.g; c1.b+=k*c2.b; c1.a+=k*c2.a; } + +#define CMUL(c, s) { c.r*=s; c.g*=s; c.b*=s; c.a*=s; } +#define CDIV(c, s) { c.r/=s; c.g/=s; c.b/=s; c.a/=s; } + +#define CPREMUL(c) { c.r*=c.a; c.g*=c.a; c.b*=c.a; } +#define CUNPREMUL(c) { c.r/=c.a; c.g/=c.a; c.b/=c.a; } + +/*------------------------------------------------------- + * Color-to-memory functions + *-------------------------------------------------------*/ + +#define CSTORE_RGBA1D_8(c, rgba, x) { \ + rgba[x*4+0] = (SHuint8)SH_FLOOR(c.r * 255); \ + rgba[x*4+1] = (SHuint8)SH_FLOOR(c.g * 255); \ + rgba[x*4+2] = (SHuint8)SH_FLOOR(c.b * 255); \ + rgba[x*4+3] = (SHuint8)SH_FLOOR(c.a * 255); } + +#define CSTORE_RGBA1D_F(c, rgba, x) { \ + rgba[x*4+0] = c.r; \ + rgba[x*4+1] = c.g; \ + rgba[x*4+2] = c.b; \ + rgba[x*4+3] = c.a; } + +#define CSTORE_RGBA2D_8(c, rgba, x, y, width) { \ + rgba[y*width*4+x*4+0] = (SHuint8)SH_FLOOR(c.r * 255); \ + rgba[y*width*4+x*4+1] = (SHuint8)SH_FLOOR(c.g * 255); \ + rgba[y*width*4+x*4+2] = (SHuint8)SH_FLOOR(c.b * 255); \ + rgba[y*width*4+x*4+3] = (SHuint8)SH_FLOOR(c.a * 255); } + +#define CSTORE_RGBA2D_F(c, rgba, x, y, width) { \ + rgba[y*width*4+x*4+0] = c.r; \ + rgba[y*width*4+x*4+1] = c.g; \ + rgba[y*width*4+x*4+2] = c.b; \ + rgba[y*width*4+x*4+3] = c.a; } + +#define INT2COLCOORD(i, max) ( (SHfloat)i / (SHfloat)max ) +#define COL2INTCOORD(c, max) ( (SHuint)SH_FLOOR(c * (SHfloat)max + 0.5f) ) + +void shStoreColor(SHColor *c, void *data, SHImageFormatDesc *f); +void shLoadColor(SHColor *c, const void *data, SHImageFormatDesc *f); + + +#endif /* __SHIMAGE_H */ diff --git a/simgear/canvas/ShaderVG/src/shPaint.c b/simgear/canvas/ShaderVG/src/shPaint.c new file mode 100644 index 00000000..010ac474 --- /dev/null +++ b/simgear/canvas/ShaderVG/src/shPaint.c @@ -0,0 +1,518 @@ +/* + * Copyright (c) 2007 Ivan Leben + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#define VG_API_EXPORT +#include "vg/openvg.h" +#include "shContext.h" +#include "shPaint.h" +#include + +#define _ITEM_T SHStop +#define _ARRAY_T SHStopArray +#define _FUNC_T shStopArray +#define _COMPARE_T(s1,s2) 0 +#define _ARRAY_DEFINE +#include "shArrayBase.h" + +#define _ITEM_T SHPaint* +#define _ARRAY_T SHPaintArray +#define _FUNC_T shPaintArray +#define _ARRAY_DEFINE +#include "shArrayBase.h" + +// We currently do not use gradients which need textures, so disable them to +// prevent freeing resources outside the correct OpenGL thread/context. +#define SH_NO_PAINT_TEXTURE + +void SHPaint_ctor(SHPaint *p) +{ + int i; + + p->type = VG_PAINT_TYPE_COLOR; + CSET(p->color, 0,0,0,1); + SH_INITOBJ(SHStopArray, p->instops); + SH_INITOBJ(SHStopArray, p->stops); + p->premultiplied = VG_FALSE; + p->spreadMode = VG_COLOR_RAMP_SPREAD_PAD; + p->tilingMode = VG_TILE_FILL; + for (i=0; i<4; ++i) p->linearGradient[i] = 0.0f; + for (i=0; i<5; ++i) p->radialGradient[i] = 0.0f; + p->pattern = VG_INVALID_HANDLE; + +#ifndef SH_NO_PAINT_TEXTURE + glGenTextures(1, &p->texture); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glBindTexture(GL_TEXTURE_2D, p->texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SH_GRADIENT_TEX_WIDTH, SH_GRADIENT_TEX_HEIGHT, 0, + GL_RGBA, GL_FLOAT, NULL); + GL_CEHCK_ERROR; +#else + p->texture = 0; +#endif +} + +void SHPaint_dtor(SHPaint *p) +{ + SH_DEINITOBJ(SHStopArray, p->instops); + SH_DEINITOBJ(SHStopArray, p->stops); + +#ifndef SH_NO_PAINT_TEXTURE + if (glIsTexture(p->texture)) + glDeleteTextures(1, &p->texture); +#endif +} + +VG_API_CALL VGPaint vgCreatePaint(void) +{ + SHPaint *p = NULL; + VG_GETCONTEXT(VG_INVALID_HANDLE); + + /* Create new paint object */ + SH_NEWOBJ(SHPaint, p); + VG_RETURN_ERR_IF(!p, VG_OUT_OF_MEMORY_ERROR, + VG_INVALID_HANDLE); + + /* Add to resource list */ + shPaintArrayPushBack(&context->paints, p); + + VG_RETURN((VGPaint)p); +} + +VG_API_CALL void vgDestroyPaint(VGPaint paint) +{ + SHint index; + VG_GETCONTEXT(VG_NO_RETVAL); + + /* Check if handle valid */ + index = shPaintArrayFind(&context->paints, (SHPaint*)paint); + VG_RETURN_ERR_IF(index == -1, VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + /* Delete object and remove resource */ + SH_DELETEOBJ(SHPaint, (SHPaint*)paint); + shPaintArrayRemoveAt(&context->paints, index); + + VG_RETURN(VG_NO_RETVAL); +} + +VG_API_CALL void vgSetPaint(VGPaint paint, VGbitfield paintModes) +{ + VG_GETCONTEXT(VG_NO_RETVAL); + + /* Check if handle valid */ + VG_RETURN_ERR_IF(!shIsValidPaint(context, paint) && + paint != VG_INVALID_HANDLE, + VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + /* Check for invalid mode */ + VG_RETURN_ERR_IF(paintModes & ~(VG_STROKE_PATH | VG_FILL_PATH), + VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL); + + /* Set stroke / fill */ + if (paintModes & VG_STROKE_PATH) + context->strokePaint = (SHPaint*)paint; + if (paintModes & VG_FILL_PATH) + context->fillPaint = (SHPaint*)paint; + + VG_RETURN(VG_NO_RETVAL); +} + +VG_API_CALL void vgPaintPattern(VGPaint paint, VGImage pattern) +{ + VG_GETCONTEXT(VG_NO_RETVAL); + + /* Check if handle valid */ + VG_RETURN_ERR_IF(!shIsValidPaint(context, paint), + VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + /* Check if pattern image valid */ + VG_RETURN_ERR_IF(!shIsValidImage(context, pattern), + VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + /* TODO: Check if pattern image is current rendering target */ + + /* Set pattern image */ + ((SHPaint*)paint)->pattern = pattern; + + VG_RETURN(VG_NO_RETVAL); +} + +void shUpdateColorRampTexture(SHPaint *p) +{ +#ifndef SH_NO_PAINT_TEXTURE + SHint s=0; + SHStop *stop1, *stop2; + SHfloat rgba[SH_GRADIENT_TEX_COORDSIZE]; + SHint x1=0, x2=0, dx, x; + SHColor dc, c; + SHfloat k; + + /* Write first pixel color */ + stop1 = &p->stops.items[0]; + CSTORE_RGBA1D_F(stop1->color, rgba, x1); + + /* Walk stops */ + for (s=1; sstops.size; ++s, x1=x2, stop1=stop2) { + + /* Pick next stop */ + stop2 = &p->stops.items[s]; + x2 = (SHint)(stop2->offset * (SH_GRADIENT_TEX_WIDTH-1)); + + SH_ASSERT(x1 >= 0 && x1 < SH_GRADIENT_TEX_WIDTH && + x2 >= 0 && x2 < SH_GRADIENT_TEX_WIDTH && + x1 <= x2); + + dx = x2 - x1; + CSUBCTO(stop2->color, stop1->color, dc); + + /* Interpolate inbetween */ + for (x=x1+1; x<=x2; ++x) { + + k = (SHfloat)(x-x1)/dx; + CSETC(c, stop1->color); + CADDCK(c, dc, k); + CSTORE_RGBA1D_F(c, rgba, x); + } + } + + /* Update texture image */ + glBindTexture(GL_TEXTURE_2D, p->texture); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + for(int i = 0; i < SH_GRADIENT_TEX_HEIGHT ; i++) + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, i, SH_GRADIENT_TEX_WIDTH, 1, GL_RGBA, GL_FLOAT, rgba); + + GL_CEHCK_ERROR; +#else + printf("ShaderVG: gradients not supported!"); +#endif +} + +void shValidateInputStops(SHPaint *p) +{ + SHStop *instop, stop = {0, {0,0,0,0}}; + SHfloat lastOffset=0.0f; + int i; + + shStopArrayClear(&p->stops); + shStopArrayReserve(&p->stops, p->instops.size); + + /* Assure input stops are properly defined */ + for (i=0; iinstops.size; ++i) { + + /* Copy stop color */ + instop = &p->instops.items[i]; + stop.color = instop->color; + + /* Offset must be in [0,1] */ + if (instop->offset < 0.0f || instop->offset > 1.0f) + continue; + + /* Discard whole sequence if not in ascending order */ + if (instop->offset < lastOffset) + {shStopArrayClear(&p->stops); break;} + + /* Add stop at offset 0 with same color if first not at 0 */ + if (p->stops.size == 0 && instop->offset != 0.0f) { + stop.offset = 0.0f; + shStopArrayPushBackP(&p->stops, &stop);} + + /* Add current stop to array */ + stop.offset = instop->offset; + shStopArrayPushBackP(&p->stops, &stop); + + /* Save last offset */ + lastOffset = instop->offset; + } + + /* Add stop at offset 1 with same color if last not at 1 */ + if (p->stops.size > 0 && lastOffset != 1.0f) { + stop.offset = 1.0f; + shStopArrayPushBackP(&p->stops, &stop); + } + + /* Add 2 default stops if no valid found */ + if (p->stops.size == 0) { + /* First opaque black */ + stop.offset = 0.0f; + CSET(stop.color, 0,0,0,1); + shStopArrayPushBackP(&p->stops, &stop); + /* Last opaque white */ + stop.offset = 1.0f; + CSET(stop.color, 1,1,1,1); + shStopArrayPushBackP(&p->stops, &stop); + } + + /* Update texture */ + shUpdateColorRampTexture(p); +} + +void shGenerateStops(SHPaint *p, SHfloat minOffset, SHfloat maxOffset, + SHStopArray *outStops) +{ + SHStop *s1,*s2; + SHint i1,i2; + SHfloat o=0.0f; + SHfloat ostep=0.0f; + SHint istep=1; + SHint istart=0; + SHint iend=p->stops.size-1; + SHint minDone=0; + SHint maxDone=0; + SHStop outStop; + + /* Start below zero? */ + if (minOffset < 0.0f) { + if (p->spreadMode == VG_COLOR_RAMP_SPREAD_PAD) { + /* Add min offset stop */ + outStop = p->stops.items[0]; + outStop.offset = minOffset; + shStopArrayPushBackP(outStops, &outStop); + /* Add max offset stop and exit */ + if (maxOffset < 0.0f) { + outStop.offset = maxOffset; + shStopArrayPushBackP(outStops, &outStop); + return; } + }else{ + /* Pad starting offset to nearest factor of 2 */ + SHint ioff = (SHint)SH_FLOOR(minOffset); + o = (SHfloat)(ioff - (ioff & 1)); + } + } + + /* Construct stops until max offset reached */ + for (i1=istart, i2=istart+istep; maxDone!=1; + i1+=istep, i2+=istep, o+=ostep) { + + /* All stops consumed? */ + if (i1==iend) { switch(p->spreadMode) { + + case VG_COLOR_RAMP_SPREAD_PAD: + /* Pick last stop */ + outStop = p->stops.items[i1]; + if (!minDone) { + /* Add min offset stop with last color */ + outStop.offset = minOffset; + shStopArrayPushBackP(outStops, &outStop); } + /* Add max offset stop with last color */ + outStop.offset = maxOffset; + shStopArrayPushBackP(outStops, &outStop); + return; + + case VG_COLOR_RAMP_SPREAD_REPEAT: + /* Reset iteration */ + i1=istart; i2=istart+istep; + /* Add stop1 if past min offset */ + if (minDone) { + outStop = p->stops.items[0]; + outStop.offset = o; + shStopArrayPushBackP(outStops, &outStop); } + break; + + case VG_COLOR_RAMP_SPREAD_REFLECT: + /* Reflect iteration direction */ + istep = -istep; + i2 = i1 + istep; + iend = (istep==1) ? p->stops.size-1 : 0; + break; + } + } + + /* 2 stops and their offset distance */ + s1 = &p->stops.items[i1]; + s2 = &p->stops.items[i2]; + ostep = s2->offset - s1->offset; + ostep = SH_ABS(ostep); + + /* Add stop1 if reached min offset */ + if (!minDone && o+ostep > minOffset) { + minDone = 1; + outStop = *s1; + outStop.offset = o; + shStopArrayPushBackP(outStops, &outStop); + } + + /* Mark done if reached max offset */ + if (o+ostep > maxOffset) + maxDone = 1; + + /* Add stop2 if past min offset */ + if (minDone) { + outStop = *s2; + outStop.offset = o+ostep; + shStopArrayPushBackP(outStops, &outStop); + } + } +} + +void shSetGradientTexGLState(SHPaint *p) +{ +#ifndef SH_NO_PAINT_TEXTURE + glBindTexture(GL_TEXTURE_2D, p->texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + switch (p->spreadMode) { + case VG_COLOR_RAMP_SPREAD_PAD: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); break; + case VG_COLOR_RAMP_SPREAD_REPEAT: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); break; + case VG_COLOR_RAMP_SPREAD_REFLECT: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); break; + } +#else + printf("ShaderVG: gradients not supported!"); +#endif +} + +void shSetPatternTexGLState(SHPaint *p, VGContext *c) +{ + glBindTexture(GL_TEXTURE_2D, ((SHImage*)p->pattern)->texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + switch(p->tilingMode) { + case VG_TILE_FILL: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, + (GLfloat*)&c->tileFillColor); + break; + case VG_TILE_PAD: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + break; + case VG_TILE_REPEAT: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + break; + case VG_TILE_REFLECT: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); + break; + } +} + +int shLoadLinearGradientMesh(SHPaint *p, VGPaintMode mode, VGMatrixMode matrixMode) +{ + SHMatrix3x3 *m = 0; + SHMatrix3x3 mu2p; + GLfloat u2p[9]; + + /* Pick paint transform matrix */ + SH_GETCONTEXT(0); + if (mode == VG_FILL_PATH) + m = &context->fillTransform; + else if (mode == VG_STROKE_PATH) + m = &context->strokeTransform; + + /* Back to paint space */ + shInvertMatrix(m, &mu2p); + shMatrixToVG(&mu2p, (SHfloat*)u2p); + + /* Setup shader */ + glUniform1i(context->locationDraw.paintType, VG_PAINT_TYPE_LINEAR_GRADIENT); + glUniform2fv(context->locationDraw.paintParams, 2, p->linearGradient); + glUniformMatrix3fv(context->locationDraw.paintInverted, 1, GL_FALSE, u2p); + glActiveTexture(GL_TEXTURE1); + shSetGradientTexGLState(p); + glEnable(GL_TEXTURE_2D); + glUniform1i(context->locationDraw.rampSampler, 1); + GL_CEHCK_ERROR; + + return 1; +} + +int shLoadRadialGradientMesh(SHPaint *p, VGPaintMode mode, VGMatrixMode matrixMode) +{ + SHMatrix3x3 *m = 0; + SHMatrix3x3 mu2p; + GLfloat u2p[9]; + + /* Pick paint transform matrix */ + SH_GETCONTEXT(0); + if (mode == VG_FILL_PATH) + m = &context->fillTransform; + else if (mode == VG_STROKE_PATH) + m = &context->strokeTransform; + + /* Back to paint space */ + shInvertMatrix(m, &mu2p); + shMatrixToVG(&mu2p, (SHfloat*)u2p); + + /* Setup shader */ + glUniform1i(context->locationDraw.paintType, VG_PAINT_TYPE_RADIAL_GRADIENT); + glUniform2fv(context->locationDraw.paintParams, 3, p->radialGradient); + glUniformMatrix3fv(context->locationDraw.paintInverted, 1, GL_FALSE, u2p); + glActiveTexture(GL_TEXTURE1); + shSetGradientTexGLState(p); + glEnable(GL_TEXTURE_2D); + glUniform1i(context->locationDraw.rampSampler, 1); + GL_CEHCK_ERROR; + + return 1; +} + +int shLoadPatternMesh(SHPaint *p, VGPaintMode mode, VGMatrixMode matrixMode) +{ + SHImage *i = (SHImage*)p->pattern; + SHMatrix3x3 *m = 0; + SHMatrix3x3 mu2p; + GLfloat u2p[9]; + + /* Pick paint transform matrix */ + SH_GETCONTEXT(0); + if (mode == VG_FILL_PATH) + m = &context->fillTransform; + else if (mode == VG_STROKE_PATH) + m = &context->strokeTransform; + + /* Back to paint space */ + shInvertMatrix(m, &mu2p); + shMatrixToVG(&mu2p, (SHfloat*)u2p); + + /* Setup shader */ + glUniform1i(context->locationDraw.paintType, VG_PAINT_TYPE_PATTERN); + glUniform2f(context->locationDraw.paintParams, (GLfloat)i->width, (GLfloat)i->height); + glUniformMatrix3fv(context->locationDraw.paintInverted, 1, GL_FALSE, u2p); + glActiveTexture(GL_TEXTURE1); + shSetPatternTexGLState(p, context); + glEnable(GL_TEXTURE_2D); + glUniform1i(context->locationDraw.patternSampler, 1); + GL_CEHCK_ERROR; + + return 1; +} + +int shLoadOneColorMesh(SHPaint *p) +{ + static GLfloat id[9] = { + 1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 1.0f }; + SH_GETCONTEXT(0); + + /* Setup shader */ + glUniform1i(context->locationDraw.paintType, VG_PAINT_TYPE_COLOR); + glUniform4fv(context->locationDraw.paintColor, 1, (GLfloat*)&p->color); + glUniformMatrix3fv(context->locationDraw.paintInverted, 1, GL_FALSE, id); + + return 1; +} + diff --git a/simgear/canvas/ShaderVG/src/shPaint.h b/simgear/canvas/ShaderVG/src/shPaint.h new file mode 100644 index 00000000..2a8301d8 --- /dev/null +++ b/simgear/canvas/ShaderVG/src/shPaint.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2007 Ivan Leben + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __SHPAINT_H +#define __SHPAINT_H + +#include "shDefs.h" +#include "shArrays.h" +#include "shImage.h" + +typedef struct +{ + float offset; + SHColor color; + +} SHStop; + +#define _ITEM_T SHStop +#define _ARRAY_T SHStopArray +#define _FUNC_T shStopArray +#define _ARRAY_DECLARE +#include "shArrayBase.h" + +typedef struct +{ + VGPaintType type; + SHColor color; + SHColorArray colors; + SHStopArray instops; + SHStopArray stops; + VGboolean premultiplied; + VGColorRampSpreadMode spreadMode; + VGTilingMode tilingMode; + SHfloat linearGradient[4]; + SHfloat radialGradient[5]; + GLuint texture; + VGImage pattern; + +} SHPaint; + +void SHPaint_ctor(SHPaint *p); +void SHPaint_dtor(SHPaint *p); + +#define _ITEM_T SHPaint* +#define _ARRAY_T SHPaintArray +#define _FUNC_T shPaintArray +#define _ARRAY_DECLARE +#include "shArrayBase.h" + +void shValidateInputStops(SHPaint *p); +void shSetGradientTexGLState(SHPaint *p); + +int shLoadLinearGradientMesh(SHPaint *p, VGPaintMode mode, VGMatrixMode matrixMode); +int shLoadRadialGradientMesh(SHPaint *p, VGPaintMode mode, VGMatrixMode matrixMode); +int shLoadPatternMesh(SHPaint *p, VGPaintMode mode, VGMatrixMode matrixMode); +int shLoadOneColorMesh(SHPaint *p); + + +#endif /* __SHPAINT_H */ diff --git a/simgear/canvas/ShaderVG/src/shParams.c b/simgear/canvas/ShaderVG/src/shParams.c new file mode 100644 index 00000000..62bd29cf --- /dev/null +++ b/simgear/canvas/ShaderVG/src/shParams.c @@ -0,0 +1,1403 @@ +/* + * Copyright (c) 2007 Ivan Leben + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#define VG_API_EXPORT +#include +#include "vg/openvg.h" +#include "shContext.h" + +/*---------------------------------------------------- + * Returns true (1) if the specified parameter takes + * a vector of values (more than 1) or false (0) + * otherwise. + *----------------------------------------------------*/ + +int shIsParamVector(SHint type) +{ + return + (type == VG_SCISSOR_RECTS || + type == VG_STROKE_DASH_PATTERN || + type == VG_TILE_FILL_COLOR || + type == VG_CLEAR_COLOR || + type == VG_PAINT_COLOR || + type == VG_PAINT_COLOR_RAMP_STOPS || + type == VG_PAINT_LINEAR_GRADIENT || + type == VG_PAINT_RADIAL_GRADIENT); +} + +/*---------------------------------------------------- + * Returns true (1) if the given integer is a valid + * enumeration value for the specified parameter or + * false (0) otherwise. + *----------------------------------------------------*/ + +int shIsEnumValid(SHint type, VGint val) +{ + switch(type) + { + case VG_MATRIX_MODE: + return (val == VG_MATRIX_PATH_USER_TO_SURFACE || + val == VG_MATRIX_IMAGE_USER_TO_SURFACE || + val == VG_MATRIX_FILL_PAINT_TO_USER || + val == VG_MATRIX_STROKE_PAINT_TO_USER); + + case VG_FILL_RULE: + return (val == VG_EVEN_ODD || + val == VG_NON_ZERO) ? VG_TRUE : VG_FALSE; + + case VG_IMAGE_QUALITY: + return (val == VG_IMAGE_QUALITY_NONANTIALIASED || + val == VG_IMAGE_QUALITY_FASTER || + val == VG_IMAGE_QUALITY_BETTER); + + case VG_RENDERING_QUALITY: + return (val == VG_RENDERING_QUALITY_NONANTIALIASED || + val == VG_RENDERING_QUALITY_FASTER || + val == VG_RENDERING_QUALITY_BETTER); + + case VG_BLEND_MODE: + return (val == VG_BLEND_SRC || + val == VG_BLEND_SRC_OVER || + val == VG_BLEND_DST_OVER || + val == VG_BLEND_SRC_IN || + val == VG_BLEND_DST_IN || + val == VG_BLEND_MULTIPLY || + val == VG_BLEND_SCREEN || + val == VG_BLEND_DARKEN || + val == VG_BLEND_LIGHTEN || + val == VG_BLEND_ADDITIVE || + val == VG_BLEND_SRC_OUT_SH || + val == VG_BLEND_DST_OUT_SH || + val == VG_BLEND_SRC_ATOP_SH || + val == VG_BLEND_DST_ATOP_SH); + + case VG_IMAGE_MODE: + return (val == VG_DRAW_IMAGE_NORMAL || + val == VG_DRAW_IMAGE_MULTIPLY || + val == VG_DRAW_IMAGE_STENCIL); + + case VG_STROKE_CAP_STYLE: + return (val == VG_CAP_BUTT || + val == VG_CAP_ROUND || + val == VG_CAP_SQUARE); + + case VG_STROKE_JOIN_STYLE: + return (val == VG_JOIN_MITER || + val == VG_JOIN_ROUND || + val == VG_JOIN_BEVEL); + + case VG_STROKE_DASH_PHASE_RESET: + case VG_SCISSORING: + case VG_MASKING: + return (val == VG_TRUE || + val == VG_FALSE); + + case VG_PIXEL_LAYOUT: + return (val == VG_PIXEL_LAYOUT_UNKNOWN || + val == VG_PIXEL_LAYOUT_RGB_VERTICAL || + val == VG_PIXEL_LAYOUT_BGR_VERTICAL || + val == VG_PIXEL_LAYOUT_RGB_HORIZONTAL || + val == VG_PIXEL_LAYOUT_BGR_HORIZONTAL); + + case VG_FILTER_FORMAT_LINEAR: + case VG_FILTER_FORMAT_PREMULTIPLIED: + return (val == VG_TRUE || + val == VG_FALSE); + + case VG_PAINT_TYPE: + return (val == VG_PAINT_TYPE_COLOR || + val == VG_PAINT_TYPE_LINEAR_GRADIENT || + val == VG_PAINT_TYPE_RADIAL_GRADIENT || + val == VG_PAINT_TYPE_PATTERN); + + case VG_PAINT_COLOR_RAMP_SPREAD_MODE: + return (val == VG_COLOR_RAMP_SPREAD_PAD || + val == VG_COLOR_RAMP_SPREAD_REPEAT || + val == VG_COLOR_RAMP_SPREAD_REFLECT); + + case VG_PAINT_PATTERN_TILING_MODE: + return (val == VG_TILE_FILL || + val == VG_TILE_PAD || + val == VG_TILE_REPEAT || + val == VG_TILE_REFLECT); + + case VG_IMAGE_FORMAT: + return (val >= VG_sRGBX_8888 && + val <= VG_lABGR_8888_PRE); + + default: + return 1; + } +} + +/*-------------------------------------------------------- + * These two functions check for invalid (erroneus) float + * input and correct it to acceptable ranges. + *---------------------------------------------------*/ + +SHfloat getMaxFloat() +{ + SHfloatint fi; + fi.i = SH_MAX_FLOAT_BITS; + return fi.f; +} + +SHfloat shValidInputFloat(VGfloat f) +{ + SHfloat max = getMaxFloat(); + if (SH_ISNAN(f)) return 0.0f; /* convert NAN to zero */ + SH_CLAMP(f, -max, max); /* clamp to valid range */ + return (SHfloat)f; +} + +static SHint shValidInputFloat2Int(VGfloat f) +{ + double v = (double)SH_FLOOR(shValidInputFloat(f)); + SH_CLAMP(v, (double)SH_MIN_INT, (double)SH_MAX_INT); + return (SHint)v; +} + +/*--------------------------------------------------- + * Interpretes the input value vector as an array of + * integers and returns the value at given index + *---------------------------------------------------*/ + +static SHint shParamToInt(const void *values, SHint floats, SHint index) +{ + if (floats) + return shValidInputFloat2Int(((const VGfloat*)values)[index]); + else + return (SHint)((const VGint*)values)[index]; +} + +/*--------------------------------------------------- + * Interpretes the input value vector as an array of + * floats and returns the value at given index + *---------------------------------------------------*/ + +static VGfloat shParamToFloat(const void *values, SHint floats, SHint index) +{ + if (floats) + return shValidInputFloat(((const VGfloat*)values)[index]); + else + return (SHfloat)((const VGint*)values)[index]; +} + +/*--------------------------------------------------- + * Interpretes the output value vector as an array of + * integers and sets the value at given index + *---------------------------------------------------*/ + +static void shIntToParam(SHint i, SHint count, void *output, SHint floats, SHint index) +{ + if (index >= count) + return; + if (floats) + ((VGfloat*)output)[index] = (VGfloat)i; + else + ((VGint*)output)[index] = (VGint)i; +} + +/*---------------------------------------------------- + * Interpretes the output value vector as an array of + * floats and sets the value at given index + *----------------------------------------------------*/ + +static void shFloatToParam(SHfloat f, SHint count, void *output, SHint floats, SHint index) +{ + if (index >= count) + return; + if (floats) + ((VGfloat*)output)[index] = (VGfloat)f; + else + ((VGint*)output)[index] = (VGint)shValidInputFloat2Int(f); +} + +/*--------------------------------------------------------- + * Sets a parameter by interpreting the input value vector + * according to the parameter type and input type. + *---------------------------------------------------------*/ + +static void shSet(VGContext *context, VGParamType type, SHint count, + const void* values, SHint floats) +{ + SHfloat fvalue = 0.0f; + SHint ivalue = 0; + VGboolean bvalue = VG_FALSE; + int i = 0; + + /* Check for negative count */ + SH_RETURN_ERR_IF(count<0, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + + /* Check for empty vector */ + SH_RETURN_ERR_IF(!values && count!=0, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + + /* Pre-convert first value for non-vector params */ + if (count == 1) { + fvalue = shParamToFloat(values, floats, 0); + ivalue = shParamToInt(values, floats, 0); + bvalue = (ivalue ? VG_TRUE : VG_FALSE); + } + + switch (type) + { + case VG_MATRIX_MODE: + SH_RETURN_ERR_IF(count!=1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + SH_RETURN_ERR_IF(!shIsEnumValid(type,ivalue), VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + context->matrixMode = (VGMatrixMode)ivalue; + break; + + case VG_FILL_RULE: + SH_RETURN_ERR_IF(count!=1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + SH_RETURN_ERR_IF(!shIsEnumValid(type,ivalue), VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + context->fillRule = (VGFillRule)ivalue; + break; + + case VG_IMAGE_QUALITY: + SH_RETURN_ERR_IF(count!=1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + SH_RETURN_ERR_IF(!shIsEnumValid(type,ivalue), VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + context->imageQuality = (VGImageQuality)ivalue; + break; + + case VG_RENDERING_QUALITY: + SH_RETURN_ERR_IF(count!=1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + SH_RETURN_ERR_IF(!shIsEnumValid(type,ivalue), VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + context->renderingQuality = (VGRenderingQuality)ivalue; + break; + + case VG_BLEND_MODE: + SH_RETURN_ERR_IF(count!=1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + SH_RETURN_ERR_IF(!shIsEnumValid(type,ivalue), VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + context->blendMode = (VGBlendMode)ivalue; + break; + + case VG_IMAGE_MODE: + SH_RETURN_ERR_IF(count!=1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + SH_RETURN_ERR_IF(!shIsEnumValid(type,ivalue), VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + context->imageMode = (VGImageMode)ivalue; + break; + + case VG_STROKE_CAP_STYLE: + SH_RETURN_ERR_IF(count!=1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + SH_RETURN_ERR_IF(!shIsEnumValid(type,ivalue), VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + context->strokeCapStyle = (VGCapStyle)ivalue; + break; + + case VG_STROKE_JOIN_STYLE: + SH_RETURN_ERR_IF(count!=1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + SH_RETURN_ERR_IF(!shIsEnumValid(type,ivalue), VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + context->strokeJoinStyle = (VGJoinStyle)ivalue; + break; + + case VG_PIXEL_LAYOUT: + SH_RETURN_ERR_IF(count!=1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + SH_RETURN_ERR_IF(!shIsEnumValid(type,ivalue), VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + context->pixelLayout = (VGPixelLayout)ivalue; + break; + + case VG_FILTER_CHANNEL_MASK: + SH_RETURN_ERR_IF(count!=1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + context->filterChannelMask = (VGbitfield)ivalue; + break; + + case VG_FILTER_FORMAT_LINEAR: + SH_RETURN_ERR_IF(count!=1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + context->filterFormatLinear = bvalue; + break; + + case VG_FILTER_FORMAT_PREMULTIPLIED: + SH_RETURN_ERR_IF(count!=1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + context->filterFormatPremultiplied = bvalue; + break; + + case VG_STROKE_DASH_PHASE_RESET: + SH_RETURN_ERR_IF(count!=1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + context->strokeDashPhaseReset = bvalue; + break; + + case VG_MASKING: + SH_RETURN_ERR_IF(count!=1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + context->masking = bvalue; + break; + + case VG_SCISSORING: + SH_RETURN_ERR_IF(count!=1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + context->scissoring = bvalue; + break; + + case VG_STROKE_LINE_WIDTH: + SH_RETURN_ERR_IF(count!=1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + context->strokeLineWidth = fvalue; + break; + + case VG_STROKE_MITER_LIMIT: + SH_RETURN_ERR_IF(count!=1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + context->strokeMiterLimit = SH_MAX(fvalue, 1.0f); + break; + + case VG_STROKE_DASH_PHASE: + SH_RETURN_ERR_IF(count!=1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + context->strokeDashPhase = fvalue; + break; + + case VG_STROKE_DASH_PATTERN: + + /* TODO: limit by the VG_MAX_DASH_COUNT value */ + shFloatArrayClear(&context->strokeDashPattern); + for (i=0; istrokeDashPattern, + shParamToFloat(values, floats, i)); + break; + case VG_TILE_FILL_COLOR: + + SH_RETURN_ERR_IF(count!=4, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + CSET(context->tileFillColor, + shParamToFloat(values, floats, 0), + shParamToFloat(values, floats, 1), + shParamToFloat(values, floats, 2), + shParamToFloat(values, floats, 3)); + + break; + case VG_CLEAR_COLOR: + + SH_RETURN_ERR_IF(count!=4, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + CSET(context->clearColor, + shParamToFloat(values, floats, 0), + shParamToFloat(values, floats, 1), + shParamToFloat(values, floats, 2), + shParamToFloat(values, floats, 3)); + + break; + case VG_SCISSOR_RECTS: + + SH_RETURN_ERR_IF(count % 4, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shRectArrayClear(&context->scissor); + for (i=0; iscissor, &r); + } + + break; + + case VG_MAX_SCISSOR_RECTS: + case VG_MAX_DASH_COUNT: + case VG_MAX_KERNEL_SIZE: + case VG_MAX_SEPARABLE_KERNEL_SIZE: + case VG_MAX_COLOR_RAMP_STOPS: + case VG_MAX_IMAGE_WIDTH: + case VG_MAX_IMAGE_HEIGHT: + case VG_MAX_IMAGE_PIXELS: + case VG_MAX_IMAGE_BYTES: + case VG_MAX_FLOAT: + case VG_MAX_GAUSSIAN_STD_DEVIATION: + /* Read-only */ break; + + default: + /* Invalid VGParamType */ + SH_RETURN_ERR(VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + } + + SH_RETURN(SH_NO_RETVAL); +} + +/*-------------------------------------------------- + * Sets a parameter of a single integer value + *--------------------------------------------------*/ + +VG_API_CALL void vgSetf (VGParamType type, VGfloat value) +{ + VG_GETCONTEXT(VG_NO_RETVAL); + + /* Check if target vector */ + VG_RETURN_ERR_IF(shIsParamVector(type), + VG_ILLEGAL_ARGUMENT_ERROR, + VG_NO_RETVAL); + + /* Error code will be set by shSet */ + shSet(context, type, 1, &value, 1); + VG_RETURN(VG_NO_RETVAL); +} + +/*-------------------------------------------------- + * Sets a parameter of a single float value + *--------------------------------------------------*/ + +VG_API_CALL void vgSeti (VGParamType type, VGint value) +{ + VG_GETCONTEXT(VG_NO_RETVAL); + + /* Check if target vector */ + VG_RETURN_ERR_IF(shIsParamVector(type), + VG_ILLEGAL_ARGUMENT_ERROR, + VG_NO_RETVAL); + + /* Error code will be set by shSet */ + shSet(context, type, 1, &value, 0); + VG_RETURN(VG_NO_RETVAL); +} + +/*------------------------------------------------------- + * Sets a parameter which takes a vector of float values + *-------------------------------------------------------*/ + +VG_API_CALL void vgSetfv(VGParamType type, VGint count, + const VGfloat * values) +{ + VG_GETCONTEXT(VG_NO_RETVAL); + + /* TODO: check input array alignment */ + + /* Error code will be set by shSet */ + shSet(context, type, count, values, 1); + VG_RETURN(VG_NO_RETVAL); +} + +/*--------------------------------------------------------- + * Sets a parameter which takes a vector of integer values + *---------------------------------------------------------*/ + +VG_API_CALL void vgSetiv(VGParamType type, VGint count, + const VGint * values) +{ + VG_GETCONTEXT(VG_NO_RETVAL); + + /* TODO: check input array alignment */ + + /* Error code wil be set by shSet */ + shSet(context, type, count, values, 0); + VG_RETURN(VG_NO_RETVAL); +} + +/*--------------------------------------------------------- + * Outputs a parameter by interpreting the output value + * vector according to the parameter type and input type. + *---------------------------------------------------------*/ + +static void shGet(VGContext *context, VGParamType type, SHint count, void *values, SHint floats) +{ + int i; + + /* Check for invalid array / count */ + SH_RETURN_ERR_IF(!values || count<=0, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + + switch (type) + { + case VG_MATRIX_MODE: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam((SHint)context->matrixMode, count, values, floats, 0); + break; + + case VG_FILL_RULE: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam((SHint)context->fillRule, count, values, floats, 0); + break; + + case VG_IMAGE_QUALITY: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam((SHint)context->imageQuality, count, values, floats, 0); + break; + + case VG_RENDERING_QUALITY: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam((SHint)context->renderingQuality, count, values, floats, 0); + break; + + case VG_BLEND_MODE: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam((SHint)context->blendMode, count, values, floats, 0); + break; + + case VG_IMAGE_MODE: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam((SHint)context->imageMode, count, values, floats, 0); + break; + + case VG_STROKE_CAP_STYLE: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam((SHint)context->strokeCapStyle, count, values, floats, 0); + break; + + case VG_STROKE_JOIN_STYLE: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam((SHint)context->strokeJoinStyle, count, values, floats, 0); + break; + + case VG_PIXEL_LAYOUT: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam((SHint)context->pixelLayout, count, values, floats, 0); + break; + + case VG_FILTER_CHANNEL_MASK: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam((SHint)context->filterChannelMask, count, values, floats, 0); + break; + + case VG_FILTER_FORMAT_LINEAR: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam((SHint)context->filterFormatLinear, count, values, floats, 0); + break; + + case VG_FILTER_FORMAT_PREMULTIPLIED: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam((SHint)context->filterFormatPremultiplied, count, values, floats, 0); + break; + + case VG_STROKE_DASH_PHASE_RESET: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam((SHint)context->strokeDashPhaseReset, count, values, floats, 0); + break; + + case VG_MASKING: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam((SHint)context->masking, count, values, floats, 0); + break; + + case VG_SCISSORING: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam((SHint)context->scissoring, count, values, floats, 0); + break; + + case VG_STROKE_LINE_WIDTH: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shFloatToParam(context->strokeLineWidth, count, values, floats, 0); + break; + + case VG_STROKE_MITER_LIMIT: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shFloatToParam(context->strokeMiterLimit, count, values, floats, 0); + break; + + case VG_STROKE_DASH_PHASE: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shFloatToParam(context->strokeDashPhase, count, values, floats, 0); + break; + + case VG_STROKE_DASH_PATTERN: + + SH_RETURN_ERR_IF(count > context->strokeDashPattern.size, + VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + + for (i=0; istrokeDashPattern.size; ++i) + shFloatToParam(context->strokeDashPattern.items[i], + count, values, floats, i); + + break; + case VG_TILE_FILL_COLOR: + + SH_RETURN_ERR_IF(count > 4, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shFloatToParam(context->tileFillColor.r, count, values, floats, 0); + shFloatToParam(context->tileFillColor.g, count, values, floats, 1); + shFloatToParam(context->tileFillColor.b, count, values, floats, 2); + shFloatToParam(context->tileFillColor.a, count, values, floats, 3); + + break; + case VG_CLEAR_COLOR: + + SH_RETURN_ERR_IF(count > 4, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shFloatToParam(context->clearColor.r, count, values, floats, 0); + shFloatToParam(context->clearColor.g, count, values, floats, 1); + shFloatToParam(context->clearColor.b, count, values, floats, 2); + shFloatToParam(context->clearColor.a, count, values, floats, 3); + + break; + case VG_SCISSOR_RECTS: + + SH_RETURN_ERR_IF(count > context->scissor.size * 4, + VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + + for (i=0; iscissor.size; ++i) { + shIntToParam((SHint)context->scissor.items[i].x, count, values, floats, i*4+0); + shIntToParam((SHint)context->scissor.items[i].y, count, values, floats, i*4+1); + shIntToParam((SHint)context->scissor.items[i].w, count, values, floats, i*4+2); + shIntToParam((SHint)context->scissor.items[i].h, count, values, floats, i*4+3); + } + + break; + + case VG_MAX_SCISSOR_RECTS: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam(SH_MAX_SCISSOR_RECTS, count, values, floats, 0); + break; + + case VG_MAX_DASH_COUNT: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam(SH_MAX_DASH_COUNT, count, values, floats, 0); + break; + + case VG_MAX_COLOR_RAMP_STOPS: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam(SH_MAX_COLOR_RAMP_STOPS, count, values, floats, 0); + break; + + case VG_MAX_IMAGE_WIDTH: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam(SH_MAX_IMAGE_WIDTH, count, values, floats, 0); + break; + + case VG_MAX_IMAGE_HEIGHT: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam(SH_MAX_IMAGE_WIDTH, count, values, floats, 0); + break; + + case VG_MAX_IMAGE_PIXELS: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam(SH_MAX_IMAGE_HEIGHT, count, values, floats, 0); + break; + + case VG_MAX_IMAGE_BYTES: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam(SH_MAX_IMAGE_BYTES, count, values, floats, 0); + break; + + case VG_MAX_FLOAT: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shFloatToParam(getMaxFloat(), count, values, floats, 0); + break; + + case VG_MAX_KERNEL_SIZE: /* TODO: depends on convolution implementation */ + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam(0, count, values, floats, 0); + break; + + case VG_MAX_SEPARABLE_KERNEL_SIZE: /* TODO: depends on convolution implementation */ + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam(0, count, values, floats, 0); + break; + + case VG_MAX_GAUSSIAN_STD_DEVIATION: /* TODO: depends on gaussian blur implementation */ + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shFloatToParam(0.0f, count, values, floats, 0); + break; + + default: + /* Invalid VGParamType */ + SH_RETURN_ERR(VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + } + + SH_RETURN(SH_NO_RETVAL); +} + +/*--------------------------------------------------------- + * Returns a parameter of a single float value + *---------------------------------------------------------*/ + +VG_API_CALL VGfloat vgGetf(VGParamType type) +{ + VGfloat retval = 0.0f; + VG_GETCONTEXT(retval); + + /* Check if target vector */ + VG_RETURN_ERR_IF(shIsParamVector(type), + VG_ILLEGAL_ARGUMENT_ERROR, + retval); + + /* Error code will be set by shGet */ + shGet(context, type, 1, &retval, 1); + VG_RETURN(retval); +} + +/*--------------------------------------------------------- + * Returns a parameter of a single integer value + *---------------------------------------------------------*/ + +VG_API_CALL VGint vgGeti(VGParamType type) +{ + VGint retval = 0; + VG_GETCONTEXT(retval); + + /* Check if target vector */ + VG_RETURN_ERR_IF(shIsParamVector(type), + VG_ILLEGAL_ARGUMENT_ERROR, + retval); + + /* Error code will be set by shGet */ + shGet(context, type, 1, &retval, 0); + VG_RETURN(retval); +} + +/*--------------------------------------------------------- + * Outputs a parameter of a float vector value + *---------------------------------------------------------*/ + +VG_API_CALL void vgGetfv(VGParamType type, VGint count, VGfloat * values) +{ + VG_GETCONTEXT(VG_NO_RETVAL); + + /* TODO: check output array alignment */ + + /* Error code will be set by shGet */ + shGet(context, type, count, values, 1); + VG_RETURN(VG_NO_RETVAL); +} + +/*--------------------------------------------------------- + * Outputs a parameter of an integer vector value + *---------------------------------------------------------*/ + +VG_API_CALL void vgGetiv(VGParamType type, VGint count, VGint * values) +{ + VG_GETCONTEXT(VG_NO_RETVAL); + + /* TODO: check output array alignment */ + + /* Error code will be set by shGet */ + shGet(context, type, count, values, 0); + VG_RETURN(VG_NO_RETVAL); +} + +/*--------------------------------------------------------- + * Returns the size of the output array required to + * receive the whole vector of parameter values + *---------------------------------------------------------*/ + +VG_API_CALL VGint vgGetVectorSize(VGParamType type) +{ + int retval = 0; + VG_GETCONTEXT(retval); + + switch(type) + { + case VG_MATRIX_MODE: + case VG_FILL_RULE: + case VG_IMAGE_QUALITY: + case VG_RENDERING_QUALITY: + case VG_BLEND_MODE: + case VG_IMAGE_MODE: + case VG_STROKE_CAP_STYLE: + case VG_STROKE_JOIN_STYLE: + case VG_PIXEL_LAYOUT: + case VG_FILTER_CHANNEL_MASK: + case VG_FILTER_FORMAT_LINEAR: + case VG_FILTER_FORMAT_PREMULTIPLIED: + case VG_STROKE_DASH_PHASE_RESET: + case VG_MASKING: + case VG_SCISSORING: + case VG_STROKE_LINE_WIDTH: + case VG_STROKE_MITER_LIMIT: + case VG_STROKE_DASH_PHASE: + case VG_MAX_SCISSOR_RECTS: + case VG_MAX_DASH_COUNT: + case VG_MAX_KERNEL_SIZE: + case VG_MAX_SEPARABLE_KERNEL_SIZE: + case VG_MAX_COLOR_RAMP_STOPS: + case VG_MAX_IMAGE_WIDTH: + case VG_MAX_IMAGE_HEIGHT: + case VG_MAX_IMAGE_PIXELS: + case VG_MAX_IMAGE_BYTES: + case VG_MAX_FLOAT: + case VG_MAX_GAUSSIAN_STD_DEVIATION: + retval = 1; + break; + + case VG_TILE_FILL_COLOR: + case VG_CLEAR_COLOR: + retval = 4; + break; + + case VG_STROKE_DASH_PATTERN: + retval = context->strokeDashPattern.size; + break; + + case VG_SCISSOR_RECTS: + retval = context->scissor.size * 4; + break; + + default: + /* Invalid VGParamType */ + VG_RETURN_ERR(VG_ILLEGAL_ARGUMENT_ERROR, retval); + } + + VG_RETURN(retval); +} + +/*----------------------------------------------------------- + * Sets a resource parameter by interpreting the input value + * vector according to the parameter type and input type. + *-----------------------------------------------------------*/ + +static void shSetParameter(VGContext *context, VGHandle object, + SHResourceType rtype, VGint ptype, + SHint count, const void *values, SHint floats) +{ +//SHfloat fvalue = 0.0f; + SHint ivalue = 0; +//VGboolean bvalue = VG_FALSE; + int i; + + /* Check for negative count */ + SH_RETURN_ERR_IF(count<0, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + + /* Check for empty vector */ + SH_RETURN_ERR_IF(!values && count!=0, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + + /* Pre-convert first value for non-vector params */ + if (count == 1) { +// fvalue = shParamToFloat(values, floats, 0); + ivalue = shParamToInt(values, floats, 0); +// bvalue = (ivalue ? VG_TRUE : VG_FALSE); + } + + switch (rtype) + { + case SH_RESOURCE_PATH: switch (ptype) { /* Path parameters */ + + case VG_PATH_FORMAT: + case VG_PATH_DATATYPE: + case VG_PATH_SCALE: + case VG_PATH_BIAS: + case VG_PATH_NUM_SEGMENTS: + case VG_PATH_NUM_COORDS: + /* Read-only */ break; + + default: + /* Invalid VGParamType */ + SH_RETURN_ERR(VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + + } break; + case SH_RESOURCE_PAINT: switch (ptype) { /* Paint parameters */ + + case VG_PAINT_TYPE: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + SH_RETURN_ERR_IF(!shIsEnumValid(ptype,ivalue), VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + ((SHPaint*)object)->type = (VGPaintType)ivalue; + break; + + case VG_PAINT_COLOR: + SH_RETURN_ERR_IF(count != 4, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + ((SHPaint*)object)->color.r = shParamToFloat(values, floats, 0); + ((SHPaint*)object)->color.g = shParamToFloat(values, floats, 1); + ((SHPaint*)object)->color.b = shParamToFloat(values, floats, 2); + ((SHPaint*)object)->color.a = shParamToFloat(values, floats, 3); + break; + + case VG_PAINT_COLOR_RAMP_SPREAD_MODE: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + SH_RETURN_ERR_IF(!shIsEnumValid(ptype,ivalue), VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + ((SHPaint*)object)->spreadMode = (VGColorRampSpreadMode)ivalue; + break; + + case VG_PAINT_COLOR_RAMP_PREMULTIPLIED: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + SH_RETURN_ERR_IF(!shIsEnumValid(ptype,ivalue), VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + ((SHPaint*)object)->premultiplied = (VGboolean)ivalue; + break; + + case VG_PAINT_COLOR_RAMP_STOPS: { + + int max; SHPaint *paint; SHStop stop; + SH_RETURN_ERR_IF(count % 5, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + max = SH_MIN(count, SH_MAX_COLOR_RAMP_STOPS * 5); + paint = (SHPaint*)object; + shStopArrayClear(&paint->instops); + + for (i=0; iinstops, &stop); } + + shValidateInputStops(paint); + break;} + + case VG_PAINT_LINEAR_GRADIENT: + SH_RETURN_ERR_IF(count != 4, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + for (i=0; i<4; ++i) + ((SHPaint*)object)->linearGradient[i] = shParamToFloat(values, floats, i); + break; + + case VG_PAINT_RADIAL_GRADIENT: + SH_RETURN_ERR_IF(count != 5, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + for (i=0; i<5; ++i) + ((SHPaint*)object)->radialGradient[i] = shParamToFloat(values, floats, i); + break; + + case VG_PAINT_PATTERN_TILING_MODE: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + SH_RETURN_ERR_IF(!shIsEnumValid(ptype,ivalue), VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + ((SHPaint*)object)->tilingMode = (VGTilingMode)ivalue; + break; + + default: + /* Invalid VGParamType */ + SH_RETURN_ERR(VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + + } break; + case SH_RESOURCE_IMAGE: switch (ptype) {/* Image parameters */ + + case VG_IMAGE_FORMAT: + case VG_IMAGE_WIDTH: + case VG_IMAGE_HEIGHT: + /* Read-only */ break; + + default: + /* Invalid VGParamType */ + SH_RETURN_ERR(VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + + } break; + + default: + /* Invalid resource handle */ + SH_ASSERT(rtype!=SH_RESOURCE_INVALID); + break; + } + + SH_RETURN(SH_NO_RETVAL); +} + +/*------------------------------------------------------------ + * Sets a resource parameter which takes a single float value + *------------------------------------------------------------*/ + +VG_API_CALL void vgSetParameterf(VGHandle object, VGint paramType, VGfloat value) +{ + SHResourceType resType; + VG_GETCONTEXT(VG_NO_RETVAL); + + /* Validate object */ + resType = shGetResourceType(context, object); + VG_RETURN_ERR_IF(resType == SH_RESOURCE_INVALID, + VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + /* Check if param vector */ + VG_RETURN_ERR_IF(shIsParamVector(paramType), + VG_ILLEGAL_ARGUMENT_ERROR, + VG_NO_RETVAL); + + /* Error code will be set by shSetParam() */ + shSetParameter(context, object, resType, paramType, 1, &value, 1); + VG_RETURN(VG_NO_RETVAL); +} + +/*-------------------------------------------------------------- + * Sets a resource parameter which takes a single integer value + *--------------------------------------------------------------*/ + +VG_API_CALL void vgSetParameteri(VGHandle object, VGint paramType, VGint value) +{ + SHResourceType resType; + VG_GETCONTEXT(VG_NO_RETVAL); + + /* Validate object */ + resType = shGetResourceType(context, object); + VG_RETURN_ERR_IF(resType == SH_RESOURCE_INVALID, + VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + /* Check if param vector */ + VG_RETURN_ERR_IF(shIsParamVector(paramType), + VG_ILLEGAL_ARGUMENT_ERROR, + VG_NO_RETVAL); + + /* Error code will be set by shSetParam() */ + shSetParameter(context, object, resType, paramType, 1, &value, 0); + VG_RETURN(VG_NO_RETVAL); +} + +/*---------------------------------------------------------------- + * Sets a resource parameter which takes a vector of float values + *----------------------------------------------------------------*/ + +VG_API_CALL void vgSetParameterfv(VGHandle object, VGint paramType, + VGint count, const VGfloat * values) +{ + SHResourceType resType; + VG_GETCONTEXT(VG_NO_RETVAL); + + /* Validate object */ + resType = shGetResourceType(context, object); + VG_RETURN_ERR_IF(resType == SH_RESOURCE_INVALID, + VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + /* TODO: Check for input array alignment */ + + /* Error code will be set by shSetParam() */ + shSetParameter(context, object, resType, paramType, count, values, 1); + VG_RETURN(VG_NO_RETVAL); +} + +/*------------------------------------------------------------------ + * Sets a resource parameter which takes a vector of integer values + *------------------------------------------------------------------*/ + +VG_API_CALL void vgSetParameteriv(VGHandle object, VGint paramType, + VGint count, const VGint * values) +{ + SHResourceType resType; + VG_GETCONTEXT(VG_NO_RETVAL); + + /* Validate object */ + resType = shGetResourceType(context, object); + VG_RETURN_ERR_IF(resType == SH_RESOURCE_INVALID, + VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + /* TODO: Check for input array alignment */ + + /* Error code will be set by shSetParam() */ + shSetParameter(context, object, resType, paramType, count, values, 0); + VG_RETURN(VG_NO_RETVAL); +} + +/*--------------------------------------------------------------- + * Outputs a resource parameter by interpreting the output value + * vector according to the parameter type and input type. + *---------------------------------------------------------------*/ + +static void shGetParameter(VGContext *context, VGHandle object, + SHResourceType rtype, VGint ptype, + SHint count, void *values, SHint floats) +{ + int i; + + /* Check for invalid array / count */ + SH_RETURN_ERR_IF(!values || count<=0, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + + switch (rtype) + { + case SH_RESOURCE_PATH: switch (ptype) { /* Path parameters */ + + case VG_PATH_FORMAT: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam(((SHPath*)object)->format, count, values, floats, 0); + break; + + case VG_PATH_DATATYPE: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam(((SHPath*)object)->datatype, count, values, floats, 0); + break; + + case VG_PATH_SCALE: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shFloatToParam(((SHPath*)object)->scale, count, values, floats, 0); + break; + + case VG_PATH_BIAS: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shFloatToParam(((SHPath*)object)->bias, count, values, floats, 0); + break; + + case VG_PATH_NUM_SEGMENTS: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam(((SHPath*)object)->segCount, count, values, floats, 0); + break; + + case VG_PATH_NUM_COORDS: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam(((SHPath*)object)->dataCount, count, values, floats, 0); + break; + + default: + /* Invalid VGParamType */ + SH_RETURN_ERR(VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + + } break; + case SH_RESOURCE_PAINT: switch (ptype) { /* Paint parameters */ + + case VG_PAINT_TYPE: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam(((SHPaint*)object)->type, count, values, floats, 0); + break; + + case VG_PAINT_COLOR: + SH_RETURN_ERR_IF(count > 4, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shFloatToParam(((SHPaint*)object)->color.r, count, values, floats, 0); + shFloatToParam(((SHPaint*)object)->color.g, count, values, floats, 1); + shFloatToParam(((SHPaint*)object)->color.b, count, values, floats, 2); + shFloatToParam(((SHPaint*)object)->color.a, count, values, floats, 3); + break; + + case VG_PAINT_COLOR_RAMP_SPREAD_MODE: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam(((SHPaint*)object)->spreadMode, count, values, floats, 0); + break; + + case VG_PAINT_COLOR_RAMP_PREMULTIPLIED: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam(((SHPaint*)object)->spreadMode, count, values, floats, 0); + break; + + case VG_PAINT_COLOR_RAMP_STOPS:{ + + int i; SHPaint* paint = (SHPaint*)object; SHStop *stop; + SH_RETURN_ERR_IF(count > paint->stops.size * 5, + VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + + for (i=0; istops.size; ++i) { + stop = &paint->stops.items[i]; + shFloatToParam(stop->offset, count, values, floats, i*5+0); + shFloatToParam(stop->color.r, count, values, floats, i*5+1); + shFloatToParam(stop->color.g, count, values, floats, i*5+2); + shFloatToParam(stop->color.b, count, values, floats, i*5+3); + shFloatToParam(stop->color.a, count, values, floats, i*5+4); + } + + break;} + + case VG_PAINT_LINEAR_GRADIENT: + SH_RETURN_ERR_IF(count > 4, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + for (i=0; i<4; ++i) + shFloatToParam(((SHPaint*)object)->linearGradient[i], + count, values, floats, i); + break; + + case VG_PAINT_RADIAL_GRADIENT: + SH_RETURN_ERR_IF(count > 5, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + for (i=0; i<5; ++i) + shFloatToParam(((SHPaint*)object)->radialGradient[i], + count, values, floats, i); + break; + + case VG_PAINT_PATTERN_TILING_MODE: + SH_RETURN_ERR_IF(count != 1, VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + shIntToParam(((SHPaint*)object)->tilingMode, count, values, floats, 0); + break; + + default: + /* Invalid VGParamType */ + SH_RETURN_ERR(VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + + } break; + case SH_RESOURCE_IMAGE: switch (ptype) { /* Image parameters */ + + /* TODO: output image parameters when image implemented */ + case VG_IMAGE_FORMAT: + break; + + case VG_IMAGE_WIDTH: + break; + + case VG_IMAGE_HEIGHT: + break; + + default: + /* Invalid VGParamType */ + SH_RETURN_ERR(VG_ILLEGAL_ARGUMENT_ERROR, SH_NO_RETVAL); + + } break; + + default: + /* Invalid resource handle */ + SH_ASSERT(rtype!=SH_RESOURCE_INVALID); + break; + } + + SH_RETURN(SH_NO_RETVAL); +} + +/*---------------------------------------------------------- + * Returns a resource parameter of a single float value + *----------------------------------------------------------*/ + +VG_API_CALL VGfloat vgGetParameterf(VGHandle object, VGint paramType) +{ + VGfloat retval = 0.0f; + SHResourceType resType; + VG_GETCONTEXT(retval); + + /* Validate object */ + resType = shGetResourceType(context, object); + VG_RETURN_ERR_IF(resType == SH_RESOURCE_INVALID, + VG_BAD_HANDLE_ERROR, retval); + + /* Check if param vector */ + VG_RETURN_ERR_IF(shIsParamVector(paramType), + VG_ILLEGAL_ARGUMENT_ERROR, retval); + + /* Error code will be set by shGetParameter() */ + shGetParameter(context, object, resType, paramType, 1, &retval, 1); + VG_RETURN(retval); +} + +/*---------------------------------------------------------- + * Returns a resource parameter of a single integer value + *----------------------------------------------------------*/ + +VG_API_CALL VGint vgGetParameteri(VGHandle object, VGint paramType) +{ + VGint retval = 0; + SHResourceType resType; + VG_GETCONTEXT(retval); + + /* Validate object */ + resType = shGetResourceType(context, object); + VG_RETURN_ERR_IF(resType == SH_RESOURCE_INVALID, + VG_BAD_HANDLE_ERROR, retval); + + /* Check if param vector */ + VG_RETURN_ERR_IF(shIsParamVector(paramType), + VG_ILLEGAL_ARGUMENT_ERROR, retval); + + /* Error code will be set by shGetParameter() */ + shGetParameter(context, object, resType, paramType, 1, &retval, 0); + VG_RETURN(retval); +} + +/*---------------------------------------------------------- + * Outputs a resource parameter of a float vector value + *----------------------------------------------------------*/ + +VG_API_CALL void vgGetParameterfv(VGHandle object, VGint paramType, + VGint count, VGfloat * values) +{ + SHResourceType resType; + VG_GETCONTEXT(VG_NO_RETVAL); + + /* Validate object */ + resType = shGetResourceType(context, object); + VG_RETURN_ERR_IF(resType == SH_RESOURCE_INVALID, + VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + /* TODO: Check output array alignment */ + + /* Error code will be set by shGetParameter() */ + shGetParameter(context, object, resType, paramType, count, values, 1); + VG_RETURN(VG_NO_RETVAL); +} + +/*---------------------------------------------------------- + * Outputs a resource parameter of an integer vector value + *----------------------------------------------------------*/ + +VG_API_CALL void vgGetParameteriv(VGHandle object, VGint paramType, + VGint count, VGint * values) +{ + SHResourceType resType; + VG_GETCONTEXT(VG_NO_RETVAL); + + /* Validate object */ + resType = shGetResourceType(context, object); + VG_RETURN_ERR_IF(resType == SH_RESOURCE_INVALID, + VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + /* TODO: Check output array alignment */ + + /* Error code will be set by shGetParameter() */ + shGetParameter(context, object, resType, paramType, count, values, 0); + VG_RETURN(VG_NO_RETVAL); +} + +/*--------------------------------------------------------- + * Returns the size of the output array required to + * receive the whole vector of resource parameter values + *---------------------------------------------------------*/ + +VG_API_CALL VGint vgGetParameterVectorSize(VGHandle object, VGint ptype) +{ + int retval = 0; + SHResourceType rtype; + VG_GETCONTEXT(retval); + + /* Validate object */ + rtype = shGetResourceType(context, object); + VG_RETURN_ERR_IF(rtype == SH_RESOURCE_INVALID, + VG_BAD_HANDLE_ERROR, retval); + + switch (rtype) + { + case SH_RESOURCE_PATH: switch (ptype) { /* Path parameters */ + + case VG_PATH_FORMAT: + case VG_PATH_DATATYPE: + case VG_PATH_SCALE: + case VG_PATH_BIAS: + case VG_PATH_NUM_SEGMENTS: + case VG_PATH_NUM_COORDS: + retval = 1; break; + + default: + /* Invalid VGParamType */ + VG_RETURN_ERR(VG_ILLEGAL_ARGUMENT_ERROR, retval); + + } break; + case SH_RESOURCE_PAINT: switch (ptype) { /* Paint parameters */ + + case VG_PAINT_TYPE: + retval = 1; break; + + case VG_PAINT_COLOR: + retval = 4; break; + + case VG_PAINT_COLOR_RAMP_SPREAD_MODE: + retval = 1; break; + + case VG_PAINT_COLOR_RAMP_PREMULTIPLIED: + retval = 1; break; + + case VG_PAINT_COLOR_RAMP_STOPS: + retval = ((SHPaint*)object)->stops.size*5; break; + + case VG_PAINT_LINEAR_GRADIENT: + retval = 4; break; + + case VG_PAINT_RADIAL_GRADIENT: + retval = 5; break; + + case VG_PAINT_PATTERN_TILING_MODE: + retval = 1; break; + + default: + /* Invalid VGParamType */ + VG_RETURN_ERR(VG_ILLEGAL_ARGUMENT_ERROR, retval); + + } break; + case SH_RESOURCE_IMAGE: switch (ptype) { /* Image parameters */ + + case VG_IMAGE_FORMAT: + case VG_IMAGE_WIDTH: + case VG_IMAGE_HEIGHT: + retval = 1; break; + + default: + /* Invalid VGParamType */ + VG_RETURN_ERR(VG_ILLEGAL_ARGUMENT_ERROR, retval); + + } break; + + default: + /* Invalid resource handle */ + SH_ASSERT(rtype!=SH_RESOURCE_INVALID); + break; + } + + VG_RETURN(retval); +} + +VG_API_CALL const VGubyte * vgGetString(VGStringID name) +{ + VG_GETCONTEXT(NULL); + + switch(name) { + case VG_VENDOR: + VG_RETURN((const VGubyte*)context->vendor); + case VG_RENDERER: + VG_RETURN((const VGubyte*)context->renderer); + case VG_VERSION: + VG_RETURN((const VGubyte*)context->version); + case VG_EXTENSIONS: + VG_RETURN((const VGubyte*)context->extensions); + default: + VG_RETURN(NULL); + } +} diff --git a/simgear/canvas/ShaderVG/src/shPath.c b/simgear/canvas/ShaderVG/src/shPath.c new file mode 100644 index 00000000..1b7f2588 --- /dev/null +++ b/simgear/canvas/ShaderVG/src/shPath.c @@ -0,0 +1,1305 @@ +/* + * Copyright (c) 2007 Ivan Leben + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#define VG_API_EXPORT +#include "vg/openvg.h" +#include "shContext.h" +#include "shPath.h" +#include +#include + +#define _ITEM_T SHVertex +#define _ARRAY_T SHVertexArray +#define _FUNC_T shVertexArray +#define _COMPARE_T(v1,v2) 0 +#define _ARRAY_DEFINE +#include "shArrayBase.h" + +#define _ITEM_T SHPath* +#define _ARRAY_T SHPathArray +#define _FUNC_T shPathArray +#define _ARRAY_DEFINE +#include "shArrayBase.h" + + +static const SHint shCoordsPerCommand[] = { + 0, /* VG_CLOSE_PATH */ + 2, /* VG_MOTE_TO */ + 2, /* VG_LINE_TO */ + 1, /* VG_HLINE_TO */ + 1, /* VG_VLINE_TO */ + 4, /* VG_QUAD_TO */ + 6, /* VG_CUBIC_TO */ + 2, /* VG_SQUAD_TO */ + 4, /* VG_SCUBIC_TO */ + 5, /* VG_SCCWARC_TO */ + 5, /* VG_SCWARC_TO */ + 5, /* VG_LCCWARC_TO */ + 5 /* VG_LCWARC_TO */ +}; + +#define SH_PATH_MAX_COORDS 6 +#define SH_PATH_MAX_COORDS_PROCESSED 12 + +static const SHint shBytesPerDatatype[] = { + 1, /* VG_PATH_DATATYPE_S_8 */ + 2, /* VG_PATH_DATATYPE_S_16 */ + 4, /* VG_PATH_DATATYPE_S_32 */ + 4 /* VG_PATH_DATATYPE_F */ +}; + +#define SH_PATH_MAX_BYTES 4 + +/*----------------------------------------------------- + * Path constructor + *-----------------------------------------------------*/ + +void shClearSegCallbacks(SHPath *p); +void SHPath_ctor(SHPath *p) +{ + p->format = 0; + p->scale = 0.0f; + p->bias = 0.0f; + p->caps = 0; + p->datatype = VG_PATH_DATATYPE_F; + + p->segs = NULL; + p->data = NULL; + p->segCount = 0; + p->dataCount = 0; + + SH_INITOBJ(SHVertexArray, p->vertices); + SH_INITOBJ(SHVector2Array, p->stroke); +} + +/*----------------------------------------------------- + * Path destructor + *-----------------------------------------------------*/ + +void SHPath_dtor(SHPath *p) +{ + if (p->segs) free(p->segs); + if (p->data) free(p->data); + + SH_DEINITOBJ(SHVertexArray, p->vertices); + SH_DEINITOBJ(SHVector2Array, p->stroke); +} + +/*----------------------------------------------------- + * Returns true (1) if given path data type is valid + *-----------------------------------------------------*/ + +static SHint shIsValidDatatype(VGPathDatatype t) +{ + return (t == VG_PATH_DATATYPE_S_8 || + t == VG_PATH_DATATYPE_S_16 || + t == VG_PATH_DATATYPE_S_32 || + t == VG_PATH_DATATYPE_F); +} + +static SHint shIsValidCommand(SHint c) +{ + return (c >= (VG_CLOSE_PATH >> 1) && + c <= (VG_LCWARC_TO >> 1)); +} + +static SHint shIsArcSegment(SHint s) +{ + return (s == VG_SCWARC_TO || s == VG_SCCWARC_TO || + s == VG_LCWARC_TO || s == VG_LCCWARC_TO); +} + +/*------------------------------------------------------- + * Allocates a path resource in the current context and + * sets its capabilities. + *-------------------------------------------------------*/ + +VG_API_CALL VGPath vgCreatePath(VGint pathFormat, + VGPathDatatype datatype, + VGfloat scale, VGfloat bias, + VGint segmentCapacityHint, + VGint coordCapacityHint, + VGbitfield capabilities) +{ + SHPath *p = NULL; + VG_GETCONTEXT(VG_INVALID_HANDLE); + + /* Only standard format supported */ + VG_RETURN_ERR_IF(pathFormat != VG_PATH_FORMAT_STANDARD, + VG_UNSUPPORTED_PATH_FORMAT_ERROR, + VG_INVALID_HANDLE); + + /* Dataype must be valid, scale not zero */ + VG_RETURN_ERR_IF(!shIsValidDatatype(datatype) || scale == 0.0f, + VG_ILLEGAL_ARGUMENT_ERROR, VG_INVALID_HANDLE); + + /* Allocate new resource */ + SH_NEWOBJ(SHPath, p); + VG_RETURN_ERR_IF(!p, VG_OUT_OF_MEMORY_ERROR, VG_INVALID_HANDLE); + shPathArrayPushBack(&context->paths, p); + + /* Set parameters */ + p->format = pathFormat; + p->scale = scale; + p->bias = bias; + p->segHint = segmentCapacityHint; + p->dataHint = coordCapacityHint; + p->datatype = datatype; + p->caps = capabilities & VG_PATH_CAPABILITY_ALL; + + /* Init cache flags */ + p->cacheDataValid = VG_TRUE; + p->cacheTransformInit = VG_FALSE; + p->cacheStrokeInit = VG_FALSE; + + VG_RETURN((VGPath)p); +} + +/*----------------------------------------------------- + * Clears the specified path of all data and sets new + * capabilities to it. + *-----------------------------------------------------*/ + +VG_API_CALL void vgClearPath(VGPath path, VGbitfield capabilities) +{ + SHPath *p = NULL; + VG_GETCONTEXT(VG_NO_RETVAL); + + VG_RETURN_ERR_IF(!shIsValidPath(context, path), + VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + /* Clear raw data */ + p = (SHPath*)path; + free(p->segs); + free(p->data); + p->segs = NULL; + p->data = NULL; + p->segCount = 0; + p->dataCount = 0; + + /* Mark change */ + p->cacheDataValid = VG_FALSE; + + /* Downsize arrays to save memory */ + shVertexArrayRealloc(&p->vertices, 1); + shVector2ArrayRealloc(&p->stroke, 1); + + /* Re-set capabilities */ + p->caps = capabilities & VG_PATH_CAPABILITY_ALL; + + VG_RETURN(VG_NO_RETVAL); +} + +/*--------------------------------------------------------- + * Disposes specified path resource in the current context + *---------------------------------------------------------*/ + +VG_API_CALL void vgDestroyPath(VGPath path) +{ + int index; + VG_GETCONTEXT(VG_NO_RETVAL); + + /* Check if handle valid */ + index = shPathArrayFind(&context->paths, (SHPath*)path); + VG_RETURN_ERR_IF(index == -1, VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + /* Delete object and remove resource */ + SH_DELETEOBJ(SHPath, (SHPath*)path); + shPathArrayRemoveAt(&context->paths, index); + + VG_RETURN_ERR(VG_NO_ERROR, VG_NO_RETVAL); +} + +/*----------------------------------------------------- + * Removes capabilities defined in the given bitfield + * from the specified path. + *-----------------------------------------------------*/ + +VG_API_CALL void vgRemovePathCapabilities(VGPath path, VGbitfield capabilities) +{ + VG_GETCONTEXT(VG_NO_RETVAL); + + VG_RETURN_ERR_IF(!shIsValidPath(context, path), + VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + capabilities &= VG_PATH_CAPABILITY_ALL; + ((SHPath*)path)->caps &= ~capabilities; + + VG_RETURN(VG_NO_RETVAL); +} + +/*----------------------------------------------------- + * Returns capabilities of a path resource + *-----------------------------------------------------*/ + +VG_API_CALL VGbitfield vgGetPathCapabilities(VGPath path) +{ + VG_GETCONTEXT(0x0); + + VG_RETURN_ERR_IF(!shIsValidPath(context, path), + VG_BAD_HANDLE_ERROR, 0x0); + + VG_RETURN( ((SHPath*)path)->caps ); +} + +/*----------------------------------------------------- + * Walks the given path segments and returns the total + * number of coordinates. + *-----------------------------------------------------*/ + +static SHint shCoordCountForData(VGint segcount, const SHuint8 *segs) +{ + int s; + int command; + int count = 0; + + for (s=0; s> 1); + if (!shIsValidCommand(command)) return -1; + count += shCoordsPerCommand[command]; + } + + return count; +} + +/*------------------------------------------------------- + * Interpretes the path data array according to the + * path data type and returns the value at given index + * in final interpretation (including scale and bias) + *-------------------------------------------------------*/ + +static SHfloat shRealCoordFromData(VGPathDatatype type, SHfloat scale, SHfloat bias, + void *data, SHint index) +{ + switch (type) { + case VG_PATH_DATATYPE_S_8: + return ( (SHfloat) ((SHint8*)data)[index] ) * scale + bias; + case VG_PATH_DATATYPE_S_16: + return ( (SHfloat) ((SHint16*)data)[index] ) * scale + bias; + case VG_PATH_DATATYPE_S_32: + return ( (SHfloat) ((SHint32*)data)[index] ) * scale + bias;; + default: + return ( (SHfloat) ((SHfloat32*)data)[index] ) * scale + bias; + } +} + +/*------------------------------------------------------- + * Interpretes the path data array according to the + * path data type and sets the value at given index + * from final interpretation (including scale and bias) + *-------------------------------------------------------*/ + +static void shRealCoordToData(VGPathDatatype type, SHfloat scale, SHfloat bias, + void *data, SHint index, SHfloat c) +{ + c -= bias; + c /= scale; + + switch (type) { + case VG_PATH_DATATYPE_S_8: + ((SHint8*)data) [index] = (SHint8)SH_FLOOR(c + 0.5f); break; + case VG_PATH_DATATYPE_S_16: + ((SHint16*)data) [index] = (SHint16)SH_FLOOR(c + 0.5f); break; + case VG_PATH_DATATYPE_S_32: + ((SHint32*)data) [index] = (SHint32)SH_FLOOR(c + 0.5f); break; + default: + ((SHfloat32*)data) [index] = (SHfloat32)c; break; + } +} + +/*------------------------------------------------- + * Resizes storage for segment and coordinate data + * of the specified path by given number of items + *-------------------------------------------------*/ + +static int shResizePathData(SHPath *p, SHint newSegCount, SHint newDataCount, + SHuint8 **newSegs, SHuint8 **newData) +{ + SHint oldDataSize = 0; + SHint newDataSize = 0; + + /* Allocate memory for new segments */ + (*newSegs) = (SHuint8*)malloc(p->segCount + newSegCount); + if ((*newSegs) == NULL) return 0; + + /* Allocate memory for new data */ + oldDataSize = p->dataCount * shBytesPerDatatype[p->datatype]; + newDataSize = newDataCount * shBytesPerDatatype[p->datatype]; + (*newData) = (SHuint8*)malloc(oldDataSize + newDataSize); + if ((*newData) == NULL) {free(*newSegs); return 0;} + + /* Copy old segments */ + memcpy(*newSegs, p->segs, p->segCount); + + /* Copy old data */ + memcpy(*newData, p->data, oldDataSize); + + return 1; +} + +/*------------------------------------------------------------- + * Appends path data from source to destination path resource + *-------------------------------------------------------------*/ + +VG_API_CALL void vgAppendPath(VGPath dstPath, VGPath srcPath) +{ + int i; + SHPath *src, *dst; + SHuint8 *newSegs = NULL; + SHuint8 *newData = NULL; + VG_GETCONTEXT(VG_NO_RETVAL); + + VG_RETURN_ERR_IF(!shIsValidPath(context, srcPath) || + !shIsValidPath(context, dstPath), + VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + src = (SHPath*)srcPath; dst = (SHPath*)dstPath; + VG_RETURN_ERR_IF(!(src->caps & VG_PATH_CAPABILITY_APPEND_FROM) || + !(dst->caps & VG_PATH_CAPABILITY_APPEND_TO), + VG_PATH_CAPABILITY_ERROR, VG_NO_RETVAL); + + /* Resize path storage */ + shResizePathData(dst, src->segCount, src->dataCount, &newSegs, &newData); + VG_RETURN_ERR_IF(!newData, VG_OUT_OF_MEMORY_ERROR, VG_NO_RETVAL); + + /* Copy new segments */ + memcpy(newSegs+dst->segCount, src->segs, src->segCount); + + /* Copy new coordinates */ + for (i=0; idataCount; ++i) { + + SHfloat coord = shRealCoordFromData(src->datatype, src->scale, + src->bias, src->data, i); + + shRealCoordToData(dst->datatype, dst->scale, dst->bias, + newData, dst->dataCount+i, coord); + } + + /* Free old arrays */ + free(dst->segs); + free(dst->data); + + /* Adjust new properties */ + dst->segs = newSegs; + dst->data = newData; + dst->segCount += src->segCount; + dst->dataCount += src->dataCount; + + /* Mark change */ + dst->cacheDataValid = VG_FALSE; + + VG_RETURN(VG_NO_RETVAL); +} + +/*----------------------------------------------------- + * Appends data to destination path resource + *-----------------------------------------------------*/ + +SHfloat shValidInputFloat(VGfloat f); +VG_API_CALL void vgAppendPathData(VGPath dstPath, VGint newSegCount, + const VGubyte *segs, const void *data) +{ + int i; + SHPath *dst = NULL; + SHint newDataCount = 0; + SHint oldDataSize = 0; + SHint newDataSize = 0; + SHuint8 *newSegs = NULL; + SHuint8 *newData = NULL; + VG_GETCONTEXT(VG_NO_RETVAL); + + VG_RETURN_ERR_IF(!shIsValidPath(context, dstPath), + VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + dst = (SHPath*)dstPath; + VG_RETURN_ERR_IF(!(dst->caps & VG_PATH_CAPABILITY_APPEND_TO), + VG_PATH_CAPABILITY_ERROR, VG_NO_RETVAL); + + VG_RETURN_ERR_IF(!segs || !data || newSegCount <= 0, + VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL); + + /* TODO: check segment + data array alignment */ + + /* Count number of coordinatess in appended data */ + newDataCount = shCoordCountForData(newSegCount, segs); + newDataSize = newDataCount * shBytesPerDatatype[dst->datatype]; + oldDataSize = dst->dataCount * shBytesPerDatatype[dst->datatype]; + VG_RETURN_ERR_IF(newDataCount == -1, VG_ILLEGAL_ARGUMENT_ERROR, + VG_NO_RETVAL); + + /* Resize path storage */ + shResizePathData(dst, newSegCount, newDataCount, &newSegs, &newData); + VG_RETURN_ERR_IF(!newData, VG_OUT_OF_MEMORY_ERROR, VG_NO_RETVAL); + + /* Copy new segments */ + memcpy(newSegs+dst->segCount, segs, newSegCount); + + /* Copy new coordinates */ + if (dst->datatype == VG_PATH_DATATYPE_F) { + for (i=0; idataCount+i] = + shValidInputFloat( ((VGfloat*)data) [i] ); + }else{ + memcpy(newData+oldDataSize, data, newDataSize); + } + + /* Free old arrays */ + free(dst->segs); + free(dst->data); + + /* Adjust new properties */ + dst->segs = newSegs; + dst->data = newData; + dst->segCount += newSegCount; + dst->dataCount += newDataCount; + + /* Mark change */ + dst->cacheDataValid = VG_FALSE; + + VG_RETURN(VG_NO_RETVAL); +} + +/*-------------------------------------------------------- + * Modifies the coordinates of the existing path segments + *--------------------------------------------------------*/ + +VG_API_CALL void vgModifyPathCoords(VGPath dstPath, VGint startIndex, + VGint numSegments, const void * data) +{ + int i; + SHPath *p; + SHint newDataCount; + SHint newDataSize; + SHint dataStartCount; + SHint dataStartSize; + VG_GETCONTEXT(VG_NO_RETVAL); + + VG_RETURN_ERR_IF(!shIsValidPath(context, dstPath), + VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + p = (SHPath*)dstPath; + VG_RETURN_ERR_IF(!(p->caps & VG_PATH_CAPABILITY_MODIFY), + VG_PATH_CAPABILITY_ERROR, VG_NO_RETVAL); + + VG_RETURN_ERR_IF(!data || startIndex<0 || numSegments <=0 || + startIndex + numSegments > p->segCount, + VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL); + + /* TODO: check data array alignment */ + + /* Find start of the coordinates to be changed */ + dataStartCount = shCoordCountForData(startIndex, p->segs); + dataStartSize = dataStartCount * shBytesPerDatatype[p->datatype]; + + /* Find byte size of coordinates to be changed */ + newDataCount = shCoordCountForData(numSegments, &p->segs[startIndex]); + newDataSize = newDataCount * shBytesPerDatatype[p->datatype]; + + /* Copy new coordinates */ + if (p->datatype == VG_PATH_DATATYPE_F) { + for (i=0; idata) [dataStartCount+i] = + shValidInputFloat( ((VGfloat*)data) [i] ); + }else{ + memcpy( ((SHuint8*)p->data) + dataStartSize, data, newDataSize); + } + + /* Mark change */ + p->cacheDataValid = VG_FALSE; + + VG_RETURN(VG_NO_RETVAL); +} + +/*------------------------------------------------------------ + * Converts standart endpoint arc parametrization into center + * arc parametrization for further internal processing + *------------------------------------------------------------*/ + +SHint shCentralizeArc(SHuint command, SHfloat *data) +{ + SHfloat rx,ry,r,a; + SHVector2 p1, p2, pp1,pp2; + SHVector2 d, dt; + SHfloat dist, halfdist, q; + SHVector2 c1, c2, *c; + SHVector2 pc1, pc2; + SHfloat a1, ad, a2; + SHVector2 ux, uy; + SHMatrix3x3 user2arc; + SHMatrix3x3 arc2user; + + rx = data[2]; + ry = data[3]; + a = SH_DEG2RAD(data[4]); + SET2(p1, data[0], data[1]); + SET2(p2, data[5], data[6]); + + /* Check for invalid radius and return line */ + if (SH_NEARZERO(rx) || SH_NEARZERO(ry)) { + data[2] = p2.x; data[3] = p2.y; + return 0; + } + + /* Rotate to arc coordinates. + Scale to correct eccentricity. */ + IDMAT(user2arc); + ROTATEMATL(user2arc, -a); + SCALEMATL(user2arc, 1, rx/ry); + TRANSFORM2TO(p1, user2arc, pp1); + TRANSFORM2TO(p2, user2arc, pp2); + + /* Distance between points and + perpendicular vector */ + SET2V(d, pp2); SUB2V(d, pp1); + dist = NORM2(d); + halfdist = dist * 0.5f; + SET2(dt, -d.y, d.x); + DIV2(dt, dist); + + /* Check if too close and return line */ + if (halfdist == 0.0f) { + data[2] = p2.x; data[3] = p2.y; + return 0; + } + + /* Scale radius if too far away */ + r = rx; + if (halfdist > rx) + r = halfdist; + + /* Intersections of circles centered to start and + end point. (i.e. centers of two possible arcs) */ + q = SH_SIN(SH_ACOS(halfdist/r)) * r; + if (SH_ISNAN(q)) q = 0.0f; + c1.x = pp1.x + d.x/2 + dt.x * q; + c1.y = pp1.y + d.y/2 + dt.y * q; + c2.x = pp1.x + d.x/2 - dt.x * q; + c2.y = pp1.y + d.y/2 - dt.y * q; + + /* Pick the right arc center */ + switch (command & 0x1E) { + case VG_SCWARC_TO: case VG_LCCWARC_TO: + c = &c2; break; + case VG_LCWARC_TO: case VG_SCCWARC_TO: + c = &c1; break; + default: + c = &c1; + } + + /* Find angles of p1,p2 towards the chosen center */ + SET2V(pc1, pp1); SUB2V(pc1, (*c)); + SET2V(pc2, pp2); SUB2V(pc2, (*c)); + a1 = shVectorOrientation(&pc1); + + /* Correct precision error when ry very small + (q gets very large and points very far appart) */ + if (SH_ISNAN(a1)) a1 = 0.0f; + + /* Small or large one? */ + switch (command & 0x1E) { + case VG_SCWARC_TO: case VG_SCCWARC_TO: + ad = ANGLE2(pc1,pc2); break; + case VG_LCWARC_TO: case VG_LCCWARC_TO: + ad = 2*PI - ANGLE2(pc1,pc2); break; + default: + ad = 0.0f; + } + + /* Correct precision error when solution is single + (pc1 and pc2 are nearly collinear but not really) */ + if (SH_ISNAN(ad)) ad = PI; + + /* CW or CCW? */ + switch (command & 0x1E) { + case VG_SCWARC_TO: case VG_LCWARC_TO: + a2 = a1 - ad; break; + case VG_SCCWARC_TO: case VG_LCCWARC_TO: + a2 = a1 + ad; break; + default: + a2 = a1; + } + + /* Arc unit vectors */ + SET2(ux, r, 0); + SET2(uy, 0, r); + + /* Transform back to user coordinates */ + IDMAT(arc2user); + SCALEMATL(arc2user, 1, ry/rx); + ROTATEMATL(arc2user, a); + TRANSFORM2((*c), arc2user); + TRANSFORM2(ux, arc2user); + TRANSFORM2(uy, arc2user); + + /* Write out arc coords */ + data[2] = c->x; data[3] = c->y; + data[4] = ux.x; data[5] = ux.y; + data[6] = uy.x; data[7] = uy.y; + data[8] = a1; data[9] = a2; + data[10] = p2.x; data[11] = p2.y; + return 1; +} + +/*------------------------------------------------------- + * Walks the raw (standard) path data and simplifies the + * complex and implicit segments according to given + * simplificatin request flags. Instead of storing the + * processed data into another array, the given callback + * function is called, so we don't need to walk the + * raw data twice just to find the neccessary memory + * size for processed data. + *-------------------------------------------------------*/ + +#define SH_PROCESS_SIMPLIFY_LINES (1 << 0) +#define SH_PROCESS_SIMPLIFY_CURVES (1 << 1) +#define SH_PROCESS_CENTRALIZE_ARCS (1 << 2) +#define SH_PROCESS_REPAIR_ENDS (1 << 3) + +void shProcessPathData(SHPath *p, + int flags, + SegmentFunc callback, + void *userData) +{ + SHint i=0, s=0, d=0, c=0; + SHuint command; + SHuint segment; + SHint segindex; + VGPathAbsRel absrel; + SHint numcoords; + SHfloat data[SH_PATH_MAX_COORDS_PROCESSED]; + SHVector2 start; /* start of the current contour */ + SHVector2 pen; /* current pen position */ + SHVector2 tan; /* backward tangent for smoothing */ + SHint open = 0; /* contour-open flag */ + + /* Reset points */ + SET2(start, 0,0); + SET2(pen, 0,0); + SET2(tan, 0,0); + + for (s=0; ssegCount; ++s, d+=numcoords) { + + /* Extract command */ + command = (p->segs[s]); + absrel = (command & 1); + segment = (command & 0x1E); + segindex = (segment >> 1); + numcoords = shCoordsPerCommand[segindex]; + + /* Repair segment start / end */ + if (flags & SH_PROCESS_REPAIR_ENDS) { + + /* Prevent double CLOSE_PATH */ + if (!open && segment == VG_CLOSE_PATH) + continue; + + /* Implicit MOVE_TO if segment starts without */ + if (!open && segment != VG_MOVE_TO) { + data[0] = pen.x; data[1] = pen.y; + data[2] = pen.x; data[3] = pen.y; + (*callback)(p,VG_MOVE_TO,command,data,userData); + open = 1; + } + + /* Avoid a MOVE_TO at the end of data */ + if (segment == VG_MOVE_TO) { + if (s == p->segCount-1) break; + else { + /* Avoid a lone MOVE_TO */ + SHuint nextsegment = (p->segs[s+1] & 0x1E); + if (nextsegment == VG_MOVE_TO) + {open = 0; continue;} + }} + } + + /* Place pen into first two coords */ + data[0] = pen.x; + data[1] = pen.y; + c = 2; + + /* Unpack coordinates from path data */ + for (i=0; idatatype, p->scale, p->bias, + p->data, d+i); + + /* Simplify complex segments */ + switch (segment) + { + case VG_CLOSE_PATH: + + data[2] = start.x; + data[3] = start.y; + + SET2V(pen, start); + SET2V(tan, start); + open = 0; + + (*callback)(p,VG_CLOSE_PATH,command,data,userData); + + break; + case VG_MOVE_TO: + + if (absrel == VG_RELATIVE) { + data[2] += pen.x; data[3] += pen.y; + } + + SET2(pen, data[2], data[3]); + SET2V(start, pen); + SET2V(tan, pen); + open = 1; + + (*callback)(p,VG_MOVE_TO,command,data,userData); + + break; + case VG_LINE_TO: + + if (absrel == VG_RELATIVE) { + data[2] += pen.x; data[3] += pen.y; + } + + SET2(pen, data[2], data[3]); + SET2V(tan, pen); + + (*callback)(p,VG_LINE_TO,command,data,userData); + + break; + case VG_HLINE_TO: + + if (absrel == VG_RELATIVE) + data[2] += pen.x; + + SET2(pen, data[2], pen.y); + SET2V(tan, pen); + + if (flags & SH_PROCESS_SIMPLIFY_LINES) { + data[3] = pen.y; + (*callback)(p,VG_LINE_TO,command,data,userData); + break; + } + + (*callback)(p,VG_HLINE_TO,command,data,userData); + + break; + case VG_VLINE_TO: + + if (absrel == VG_RELATIVE) + data[2] += pen.y; + + SET2(pen, pen.x, data[2]); + SET2V(tan, pen); + + if (flags & SH_PROCESS_SIMPLIFY_LINES) { + data[2] = pen.x; data[3] = pen.y; + (*callback)(p,VG_LINE_TO,command,data,userData); + break; + } + + (*callback)(p,VG_VLINE_TO,command,data,userData); + + break; + case VG_QUAD_TO: + + if (absrel == VG_RELATIVE) { + data[2] += pen.x; data[3] += pen.y; + data[4] += pen.x; data[5] += pen.y; + } + + SET2(tan, data[2], data[3]); + SET2(pen, data[4], data[5]); + + (*callback)(p,VG_QUAD_TO,command,data,userData); + + break; + case VG_CUBIC_TO: + + if (absrel == VG_RELATIVE) { + data[2] += pen.x; data[3] += pen.y; + data[4] += pen.x; data[5] += pen.y; + data[6] += pen.x; data[7] += pen.y; + } + + SET2(tan, data[4], data[5]); + SET2(pen, data[6], data[7]); + + (*callback)(p,VG_CUBIC_TO,command,data,userData); + + break; + case VG_SQUAD_TO: + + if (absrel == VG_RELATIVE) { + data[2] += pen.x; data[3] += pen.y; + } + + SET2(tan, 2*pen.x - tan.x, 2*pen.y - tan.y); + SET2(pen, data[2], data[3]); + + if (flags & SH_PROCESS_SIMPLIFY_CURVES) { + data[2] = tan.x; data[3] = tan.y; + data[4] = pen.x; data[5] = pen.y; + (*callback)(p,VG_QUAD_TO,command,data,userData); + break; + } + + (*callback)(p,VG_SQUAD_TO,command,data,userData); + + break; + case VG_SCUBIC_TO: + + if (absrel == VG_RELATIVE) { + data[2] += pen.x; data[3] += pen.y; + data[4] += pen.x; data[5] += pen.y; + } + + SET2(tan, data[2], data[3]); + SET2(pen, data[4], data[5]); + + if (flags & SH_PROCESS_SIMPLIFY_CURVES) { + data[2] = 2*pen.x - tan.x; + data[3] = 2*pen.y - tan.y; + data[4] = tan.x; data[5] = tan.y; + data[6] = pen.x; data[7] = pen.y; + (*callback)(p,VG_CUBIC_TO,command,data,userData); + break; + } + + (*callback)(p,VG_SCUBIC_TO,command,data,userData); + + break; + case VG_SCWARC_TO: case VG_SCCWARC_TO: + case VG_LCWARC_TO: case VG_LCCWARC_TO: + + if (absrel == VG_RELATIVE) { + data[5] += pen.x; data[6] += pen.y; + } + + data[2] = SH_ABS(data[2]); + data[3] = SH_ABS(data[3]); + + SET2(tan, data[5], data[6]); + SET2V(pen, tan); + + if (flags & SH_PROCESS_CENTRALIZE_ARCS) { + if (shCentralizeArc(command, data)) + (*callback)(p,segment,command,data,userData); + else + (*callback)(p,VG_LINE_TO,command,data,userData); + break; + } + + (*callback)(p,segment,command,data,userData); + break; + + } /* switch (command) */ + } /* for each segment */ +} + +/*------------------------------------------------------- + * Walks raw path data and counts the resulting number + * of segments and coordinates if the simplifications + * specified in the given processing flags were applied. + *-------------------------------------------------------*/ + +static void shProcessedDataCount(SHPath *p, SHint flags, + SHint *segCount, SHint *dataCount) +{ + SHint s, segment, segindex; + *segCount = 0; *dataCount = 0; + + for (s=0; ssegCount; ++s) { + + segment = (p->segs[s] & 0x1E); + segindex = (segment >> 1); + + switch (segment) { + case VG_HLINE_TO: case VG_VLINE_TO: + + if (flags & SH_PROCESS_SIMPLIFY_LINES) + *dataCount += shCoordsPerCommand[VG_LINE_TO >> 1]; + else *dataCount += shCoordsPerCommand[segindex]; + break; + + case VG_SQUAD_TO: + + if (flags & SH_PROCESS_SIMPLIFY_CURVES) + *dataCount += shCoordsPerCommand[VG_QUAD_TO >> 1]; + else *dataCount += shCoordsPerCommand[segindex]; + break; + + case VG_SCUBIC_TO: + + if (flags & SH_PROCESS_SIMPLIFY_CURVES) + *dataCount += shCoordsPerCommand[VG_CUBIC_TO >> 1]; + else *dataCount += shCoordsPerCommand[segindex]; + break; + + case VG_SCWARC_TO: case VG_SCCWARC_TO: + case VG_LCWARC_TO: case VG_LCCWARC_TO: + + if (flags & SH_PROCESS_CENTRALIZE_ARCS) + *dataCount += 10; + else *dataCount += shCoordsPerCommand[segindex]; + break; + + default: + *dataCount += shCoordsPerCommand[segindex]; + } + + *segCount += 1; + } +} + +static void shTransformSegment(SHPath *p, VGPathSegment segment, + VGPathCommand originalCommand, + SHfloat *data, void *userData) +{ + int i, numPoints; SHVector2 point; + SHuint8* newSegs = (SHuint8*) ((void**)userData)[0]; + SHint* segCount = (SHint*) ((void**)userData)[1]; + SHuint8* newData = (SHuint8*) ((void**)userData)[2]; + SHint* dataCount = (SHint*) ((void**)userData)[3]; + SHPath* dst = (SHPath*) ((void**)userData)[4]; + SHMatrix3x3 *ctm; + + /* Get current transform matrix */ + VG_GETCONTEXT(VG_NO_RETVAL); + ctm = &context->pathTransform; + + switch (segment) { + case VG_CLOSE_PATH: + + /* No cordinates for this segment */ + + break; + case VG_MOVE_TO: + case VG_LINE_TO: + case VG_QUAD_TO: + case VG_CUBIC_TO: + case VG_SQUAD_TO: + case VG_SCUBIC_TO: + + /* Walk over control points */ + numPoints = shCoordsPerCommand[segment >> 1] / 2; + for (i=0; idatatype, dst->scale, dst->bias, + newData, (*dataCount)++, point.x); + + shRealCoordToData(dst->datatype, dst->scale, dst->bias, + newData, (*dataCount)++, point.y); + } + + break; + default:{ + + SHMatrix3x3 u, u2; + SHfloat a, cosa, sina, rx, ry; + SHfloat A,B,C,AC,K,A2,C2; + SHint invertible; + SHVector2 p; + SHfloat out[5]; + SHint i; + + SH_ASSERT(segment==VG_SCWARC_TO || segment==VG_SCCWARC_TO || + segment==VG_LCWARC_TO || segment==VG_LCCWARC_TO); + + rx = data[2]; ry = data[3]; + a = SH_DEG2RAD(data[4]); + cosa = SH_COS(a); sina = SH_SIN(a); + + /* Center parametrization of the elliptical arc. */ + SETMAT(u, rx * cosa, -ry * sina, 0, + rx * sina, ry * cosa, 0, + 0, 0, 1); + + /* Add current transformation */ + MULMATMAT((*ctm), u, u2); + + /* Inverse (transforms ellipse back to unit circle) */ + invertible = shInvertMatrix(&u2, &u); + if (!invertible) { + + /* Zero-out radii and rotation */ + out[0] = out[1] = out[2] = 0.0f; + + }else{ + + /* Extract implicit ellipse equation */ + A = u.m[0][0]*u.m[0][0] + u.m[1][0]*u.m[1][0]; + B = 2*( u.m[0][0]*u.m[0][1] + u.m[1][0]*u.m[1][1] ); + C = u.m[0][1]*u.m[0][1] + u.m[1][1]*u.m[1][1]; + AC = A-C; + + /* Find rotation and new radii */ + if (B == 0.0f) { + + /* 0 or 90 degree */ + out[2] = 0.0f; + A2 = A; + C2 = C; + + }else if (AC == 0.0f) { + + /* 45 degree */ + out[2] = PI/4; + out[2] = SH_RAD2DEG(out[2]); + A2 = A + B * 0.5f; + C2 = A - B * 0.5f; + + }else{ + + /* Any other angle */ + out[2] = 0.5f * SH_ATAN(B / AC); + out[2] = SH_RAD2DEG(out[2]); + + K = 1 + (B*B) / (AC*AC); + if (K <= 0.0f) K = 0.0f; + else K = SH_SQRT(K); + + A2 = 0.5f * (A + C + K*AC); + C2 = 0.5f * (A + C - K*AC); + } + + /* New radii */ + out[0] = (A2 <= 0.0f ? 0.0f : 1 / SH_SQRT(A2)); + out[1] = (C2 <= 0.0f ? 0.0f : 1 / SH_SQRT(C2)); + + /* Check for a mirror component in the transform matrix */ + if (ctm->m[0][0] * ctm->m[1][1] - ctm->m[1][0] * ctm->m[0][1] < 0.0f) { + switch (segment) { + case VG_SCWARC_TO: segment = VG_SCCWARC_TO; break; + case VG_LCWARC_TO: segment = VG_LCCWARC_TO; break; + case VG_SCCWARC_TO: segment = VG_SCWARC_TO; break; + case VG_LCCWARC_TO: segment = VG_LCWARC_TO; break; + default: break; } + } + + }/* if (invertible) */ + + /* Transform target point */ + SET2(p, data[5], data[6]); + TRANSFORM2(p, context->pathTransform); + out[3] = p.x; out[4] = p.y; + + /* Write coordinates back to path data */ + for (i=0; i<5; ++i) + shRealCoordToData(dst->datatype, dst->scale, dst->bias, + newData, (*dataCount)++, out[i]); + + break;} + } + + /* Write segment to new dst path data */ + newSegs[(*segCount)++] = segment | VG_ABSOLUTE; +} + +VG_API_CALL void vgTransformPath(VGPath dstPath, VGPath srcPath) +{ + SHint newSegCount=0; + SHint newDataCount=0; + SHPath *src, *dst; + SHuint8 *newSegs = NULL; + SHuint8 *newData = NULL; + SHint segCount = 0; + SHint dataCount = 0; + void *userData[5]; + SHint processFlags = + SH_PROCESS_SIMPLIFY_LINES; + + VG_GETCONTEXT(VG_NO_RETVAL); + + VG_RETURN_ERR_IF(!shIsValidPath(context, dstPath) || + !shIsValidPath(context, srcPath), + VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + src = (SHPath*)srcPath; dst = (SHPath*)dstPath; + VG_RETURN_ERR_IF(!(src->caps & VG_PATH_CAPABILITY_TRANSFORM_FROM) || + !(dst->caps & VG_PATH_CAPABILITY_TRANSFORM_TO), + VG_PATH_CAPABILITY_ERROR, VG_NO_RETVAL); + + /* Resize path storage */ + shProcessedDataCount(src, processFlags, &newSegCount, &newDataCount); + shResizePathData(dst, newSegCount, newDataCount, &newSegs, &newData); + VG_RETURN_ERR_IF(!newData, VG_OUT_OF_MEMORY_ERROR, VG_NO_RETVAL); + + /* Transform src path into new data */ + segCount = dst->segCount; + dataCount = dst->dataCount; + userData[0] = newSegs; userData[1] = &segCount; + userData[2] = newData; userData[3] = &dataCount; + userData[4] = dst; + shProcessPathData(src, processFlags, shTransformSegment, userData); + + /* Free old arrays */ + free(dst->segs); + free(dst->data); + + /* Adjust new properties */ + dst->segs = newSegs; + dst->data = newData; + dst->segCount = segCount; + dst->dataCount = dataCount; + + /* Mark change */ + dst->cacheDataValid = VG_FALSE; + + VG_RETURN_ERR(VG_NO_ERROR, VG_NO_RETVAL); +} + +static void shInterpolateSegment(SHPath *p, VGPathSegment segment, + VGPathCommand originalCommand, + SHfloat *data, void *userData) +{ + SHuint8* procSegs = (SHuint8*) ((void**)userData)[0]; + SHint* procSegCount = (SHint*) ((void**)userData)[1]; + SHfloat* procData = (SHfloat*) ((void**)userData)[2]; + SHint* procDataCount = (SHint*) ((void**)userData)[3]; + SHint segindex, i; + + /* Write the processed segment back */ + procSegs[(*procSegCount)++] = segment | VG_ABSOLUTE; + + /* Write the processed data back (exclude first 2 pen coords!) */ + segindex = (segment >> 1); + for (i=2; i<2+shCoordsPerCommand[segindex]; ++i) + procData[(*procDataCount)++] = data[i]; +} + +VG_API_CALL VGboolean vgInterpolatePath(VGPath dstPath, VGPath startPath, + VGPath endPath, VGfloat amount) +{ + SHPath *dst, *start, *end; + SHuint8 *procSegs1, *procSegs2; + SHfloat *procData1, *procData2; + SHint procSegCount1=0, procSegCount2=0; + SHint procDataCount1=0, procDataCount2=0; + SHuint8 *newSegs, *newData=0; + void *userData[4]; + SHint segment1, segment2; + SHint segindex, s,d,i; + SHint processFlags = + SH_PROCESS_SIMPLIFY_LINES | + SH_PROCESS_SIMPLIFY_CURVES; + + VG_GETCONTEXT(VG_FALSE); + + VG_RETURN_ERR_IF(!shIsValidPath(context, dstPath) || + !shIsValidPath(context, startPath) || + !shIsValidPath(context, endPath), + VG_BAD_HANDLE_ERROR, VG_FALSE); + + dst = (SHPath*)dstPath; start = (SHPath*)startPath; end = (SHPath*)endPath; + VG_RETURN_ERR_IF(!(start->caps & VG_PATH_CAPABILITY_INTERPOLATE_FROM) || + !(end->caps & VG_PATH_CAPABILITY_INTERPOLATE_FROM) || + !(dst->caps & VG_PATH_CAPABILITY_INTERPOLATE_TO), + VG_PATH_CAPABILITY_ERROR, VG_FALSE); + + /* Segment count must be equal */ + VG_RETURN_ERR_IF(start->segCount != end->segCount, + VG_NO_ERROR, VG_FALSE); + + /* Allocate storage for processed path data */ + shProcessedDataCount(start, processFlags, &procSegCount1, &procDataCount1); + shProcessedDataCount(end, processFlags, &procSegCount2, &procDataCount2); + procSegs1 = (SHuint8*)malloc(procSegCount1 * sizeof(SHuint8)); + procSegs2 = (SHuint8*)malloc(procSegCount2 * sizeof(SHuint8)); + procData1 = (SHfloat*)malloc(procDataCount1 * sizeof(SHfloat)); + procData2 = (SHfloat*)malloc(procDataCount2 * sizeof(SHfloat)); + if (!procSegs1 || !procSegs2 || !procData1 || !procData2) { + free(procSegs1); free(procSegs2); free(procData1); free(procData2); + VG_RETURN_ERR(VG_OUT_OF_MEMORY_ERROR, VG_FALSE); + } + + /* Process data of start path */ + procSegCount1 = 0; procDataCount1 = 0; + userData[0] = procSegs1; userData[1] = &procSegCount1; + userData[2] = procData1; userData[3] = &procDataCount1; + shProcessPathData(start, processFlags, shInterpolateSegment, userData); + + /* Process data of end path */ + procSegCount2 = 0; procDataCount2 = 0; + userData[0] = procSegs2; userData[1] = &procSegCount2; + userData[2] = procData2; userData[3] = &procDataCount2; + shProcessPathData(end, processFlags, shInterpolateSegment, userData); + SH_ASSERT(procSegCount1 == procSegCount2 && + procDataCount1 == procDataCount2); + + /* Resize dst path storage to include interpolated data */ + shResizePathData(dst, procSegCount1, procDataCount1, &newSegs, &newData); + if (!newData) { + free(procSegs1); free(procData1); + free(procSegs2); free(procData2); + VG_RETURN_ERR(VG_OUT_OF_MEMORY_ERROR, VG_FALSE); + } + + /* Interpolate data between paths */ + for (s=0, d=0; s> 1); + newSegs[s] = segment1 | VG_ABSOLUTE; + for (i=0; idatatype, dst->scale, dst->bias, + newData, dst->dataCount + d, value); + } + } + + /* Free processed data */ + free(procSegs1); free(procData1); + free(procSegs2); free(procData2); + + /* Assign interpolated data */ + dst->segs = newSegs; + dst->data = newData; + dst->segCount += procSegCount1; + dst->dataCount += procDataCount1; + + /* Mark change */ + dst->cacheDataValid = VG_FALSE; + + VG_RETURN_ERR(VG_NO_ERROR, VG_TRUE); +} diff --git a/simgear/canvas/ShaderVG/src/shPath.h b/simgear/canvas/ShaderVG/src/shPath.h new file mode 100644 index 00000000..7157ceb8 --- /dev/null +++ b/simgear/canvas/ShaderVG/src/shPath.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2007 Ivan Leben + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __SHPATH_H +#define __SHPATH_H + +#include "shVectors.h" +#include "shArrays.h" + +/* Helper structures for subdivision */ +typedef struct { + SHVector2 p1; + SHVector2 p2; + SHVector2 p3; +} SHQuad; + +typedef struct { + SHVector2 p1; + SHVector2 p2; + SHVector2 p3; + SHVector2 p4; +} SHCubic; + +typedef struct { + SHVector2 p1; + SHVector2 p2; + SHfloat a1; + SHfloat a2; +} SHArc; + +/* SHVertex */ +typedef struct +{ + SHVector2 point; + SHVector2 tangent; + SHfloat length; + SHuint flags; + +} SHVertex; + +/* Vertex flags for contour definition */ +#define SH_VERTEX_FLAG_CLOSE (1 << 0) +#define SH_VERTEX_FLAG_SEGEND (1 << 1) +#define SH_SEGMENT_TYPE_COUNT 13 + +/* Vertex array */ +#define _ITEM_T SHVertex +#define _ARRAY_T SHVertexArray +#define _FUNC_T shVertexArray +#define _ARRAY_DECLARE +#include "shArrayBase.h" + + +/* SHPath */ +typedef struct SHPath +{ + /* Properties */ + VGint format; + SHfloat scale; + SHfloat bias; + SHint segHint; + SHint dataHint; + VGbitfield caps; + VGPathDatatype datatype; + + /* Raw data */ + SHuint8 *segs; + void *data; + SHint segCount; + SHint dataCount; + + /* Subdivision */ + SHVertexArray vertices; + SHVector2 min, max; + + /* Additional stroke geometry (dash vertices if + path dashed or triangle vertices if width > 1 */ + SHVector2Array stroke; + + /* Cache */ + VGboolean cacheDataValid; + + VGboolean cacheTransformInit; + SHMatrix3x3 cacheTransform; + + VGboolean cacheStrokeInit; + VGboolean cacheStrokeTessValid; + SHfloat cacheStrokeLineWidth; + VGCapStyle cacheStrokeCapStyle; + VGJoinStyle cacheStrokeJoinStyle; + SHfloat cacheStrokeMiterLimit; + SHfloat cacheStrokeDashPhase; + VGboolean cacheStrokeDashPhaseReset; + +} SHPath; + +void SHPath_ctor(SHPath *p); +void SHPath_dtor(SHPath *p); + + +/* Processing normalization flags */ +#define SH_PROCESS_SIMPLIFY_LINES (1 << 0) +#define SH_PROCESS_SIMPLIFY_CURVES (1 << 1) +#define SH_PROCESS_CENTRALIZE_ARCS (1 << 2) +#define SH_PROCESS_REPAIR_ENDS (1 << 3) + +/* Segment callback function type */ +typedef void (*SegmentFunc) (SHPath *p, VGPathSegment segment, + VGPathCommand originalCommand, + SHfloat *data, void *userData); + +/* Processes raw path data into normalized segments */ +void shProcessPathData(SHPath *p, int flags, + SegmentFunc callback, + void *userData); + + +/* Pointer-to-path array */ +#define _ITEM_T SHPath* +#define _ARRAY_T SHPathArray +#define _FUNC_T shPathArray +#define _ARRAY_DECLARE +#include "shArrayBase.h" + +#endif /* __SHPATH_H */ diff --git a/simgear/canvas/ShaderVG/src/shPipeline.c b/simgear/canvas/ShaderVG/src/shPipeline.c new file mode 100644 index 00000000..f04996d2 --- /dev/null +++ b/simgear/canvas/ShaderVG/src/shPipeline.c @@ -0,0 +1,522 @@ +/* +* Copyright (c) 2007 Ivan Leben + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#define VG_API_EXPORT +#include "vg/openvg.h" +#include "shDefs.h" +#include "shExtensions.h" +#include "shContext.h" +#include "shPath.h" +#include "shImage.h" +#include "shGeometry.h" +#include "shPaint.h" + +void shPremultiplyFramebuffer() +{ + /* Multiply target color with its own alpha */ + glBlendFunc(GL_ZERO, GL_DST_ALPHA); +} + +void shUnpremultiplyFramebuffer() +{ + /* TODO: hmmmm..... any idea? */ +} + +void updateBlendingStateGL(VGContext *c, int alphaIsOne) +{ + /* Most common drawing mode (SRC_OVER with alpha=1) + as well as SRC is optimized by turning OpenGL + blending off. In other cases its turned on. */ + + switch (c->blendMode) + { + case VG_BLEND_SRC: + glBlendFunc(GL_ONE, GL_ZERO); + glDisable(GL_BLEND); break; + + case VG_BLEND_SRC_IN: + glBlendFunc(GL_DST_ALPHA, GL_ZERO); + glEnable(GL_BLEND); break; + + case VG_BLEND_DST_IN: + glBlendFunc(GL_ZERO, GL_SRC_ALPHA); + glEnable(GL_BLEND); break; + + case VG_BLEND_SRC_OUT_SH: + glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ZERO); + glEnable(GL_BLEND); break; + + case VG_BLEND_DST_OUT_SH: + glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); break; + + case VG_BLEND_SRC_ATOP_SH: + glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); break; + + case VG_BLEND_DST_ATOP_SH: + glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA); + glEnable(GL_BLEND); break; + + case VG_BLEND_DST_OVER: + glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA); + glEnable(GL_BLEND); break; + + case VG_BLEND_SRC_OVER: default: + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + if (alphaIsOne) { + glDisable(GL_BLEND); + } else { + glEnable(GL_BLEND); + } + break; + }; +} + +/*----------------------------------------------------------- + * Draws the triangles representing the stroke of a path. + *-----------------------------------------------------------*/ + +static void shDrawStroke(SHPath *p) +{ + VG_GETCONTEXT(VG_NO_RETVAL); + glEnableVertexAttribArray(context->locationDraw.pos); + glVertexAttribPointer(context->locationDraw.pos, 2, GL_FLOAT, GL_FALSE, 0, p->stroke.items); + glDrawArrays(GL_TRIANGLES, 0, p->stroke.size); + glDisableVertexAttribArray(context->locationDraw.pos); + GL_CEHCK_ERROR; +} + +/*----------------------------------------------------------- + * Draws the subdivided vertices in the OpenGL mode given + * (this could be VG_TRIANGLE_FAN or VG_LINE_STRIP). + *-----------------------------------------------------------*/ + +static void shDrawVertices(SHPath *p, GLenum mode) +{ + int start = 0; + int size = 0; + + /* We separate vertex arrays by contours to properly + handle the fill modes */ + VG_GETCONTEXT(VG_NO_RETVAL); + glEnableVertexAttribArray(context->locationDraw.pos); + glVertexAttribPointer(context->locationDraw.pos, 2, GL_FLOAT, GL_FALSE, sizeof(SHVertex), p->vertices.items); + + while (start < p->vertices.size) { + size = p->vertices.items[start].flags; + glDrawArrays(mode, start, size); + start += size; + } + + glDisableVertexAttribArray(context->locationDraw.pos); + GL_CEHCK_ERROR; +} + +/*-------------------------------------------------------------- + * Constructs & draws colored OpenGL primitives that cover the + * given bounding box to represent the currently selected + * stroke or fill paint + *--------------------------------------------------------------*/ + +static void shDrawPaintMesh(VGContext *c, SHVector2 *min, SHVector2 *max, + VGPaintMode mode, GLenum texUnit) +{ + SHPaint *p = 0; + SHVector2 pmin, pmax; + SHfloat K = 1.0f; + + /* Pick the right paint */ + if (mode == VG_FILL_PATH) { + p = (c->fillPaint ? c->fillPaint : &c->defaultPaint); + }else if (mode == VG_STROKE_PATH) { + p = (c->strokePaint ? c->strokePaint : &c->defaultPaint); + K = SH_CEIL(c->strokeMiterLimit * c->strokeLineWidth) + 1.0f; + } + + /* We want to be sure to cover every pixel of this path so better + take a pixel more than leave some out (multisampling is tricky). */ + SET2V(pmin, (*min)); SUB2(pmin, K,K); + SET2V(pmax, (*max)); ADD2(pmax, K,K); + + /* Construct appropriate OpenGL primitives so as + to fill the stencil mask with select paint */ + + switch (p->type) { + case VG_PAINT_TYPE_LINEAR_GRADIENT: + shLoadLinearGradientMesh(p, mode, VG_MATRIX_PATH_USER_TO_SURFACE); + break; + + case VG_PAINT_TYPE_RADIAL_GRADIENT: + shLoadRadialGradientMesh(p, mode, VG_MATRIX_PATH_USER_TO_SURFACE); + break; + + case VG_PAINT_TYPE_PATTERN: + if (p->pattern != VG_INVALID_HANDLE) { + shLoadPatternMesh(p, mode, VG_MATRIX_PATH_USER_TO_SURFACE); + break; + }/* else behave as a color paint */ + + case VG_PAINT_TYPE_COLOR: + shLoadOneColorMesh(p); + break; + } + + GLfloat v[] = { pmin.x, pmin.y, + pmax.x, pmin.y, + pmin.x, pmax.y, + pmax.x, pmax.y }; + glEnableVertexAttribArray(c->locationDraw.pos); + glVertexAttribPointer(c->locationDraw.pos, 2, GL_FLOAT, GL_FALSE, 0, v); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glDisableVertexAttribArray(c->locationDraw.pos); + GL_CEHCK_ERROR; +} + +VGboolean shIsTessCacheValid (VGContext *c, SHPath *p) +{ + SHfloat nX, nY; + SHVector2 X, Y; + SHMatrix3x3 mi; //, mchange; + VGboolean valid = VG_TRUE; + + if (p->cacheDataValid == VG_FALSE) { + valid = VG_FALSE; + } + else if (p->cacheTransformInit == VG_FALSE) { + valid = VG_FALSE; + } + else if (shInvertMatrix( &p->cacheTransform, &mi ) == VG_FALSE) { + valid = VG_FALSE; + } + else + { + /* TODO: Compare change matrix for any scale or shear */ +// MULMATMAT( c->pathTransform, mi, mchange ); + SET2( X, mi.m[0][0], mi.m[1][0] ); + SET2( Y, mi.m[0][1], mi.m[1][1] ); + nX = NORM2( X ); nY = NORM2( Y ); + if (nX > 1.01f || nX < 0.99 || + nY > 1.01f || nY < 0.99) + valid = VG_FALSE; + } + + if (valid == VG_FALSE) + { + /* Update cache */ + p->cacheDataValid = VG_TRUE; + p->cacheTransformInit = VG_TRUE; + p->cacheTransform = c->pathTransform; + p->cacheStrokeTessValid = VG_FALSE; + } + + return valid; +} + +VGboolean shIsStrokeCacheValid (VGContext *c, SHPath *p) +{ + VGboolean valid = VG_TRUE; + + if (p->cacheStrokeInit == VG_FALSE) { + valid = VG_FALSE; + } + else if (p->cacheStrokeTessValid == VG_FALSE) { + valid = VG_FALSE; + } + else if (c->strokeDashPattern.size > 0) { + valid = VG_FALSE; + } + else if (p->cacheStrokeLineWidth != c->strokeLineWidth || + p->cacheStrokeCapStyle != c->strokeCapStyle || + p->cacheStrokeJoinStyle != c->strokeJoinStyle || + p->cacheStrokeMiterLimit != c->strokeMiterLimit) { + valid = VG_FALSE; + } + + if (valid == VG_FALSE) + { + /* Update cache */ + p->cacheStrokeInit = VG_TRUE; + p->cacheStrokeTessValid = VG_TRUE; + p->cacheStrokeLineWidth = c->strokeLineWidth; + p->cacheStrokeCapStyle = c->strokeCapStyle; + p->cacheStrokeJoinStyle = c->strokeJoinStyle; + p->cacheStrokeMiterLimit = c->strokeMiterLimit; + } + + return valid; +} + +/*----------------------------------------------------------- + * Tessellates / strokes the path and draws it according to + * VGContext state. + *-----------------------------------------------------------*/ + +VG_API_CALL void vgDrawPath(VGPath path, VGbitfield paintModes) +{ + SHPath *p; + SHMatrix3x3 mi; + SHfloat mgl[16]; + SHPaint *fill, *stroke; + SHRectangle *rect; + + VG_GETCONTEXT(VG_NO_RETVAL); + + VG_RETURN_ERR_IF(!shIsValidPath(context, path), + VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + VG_RETURN_ERR_IF(paintModes & (~(VG_STROKE_PATH | VG_FILL_PATH)), + VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL); + + /* Check whether scissoring is enabled and scissor + rectangle is valid */ + if (context->scissoring == VG_TRUE) { + rect = &context->scissor.items[0]; + if (context->scissor.size == 0) VG_RETURN( VG_NO_RETVAL ); + if (rect->w <= 0.0f || rect->h <= 0.0f) VG_RETURN( VG_NO_RETVAL ); + glScissor( (GLint)rect->x, (GLint)rect->y, (GLint)rect->w, (GLint)rect->h ); + glEnable( GL_SCISSOR_TEST ); + } + + p = (SHPath*)path; + + /* If user-to-surface matrix invertible tessellate in + surface space for better path resolution */ + if (shIsTessCacheValid( context, p ) == VG_FALSE) + { + if (shInvertMatrix(&context->pathTransform, &mi)) { + shFlattenPath(p, 1); + shTransformVertices(&mi, p); + }else shFlattenPath(p, 0); + shFindBoundbox(p); + } + + /* Pick paint if available or default*/ + fill = (context->fillPaint ? context->fillPaint : &context->defaultPaint); + stroke = (context->strokePaint ? context->strokePaint : &context->defaultPaint); + + /* Apply transformation */ + shMatrixToGL(&context->pathTransform, mgl); + glUseProgram(context->progDraw); + glUniformMatrix4fv(context->locationDraw.model, 1, GL_FALSE, mgl); + glUniform1i(context->locationDraw.drawMode, 0); /* drawMode: path */ + GL_CEHCK_ERROR; + + if (paintModes & VG_FILL_PATH) { + + /* Tesselate into stencil */ + glEnable(GL_STENCIL_TEST); + if( context->fillRule == VG_EVEN_ODD ) + { + glStencilFunc(GL_ALWAYS, 0, 0); + glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT); + } + else + { + // pseudo non-zero fill rule. Fill everything at least covered once, don't + // care for possible decrements. + // TODO implement real non-zero fill-rule + glStencilFunc(GL_ALWAYS, 1, 1); + glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); + } + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + shDrawVertices(p, GL_TRIANGLE_FAN); + + /* Setup blending */ + updateBlendingStateGL(context, + fill->type == VG_PAINT_TYPE_COLOR && + fill->color.a == 1.0f); + + /* Draw paint where stencil odd */ + glStencilFunc(GL_EQUAL, 1, 1); + glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + shDrawPaintMesh(context, &p->min, &p->max, VG_FILL_PATH, GL_TEXTURE0); + + /* Reset state */ + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glDisable(GL_STENCIL_TEST); +// glDisable(GL_BLEND); + } + + if ((paintModes & VG_STROKE_PATH) && + context->strokeLineWidth > 0.0f) { +#if 0 + if (1) {/*context->strokeLineWidth > 1.0f) {*/ +#endif + if (shIsStrokeCacheValid( context, p ) == VG_FALSE) + { + /* Generate stroke triangles in user space */ + shVector2ArrayClear(&p->stroke); + shStrokePath(context, p); + } + + /* Stroke into stencil */ + glEnable(GL_STENCIL_TEST); + glStencilFunc(GL_NOTEQUAL, 1, 1); + glStencilOp(GL_KEEP, GL_INCR, GL_INCR); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + shDrawStroke(p); + + /* Setup blending */ + updateBlendingStateGL(context, + stroke->type == VG_PAINT_TYPE_COLOR && + stroke->color.a == 1.0f); + + /* Draw paint where stencil odd */ + glStencilFunc(GL_EQUAL, 1, 1); + glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + shDrawPaintMesh(context, &p->min, &p->max, VG_STROKE_PATH, GL_TEXTURE0); + + /* Reset state */ + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glDisable(GL_STENCIL_TEST); +// glDisable(GL_BLEND); + #if 0 + }else{ + + /* Simulate thin stroke by alpha */ + SHColor c = stroke->color; + if (context->strokeLineWidth < 1.0f) + c.a *= context->strokeLineWidth; + + /* Draw contour as a line */ + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + shDrawVertices(p, GL_LINE_STRIP); + glDisable(GL_BLEND); + } +#endif + } + + if (context->scissoring == VG_TRUE) + glDisable( GL_SCISSOR_TEST ); + + VG_RETURN(VG_NO_RETVAL); +} + +VG_API_CALL void vgDrawImage(VGImage image) +{ + SHImage *i; + SHfloat mgl[16]; + SHPaint *fill; + SHVector2 min, max; + SHRectangle *rect; + + VG_GETCONTEXT(VG_NO_RETVAL); + + VG_RETURN_ERR_IF(!shIsValidImage(context, image), + VG_BAD_HANDLE_ERROR, VG_NO_RETVAL); + + /* TODO: check if image is current render target */ + + /* Check whether scissoring is enabled and scissor + rectangle is valid */ + if (context->scissoring == VG_TRUE) { + rect = &context->scissor.items[0]; + if (context->scissor.size == 0) VG_RETURN( VG_NO_RETVAL ); + if (rect->w <= 0.0f || rect->h <= 0.0f) VG_RETURN( VG_NO_RETVAL ); + glScissor( (GLint)rect->x, (GLint)rect->y, (GLint)rect->w, (GLint)rect->h ); + glEnable( GL_SCISSOR_TEST ); + } + + /* Apply image-user-to-surface transformation */ + i = (SHImage*)image; + shMatrixToGL(&context->imageTransform, mgl); + glUseProgram(context->progDraw); + glUniformMatrix4fv(context->locationDraw.model, 1, GL_FALSE, mgl); + glUniform1i(context->locationDraw.drawMode, 1); /* drawMode: image */ + GL_CEHCK_ERROR; + + /* Clamp to edge for proper filtering, modulate for multiply mode */ + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, i->texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + /* Adjust antialiasing to settings */ + if (context->imageQuality == VG_IMAGE_QUALITY_NONANTIALIASED) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + }else{ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + + glEnableVertexAttribArray(context->locationDraw.textureUV); + GLfloat uv[] = { 0.0f, 0.0f, + 1.0f, 0.0f, + 0.0f, 1.0f, + 1.0f, 1.0f }; + glVertexAttribPointer(context->locationDraw.textureUV, 2, GL_FLOAT, GL_FALSE, 0, uv); + glUniform1i(context->locationDraw.imageSampler, 0); + GL_CEHCK_ERROR; + + /* Pick fill paint */ + fill = (context->fillPaint ? context->fillPaint : &context->defaultPaint); + + /* Setup blending */ + updateBlendingStateGL(context, 0); + + /* Draw textured quad */ + glEnable(GL_TEXTURE_2D); + + if (context->imageMode == VG_DRAW_IMAGE_MULTIPLY){ + /* Multiply each colors */ + glUniform1i(context->locationDraw.imageMode, VG_DRAW_IMAGE_MULTIPLY ); + switch(fill->type){ + case VG_PAINT_TYPE_RADIAL_GRADIENT: + shLoadRadialGradientMesh(fill, VG_FILL_PATH, VG_MATRIX_IMAGE_USER_TO_SURFACE); + break; + case VG_PAINT_TYPE_LINEAR_GRADIENT: + shLoadLinearGradientMesh(fill, VG_FILL_PATH, VG_MATRIX_IMAGE_USER_TO_SURFACE); + break; + case VG_PAINT_TYPE_PATTERN: + shLoadPatternMesh(fill, VG_FILL_PATH, VG_MATRIX_IMAGE_USER_TO_SURFACE); + break; + default: + case VG_PAINT_TYPE_COLOR: + shLoadOneColorMesh(fill); + break; + } + } else { + glUniform1i(context->locationDraw.imageMode, VG_DRAW_IMAGE_NORMAL ); + } + + GLfloat v[] = { 0.0f, 0.0f, + i->width, 0.0f, + 0.0f, i->height, + i->width, i->height }; + glVertexAttribPointer(context->locationDraw.pos, 2, GL_FLOAT, GL_FALSE, 0, v); + glEnableVertexAttribArray(context->locationDraw.pos); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glDisableVertexAttribArray(context->locationDraw.pos); + + glDisable(GL_TEXTURE_2D); + GL_CEHCK_ERROR; + + glDisableVertexAttribArray(context->locationDraw.textureUV); + + if (context->scissoring == VG_TRUE) + glDisable( GL_SCISSOR_TEST ); + + VG_RETURN(VG_NO_RETVAL); +} diff --git a/simgear/canvas/ShaderVG/src/shVectors.c b/simgear/canvas/ShaderVG/src/shVectors.c new file mode 100644 index 00000000..a0bba0ae --- /dev/null +++ b/simgear/canvas/ShaderVG/src/shVectors.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2007 Ivan Leben + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "shVectors.h" + +#define _ITEM_T SHVector2 +#define _ARRAY_T SHVector2Array +#define _FUNC_T shVector2Array +#define _COMPARE_T(v1,v2) EQ2V(v1,v2) +#define _ARRAY_DEFINE +#include "shArrayBase.h" + +void SHVector2_ctor(SHVector2 *v) { + v->x=0.0f; v->y=0.0f; +} + +void SHVector2_dtor(SHVector2 *v) { +} + +void SHVector3_ctor(SHVector3 *v) { + v->x=0.0f; v->y=0.0f; v->z=0.0f; +} + +void SHVector3_dtor(SHVector3 *v) { +} + +void SHVector4_ctor(SHVector4 *v) { + v->x=0.0f; v->y=0.0f; v->z=0.0f; v->w=0.0f; +} + +void SHVector4_dtor(SHVector4 *v) { +} + +void SHRectangle_ctor(SHRectangle *r) { + r->x=0.0f; r->y=0.0f; r->w=0.0f; r->h=0.0f; +} + +void SHRectangle_dtor(SHRectangle *r) { +} + +void shRectangleSet(SHRectangle *r, SHfloat x, + SHfloat y, SHfloat w, SHfloat h) +{ + r->x=x; r->y=y; r->w=w; r->h=h; +} + +void SHMatrix3x3_ctor(SHMatrix3x3 *mt) +{ + IDMAT((*mt)); +} + +void SHMatrix3x3_dtor(SHMatrix3x3 *mt) +{ +} + +void shMatrixToGL(SHMatrix3x3 *m, SHfloat mgl[16]) +{ + /* When 2D vectors are specified OpenGL defaults Z to 0.0f so we + have to shift the third column of our 3x3 matrix to right */ + mgl[0] = m->m[0][0]; mgl[4] = m->m[0][1]; mgl[8] = 0.0f; mgl[12] = m->m[0][2]; + mgl[1] = m->m[1][0]; mgl[5] = m->m[1][1]; mgl[9] = 0.0f; mgl[13] = m->m[1][2]; + mgl[2] = 0.0f; mgl[6] = 0.0f ; mgl[10] = 1.0f; mgl[14] = 0.0f; + mgl[3] = m->m[2][0]; mgl[7] = m->m[2][1]; mgl[11] = 0.0f; mgl[15] = m->m[2][2]; +} + +int shInvertMatrix(SHMatrix3x3 *m, SHMatrix3x3 *mout) +{ + /* Calculate determinant */ + SHfloat D0 = m->m[1][1]*m->m[2][2] - m->m[2][1]*m->m[1][2]; + SHfloat D1 = m->m[2][0]*m->m[1][2] - m->m[1][0]*m->m[2][2]; + SHfloat D2 = m->m[1][0]*m->m[2][1] - m->m[2][0]*m->m[1][1]; + SHfloat D = m->m[0][0]*D0 + m->m[0][1]*D1 + m->m[0][2]*D2; + + /* Check if singular */ + if( D == 0.0f ) return 0; + D = 1.0f / D; + + /* Calculate inverse */ + mout->m[0][0] = D * D0; + mout->m[1][0] = D * D1; + mout->m[2][0] = D * D2; + mout->m[0][1] = D * (m->m[2][1]*m->m[0][2] - m->m[0][1]*m->m[2][2]); + mout->m[1][1] = D * (m->m[0][0]*m->m[2][2] - m->m[2][0]*m->m[0][2]); + mout->m[2][1] = D * (m->m[2][0]*m->m[0][1] - m->m[0][0]*m->m[2][1]); + mout->m[0][2] = D * (m->m[0][1]*m->m[1][2] - m->m[1][1]*m->m[0][2]); + mout->m[1][2] = D * (m->m[1][0]*m->m[0][2] - m->m[0][0]*m->m[1][2]); + mout->m[2][2] = D * (m->m[0][0]*m->m[1][1] - m->m[1][0]*m->m[0][1]); + + return 1; +} + +SHfloat shVectorOrientation(SHVector2 *v) { + SHfloat norm = (SHfloat)NORM2((*v)); + SHfloat cosa = v->x/norm; + SHfloat sina = v->y/norm; + return (SHfloat)(sina>=0 ? SH_ACOS(cosa) : 2*PI-SH_ACOS(cosa)); +} + +int shLineLineXsection(SHVector2 *o1, SHVector2 *v1, + SHVector2 *o2, SHVector2 *v2, + SHVector2 *xsection) +{ + SHfloat rightU = o2->x - o1->x; + SHfloat rightD = o2->y - o1->y; + + SHfloat D = v1->x * (-v2->y) - v1->y * (-v2->x); + SHfloat DX = rightU * (-v2->y) - rightD * (-v2->x); +/*SHfloat DY = v1.x * rightD - v1.y * rightU;*/ + + SHfloat t1 = DX / D; + + if (D == 0.0f) + return 0; + + xsection->x = o1->x + t1*v1->x; + xsection->y = o1->y + t1*v1->y; + return 1; +} + +void shCalcOrtho2D(float* mat, float left, float right, float bottom, float top, float near, float far) +{ + /* http://en.wikipedia.org/wiki/Orthographic_projection */ + const float zNear = near; + const float zFar = far; + const float inv_z = 1.0f / (zFar - zNear); + const float inv_y = 1.0f / (top - bottom); + const float inv_x = 1.0f / (right - left); + + /* first column */ + *mat++ = (2.0f*inv_x); + *mat++ = (0.0f); + *mat++ = (0.0f); + *mat++ = (0.0f); + + /* second */ + *mat++ = (0.0f); + *mat++ = (2.0*inv_y); + *mat++ = (0.0f); + *mat++ = (0.0f); + + /* third */ + *mat++ = (0.0f); + *mat++ = (0.0f); + *mat++ = (-2.0f*inv_z); + *mat++ = (0.0f); + + /* fourth */ + *mat++ = (-(right + left)*inv_x); + *mat++ = (-(top + bottom)*inv_y); + *mat++ = (-(zFar + zNear)*inv_z); + *mat++ = (1.0f); +} + +void shMatrixToVG(SHMatrix3x3 *m, SHfloat mvg[9]) +{ + mvg[0] = m->m[0][0]; mvg[3] = m->m[0][1]; mvg[6] = m->m[0][2]; + mvg[1] = m->m[1][0]; mvg[4] = m->m[1][1]; mvg[7] = m->m[1][2]; + mvg[2] = m->m[2][0]; mvg[5] = m->m[2][1]; mvg[8] = m->m[2][2]; +} + +void shIdMatrixGL(SHfloat mgl[16]) +{ + mgl[0] = 1.0f; mgl[4] = 0.0f; mgl[8] = 0.0f; mgl[12] = 0.0f; + mgl[1] = 0.0f; mgl[5] = 1.0f; mgl[9] = 0.0f; mgl[13] = 0.0f; + mgl[2] = 0.0f; mgl[6] = 0.0f; mgl[10] = 1.0f; mgl[14] = 0.0f; + mgl[3] = 0.0f; mgl[7] = 0.0f; mgl[11] = 0.0f; mgl[15] = 1.0f; +} diff --git a/simgear/canvas/ShaderVG/src/shVectors.h b/simgear/canvas/ShaderVG/src/shVectors.h new file mode 100644 index 00000000..e810e5e9 --- /dev/null +++ b/simgear/canvas/ShaderVG/src/shVectors.h @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2007 Ivan Leben + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __SHVECTORS_H +#define __SHVECTORS_H + +#include "shDefs.h" + +/* Vector structures + *--------------------------------------------------------------*/ +typedef struct +{ + SHfloat x,y; +} SHVector2; + +void SHVector2_ctor(SHVector2 *v); +void SHVector2_dtor(SHVector2 *v); + +typedef struct +{ + SHfloat x,y,z; +} SHVector3; + +void SHVector3_ctor(SHVector3 *v); +void SHVector3_dtor(SHVector3 *v); + +typedef struct +{ + SHfloat x,y,z,w; +} SHVector4; + +void SHVector4_ctor(SHVector4 *v); +void SHVector4_dtor(SHVector4 *v); + +typedef struct +{ + SHfloat x,y,w,h; +} SHRectangle; + +void SHRectangle_ctor(SHRectangle *r); +void SHRectangle_dtor(SHRectangle *r); +void shRectangleSet(SHRectangle *r, SHfloat x, + SHfloat y, SHfloat w, SHfloat h); + +typedef struct +{ + SHfloat m[3][3]; +} SHMatrix3x3; + +void SHMatrix3x3_ctor(SHMatrix3x3 *m); +void SHMatrix3x3_dtor(SHMatrix3x3 *m); + +/*------------------------------------------------------------ + * Vector Arrays + *------------------------------------------------------------*/ + +#define _ITEM_T SHVector2 +#define _ARRAY_T SHVector2Array +#define _FUNC_T shVector2Array +#define _ARRAY_DECLARE +#include "shArrayBase.h" + +/*-------------------------------------------------------- + * Macros for typical vector operations. The only way to + * inline in C is to actually write a macro + *--------------------------------------------------------- */ + +#define SET2(v,xs,ys) { v.x=xs; v.y=ys; } +#define SET3(v,xs,ys,zs) { v.x=xs; v.y=ys; v.z=zs; } +#define SET4(v,xs,ys,zs,ws) { v.x=xs; v.y=ys; v.z=zs; v.w=ws; } + +#define SET2V(v1,v2) { v1.x=v2.x; v1.y=v2.y; } +#define SET3V(v1,v2) { v1.x=v2.x; v1.y=v2.y; v1.z=v2.z; } +#define SET4V(v1,v2) { v1.x=v2.x; v1.y=v2.y; v1.z=v2.z; v1.w=v2.w; } + +#define EQ2(v,xx,yy) ( v.x==xx && v.y==yy ) +#define EQ3(v,xx,yy,zz) ( v.x==xx && v.y==yy && v.z==zz ) +#define EQ4(v,xx,yy,zz,ww) ( v.x==xx && v.y==yy && v.z==zz && v.w==ww ) + +#define ISZERO2(v) ( v.x==0.0f && v.y==0.0f ) +#define ISZERO3(v) ( v.x==0.0f && v.y==0.0f && v.z==0.0f) +#define ISZERO4(v) ( v.x==0.0f && v.y==0.0f && v.z==0.0f && v.w==0.0f ) + +#define EQ2V(v1,v2) ( v1.x==v2.x && v1.y==v2.y ) +#define EQ3V(v1,v2) ( v1.x==v2.x && v1.y==v2.y && v1.z==v2.z ) +#define EQ4V(v1,v2) ( v1.x==v2.x && v1.y==v2.y && v1.z==v2.z && v1.w==v2.w ) + +#define ADD2(v,xx,yy) { v.x+=xx; v.y+=yy; } +#define ADD3(v,xx,yy,zz) { v.x+=xx; v.y+=yy; v.z+=zz; } +#define ADD4(v,xx,yy,zz,ww) { v.x+=xx; v.y+=yy; v.z+=zz; v.w+=ww; } + +#define ADD2V(v1,v2) { v1.x+=v2.x; v1.y+=v2.y; } +#define ADD3V(v1,v2) { v1.x+=v2.x; v1.y+=v2.y; v1.z+=v2.z; } +#define ADD4V(v1,v2) { v1.x+=v2.x; v1.y+=v2.y; v1.z+=v2.z; v1.w+=v2.w; } + +#define SUB2(v,xx,yy) { v.x-=xx; v.y-=yy; } +#define SUB3(v,xx,yy,zz) { v.x-=xx; v.y-=yy; v.z-=zz; } +#define SUB4(v,xx,yy,zz,ww) { v.x-=xx; v.y-=yy; v.z-=zz; v.w-=v2.w; } + +#define SUB2V(v1,v2) { v1.x-=v2.x; v1.y-=v2.y; } +#define SUB3V(v1,v2) { v1.x-=v2.x; v1.y-=v2.y; v1.z-=v2.z; } +#define SUB4V(v1,v2) { v1.x-=v2.x; v1.y-=v2.y; v1.z-=v2.z; v1.w-=v2.w; } + +#define MUL2(v,f) { v.x*=f; v.y*=f; } +#define MUL3(v,f) { v.x*=f; v.y*=f; v.z*=z; } +#define MUL4(v,f) { v.x*=f; v.y*=f; v.z*=z; v.w*=w; } + +#define DIV2(v,f) { v.x/=f; v.y/=f; } +#define DIV3(v,f) { v.x/=f; v.y/=f; v.z/=z; } +#define DIV4(v,f) { v.x/=f; v.y/=f; v.z/=z; v.w/=w; } + +#define ABS2(v) { v.x=SH_ABS(v.x); v.y=SH_ABS(v.y); } +#define ABS3(v) { v.x=SH_ABS(v.x); v.y=SH_ABS(v.y); v.z=SH_ABS(v.z); } +#define ABS4(v) { v.x=SH_ABS(v.x); v.y=SH_ABS(v.y); v.z=SH_ABS(v.z); v.w=SH_ABS(v.w); } + +#define NORMSQ2(v) (v.x*v.x + v.y*v.y) +#define NORMSQ3(v) (v.x*v.x + v.y*v.y + v.z*v.z) +#define NORMSQ4(v) (v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w) + +#define NORM2(v) SH_SQRT(NORMSQ2(v)) +#define NORM3(v) SH_SQRT(NORMSQ3(v)) +#define NORM4(v) SH_SQRT(NORMSQ4(v)) + +#define NORMALIZE2(v) { SHfloat n=NORM2(v); v.x/=n; v.y/=n; } +#define NORMALIZE3(v) { SHfloat n=NORM3(v); v.x/=n; v.y/=n; v.z/=n; } +#define NORMALIZE4(v) { SHfloat n=NORM4(v); v.x/=n; v.y/=n; v.z/=n; v.w/=w; } + +#define DOT2(v1,v2) (v1.x*v2.x + v1.y*v2.y) +#define DOT3(v1,v2) (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z) +#define DOT4(v1,v2) (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z + v1.w*v2.w) + +#define CROSS2(v1,v2) (v1.x*v2.y - v2.x*v1.y) + +#define ANGLE2(v1,v2) (SH_ACOS( DOT2(v1,v2) / (NORM2(v1)*NORM2(v2)) )) +#define ANGLE2N(v1,v2) (SH_ACOS( DOT2(v1,v2) )) + +#define OFFSET2V(v, o, s) { v.x += o.x*s; v.y += o.y*s; } +#define OFFSET3V(v, o, s) { v.x += o.x*s; v.y += o.y*s; v.z += o.z*s; } +#define OFFSET4V(v, o, s) { v.x += o.x*s; v.y += o.y*s; v.z += o.z*s; v.w += o.w*s; } + +/*----------------------------------------------------- + * Macros for matrix operations + *-----------------------------------------------------*/ + +#define SETMAT(mat, m00, m01, m02, m10, m11, m12, m20, m21, m22) { \ +mat.m[0][0] = m00; mat.m[0][1] = m01; mat.m[0][2] = m02; \ + mat.m[1][0] = m10; mat.m[1][1] = m11; mat.m[1][2] = m12; \ + mat.m[2][0] = m20; mat.m[2][1] = m21; mat.m[2][2] = m22; } + +#define SETMATMAT(m1, m2) { \ +int i,j; \ + for(i=0;i<3;i++) \ + for(j=0;j<3;j++) \ + m1.m[i][j] = m2.m[i][j]; } + +#define MULMATS(mat, s) { \ +int i,j; \ + for(i=0;i<3;i++) \ + for(j=0;j<3;j++) \ + mat.m[i][j] *= s; } + +#define DIVMATS(mat, s) { \ +int i,j; \ + for(i=0;i<3;i++) \ + for(j=0;j<3;j++) \ + mat.m[i][j] /= s; } + +#define MULMATMAT(m1, m2, mout) { \ +int i,j; \ + for(i=0;i<3;i++) \ + for(j=0;j<3;j++) \ + mout.m[i][j] = \ + m1.m[i][0] * m2.m[0][j] + \ + m1.m[i][1] * m2.m[1][j] + \ + m1.m[i][2] * m2.m[2][j]; } + +#define IDMAT(mat) SETMAT(mat, 1,0,0, 0,1,0, 0,0,1) + +#define TRANSLATEMATL(mat, tx, ty) { \ +SHMatrix3x3 trans,temp; \ + SETMAT(trans, 1,0,tx, 0,1,ty, 0,0,1); \ + MULMATMAT(trans, mat, temp); \ + SETMATMAT(mat, temp); } + +#define TRANSLATEMATR(mat, tx, ty) { \ +SHMatrix3x3 trans,temp; \ + SETMAT(trans, 1,0,tx, 0,1,ty, 0,0,1); \ + MULMATMAT(mat, trans, temp); \ + SETMATMAT(mat, temp); } + +#define SCALEMATL(mat, sx, sy) { \ +SHMatrix3x3 scale, temp; \ + SETMAT(scale, sx,0,0, 0,sy,0, 0,0,1); \ + MULMATMAT(scale, mat, temp); \ + SETMATMAT(mat, temp); } + +#define SCALEMATR(mat, sx, sy) { \ +SHMatrix3x3 scale, temp; \ + SETMAT(scale, sx,0,0, 0,sy,0, 0,0,1); \ + MULMATMAT(mat, scale, temp); \ + SETMATMAT(mat, temp); } + +#define SHEARMATL(mat, shx, shy) {\ +SHMatrix3x3 shear, temp;\ + SETMAT(shear, 1,shx,0, shy,1,0, 0,0,1); \ + MULMATMAT(shear, mat, temp); \ + SETMATMAT(mat, temp); } + +#define SHEARMATR(mat, shx, shy) {\ +SHMatrix3x3 shear, temp;\ + SETMAT(shear, 1,shx,0, shy,1,0, 0,0,1); \ + MULMATMAT(mat, shear, temp); \ + SETMATMAT(mat, temp); } + +#define ROTATEMATL(mat, a) { \ +SHfloat cosa=SH_COS(a), sina=SH_SIN(a); \ + SHMatrix3x3 rot, temp; \ + SETMAT(rot, cosa,-sina,0, sina,cosa,0, 0,0,1); \ + MULMATMAT(rot, mat, temp); \ + SETMATMAT(mat, temp); } + +#define ROTATEMATR(mat, a) { \ +SHfloat cosa=SH_COS(a), sina=SH_SIN(a); \ + SHMatrix3x3 rot, temp; \ + SETMAT(rot, cosa,-sina,0, sina,cosa,0, 0,0,1); \ + MULMATMAT(mat, rot, temp); \ + SETMATMAT(mat, temp); } + +#define TRANSFORM2TO(v, mat, vout) { \ +vout.x = v.x*mat.m[0][0] + v.y*mat.m[0][1] + 1*mat.m[0][2]; \ + vout.y = v.x*mat.m[1][0] + v.y*mat.m[1][1] + 1*mat.m[1][2]; } + +#define TRANSFORM2(v, mat) { \ +SHVector2 temp; TRANSFORM2TO(v, mat, temp); v = temp; } + +#define TRANSFORM2DIRTO(v, mat, vout) { \ +vout.x = v.x*mat.m[0][0] + v.y*mat.m[0][1]; \ + vout.y = v.x*mat.m[1][0] + v.y*mat.m[1][1]; } + +#define TRANSFORM2DIR(v, mat) { \ +SHVector2 temp; TRANSFORM2DIRTO(v, mat, temp); v = temp; } + + +/*-------------------------------------------------------- + * Additional functions + *--------------------------------------------------------- */ + +void shMatrixToGL(SHMatrix3x3 *m, SHfloat mgl[16]); + +SHint shInvertMatrix(SHMatrix3x3 *m, SHMatrix3x3 *mout); + +SHfloat shVectorOrientation(SHVector2 *v); + +int shLineLineXsection(SHVector2 *o1, SHVector2 *v1, + SHVector2 *o2, SHVector2 *v2, + SHVector2 *xsection); +void shCalcOrtho2D(float* mat, float left, float right, float bottom, float top, float near, float far); +void shMatrixToVG(SHMatrix3x3 *m, SHfloat mvg[9]); +void shIdMatrixGL(SHfloat mgl[16]); + +#endif/* __SHVECTORS_H */ diff --git a/simgear/canvas/ShaderVG/src/shVgu.c b/simgear/canvas/ShaderVG/src/shVgu.c new file mode 100644 index 00000000..5d63a2ac --- /dev/null +++ b/simgear/canvas/ShaderVG/src/shVgu.c @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2007 Ivan Leben + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#define VG_API_EXPORT +#include "vg/openvg.h" +#include "vg/vgu.h" +#include "shDefs.h" +#include "shContext.h" +#include + +static VGUErrorCode shAppend(VGPath path, SHint commSize, const VGubyte *comm, + SHint dataSize, const VGfloat *data) +{ + VGErrorCode err = VG_NO_ERROR; + VGPathDatatype type = vgGetParameterf(path, VG_PATH_DATATYPE); + VGfloat scale = vgGetParameterf(path, VG_PATH_SCALE); + VGfloat bias = vgGetParameterf(path, VG_PATH_BIAS); + SH_ASSERT(dataSize <= 26); + + switch(type) + { + case VG_PATH_DATATYPE_S_8: { + + SHint8 data8[26]; int i; + for (i=0; i + +VGU_API_CALL VGUErrorCode vguArc(VGPath path, + VGfloat x, VGfloat y, + VGfloat width, VGfloat height, + VGfloat startAngle, VGfloat angleExtent, + VGUArcType arcType) +{ + VGUErrorCode err = VGU_NO_ERROR; + + VGubyte commStart[1] = {VG_MOVE_TO_ABS}; + VGfloat dataStart[2]; + + VGubyte commArcCCW[1] = {VG_SCCWARC_TO_ABS}; + VGubyte commArcCW[1] = {VG_SCWARC_TO_ABS}; + VGfloat dataArc[5]; + + VGubyte commEndPie[2] = {VG_LINE_TO_ABS, VG_CLOSE_PATH}; + VGfloat dataEndPie[2]; + + VGubyte commEndChord[1] = {VG_CLOSE_PATH}; + VGfloat dataEndChord[1] = {0.0f}; + + VGfloat alast, a = 0.0f; + VGfloat rx = width/2, ry = height/2; + + if (width <= 0 || height <= 0) + return VGU_ILLEGAL_ARGUMENT_ERROR; + + if (arcType != VGU_ARC_OPEN && + arcType != VGU_ARC_CHORD && + arcType != VGU_ARC_PIE) + return VGU_ILLEGAL_ARGUMENT_ERROR; + + startAngle = SH_DEG2RAD(startAngle); + angleExtent = SH_DEG2RAD(angleExtent); + alast = startAngle + angleExtent; + + dataStart[0] = x + SH_COS(startAngle) * rx; + dataStart[1] = y + SH_SIN(startAngle) * ry; + err = shAppend(path, 1, commStart, 2, dataStart); + if (err != VGU_NO_ERROR) return err; + + dataArc[0] = rx; + dataArc[1] = ry; + dataArc[2] = 0.0f; + + if (angleExtent > 0) { + + a = startAngle + PI; + while (a < alast) { + dataArc[3] = x + SH_COS(a) * rx; + dataArc[4] = y + SH_SIN(a) * ry; + err = shAppend(path, 1, commArcCCW, 5, dataArc); + if (err != VGU_NO_ERROR) return err; + a += PI; } + + dataArc[3] = x + SH_COS(alast) * rx; + dataArc[4] = y + SH_SIN(alast) * ry; + err = shAppend(path, 1, commArcCCW, 5, dataArc); + if (err != VGU_NO_ERROR) return err; + + }else{ + + a = startAngle - PI; + while (a > alast) { + dataArc[3] = x + SH_COS(a) * rx; + dataArc[4] = y + SH_SIN(a) * ry; + err = shAppend(path, 1, commArcCW, 5, dataArc); + if (err != VGU_NO_ERROR) return err; + a -= PI; } + + dataArc[3] = x + SH_COS(alast) * rx; + dataArc[4] = y + SH_SIN(alast) * ry; + err = shAppend(path, 1, commArcCW, 5, dataArc); + if (err != VGU_NO_ERROR) return err; + } + + + if (arcType == VGU_ARC_PIE) { + dataEndPie[0] = x; dataEndPie[1] = y; + err = shAppend(path, 2, commEndPie, 2, dataEndPie); + }else if (arcType == VGU_ARC_CHORD) { + err = shAppend(path, 1, commEndChord, 0, dataEndChord); + } + + return err; +} + +VGU_API_CALL VGUErrorCode vguComputeWarpQuadToSquare(VGfloat sx0, VGfloat sy0, + VGfloat sx1, VGfloat sy1, + VGfloat sx2, VGfloat sy2, + VGfloat sx3, VGfloat sy3, + VGfloat * matrix) +{ + /* Basic idea taken from the reference implementation */ + VGfloat mat[3][3]; + VGfloat det, det00, det01, det02; + + if( !matrix ) + return VGU_ILLEGAL_ARGUMENT_ERROR; + + if( vguComputeWarpSquareToQuad( sx0, sy0, sx1, sy1, sx2, sy2, sx3, sy3, + (VGfloat*)mat ) + == VGU_BAD_WARP_ERROR ) + return VGU_BAD_WARP_ERROR; + + // Invert the matrix... + det00 = mat[1][1]*mat[2][2] - mat[2][1]*mat[1][2]; + det01 = mat[2][0]*mat[1][2] - mat[1][0]*mat[2][2]; + det02 = mat[1][0]*mat[2][1] - mat[2][0]*mat[1][1]; + + det = mat[0][0]*det00 + mat[0][1]*det01 + mat[0][2]*det02; + if( det == 0.0f ) + return VGU_BAD_WARP_ERROR; + + det = 1 / det; + + matrix[0] = det * det00; + matrix[3] = det * det01; + matrix[6] = det * det02; + matrix[1] = det * (mat[2][1]*mat[0][2] - mat[0][1]*mat[2][2]); + matrix[4] = det * (mat[0][0]*mat[2][2] - mat[2][0]*mat[0][2]); + matrix[7] = det * (mat[2][0]*mat[0][1] - mat[0][0]*mat[2][1]); + matrix[2] = det * (mat[0][1]*mat[1][2] - mat[1][1]*mat[0][2]); + matrix[5] = det * (mat[1][0]*mat[0][2] - mat[0][0]*mat[1][2]); + matrix[8] = det * (mat[0][0]*mat[1][1] - mat[1][0]*mat[0][1]); + + return VGU_NO_ERROR; +} + +VGU_API_CALL VGUErrorCode vguComputeWarpSquareToQuad(VGfloat dx0, VGfloat dy0, + VGfloat dx1, VGfloat dy1, + VGfloat dx2, VGfloat dy2, + VGfloat dx3, VGfloat dy3, + VGfloat * matrix) +{ + /* Taken from https://github.com/mvr/shivavg (who has taken it from the + reference implementation) */ + + VGfloat diffx1 = dx1 - dx3; + VGfloat diffy1 = dy1 - dy3; + VGfloat diffx2 = dx2 - dx3; + VGfloat diffy2 = dy2 - dy3; + + VGfloat det = diffx1*diffy2 - diffx2*diffy1; + + VGfloat sumx = dx0 - dx1 + dx3 - dx2; + VGfloat sumy = dy0 - dy1 + dy3 - dy2; + + VGfloat g, h, oodet; + + if(!matrix) + return VGU_ILLEGAL_ARGUMENT_ERROR; + + if(det == 0.0f) + return VGU_BAD_WARP_ERROR; + + if(sumx == 0.0f && sumy == 0.0f) + { + /* Affine mapping */ + matrix[0] = dx1 - dx0; + matrix[1] = dy1 - dy0; + matrix[2] = 0.0f; + matrix[3] = dx3 - dx1; + matrix[4] = dy3 - dy1; + matrix[5] = 0.0f; + matrix[6] = dx0; + matrix[7] = dy0; + matrix[8] = 1.0f; + return VGU_NO_ERROR; + } + + oodet = 1.0f / det; + g = (sumx*diffy2 - diffx2*sumy) * oodet; + h = (diffx1*sumy - sumx*diffy1) * oodet; + + matrix[0] = dx1-dx0+g*dx1; + matrix[1] = dy1-dy0+g*dy1; + matrix[2] = g; + matrix[3] = dx2-dx0+h*dx2; + matrix[4] = dy2-dy0+h*dy2; + matrix[5] = h; + matrix[6] = dx0; + matrix[7] = dy0; + matrix[8] = 1.0f; + + return VGU_NO_ERROR; +} + +VGU_API_CALL VGUErrorCode vguComputeWarpQuadToQuad(VGfloat dx0, VGfloat dy0, + VGfloat dx1, VGfloat dy1, + VGfloat dx2, VGfloat dy2, + VGfloat dx3, VGfloat dy3, + VGfloat sx0, VGfloat sy0, + VGfloat sx1, VGfloat sy1, + VGfloat sx2, VGfloat sy2, + VGfloat sx3, VGfloat sy3, + VGfloat * matrix) +{ + return VGU_NO_ERROR; +} diff --git a/simgear/canvas/ShaderVG/src/shaders.c b/simgear/canvas/ShaderVG/src/shaders.c new file mode 100644 index 00000000..0b4abfc2 --- /dev/null +++ b/simgear/canvas/ShaderVG/src/shaders.c @@ -0,0 +1,494 @@ +/* + * Copyright (c) 2021 Takuma Hayashi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "vg/openvg.h" +#include "shContext.h" +#include "shDefs.h" +#include "shaders.h" +#include +#include + +static const char* vgShaderVertexPipeline = R"glsl( + #version 330 + +/*** Input *******************/ + in vec2 pos; + in vec2 textureUV; + uniform mat4 sh_Model; + uniform mat4 sh_Ortho; + uniform mat3 paintInverted; + +/*** Output ******************/ + out vec2 texImageCoord; + out vec2 paintCoord; + +/*** Grobal variables ********************/ + vec4 sh_Vertex; + +/*** Functions ****************************************/ + + // User defined shader + void shMain(void); + +/*** Main thread **************************************************/ + void main() { + + /* Stage 3: Transformation */ + sh_Vertex = vec4(pos, 0, 1); + + /* Extended Stage: User defined shader that affects gl_Position */ + shMain(); + + /* 2D pos in texture space */ + texImageCoord = textureUV; + + /* 2D pos in paint space (Back to paint space) */ + paintCoord = (paintInverted * vec3(pos, 1)).xy; + + } +)glsl"; + +static const char* vgShaderVertexUserDefault = R"glsl( + void shMain(){ gl_Position = sh_Ortho * sh_Model * sh_Vertex; } +)glsl"; + +static const char* vgShaderFragmentPipeline = R"glsl( + + #version 330 + +/*** Enum constans ************************************/ + + #define PAINT_TYPE_COLOR 0x1B00 + #define PAINT_TYPE_LINEAR_GRADIENT 0x1B01 + #define PAINT_TYPE_RADIAL_GRADIENT 0x1B02 + #define PAINT_TYPE_PATTERN 0x1B03 + + #define DRAW_IMAGE_NORMAL 0x1F00 + #define DRAW_IMAGE_MULTIPLY 0x1F01 + + #define DRAW_MODE_PATH 0 + #define DRAW_MODE_IMAGE 1 + +/*** Interpolated *************************************/ + + in vec2 texImageCoord; + in vec2 paintCoord; + +/*** Input ********************************************/ + + // Basic rendering Mode + uniform int drawMode; + // Image + uniform sampler2D imageSampler; + uniform int imageMode; + // Paint + uniform int paintType; + uniform vec4 paintColor; + uniform vec2 paintParams[3]; + // Gradient + uniform sampler2D rampSampler; + // Pattern + uniform sampler2D patternSampler; + // Color transform + uniform vec4 scaleFactorBias[2]; + +/*** Output *******************************************/ + + //out vec4 fragColor; + +/*** Built-in variables for shMain *******************************************/ + + vec4 sh_Color; + +/*** Functions ****************************************/ + + // 9.3.1 Linear Gradients + float linearGradient(vec2 fragCoord, vec2 p0, vec2 p1){ + + float x = fragCoord.x; + float y = fragCoord.y; + float x0 = p0.x; + float y0 = p0.y; + float x1 = p1.x; + float y1 = p1.y; + float dx = x1 - x0; + float dy = y1 - y0; + + return + ( dx * (x - x0) + dy * (y - y0) ) + / ( dx*dx + dy*dy ); + } + + // 9.3.2 Radial Gradients + float radialGradient(vec2 fragCoord, vec2 centerCoord, vec2 focalCoord, float r){ + + float x = fragCoord.x; + float y = fragCoord.y; + float cx = centerCoord.x; + float cy = centerCoord.y; + float fx = focalCoord.x; + float fy = focalCoord.y; + float dx = x - fx; + float dy = y - fy; + float dfx = fx - cx; + float dfy = fy - cy; + + return + ( (dx * dfx + dy * dfy) + sqrt(r*r*(dx*dx + dy*dy) - pow(dx*dfy - dy*dfx, 2.0)) ) + / ( r*r - (dfx*dfx + dfy*dfy) ); + } + + // User defined shader + void shMain(void); + +/*** Main thread *************************************/ + + void main() + { + vec4 col; + + /* Stage 6: Paint Generation */ + switch(paintType){ + case PAINT_TYPE_LINEAR_GRADIENT: + { + vec2 x0 = paintParams[0]; + vec2 x1 = paintParams[1]; + float factor = linearGradient(paintCoord, x0, x1); + col = texture(rampSampler, vec2(factor, 0.5)); + } + break; + case PAINT_TYPE_RADIAL_GRADIENT: + { + vec2 center = paintParams[0]; + vec2 focal = paintParams[1]; + float radius = paintParams[2].x; + float factor = radialGradient(paintCoord, center, focal, radius); + col = texture(rampSampler, vec2(factor, 0.5)); + } + break; + case PAINT_TYPE_PATTERN: + { + float width = paintParams[0].x; + float height = paintParams[0].y; + vec2 texCoord = vec2(paintCoord.x / width, paintCoord.y / height); + col = texture(patternSampler, texCoord); + } + break; + default: + case PAINT_TYPE_COLOR: + col = paintColor; + break; + } + + /* Stage 7: Image Interpolation */ + if(drawMode == DRAW_MODE_IMAGE) { + col = texture(imageSampler, texImageCoord) + * (imageMode == DRAW_IMAGE_MULTIPLY ? col : vec4(1.0, 1.0, 1.0, 1.0)); + } + + /* Stage 8: Color Transformation, Blending, and Antialiasing */ + sh_Color = col * scaleFactorBias[0] + scaleFactorBias[1] ; + + /* Extended Stage: User defined shader that affects gl_FragColor */ + shMain(); + } +)glsl"; + +static const char* vgShaderFragmentUserDefault = R"glsl( + void shMain(){ gl_FragColor = sh_Color; }; +)glsl"; + +static const char* vgShaderVertexColorRamp = R"glsl( + #version 330 + + in vec2 step; + in vec4 stepColor; + out vec4 interpolateColor; + + void main() + { + gl_Position = vec4(step.xy, 0, 1); + interpolateColor = stepColor; + } +)glsl"; + +static const char* vgShaderFragmentColorRamp = R"glsl( + #version 330 + + in vec4 interpolateColor; + out vec4 fragColor; + + void main() + { + fragColor = interpolateColor; + } +)glsl"; + +void shInitPiplelineShaders(void) { + + VG_GETCONTEXT(VG_NO_RETVAL); + GLint compileStatus; + const char* extendedStage; + const char* buf[2]; + GLint size[2]; + + context->vs = glCreateShader(GL_VERTEX_SHADER); + if(context->userShaderVertex){ + extendedStage = (const char*)context->userShaderVertex; + } else { + extendedStage = vgShaderVertexUserDefault; + } + buf[0] = vgShaderVertexPipeline; + buf[1] = extendedStage; + size[0] = strlen(vgShaderVertexPipeline); + size[1] = strlen(extendedStage); + glShaderSource(context->vs, 2, buf, size); + glCompileShader(context->vs); + glGetShaderiv(context->vs, GL_COMPILE_STATUS, &compileStatus); + printf("Shader compile status :%d line:%d\n", compileStatus, __LINE__); + GL_CEHCK_ERROR; + + context->fs = glCreateShader(GL_FRAGMENT_SHADER); + if(context->userShaderFragment){ + extendedStage = (const char*)context->userShaderFragment; + } else { + extendedStage = vgShaderFragmentUserDefault; + } + buf[0] = vgShaderFragmentPipeline; + buf[1] = extendedStage; + size[0] = strlen(vgShaderFragmentPipeline); + size[1] = strlen(extendedStage); + glShaderSource(context->fs, 2, buf, size); + glCompileShader(context->fs); + glGetShaderiv(context->fs, GL_COMPILE_STATUS, &compileStatus); + printf("Shader compile status :%d line:%d\n", compileStatus, __LINE__); + GL_CEHCK_ERROR; + + context->progDraw = glCreateProgram(); + glAttachShader(context->progDraw, context->vs); + glAttachShader(context->progDraw, context->fs); + glLinkProgram(context->progDraw); + GL_CEHCK_ERROR; + + context->locationDraw.pos = glGetAttribLocation(context->progDraw, "pos"); + context->locationDraw.textureUV = glGetAttribLocation(context->progDraw, "textureUV"); + context->locationDraw.model = glGetUniformLocation(context->progDraw, "sh_Model"); + context->locationDraw.projection = glGetUniformLocation(context->progDraw, "sh_Ortho"); + context->locationDraw.paintInverted = glGetUniformLocation(context->progDraw, "paintInverted"); + context->locationDraw.drawMode = glGetUniformLocation(context->progDraw, "drawMode"); + context->locationDraw.imageSampler = glGetUniformLocation(context->progDraw, "imageSampler"); + context->locationDraw.imageMode = glGetUniformLocation(context->progDraw, "imageMode"); + context->locationDraw.paintType = glGetUniformLocation(context->progDraw, "paintType"); + context->locationDraw.rampSampler = glGetUniformLocation(context->progDraw, "rampSampler"); + context->locationDraw.patternSampler = glGetUniformLocation(context->progDraw, "patternSampler"); + context->locationDraw.paintParams = glGetUniformLocation(context->progDraw, "paintParams"); + context->locationDraw.paintColor = glGetUniformLocation(context->progDraw, "paintColor"); + context->locationDraw.scaleFactorBias= glGetUniformLocation(context->progDraw, "scaleFactorBias"); + GL_CEHCK_ERROR; + + // TODO: Support color transform to remove this from here + glUseProgram(context->progDraw); + GLfloat factor_bias[8] = {1.0,1.0,1.0,1.0,0.0,0.0,0.0,0.0}; + glUniform4fv(context->locationDraw.scaleFactorBias, 2, factor_bias); + GL_CEHCK_ERROR; + + /* Initialize uniform variables */ + float mat[16]; + float volume = fmax(context->surfaceWidth, context->surfaceHeight) / 2; + shCalcOrtho2D(mat, 0, context->surfaceWidth , 0, context->surfaceHeight, -volume, volume); + glUniformMatrix4fv(context->locationDraw.projection, 1, GL_FALSE, mat); + GL_CEHCK_ERROR; +} + +void shDeinitPiplelineShaders(void){ + + VG_GETCONTEXT(VG_NO_RETVAL); + glDeleteShader(context->vs); + glDeleteShader(context->fs); + glDeleteProgram(context->progDraw); + GL_CEHCK_ERROR; +} + +void shInitRampShaders(void) { + + VG_GETCONTEXT(VG_NO_RETVAL); + GLint compileStatus; + + GLuint vs = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vs, 1, &vgShaderVertexColorRamp, NULL); + glCompileShader(vs); + glGetShaderiv(vs, GL_COMPILE_STATUS, &compileStatus); + printf("Shader compile status :%d line:%d\n", compileStatus, __LINE__); + GL_CEHCK_ERROR; + + GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fs, 1, &vgShaderFragmentColorRamp, NULL); + glCompileShader(fs); + glGetShaderiv(fs, GL_COMPILE_STATUS, &compileStatus); + printf("Shader compile status :%d line:%d\n", compileStatus, __LINE__); + GL_CEHCK_ERROR; + + context->progColorRamp = glCreateProgram(); + glAttachShader(context->progColorRamp, vs); + glAttachShader(context->progColorRamp, fs); + glLinkProgram(context->progColorRamp); + glDeleteShader(vs); + glDeleteShader(fs); + GL_CEHCK_ERROR; + + context->locationColorRamp.step = glGetAttribLocation(context->progColorRamp, "step"); + context->locationColorRamp.stepColor = glGetAttribLocation(context->progColorRamp, "stepColor"); + GL_CEHCK_ERROR; +} + +void shDeinitRampShaders(void){ + VG_GETCONTEXT(VG_NO_RETVAL); + glDeleteProgram(context->progColorRamp); +} + +VG_API_CALL void vgShaderSourceSH(VGuint shadertype, const VGbyte* string){ + VG_GETCONTEXT(VG_NO_RETVAL); + + switch(shadertype) { + case VG_FRAGMENT_SHADER_SH: + context->userShaderFragment = (const void*)string; + break; + case VG_VERTEX_SHADER_SH: + context->userShaderVertex = (const void*)string; + break; + default: + break; + } +} + +VG_API_CALL void vgCompileShaderSH(void){ + shDeinitPiplelineShaders(); + shInitPiplelineShaders(); +} + +VG_API_CALL void vgUniform1fSH(VGint location, VGfloat v0){ + glUniform1f(location, v0); + GL_CEHCK_ERROR; +} + +VG_API_CALL void vgUniform2fSH(VGint location, VGfloat v0, VGfloat v1){ + glUniform2f(location, v0, v1); + GL_CEHCK_ERROR; +} + +VG_API_CALL void vgUniform3fSH(VGint location, VGfloat v0, VGfloat v1, VGfloat v2){ + glUniform3f(location, v0, v1, v2); + GL_CEHCK_ERROR; +} + +VG_API_CALL void vgUniform4fSH(VGint location, VGfloat v0, VGfloat v1, VGfloat v2, VGfloat v3){ + glUniform4f(location, v0, v1, v2, v3); + GL_CEHCK_ERROR; +} + +VG_API_CALL void vgUniform1fvSH(VGint location, VGint count, const VGfloat *value){ + glUniform1fv(location, count, value); + GL_CEHCK_ERROR; +} + +VG_API_CALL void vgUniform2fvSH(VGint location, VGint count, const VGfloat *value){ + glUniform2fv(location, count, value); + GL_CEHCK_ERROR; +} + +VG_API_CALL void vgUniform3fvSH(VGint location, VGint count, const VGfloat *value){ + glUniform3fv(location, count, value); + GL_CEHCK_ERROR; +} + +VG_API_CALL void vgUniform4fvSH(VGint location, VGint count, const VGfloat *value){ + glUniform4fv(location, count, value); + GL_CEHCK_ERROR; +} + +VG_API_CALL void vgUniformMatrix2fvSH(VGint location, VGint count, VGboolean transpose, const VGfloat *value){ + glUniformMatrix2fv(location, count, transpose, value); + GL_CEHCK_ERROR; +} + +VG_API_CALL void vgUniformMatrix3fvSH(VGint location, VGint count, VGboolean transpose, const VGfloat *value){ + glUniformMatrix3fv(location, count, transpose, value); + GL_CEHCK_ERROR; +} + +VG_API_CALL void vgUniformMatrix4fvSH(VGint location, VGint count, VGboolean transpose, const VGfloat *value){ + glUniformMatrix4fv(location, count, transpose, value); + GL_CEHCK_ERROR; +} + +VG_API_CALL VGint vgGetUniformLocationSH(const VGbyte *name){ + VG_GETCONTEXT(-1); + VGint retval = glGetUniformLocation(context->progDraw, name); + GL_CEHCK_ERROR; + return retval; +} + +VG_API_CALL void vgGetUniformfvSH(VGint location, VGfloat *params){ + VG_GETCONTEXT(VG_NO_RETVAL); + glGetUniformfv(context->progDraw, location, params); + GL_CEHCK_ERROR; +} + +VG_API_CALL void vgUniform1iSH (VGint location, VGint v0){ + glUniform1i (location, v0); + GL_CEHCK_ERROR; +} + +VG_API_CALL void vgUniform2iSH (VGint location, VGint v0, VGint v1){ + glUniform2i (location, v0, v1); + GL_CEHCK_ERROR; +} + +VG_API_CALL void vgUniform3iSH (VGint location, VGint v0, VGint v1, VGint v2){ + glUniform3i (location, v0, v1, v2); + GL_CEHCK_ERROR; +} + +VG_API_CALL void vgUniform4iSH (VGint location, VGint v0, VGint v1, VGint v2, VGint v3){ + glUniform4i (location, v0, v1, v2, v3); + GL_CEHCK_ERROR; +} + +VG_API_CALL void vgUniform1ivSH (VGint location, VGint count, const VGint *value){ + glUniform1iv (location, count, value); + GL_CEHCK_ERROR; +} + +VG_API_CALL void vgUniform2ivSH (VGint location, VGint count, const VGint *value){ + glUniform2iv (location, count, value); + GL_CEHCK_ERROR; +} + +VG_API_CALL void vgUniform3ivSH (VGint location, VGint count, const VGint *value){ + glUniform3iv (location, count, value); + GL_CEHCK_ERROR; +} + +VG_API_CALL void vgUniform4ivSH (VGint location, VGint count, const VGint *value){ + glUniform4iv (location, count, value); + GL_CEHCK_ERROR; +} + + diff --git a/simgear/canvas/ShaderVG/src/shaders.h b/simgear/canvas/ShaderVG/src/shaders.h new file mode 100644 index 00000000..06ab466d --- /dev/null +++ b/simgear/canvas/ShaderVG/src/shaders.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2021 Takuma Hayashi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __SHADERS_H +#define __SHADERS_H + +void shInitPiplelineShaders(void); +void shDeinitPiplelineShaders(void); + +void shInitRampShaders(void); +void shDeinitRampShaders(void); + +#endif /* __SHADERS_H */