Compare commits

...

No commits in common. "gh-pages" and "master" have entirely different histories.

70 changed files with 32810 additions and 7010 deletions

1
.gitattributes vendored Normal file
View file

@ -0,0 +1 @@
* text=auto

55
.gitignore vendored Normal file
View file

@ -0,0 +1,55 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# C extensions
*.so
# Distribution / packaging
.Python
env/
bin/
build/
develop-eggs/
dist/
eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
.tox/
.coverage
.cache
nosetests.xml
coverage.xml
# Translations
*.mo
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
# Rope
.ropeproject
# Django stuff:
*.log
*.pot
# Sphinx documentation
docs/_build/
# gltools build
MANIFEST

View file

368
LICENSE.txt Normal file
View file

@ -0,0 +1,368 @@
License for:
gltools
Truetype code:
stb_truetype.h - v0.6c - public domain
authored from 2009-2012 by Sean Barrett / RAD Game Tools
UTF-8 decoder:
http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
fontstash (with modifications marked in code)
recastnavigation - Mikko Mononen
http://digestingduck.blogspot.com/
License - MIT License
TTF font DroidSans:
http://www.droidfonts.com/
License - Apache License, Version 2.0
IMGUI (with modifications marked in code)
recastnavigation - Mikko Mononen
http://digestingduck.blogspot.com/
License - MIT License
Copyright (C) 2012 Runar Tenfjord, Tenko
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 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.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, 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 or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
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 give any other recipients of the Program a copy of this License
along with the Program.
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 Program or any portion
of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
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 Program, 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 Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) 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; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, 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 executable. However, as a
special exception, the source code 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.
If distribution of executable or 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 counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program 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.
5. 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 Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program 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 to
this License.
7. 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 Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program 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 Program.
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.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program 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.
9. The Free Software Foundation may publish revised and/or new versions
of the 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 Program
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 Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, 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
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), 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 Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. 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.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; 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.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

10
MANIFEST.in Normal file
View file

@ -0,0 +1,10 @@
include Makefile
include setup_build.py
include setup_docs.py
include version.py
include MANIFEST.in
include README.rst
include LICENSE.txt
recursive-include gltools *.py *.pyx *.pxi *.pxd *.rst
recursive-include gltools *.cpp *.c *.h
prune gltools/@arch

38
Makefile Normal file
View file

@ -0,0 +1,38 @@
#
# File: Makefile (for library)
#
# The variables 'PYTHON' and 'PYVER' can be modified by
# passing parameters to make: make PYTHON=python PYVER=2.6
#
PYTHON=python2
PYVER=2.7
.PHONY: all docs test install clean
all:
@echo lib Makefile - building python extension
$(PYTHON) setup_build.py build_ext --inplace
docs: all
@echo lib Makefile - building documentation
@cd gltools/@docs ; $(PYTHON) ../../setup_docs.py build_sphinx
@cp -rf gltools/@docs/build/sphinx/html/* gltools/@docs/html/
install: all
@cp gltools.so ~/.local/lib/python$(PYVER)/site-packages/
@cp gltools/gltools.pxd ~/.local/lib/python$(PYVER)/site-packages/
sdist: clean
@echo lib Makefile - creating source distribution
$(PYTHON) setup_build.py sdist --formats=gztar,zip
clean:
-rm -rf build dist
-rm -rf gltools/@docs/build
-rm gltools/@src/Config.pxi
-rm gltools/gltools.cpp gltools.so gltools/gltools.so MANIFEST
-find gltools -iname '*.so' -exec rm {} \;
-find gltools -iname '*.dll' -exec rm {} \;
-find gltools -iname '*.pyc' -exec rm {} \;
-find gltools -iname '*.pyo' -exec rm {} \;
-find gltools -iname '*.pyd' -exec rm {} \;

49
README.rst Normal file
View file

@ -0,0 +1,49 @@
Introduction
============
gltools is library for quickly creating OpenGL based
application in Python/Cython with support for:
* Access to vertex buffers and GLSL shaders
* Access to truetype fonts
* Windows handling through GLFW
* Saving framebuffer content to PNG file.
* Simple GUI controls
OpenGL version 2.1 is targeted which should be available
in most computers these days, even in a laptop's integrated
graphics.
The license is GPL v2.
Building
========
* Python 2.7/3.x and Cython 0.17 or later.
* The geotools_ library.
* GLFW_ v3.0
* OpenGL headers
For Linux build scripts are available for ArchLinux in the AUR_
repository. These could be adapted to other Linux distros.
History
=======
* v0.2.1 : Updated to released version of GLFW3
* v0.1.1 : Added missing files and fix building against GLFW3 trunk.
Documentation
=============
See online Sphinx docs_
.. _docs: http://tenko.github.com/gltools/index.html
.. _geotools: http://github.com/tenko/geotools
.. _GLFW: http://github.com/elmindreda/glfw
.. _pypi: http://pypi.python.org/pypi/gltools
.. _AUR: https://aur.archlinux.org/packages/?O=0&K=gltools

Binary file not shown.

Before

Width:  |  Height:  |  Size: 673 B

View file

@ -1,540 +0,0 @@
/*
* basic.css
* ~~~~~~~~~
*
* Sphinx stylesheet -- basic theme.
*
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
/* -- main layout ----------------------------------------------------------- */
div.clearer {
clear: both;
}
/* -- relbar ---------------------------------------------------------------- */
div.related {
width: 100%;
font-size: 90%;
}
div.related h3 {
display: none;
}
div.related ul {
margin: 0;
padding: 0 0 0 10px;
list-style: none;
}
div.related li {
display: inline;
}
div.related li.right {
float: right;
margin-right: 5px;
}
/* -- sidebar --------------------------------------------------------------- */
div.sphinxsidebarwrapper {
padding: 10px 5px 0 10px;
}
div.sphinxsidebar {
float: left;
width: 230px;
margin-left: -100%;
font-size: 90%;
}
div.sphinxsidebar ul {
list-style: none;
}
div.sphinxsidebar ul ul,
div.sphinxsidebar ul.want-points {
margin-left: 20px;
list-style: square;
}
div.sphinxsidebar ul ul {
margin-top: 0;
margin-bottom: 0;
}
div.sphinxsidebar form {
margin-top: 10px;
}
div.sphinxsidebar input {
border: 1px solid #98dbcc;
font-family: sans-serif;
font-size: 1em;
}
div.sphinxsidebar #searchbox input[type="text"] {
width: 170px;
}
div.sphinxsidebar #searchbox input[type="submit"] {
width: 30px;
}
img {
border: 0;
}
/* -- search page ----------------------------------------------------------- */
ul.search {
margin: 10px 0 0 20px;
padding: 0;
}
ul.search li {
padding: 5px 0 5px 20px;
background-image: url(file.png);
background-repeat: no-repeat;
background-position: 0 7px;
}
ul.search li a {
font-weight: bold;
}
ul.search li div.context {
color: #888;
margin: 2px 0 0 30px;
text-align: left;
}
ul.keywordmatches li.goodmatch a {
font-weight: bold;
}
/* -- index page ------------------------------------------------------------ */
table.contentstable {
width: 90%;
}
table.contentstable p.biglink {
line-height: 150%;
}
a.biglink {
font-size: 1.3em;
}
span.linkdescr {
font-style: italic;
padding-top: 5px;
font-size: 90%;
}
/* -- general index --------------------------------------------------------- */
table.indextable {
width: 100%;
}
table.indextable td {
text-align: left;
vertical-align: top;
}
table.indextable dl, table.indextable dd {
margin-top: 0;
margin-bottom: 0;
}
table.indextable tr.pcap {
height: 10px;
}
table.indextable tr.cap {
margin-top: 10px;
background-color: #f2f2f2;
}
img.toggler {
margin-right: 3px;
margin-top: 3px;
cursor: pointer;
}
div.modindex-jumpbox {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 1em 0 1em 0;
padding: 0.4em;
}
div.genindex-jumpbox {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 1em 0 1em 0;
padding: 0.4em;
}
/* -- general body styles --------------------------------------------------- */
a.headerlink {
visibility: hidden;
}
h1:hover > a.headerlink,
h2:hover > a.headerlink,
h3:hover > a.headerlink,
h4:hover > a.headerlink,
h5:hover > a.headerlink,
h6:hover > a.headerlink,
dt:hover > a.headerlink {
visibility: visible;
}
div.body p.caption {
text-align: inherit;
}
div.body td {
text-align: left;
}
.field-list ul {
padding-left: 1em;
}
.first {
margin-top: 0 !important;
}
p.rubric {
margin-top: 30px;
font-weight: bold;
}
img.align-left, .figure.align-left, object.align-left {
clear: left;
float: left;
margin-right: 1em;
}
img.align-right, .figure.align-right, object.align-right {
clear: right;
float: right;
margin-left: 1em;
}
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left;
}
.align-center {
text-align: center;
}
.align-right {
text-align: right;
}
/* -- sidebars -------------------------------------------------------------- */
div.sidebar {
margin: 0 0 0.5em 1em;
border: 1px solid #ddb;
padding: 7px 7px 0 7px;
background-color: #ffe;
width: 40%;
float: right;
}
p.sidebar-title {
font-weight: bold;
}
/* -- topics ---------------------------------------------------------------- */
div.topic {
border: 1px solid #ccc;
padding: 7px 7px 0 7px;
margin: 10px 0 10px 0;
}
p.topic-title {
font-size: 1.1em;
font-weight: bold;
margin-top: 10px;
}
/* -- admonitions ----------------------------------------------------------- */
div.admonition {
margin-top: 10px;
margin-bottom: 10px;
padding: 7px;
}
div.admonition dt {
font-weight: bold;
}
div.admonition dl {
margin-bottom: 0;
}
p.admonition-title {
margin: 0px 10px 5px 0px;
font-weight: bold;
}
div.body p.centered {
text-align: center;
margin-top: 25px;
}
/* -- tables ---------------------------------------------------------------- */
table.docutils {
border: 0;
border-collapse: collapse;
}
table.docutils td, table.docutils th {
padding: 1px 8px 1px 5px;
border-top: 0;
border-left: 0;
border-right: 0;
border-bottom: 1px solid #aaa;
}
table.field-list td, table.field-list th {
border: 0 !important;
}
table.footnote td, table.footnote th {
border: 0 !important;
}
th {
text-align: left;
padding-right: 5px;
}
table.citation {
border-left: solid 1px gray;
margin-left: 1px;
}
table.citation td {
border-bottom: none;
}
/* -- other body styles ----------------------------------------------------- */
ol.arabic {
list-style: decimal;
}
ol.loweralpha {
list-style: lower-alpha;
}
ol.upperalpha {
list-style: upper-alpha;
}
ol.lowerroman {
list-style: lower-roman;
}
ol.upperroman {
list-style: upper-roman;
}
dl {
margin-bottom: 15px;
}
dd p {
margin-top: 0px;
}
dd ul, dd table {
margin-bottom: 10px;
}
dd {
margin-top: 3px;
margin-bottom: 10px;
margin-left: 30px;
}
dt:target, .highlighted {
background-color: #fbe54e;
}
dl.glossary dt {
font-weight: bold;
font-size: 1.1em;
}
.field-list ul {
margin: 0;
padding-left: 1em;
}
.field-list p {
margin: 0;
}
.refcount {
color: #060;
}
.optional {
font-size: 1.3em;
}
.versionmodified {
font-style: italic;
}
.system-message {
background-color: #fda;
padding: 5px;
border: 3px solid red;
}
.footnote:target {
background-color: #ffa;
}
.line-block {
display: block;
margin-top: 1em;
margin-bottom: 1em;
}
.line-block .line-block {
margin-top: 0;
margin-bottom: 0;
margin-left: 1.5em;
}
.guilabel, .menuselection {
font-family: sans-serif;
}
.accelerator {
text-decoration: underline;
}
.classifier {
font-style: oblique;
}
abbr, acronym {
border-bottom: dotted 1px;
cursor: help;
}
/* -- code displays --------------------------------------------------------- */
pre {
overflow: auto;
overflow-y: hidden; /* fixes display issues on Chrome browsers */
}
td.linenos pre {
padding: 5px 0px;
border: 0;
background-color: transparent;
color: #aaa;
}
table.highlighttable {
margin-left: 0.5em;
}
table.highlighttable td {
padding: 0 0.5em 0 0.5em;
}
tt.descname {
background-color: transparent;
font-weight: bold;
font-size: 1.2em;
}
tt.descclassname {
background-color: transparent;
}
tt.xref, a tt {
background-color: transparent;
font-weight: bold;
}
h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
background-color: transparent;
}
.viewcode-link {
float: right;
}
.viewcode-back {
float: right;
font-family: sans-serif;
}
div.viewcode-block:target {
margin: -1px -10px;
padding: 0 10px;
}
/* -- math display ---------------------------------------------------------- */
img.math {
vertical-align: middle;
}
div.body div.math p {
text-align: center;
}
span.eqno {
float: right;
}
/* -- printout stylesheet --------------------------------------------------- */
@media print {
div.document,
div.documentwrapper,
div.bodywrapper {
margin: 0 !important;
width: 100%;
}
div.sphinxsidebar,
div.related,
div.footer,
#top-link {
display: none;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

View file

@ -1,256 +0,0 @@
/*
* default.css_t
* ~~~~~~~~~~~~~
*
* Sphinx stylesheet -- default theme.
*
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
@import url("basic.css");
/* -- page layout ----------------------------------------------------------- */
body {
font-family: sans-serif;
font-size: 100%;
background-color: #11303d;
color: #000;
margin: 0;
padding: 0;
}
div.document {
background-color: #1c4e63;
}
div.documentwrapper {
float: left;
width: 100%;
}
div.bodywrapper {
margin: 0 0 0 230px;
}
div.body {
background-color: #ffffff;
color: #000000;
padding: 0 20px 30px 20px;
}
div.footer {
color: #ffffff;
width: 100%;
padding: 9px 0 9px 0;
text-align: center;
font-size: 75%;
}
div.footer a {
color: #ffffff;
text-decoration: underline;
}
div.related {
background-color: #133f52;
line-height: 30px;
color: #ffffff;
}
div.related a {
color: #ffffff;
}
div.sphinxsidebar {
}
div.sphinxsidebar h3 {
font-family: 'Trebuchet MS', sans-serif;
color: #ffffff;
font-size: 1.4em;
font-weight: normal;
margin: 0;
padding: 0;
}
div.sphinxsidebar h3 a {
color: #ffffff;
}
div.sphinxsidebar h4 {
font-family: 'Trebuchet MS', sans-serif;
color: #ffffff;
font-size: 1.3em;
font-weight: normal;
margin: 5px 0 0 0;
padding: 0;
}
div.sphinxsidebar p {
color: #ffffff;
}
div.sphinxsidebar p.topless {
margin: 5px 10px 10px 10px;
}
div.sphinxsidebar ul {
margin: 10px;
padding: 0;
color: #ffffff;
}
div.sphinxsidebar a {
color: #98dbcc;
}
div.sphinxsidebar input {
border: 1px solid #98dbcc;
font-family: sans-serif;
font-size: 1em;
}
/* -- hyperlink styles ------------------------------------------------------ */
a {
color: #355f7c;
text-decoration: none;
}
a:visited {
color: #355f7c;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
/* -- body styles ----------------------------------------------------------- */
div.body h1,
div.body h2,
div.body h3,
div.body h4,
div.body h5,
div.body h6 {
font-family: 'Trebuchet MS', sans-serif;
background-color: #f2f2f2;
font-weight: normal;
color: #20435c;
border-bottom: 1px solid #ccc;
margin: 20px -20px 10px -20px;
padding: 3px 0 3px 10px;
}
div.body h1 { margin-top: 0; font-size: 200%; }
div.body h2 { font-size: 160%; }
div.body h3 { font-size: 140%; }
div.body h4 { font-size: 120%; }
div.body h5 { font-size: 110%; }
div.body h6 { font-size: 100%; }
a.headerlink {
color: #c60f0f;
font-size: 0.8em;
padding: 0 4px 0 4px;
text-decoration: none;
}
a.headerlink:hover {
background-color: #c60f0f;
color: white;
}
div.body p, div.body dd, div.body li {
text-align: justify;
line-height: 130%;
}
div.admonition p.admonition-title + p {
display: inline;
}
div.admonition p {
margin-bottom: 5px;
}
div.admonition pre {
margin-bottom: 5px;
}
div.admonition ul, div.admonition ol {
margin-bottom: 5px;
}
div.note {
background-color: #eee;
border: 1px solid #ccc;
}
div.seealso {
background-color: #ffc;
border: 1px solid #ff6;
}
div.topic {
background-color: #eee;
}
div.warning {
background-color: #ffe4e4;
border: 1px solid #f66;
}
p.admonition-title {
display: inline;
}
p.admonition-title:after {
content: ":";
}
pre {
padding: 5px;
background-color: #eeffcc;
color: #333333;
line-height: 120%;
border: 1px solid #ac9;
border-left: none;
border-right: none;
}
tt {
background-color: #ecf0f3;
padding: 0 1px 0 1px;
font-size: 0.95em;
}
th {
background-color: #ede;
}
.warning tt {
background: #efc2c2;
}
.note tt {
background: #d6d6d6;
}
.viewcode-back {
font-family: sans-serif;
}
div.viewcode-block:target {
background-color: #f4debf;
border-top: 1px solid #ac9;
border-bottom: 1px solid #ac9;
}

View file

@ -1,247 +0,0 @@
/*
* doctools.js
* ~~~~~~~~~~~
*
* Sphinx JavaScript utilities for all documentation.
*
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
/**
* select a different prefix for underscore
*/
$u = _.noConflict();
/**
* make the code below compatible with browsers without
* an installed firebug like debugger
if (!window.console || !console.firebug) {
var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
"dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace",
"profile", "profileEnd"];
window.console = {};
for (var i = 0; i < names.length; ++i)
window.console[names[i]] = function() {};
}
*/
/**
* small helper function to urldecode strings
*/
jQuery.urldecode = function(x) {
return decodeURIComponent(x).replace(/\+/g, ' ');
}
/**
* small helper function to urlencode strings
*/
jQuery.urlencode = encodeURIComponent;
/**
* This function returns the parsed url parameters of the
* current request. Multiple values per key are supported,
* it will always return arrays of strings for the value parts.
*/
jQuery.getQueryParameters = function(s) {
if (typeof s == 'undefined')
s = document.location.search;
var parts = s.substr(s.indexOf('?') + 1).split('&');
var result = {};
for (var i = 0; i < parts.length; i++) {
var tmp = parts[i].split('=', 2);
var key = jQuery.urldecode(tmp[0]);
var value = jQuery.urldecode(tmp[1]);
if (key in result)
result[key].push(value);
else
result[key] = [value];
}
return result;
};
/**
* small function to check if an array contains
* a given item.
*/
jQuery.contains = function(arr, item) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] == item)
return true;
}
return false;
};
/**
* highlight a given string on a jquery object by wrapping it in
* span elements with the given class name.
*/
jQuery.fn.highlightText = function(text, className) {
function highlight(node) {
if (node.nodeType == 3) {
var val = node.nodeValue;
var pos = val.toLowerCase().indexOf(text);
if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) {
var span = document.createElement("span");
span.className = className;
span.appendChild(document.createTextNode(val.substr(pos, text.length)));
node.parentNode.insertBefore(span, node.parentNode.insertBefore(
document.createTextNode(val.substr(pos + text.length)),
node.nextSibling));
node.nodeValue = val.substr(0, pos);
}
}
else if (!jQuery(node).is("button, select, textarea")) {
jQuery.each(node.childNodes, function() {
highlight(this);
});
}
}
return this.each(function() {
highlight(this);
});
};
/**
* Small JavaScript module for the documentation.
*/
var Documentation = {
init : function() {
this.fixFirefoxAnchorBug();
this.highlightSearchWords();
this.initIndexTable();
},
/**
* i18n support
*/
TRANSLATIONS : {},
PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; },
LOCALE : 'unknown',
// gettext and ngettext don't access this so that the functions
// can safely bound to a different name (_ = Documentation.gettext)
gettext : function(string) {
var translated = Documentation.TRANSLATIONS[string];
if (typeof translated == 'undefined')
return string;
return (typeof translated == 'string') ? translated : translated[0];
},
ngettext : function(singular, plural, n) {
var translated = Documentation.TRANSLATIONS[singular];
if (typeof translated == 'undefined')
return (n == 1) ? singular : plural;
return translated[Documentation.PLURALEXPR(n)];
},
addTranslations : function(catalog) {
for (var key in catalog.messages)
this.TRANSLATIONS[key] = catalog.messages[key];
this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
this.LOCALE = catalog.locale;
},
/**
* add context elements like header anchor links
*/
addContextElements : function() {
$('div[id] > :header:first').each(function() {
$('<a class="headerlink">\u00B6</a>').
attr('href', '#' + this.id).
attr('title', _('Permalink to this headline')).
appendTo(this);
});
$('dt[id]').each(function() {
$('<a class="headerlink">\u00B6</a>').
attr('href', '#' + this.id).
attr('title', _('Permalink to this definition')).
appendTo(this);
});
},
/**
* workaround a firefox stupidity
*/
fixFirefoxAnchorBug : function() {
if (document.location.hash && $.browser.mozilla)
window.setTimeout(function() {
document.location.href += '';
}, 10);
},
/**
* highlight the search words provided in the url in the text
*/
highlightSearchWords : function() {
var params = $.getQueryParameters();
var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
if (terms.length) {
var body = $('div.body');
window.setTimeout(function() {
$.each(terms, function() {
body.highlightText(this.toLowerCase(), 'highlighted');
});
}, 10);
$('<p class="highlight-link"><a href="javascript:Documentation.' +
'hideSearchWords()">' + _('Hide Search Matches') + '</a></p>')
.appendTo($('#searchbox'));
}
},
/**
* init the domain index toggle buttons
*/
initIndexTable : function() {
var togglers = $('img.toggler').click(function() {
var src = $(this).attr('src');
var idnum = $(this).attr('id').substr(7);
$('tr.cg-' + idnum).toggle();
if (src.substr(-9) == 'minus.png')
$(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
else
$(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
}).css('display', '');
if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {
togglers.click();
}
},
/**
* helper function to hide the search marks again
*/
hideSearchWords : function() {
$('#searchbox .highlight-link').fadeOut(300);
$('span.highlighted').removeClass('highlighted');
},
/**
* make the url absolute
*/
makeURL : function(relativeURL) {
return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
},
/**
* get the current relative url
*/
getCurrentURL : function() {
var path = document.location.pathname;
var parts = path.split(/\//);
$.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
if (this == '..')
parts.pop();
});
var url = parts.join('/');
return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
}
};
// quick alias for translations
_ = Documentation.gettext;
$(document).ready(function() {
Documentation.init();
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 368 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 363 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 392 B

154
_static/jquery.js vendored
View file

@ -1,154 +0,0 @@
/*!
* jQuery JavaScript Library v1.4.2
* http://jquery.com/
*
* Copyright 2010, John Resig
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* Includes Sizzle.js
* http://sizzlejs.com/
* Copyright 2010, The Dojo Foundation
* Released under the MIT, BSD, and GPL Licenses.
*
* Date: Sat Feb 13 22:33:48 2010 -0500
*/
(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i?
e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r=
j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g,
"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e=
true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/,
Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&&
(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this,
a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b===
"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,
function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)||
c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded",
L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,
"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+
a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f],
d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===
a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&&
!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari=
true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,
parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent=
false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n=
s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,
applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando];
else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,
a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===
w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i,
cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ",
i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ",
" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=
this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i=
e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected=
c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g,
function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split(".");
k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a),
C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove.call(a,u)}if(f!=
null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=
e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&&
f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;
if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.each(c.data(this,
"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=
a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,
isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submitBubbles)c.event.special.submit=
{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};
if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",
e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,
"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,
d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&
!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},
toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j||this.selector,
u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),
function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];
if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift();
t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D||
g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q;if(!g)return[];
for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-
1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},
relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m++)if(p=g[m])g[m]=
l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var l=[];
h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m,
g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=
h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0;for(m=p.firstChild;m;m=
m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g,
h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocumentPosition||
!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createRange(),m=
h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&&
q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML="<a href='#'></a>";
if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}();
(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}:
function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Until$/,fb=/^(?:parents|prevUntil|prevAll)/,
gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;
c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j=
{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a===
"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType===
1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<object|<embed|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b,d){return hb.test(d)?
a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja,
""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&
this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagName("tbody")[0]||
u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childNodes.length===
1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]);
return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["",
""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!==
"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this},
serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),
function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,
global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&
e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)?
"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===
false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B=
false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since",
c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E||
d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x);
g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===
1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b===
"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional;
if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");
this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],
"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},
animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){(j.specialEasing=
j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);
this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration===
"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||
c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;
this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=
this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,
e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||
c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement?
function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=
this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.currentStyle;
k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&&
f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b);
c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,
d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-
f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset":
"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in
e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 B

View file

@ -1,62 +0,0 @@
.highlight .hll { background-color: #ffffcc }
.highlight { background: #eeffcc; }
.highlight .c { color: #408090; font-style: italic } /* Comment */
.highlight .err { border: 1px solid #FF0000 } /* Error */
.highlight .k { color: #007020; font-weight: bold } /* Keyword */
.highlight .o { color: #666666 } /* Operator */
.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #007020 } /* Comment.Preproc */
.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */
.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #A00000 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #FF0000 } /* Generic.Error */
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.highlight .gi { color: #00A000 } /* Generic.Inserted */
.highlight .go { color: #303030 } /* Generic.Output */
.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.highlight .gt { color: #0040D0 } /* Generic.Traceback */
.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #007020 } /* Keyword.Pseudo */
.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #902000 } /* Keyword.Type */
.highlight .m { color: #208050 } /* Literal.Number */
.highlight .s { color: #4070a0 } /* Literal.String */
.highlight .na { color: #4070a0 } /* Name.Attribute */
.highlight .nb { color: #007020 } /* Name.Builtin */
.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
.highlight .no { color: #60add5 } /* Name.Constant */
.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */
.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */
.highlight .ne { color: #007020 } /* Name.Exception */
.highlight .nf { color: #06287e } /* Name.Function */
.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */
.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #bb60d5 } /* Name.Variable */
.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mf { color: #208050 } /* Literal.Number.Float */
.highlight .mh { color: #208050 } /* Literal.Number.Hex */
.highlight .mi { color: #208050 } /* Literal.Number.Integer */
.highlight .mo { color: #208050 } /* Literal.Number.Oct */
.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */
.highlight .sc { color: #4070a0 } /* Literal.String.Char */
.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
.highlight .s2 { color: #4070a0 } /* Literal.String.Double */
.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */
.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
.highlight .sx { color: #c65d09 } /* Literal.String.Other */
.highlight .sr { color: #235388 } /* Literal.String.Regex */
.highlight .s1 { color: #4070a0 } /* Literal.String.Single */
.highlight .ss { color: #517918 } /* Literal.String.Symbol */
.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */
.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */

View file

@ -1,560 +0,0 @@
/*
* searchtools.js_t
* ~~~~~~~~~~~~~~~~
*
* Sphinx JavaScript utilties for the full-text search.
*
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
/**
* helper function to return a node containing the
* search summary for a given text. keywords is a list
* of stemmed words, hlwords is the list of normal, unstemmed
* words. the first one is used to find the occurance, the
* latter for highlighting it.
*/
jQuery.makeSearchSummary = function(text, keywords, hlwords) {
var textLower = text.toLowerCase();
var start = 0;
$.each(keywords, function() {
var i = textLower.indexOf(this.toLowerCase());
if (i > -1)
start = i;
});
start = Math.max(start - 120, 0);
var excerpt = ((start > 0) ? '...' : '') +
$.trim(text.substr(start, 240)) +
((start + 240 - text.length) ? '...' : '');
var rv = $('<div class="context"></div>').text(excerpt);
$.each(hlwords, function() {
rv = rv.highlightText(this, 'highlighted');
});
return rv;
}
/**
* Porter Stemmer
*/
var Stemmer = function() {
var step2list = {
ational: 'ate',
tional: 'tion',
enci: 'ence',
anci: 'ance',
izer: 'ize',
bli: 'ble',
alli: 'al',
entli: 'ent',
eli: 'e',
ousli: 'ous',
ization: 'ize',
ation: 'ate',
ator: 'ate',
alism: 'al',
iveness: 'ive',
fulness: 'ful',
ousness: 'ous',
aliti: 'al',
iviti: 'ive',
biliti: 'ble',
logi: 'log'
};
var step3list = {
icate: 'ic',
ative: '',
alize: 'al',
iciti: 'ic',
ical: 'ic',
ful: '',
ness: ''
};
var c = "[^aeiou]"; // consonant
var v = "[aeiouy]"; // vowel
var C = c + "[^aeiouy]*"; // consonant sequence
var V = v + "[aeiou]*"; // vowel sequence
var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0
var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1
var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1
var s_v = "^(" + C + ")?" + v; // vowel in stem
this.stemWord = function (w) {
var stem;
var suffix;
var firstch;
var origword = w;
if (w.length < 3)
return w;
var re;
var re2;
var re3;
var re4;
firstch = w.substr(0,1);
if (firstch == "y")
w = firstch.toUpperCase() + w.substr(1);
// Step 1a
re = /^(.+?)(ss|i)es$/;
re2 = /^(.+?)([^s])s$/;
if (re.test(w))
w = w.replace(re,"$1$2");
else if (re2.test(w))
w = w.replace(re2,"$1$2");
// Step 1b
re = /^(.+?)eed$/;
re2 = /^(.+?)(ed|ing)$/;
if (re.test(w)) {
var fp = re.exec(w);
re = new RegExp(mgr0);
if (re.test(fp[1])) {
re = /.$/;
w = w.replace(re,"");
}
}
else if (re2.test(w)) {
var fp = re2.exec(w);
stem = fp[1];
re2 = new RegExp(s_v);
if (re2.test(stem)) {
w = stem;
re2 = /(at|bl|iz)$/;
re3 = new RegExp("([^aeiouylsz])\\1$");
re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
if (re2.test(w))
w = w + "e";
else if (re3.test(w)) {
re = /.$/;
w = w.replace(re,"");
}
else if (re4.test(w))
w = w + "e";
}
}
// Step 1c
re = /^(.+?)y$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(s_v);
if (re.test(stem))
w = stem + "i";
}
// Step 2
re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
suffix = fp[2];
re = new RegExp(mgr0);
if (re.test(stem))
w = stem + step2list[suffix];
}
// Step 3
re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
suffix = fp[2];
re = new RegExp(mgr0);
if (re.test(stem))
w = stem + step3list[suffix];
}
// Step 4
re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
re2 = /^(.+?)(s|t)(ion)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(mgr1);
if (re.test(stem))
w = stem;
}
else if (re2.test(w)) {
var fp = re2.exec(w);
stem = fp[1] + fp[2];
re2 = new RegExp(mgr1);
if (re2.test(stem))
w = stem;
}
// Step 5
re = /^(.+?)e$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(mgr1);
re2 = new RegExp(meq1);
re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
w = stem;
}
re = /ll$/;
re2 = new RegExp(mgr1);
if (re.test(w) && re2.test(w)) {
re = /.$/;
w = w.replace(re,"");
}
// and turn initial Y back to y
if (firstch == "y")
w = firstch.toLowerCase() + w.substr(1);
return w;
}
}
/**
* Search Module
*/
var Search = {
_index : null,
_queued_query : null,
_pulse_status : -1,
init : function() {
var params = $.getQueryParameters();
if (params.q) {
var query = params.q[0];
$('input[name="q"]')[0].value = query;
this.performSearch(query);
}
},
loadIndex : function(url) {
$.ajax({type: "GET", url: url, data: null, success: null,
dataType: "script", cache: true});
},
setIndex : function(index) {
var q;
this._index = index;
if ((q = this._queued_query) !== null) {
this._queued_query = null;
Search.query(q);
}
},
hasIndex : function() {
return this._index !== null;
},
deferQuery : function(query) {
this._queued_query = query;
},
stopPulse : function() {
this._pulse_status = 0;
},
startPulse : function() {
if (this._pulse_status >= 0)
return;
function pulse() {
Search._pulse_status = (Search._pulse_status + 1) % 4;
var dotString = '';
for (var i = 0; i < Search._pulse_status; i++)
dotString += '.';
Search.dots.text(dotString);
if (Search._pulse_status > -1)
window.setTimeout(pulse, 500);
};
pulse();
},
/**
* perform a search for something
*/
performSearch : function(query) {
// create the required interface elements
this.out = $('#search-results');
this.title = $('<h2>' + _('Searching') + '</h2>').appendTo(this.out);
this.dots = $('<span></span>').appendTo(this.title);
this.status = $('<p style="display: none"></p>').appendTo(this.out);
this.output = $('<ul class="search"/>').appendTo(this.out);
$('#search-progress').text(_('Preparing search...'));
this.startPulse();
// index already loaded, the browser was quick!
if (this.hasIndex())
this.query(query);
else
this.deferQuery(query);
},
query : function(query) {
var stopwords = ["and","then","into","it","as","are","in","if","for","no","there","their","was","is","be","to","that","but","they","not","such","with","by","a","on","these","of","will","this","near","the","or","at"];
// Stem the searchterms and add them to the correct list
var stemmer = new Stemmer();
var searchterms = [];
var excluded = [];
var hlterms = [];
var tmp = query.split(/\s+/);
var objectterms = [];
for (var i = 0; i < tmp.length; i++) {
if (tmp[i] != "") {
objectterms.push(tmp[i].toLowerCase());
}
if ($u.indexOf(stopwords, tmp[i]) != -1 || tmp[i].match(/^\d+$/) ||
tmp[i] == "") {
// skip this "word"
continue;
}
// stem the word
var word = stemmer.stemWord(tmp[i]).toLowerCase();
// select the correct list
if (word[0] == '-') {
var toAppend = excluded;
word = word.substr(1);
}
else {
var toAppend = searchterms;
hlterms.push(tmp[i].toLowerCase());
}
// only add if not already in the list
if (!$.contains(toAppend, word))
toAppend.push(word);
};
var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
// console.debug('SEARCH: searching for:');
// console.info('required: ', searchterms);
// console.info('excluded: ', excluded);
// prepare search
var filenames = this._index.filenames;
var titles = this._index.titles;
var terms = this._index.terms;
var fileMap = {};
var files = null;
// different result priorities
var importantResults = [];
var objectResults = [];
var regularResults = [];
var unimportantResults = [];
$('#search-progress').empty();
// lookup as object
for (var i = 0; i < objectterms.length; i++) {
var others = [].concat(objectterms.slice(0,i),
objectterms.slice(i+1, objectterms.length))
var results = this.performObjectSearch(objectterms[i], others);
// Assume first word is most likely to be the object,
// other words more likely to be in description.
// Therefore put matches for earlier words first.
// (Results are eventually used in reverse order).
objectResults = results[0].concat(objectResults);
importantResults = results[1].concat(importantResults);
unimportantResults = results[2].concat(unimportantResults);
}
// perform the search on the required terms
for (var i = 0; i < searchterms.length; i++) {
var word = searchterms[i];
// no match but word was a required one
if ((files = terms[word]) == null)
break;
if (files.length == undefined) {
files = [files];
}
// create the mapping
for (var j = 0; j < files.length; j++) {
var file = files[j];
if (file in fileMap)
fileMap[file].push(word);
else
fileMap[file] = [word];
}
}
// now check if the files don't contain excluded terms
for (var file in fileMap) {
var valid = true;
// check if all requirements are matched
if (fileMap[file].length != searchterms.length)
continue;
// ensure that none of the excluded terms is in the
// search result.
for (var i = 0; i < excluded.length; i++) {
if (terms[excluded[i]] == file ||
$.contains(terms[excluded[i]] || [], file)) {
valid = false;
break;
}
}
// if we have still a valid result we can add it
// to the result list
if (valid)
regularResults.push([filenames[file], titles[file], '', null]);
}
// delete unused variables in order to not waste
// memory until list is retrieved completely
delete filenames, titles, terms;
// now sort the regular results descending by title
regularResults.sort(function(a, b) {
var left = a[1].toLowerCase();
var right = b[1].toLowerCase();
return (left > right) ? -1 : ((left < right) ? 1 : 0);
});
// combine all results
var results = unimportantResults.concat(regularResults)
.concat(objectResults).concat(importantResults);
// print the results
var resultCount = results.length;
function displayNextItem() {
// results left, load the summary and display it
if (results.length) {
var item = results.pop();
var listItem = $('<li style="display:none"></li>');
if (DOCUMENTATION_OPTIONS.FILE_SUFFIX == '') {
// dirhtml builder
var dirname = item[0] + '/';
if (dirname.match(/\/index\/$/)) {
dirname = dirname.substring(0, dirname.length-6);
} else if (dirname == 'index/') {
dirname = '';
}
listItem.append($('<a/>').attr('href',
DOCUMENTATION_OPTIONS.URL_ROOT + dirname +
highlightstring + item[2]).html(item[1]));
} else {
// normal html builders
listItem.append($('<a/>').attr('href',
item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX +
highlightstring + item[2]).html(item[1]));
}
if (item[3]) {
listItem.append($('<span> (' + item[3] + ')</span>'));
Search.output.append(listItem);
listItem.slideDown(5, function() {
displayNextItem();
});
} else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
$.get(DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' +
item[0] + '.txt', function(data) {
if (data != '') {
listItem.append($.makeSearchSummary(data, searchterms, hlterms));
Search.output.append(listItem);
}
listItem.slideDown(5, function() {
displayNextItem();
});
}, "text");
} else {
// no source available, just display title
Search.output.append(listItem);
listItem.slideDown(5, function() {
displayNextItem();
});
}
}
// search finished, update title and status message
else {
Search.stopPulse();
Search.title.text(_('Search Results'));
if (!resultCount)
Search.status.text(_('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.'));
else
Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount));
Search.status.fadeIn(500);
}
}
displayNextItem();
},
performObjectSearch : function(object, otherterms) {
var filenames = this._index.filenames;
var objects = this._index.objects;
var objnames = this._index.objnames;
var titles = this._index.titles;
var importantResults = [];
var objectResults = [];
var unimportantResults = [];
for (var prefix in objects) {
for (var name in objects[prefix]) {
var fullname = (prefix ? prefix + '.' : '') + name;
if (fullname.toLowerCase().indexOf(object) > -1) {
var match = objects[prefix][name];
var objname = objnames[match[1]][2];
var title = titles[match[0]];
// If more than one term searched for, we require other words to be
// found in the name/title/description
if (otherterms.length > 0) {
var haystack = (prefix + ' ' + name + ' ' +
objname + ' ' + title).toLowerCase();
var allfound = true;
for (var i = 0; i < otherterms.length; i++) {
if (haystack.indexOf(otherterms[i]) == -1) {
allfound = false;
break;
}
}
if (!allfound) {
continue;
}
}
var descr = objname + _(', in ') + title;
anchor = match[3];
if (anchor == '')
anchor = fullname;
else if (anchor == '-')
anchor = objnames[match[1]][1] + '-' + fullname;
result = [filenames[match[0]], fullname, '#'+anchor, descr];
switch (match[2]) {
case 1: objectResults.push(result); break;
case 0: importantResults.push(result); break;
case 2: unimportantResults.push(result); break;
}
}
}
}
// sort results descending
objectResults.sort(function(a, b) {
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
});
importantResults.sort(function(a, b) {
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
});
unimportantResults.sort(function(a, b) {
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
});
return [importantResults, objectResults, unimportantResults]
}
}
$(document).ready(function() {
Search.init();
});

View file

@ -1,151 +0,0 @@
/*
* sidebar.js
* ~~~~~~~~~~
*
* This script makes the Sphinx sidebar collapsible.
*
* .sphinxsidebar contains .sphinxsidebarwrapper. This script adds
* in .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton
* used to collapse and expand the sidebar.
*
* When the sidebar is collapsed the .sphinxsidebarwrapper is hidden
* and the width of the sidebar and the margin-left of the document
* are decreased. When the sidebar is expanded the opposite happens.
* This script saves a per-browser/per-session cookie used to
* remember the position of the sidebar among the pages.
* Once the browser is closed the cookie is deleted and the position
* reset to the default (expanded).
*
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
$(function() {
// global elements used by the functions.
// the 'sidebarbutton' element is defined as global after its
// creation, in the add_sidebar_button function
var bodywrapper = $('.bodywrapper');
var sidebar = $('.sphinxsidebar');
var sidebarwrapper = $('.sphinxsidebarwrapper');
// for some reason, the document has no sidebar; do not run into errors
if (!sidebar.length) return;
// original margin-left of the bodywrapper and width of the sidebar
// with the sidebar expanded
var bw_margin_expanded = bodywrapper.css('margin-left');
var ssb_width_expanded = sidebar.width();
// margin-left of the bodywrapper and width of the sidebar
// with the sidebar collapsed
var bw_margin_collapsed = '.8em';
var ssb_width_collapsed = '.8em';
// colors used by the current theme
var dark_color = $('.related').css('background-color');
var light_color = $('.document').css('background-color');
function sidebar_is_collapsed() {
return sidebarwrapper.is(':not(:visible)');
}
function toggle_sidebar() {
if (sidebar_is_collapsed())
expand_sidebar();
else
collapse_sidebar();
}
function collapse_sidebar() {
sidebarwrapper.hide();
sidebar.css('width', ssb_width_collapsed);
bodywrapper.css('margin-left', bw_margin_collapsed);
sidebarbutton.css({
'margin-left': '0',
'height': bodywrapper.height()
});
sidebarbutton.find('span').text('»');
sidebarbutton.attr('title', _('Expand sidebar'));
document.cookie = 'sidebar=collapsed';
}
function expand_sidebar() {
bodywrapper.css('margin-left', bw_margin_expanded);
sidebar.css('width', ssb_width_expanded);
sidebarwrapper.show();
sidebarbutton.css({
'margin-left': ssb_width_expanded-12,
'height': bodywrapper.height()
});
sidebarbutton.find('span').text('«');
sidebarbutton.attr('title', _('Collapse sidebar'));
document.cookie = 'sidebar=expanded';
}
function add_sidebar_button() {
sidebarwrapper.css({
'float': 'left',
'margin-right': '0',
'width': ssb_width_expanded - 28
});
// create the button
sidebar.append(
'<div id="sidebarbutton"><span>&laquo;</span></div>'
);
var sidebarbutton = $('#sidebarbutton');
light_color = sidebarbutton.css('background-color');
// find the height of the viewport to center the '<<' in the page
var viewport_height;
if (window.innerHeight)
viewport_height = window.innerHeight;
else
viewport_height = $(window).height();
sidebarbutton.find('span').css({
'display': 'block',
'margin-top': (viewport_height - sidebar.position().top - 20) / 2
});
sidebarbutton.click(toggle_sidebar);
sidebarbutton.attr('title', _('Collapse sidebar'));
sidebarbutton.css({
'color': '#FFFFFF',
'border-left': '1px solid ' + dark_color,
'font-size': '1.2em',
'cursor': 'pointer',
'height': bodywrapper.height(),
'padding-top': '1px',
'margin-left': ssb_width_expanded - 12
});
sidebarbutton.hover(
function () {
$(this).css('background-color', dark_color);
},
function () {
$(this).css('background-color', light_color);
}
);
}
function set_position_from_cookie() {
if (!document.cookie)
return;
var items = document.cookie.split(';');
for(var k=0; k<items.length; k++) {
var key_val = items[k].split('=');
var key = key_val[0];
if (key == 'sidebar') {
var value = key_val[1];
if ((value == 'collapsed') && (!sidebar_is_collapsed()))
collapse_sidebar();
else if ((value == 'expanded') && (sidebar_is_collapsed()))
expand_sidebar();
}
}
}
add_sidebar_button();
var sidebarbutton = $('#sidebarbutton');
set_position_from_cookie();
});

View file

@ -1,23 +0,0 @@
// Underscore.js 0.5.5
// (c) 2009 Jeremy Ashkenas, DocumentCloud Inc.
// Underscore is freely distributable under the terms of the MIT license.
// Portions of Underscore are inspired by or borrowed from Prototype.js,
// Oliver Steele's Functional, and John Resig's Micro-Templating.
// For all details and documentation:
// http://documentcloud.github.com/underscore/
(function(){var j=this,n=j._,i=function(a){this._wrapped=a},m=typeof StopIteration!=="undefined"?StopIteration:"__break__",b=j._=function(a){return new i(a)};if(typeof exports!=="undefined")exports._=b;var k=Array.prototype.slice,o=Array.prototype.unshift,p=Object.prototype.toString,q=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;b.VERSION="0.5.5";b.each=function(a,c,d){try{if(a.forEach)a.forEach(c,d);else if(b.isArray(a)||b.isArguments(a))for(var e=0,f=a.length;e<f;e++)c.call(d,
a[e],e,a);else{var g=b.keys(a);f=g.length;for(e=0;e<f;e++)c.call(d,a[g[e]],g[e],a)}}catch(h){if(h!=m)throw h;}return a};b.map=function(a,c,d){if(a&&b.isFunction(a.map))return a.map(c,d);var e=[];b.each(a,function(f,g,h){e.push(c.call(d,f,g,h))});return e};b.reduce=function(a,c,d,e){if(a&&b.isFunction(a.reduce))return a.reduce(b.bind(d,e),c);b.each(a,function(f,g,h){c=d.call(e,c,f,g,h)});return c};b.reduceRight=function(a,c,d,e){if(a&&b.isFunction(a.reduceRight))return a.reduceRight(b.bind(d,e),c);
var f=b.clone(b.toArray(a)).reverse();b.each(f,function(g,h){c=d.call(e,c,g,h,a)});return c};b.detect=function(a,c,d){var e;b.each(a,function(f,g,h){if(c.call(d,f,g,h)){e=f;b.breakLoop()}});return e};b.select=function(a,c,d){if(a&&b.isFunction(a.filter))return a.filter(c,d);var e=[];b.each(a,function(f,g,h){c.call(d,f,g,h)&&e.push(f)});return e};b.reject=function(a,c,d){var e=[];b.each(a,function(f,g,h){!c.call(d,f,g,h)&&e.push(f)});return e};b.all=function(a,c,d){c=c||b.identity;if(a&&b.isFunction(a.every))return a.every(c,
d);var e=true;b.each(a,function(f,g,h){(e=e&&c.call(d,f,g,h))||b.breakLoop()});return e};b.any=function(a,c,d){c=c||b.identity;if(a&&b.isFunction(a.some))return a.some(c,d);var e=false;b.each(a,function(f,g,h){if(e=c.call(d,f,g,h))b.breakLoop()});return e};b.include=function(a,c){if(b.isArray(a))return b.indexOf(a,c)!=-1;var d=false;b.each(a,function(e){if(d=e===c)b.breakLoop()});return d};b.invoke=function(a,c){var d=b.rest(arguments,2);return b.map(a,function(e){return(c?e[c]:e).apply(e,d)})};b.pluck=
function(a,c){return b.map(a,function(d){return d[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);var e={computed:-Infinity};b.each(a,function(f,g,h){g=c?c.call(d,f,g,h):f;g>=e.computed&&(e={value:f,computed:g})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};b.each(a,function(f,g,h){g=c?c.call(d,f,g,h):f;g<e.computed&&(e={value:f,computed:g})});return e.value};b.sortBy=function(a,c,d){return b.pluck(b.map(a,
function(e,f,g){return{value:e,criteria:c.call(d,e,f,g)}}).sort(function(e,f){e=e.criteria;f=f.criteria;return e<f?-1:e>f?1:0}),"value")};b.sortedIndex=function(a,c,d){d=d||b.identity;for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?(e=g+1):(f=g)}return e};b.toArray=function(a){if(!a)return[];if(a.toArray)return a.toArray();if(b.isArray(a))return a;if(b.isArguments(a))return k.call(a);return b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=function(a,c,d){return c&&!d?k.call(a,
0,c):a[0]};b.rest=function(a,c,d){return k.call(a,b.isUndefined(c)||d?1:c)};b.last=function(a){return a[a.length-1]};b.compact=function(a){return b.select(a,function(c){return!!c})};b.flatten=function(a){return b.reduce(a,[],function(c,d){if(b.isArray(d))return c.concat(b.flatten(d));c.push(d);return c})};b.without=function(a){var c=b.rest(arguments);return b.select(a,function(d){return!b.include(c,d)})};b.uniq=function(a,c){return b.reduce(a,[],function(d,e,f){if(0==f||(c===true?b.last(d)!=e:!b.include(d,
e)))d.push(e);return d})};b.intersect=function(a){var c=b.rest(arguments);return b.select(b.uniq(a),function(d){return b.all(c,function(e){return b.indexOf(e,d)>=0})})};b.zip=function(){for(var a=b.toArray(arguments),c=b.max(b.pluck(a,"length")),d=new Array(c),e=0;e<c;e++)d[e]=b.pluck(a,String(e));return d};b.indexOf=function(a,c){if(a.indexOf)return a.indexOf(c);for(var d=0,e=a.length;d<e;d++)if(a[d]===c)return d;return-1};b.lastIndexOf=function(a,c){if(a.lastIndexOf)return a.lastIndexOf(c);for(var d=
a.length;d--;)if(a[d]===c)return d;return-1};b.range=function(a,c,d){var e=b.toArray(arguments),f=e.length<=1;a=f?0:e[0];c=f?e[0]:e[1];d=e[2]||1;e=Math.ceil((c-a)/d);if(e<=0)return[];e=new Array(e);f=a;for(var g=0;1;f+=d){if((d>0?f-c:c-f)>=0)return e;e[g++]=f}};b.bind=function(a,c){var d=b.rest(arguments,2);return function(){return a.apply(c||j,d.concat(b.toArray(arguments)))}};b.bindAll=function(a){var c=b.rest(arguments);if(c.length==0)c=b.functions(a);b.each(c,function(d){a[d]=b.bind(a[d],a)});
return a};b.delay=function(a,c){var d=b.rest(arguments,2);return setTimeout(function(){return a.apply(a,d)},c)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(b.rest(arguments)))};b.wrap=function(a,c){return function(){var d=[a].concat(b.toArray(arguments));return c.apply(c,d)}};b.compose=function(){var a=b.toArray(arguments);return function(){for(var c=b.toArray(arguments),d=a.length-1;d>=0;d--)c=[a[d].apply(this,c)];return c[0]}};b.keys=function(a){if(b.isArray(a))return b.range(0,a.length);
var c=[];for(var d in a)q.call(a,d)&&c.push(d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=function(a){return b.select(b.keys(a),function(c){return b.isFunction(a[c])}).sort()};b.extend=function(a,c){for(var d in c)a[d]=c[d];return a};b.clone=function(a){if(b.isArray(a))return a.slice(0);return b.extend({},a)};b.tap=function(a,c){c(a);return a};b.isEqual=function(a,c){if(a===c)return true;var d=typeof a;if(d!=typeof c)return false;if(a==c)return true;if(!a&&c||a&&!c)return false;
if(a.isEqual)return a.isEqual(c);if(b.isDate(a)&&b.isDate(c))return a.getTime()===c.getTime();if(b.isNaN(a)&&b.isNaN(c))return true;if(b.isRegExp(a)&&b.isRegExp(c))return a.source===c.source&&a.global===c.global&&a.ignoreCase===c.ignoreCase&&a.multiline===c.multiline;if(d!=="object")return false;if(a.length&&a.length!==c.length)return false;d=b.keys(a);var e=b.keys(c);if(d.length!=e.length)return false;for(var f in a)if(!b.isEqual(a[f],c[f]))return false;return true};b.isEmpty=function(a){return b.keys(a).length==
0};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=function(a){return!!(a&&a.concat&&a.unshift)};b.isArguments=function(a){return a&&b.isNumber(a.length)&&!b.isArray(a)&&!r.call(a,"length")};b.isFunction=function(a){return!!(a&&a.constructor&&a.call&&a.apply)};b.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)};b.isNumber=function(a){return p.call(a)==="[object Number]"};b.isDate=function(a){return!!(a&&a.getTimezoneOffset&&a.setUTCFullYear)};b.isRegExp=function(a){return!!(a&&
a.test&&a.exec&&(a.ignoreCase||a.ignoreCase===false))};b.isNaN=function(a){return b.isNumber(a)&&isNaN(a)};b.isNull=function(a){return a===null};b.isUndefined=function(a){return typeof a=="undefined"};b.noConflict=function(){j._=n;return this};b.identity=function(a){return a};b.breakLoop=function(){throw m;};var s=0;b.uniqueId=function(a){var c=s++;return a?a+c:c};b.template=function(a,c){a=new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+a.replace(/[\r\t\n]/g,
" ").replace(/'(?=[^%]*%>)/g,"\t").split("'").join("\\'").split("\t").join("'").replace(/<%=(.+?)%>/g,"',$1,'").split("<%").join("');").split("%>").join("p.push('")+"');}return p.join('');");return c?a(c):a};b.forEach=b.each;b.foldl=b.inject=b.reduce;b.foldr=b.reduceRight;b.filter=b.select;b.every=b.all;b.some=b.any;b.head=b.first;b.tail=b.rest;b.methods=b.functions;var l=function(a,c){return c?b(a).chain():a};b.each(b.functions(b),function(a){var c=b[a];i.prototype[a]=function(){var d=b.toArray(arguments);
o.call(d,this._wrapped);return l(c.apply(b,d),this._chain)}});b.each(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var c=Array.prototype[a];i.prototype[a]=function(){c.apply(this._wrapped,arguments);return l(this._wrapped,this._chain)}});b.each(["concat","join","slice"],function(a){var c=Array.prototype[a];i.prototype[a]=function(){return l(c.apply(this._wrapped,arguments),this._chain)}});i.prototype.chain=function(){this._chain=true;return this};i.prototype.value=function(){return this._wrapped}})();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 372 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 363 B

View file

@ -1,808 +0,0 @@
/*
* websupport.js
* ~~~~~~~~~~~~~
*
* sphinx.websupport utilties for all documentation.
*
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
(function($) {
$.fn.autogrow = function() {
return this.each(function() {
var textarea = this;
$.fn.autogrow.resize(textarea);
$(textarea)
.focus(function() {
textarea.interval = setInterval(function() {
$.fn.autogrow.resize(textarea);
}, 500);
})
.blur(function() {
clearInterval(textarea.interval);
});
});
};
$.fn.autogrow.resize = function(textarea) {
var lineHeight = parseInt($(textarea).css('line-height'), 10);
var lines = textarea.value.split('\n');
var columns = textarea.cols;
var lineCount = 0;
$.each(lines, function() {
lineCount += Math.ceil(this.length / columns) || 1;
});
var height = lineHeight * (lineCount + 1);
$(textarea).css('height', height);
};
})(jQuery);
(function($) {
var comp, by;
function init() {
initEvents();
initComparator();
}
function initEvents() {
$('a.comment-close').live("click", function(event) {
event.preventDefault();
hide($(this).attr('id').substring(2));
});
$('a.vote').live("click", function(event) {
event.preventDefault();
handleVote($(this));
});
$('a.reply').live("click", function(event) {
event.preventDefault();
openReply($(this).attr('id').substring(2));
});
$('a.close-reply').live("click", function(event) {
event.preventDefault();
closeReply($(this).attr('id').substring(2));
});
$('a.sort-option').live("click", function(event) {
event.preventDefault();
handleReSort($(this));
});
$('a.show-proposal').live("click", function(event) {
event.preventDefault();
showProposal($(this).attr('id').substring(2));
});
$('a.hide-proposal').live("click", function(event) {
event.preventDefault();
hideProposal($(this).attr('id').substring(2));
});
$('a.show-propose-change').live("click", function(event) {
event.preventDefault();
showProposeChange($(this).attr('id').substring(2));
});
$('a.hide-propose-change').live("click", function(event) {
event.preventDefault();
hideProposeChange($(this).attr('id').substring(2));
});
$('a.accept-comment').live("click", function(event) {
event.preventDefault();
acceptComment($(this).attr('id').substring(2));
});
$('a.delete-comment').live("click", function(event) {
event.preventDefault();
deleteComment($(this).attr('id').substring(2));
});
$('a.comment-markup').live("click", function(event) {
event.preventDefault();
toggleCommentMarkupBox($(this).attr('id').substring(2));
});
}
/**
* Set comp, which is a comparator function used for sorting and
* inserting comments into the list.
*/
function setComparator() {
// If the first three letters are "asc", sort in ascending order
// and remove the prefix.
if (by.substring(0,3) == 'asc') {
var i = by.substring(3);
comp = function(a, b) { return a[i] - b[i]; };
} else {
// Otherwise sort in descending order.
comp = function(a, b) { return b[by] - a[by]; };
}
// Reset link styles and format the selected sort option.
$('a.sel').attr('href', '#').removeClass('sel');
$('a.by' + by).removeAttr('href').addClass('sel');
}
/**
* Create a comp function. If the user has preferences stored in
* the sortBy cookie, use those, otherwise use the default.
*/
function initComparator() {
by = 'rating'; // Default to sort by rating.
// If the sortBy cookie is set, use that instead.
if (document.cookie.length > 0) {
var start = document.cookie.indexOf('sortBy=');
if (start != -1) {
start = start + 7;
var end = document.cookie.indexOf(";", start);
if (end == -1) {
end = document.cookie.length;
by = unescape(document.cookie.substring(start, end));
}
}
}
setComparator();
}
/**
* Show a comment div.
*/
function show(id) {
$('#ao' + id).hide();
$('#ah' + id).show();
var context = $.extend({id: id}, opts);
var popup = $(renderTemplate(popupTemplate, context)).hide();
popup.find('textarea[name="proposal"]').hide();
popup.find('a.by' + by).addClass('sel');
var form = popup.find('#cf' + id);
form.submit(function(event) {
event.preventDefault();
addComment(form);
});
$('#s' + id).after(popup);
popup.slideDown('fast', function() {
getComments(id);
});
}
/**
* Hide a comment div.
*/
function hide(id) {
$('#ah' + id).hide();
$('#ao' + id).show();
var div = $('#sc' + id);
div.slideUp('fast', function() {
div.remove();
});
}
/**
* Perform an ajax request to get comments for a node
* and insert the comments into the comments tree.
*/
function getComments(id) {
$.ajax({
type: 'GET',
url: opts.getCommentsURL,
data: {node: id},
success: function(data, textStatus, request) {
var ul = $('#cl' + id);
var speed = 100;
$('#cf' + id)
.find('textarea[name="proposal"]')
.data('source', data.source);
if (data.comments.length === 0) {
ul.html('<li>No comments yet.</li>');
ul.data('empty', true);
} else {
// If there are comments, sort them and put them in the list.
var comments = sortComments(data.comments);
speed = data.comments.length * 100;
appendComments(comments, ul);
ul.data('empty', false);
}
$('#cn' + id).slideUp(speed + 200);
ul.slideDown(speed);
},
error: function(request, textStatus, error) {
showError('Oops, there was a problem retrieving the comments.');
},
dataType: 'json'
});
}
/**
* Add a comment via ajax and insert the comment into the comment tree.
*/
function addComment(form) {
var node_id = form.find('input[name="node"]').val();
var parent_id = form.find('input[name="parent"]').val();
var text = form.find('textarea[name="comment"]').val();
var proposal = form.find('textarea[name="proposal"]').val();
if (text == '') {
showError('Please enter a comment.');
return;
}
// Disable the form that is being submitted.
form.find('textarea,input').attr('disabled', 'disabled');
// Send the comment to the server.
$.ajax({
type: "POST",
url: opts.addCommentURL,
dataType: 'json',
data: {
node: node_id,
parent: parent_id,
text: text,
proposal: proposal
},
success: function(data, textStatus, error) {
// Reset the form.
if (node_id) {
hideProposeChange(node_id);
}
form.find('textarea')
.val('')
.add(form.find('input'))
.removeAttr('disabled');
var ul = $('#cl' + (node_id || parent_id));
if (ul.data('empty')) {
$(ul).empty();
ul.data('empty', false);
}
insertComment(data.comment);
var ao = $('#ao' + node_id);
ao.find('img').attr({'src': opts.commentBrightImage});
if (node_id) {
// if this was a "root" comment, remove the commenting box
// (the user can get it back by reopening the comment popup)
$('#ca' + node_id).slideUp();
}
},
error: function(request, textStatus, error) {
form.find('textarea,input').removeAttr('disabled');
showError('Oops, there was a problem adding the comment.');
}
});
}
/**
* Recursively append comments to the main comment list and children
* lists, creating the comment tree.
*/
function appendComments(comments, ul) {
$.each(comments, function() {
var div = createCommentDiv(this);
ul.append($(document.createElement('li')).html(div));
appendComments(this.children, div.find('ul.comment-children'));
// To avoid stagnating data, don't store the comments children in data.
this.children = null;
div.data('comment', this);
});
}
/**
* After adding a new comment, it must be inserted in the correct
* location in the comment tree.
*/
function insertComment(comment) {
var div = createCommentDiv(comment);
// To avoid stagnating data, don't store the comments children in data.
comment.children = null;
div.data('comment', comment);
var ul = $('#cl' + (comment.node || comment.parent));
var siblings = getChildren(ul);
var li = $(document.createElement('li'));
li.hide();
// Determine where in the parents children list to insert this comment.
for(i=0; i < siblings.length; i++) {
if (comp(comment, siblings[i]) <= 0) {
$('#cd' + siblings[i].id)
.parent()
.before(li.html(div));
li.slideDown('fast');
return;
}
}
// If we get here, this comment rates lower than all the others,
// or it is the only comment in the list.
ul.append(li.html(div));
li.slideDown('fast');
}
function acceptComment(id) {
$.ajax({
type: 'POST',
url: opts.acceptCommentURL,
data: {id: id},
success: function(data, textStatus, request) {
$('#cm' + id).fadeOut('fast');
$('#cd' + id).removeClass('moderate');
},
error: function(request, textStatus, error) {
showError('Oops, there was a problem accepting the comment.');
}
});
}
function deleteComment(id) {
$.ajax({
type: 'POST',
url: opts.deleteCommentURL,
data: {id: id},
success: function(data, textStatus, request) {
var div = $('#cd' + id);
if (data == 'delete') {
// Moderator mode: remove the comment and all children immediately
div.slideUp('fast', function() {
div.remove();
});
return;
}
// User mode: only mark the comment as deleted
div
.find('span.user-id:first')
.text('[deleted]').end()
.find('div.comment-text:first')
.text('[deleted]').end()
.find('#cm' + id + ', #dc' + id + ', #ac' + id + ', #rc' + id +
', #sp' + id + ', #hp' + id + ', #cr' + id + ', #rl' + id)
.remove();
var comment = div.data('comment');
comment.username = '[deleted]';
comment.text = '[deleted]';
div.data('comment', comment);
},
error: function(request, textStatus, error) {
showError('Oops, there was a problem deleting the comment.');
}
});
}
function showProposal(id) {
$('#sp' + id).hide();
$('#hp' + id).show();
$('#pr' + id).slideDown('fast');
}
function hideProposal(id) {
$('#hp' + id).hide();
$('#sp' + id).show();
$('#pr' + id).slideUp('fast');
}
function showProposeChange(id) {
$('#pc' + id).hide();
$('#hc' + id).show();
var textarea = $('#pt' + id);
textarea.val(textarea.data('source'));
$.fn.autogrow.resize(textarea[0]);
textarea.slideDown('fast');
}
function hideProposeChange(id) {
$('#hc' + id).hide();
$('#pc' + id).show();
var textarea = $('#pt' + id);
textarea.val('').removeAttr('disabled');
textarea.slideUp('fast');
}
function toggleCommentMarkupBox(id) {
$('#mb' + id).toggle();
}
/** Handle when the user clicks on a sort by link. */
function handleReSort(link) {
var classes = link.attr('class').split(/\s+/);
for (var i=0; i<classes.length; i++) {
if (classes[i] != 'sort-option') {
by = classes[i].substring(2);
}
}
setComparator();
// Save/update the sortBy cookie.
var expiration = new Date();
expiration.setDate(expiration.getDate() + 365);
document.cookie= 'sortBy=' + escape(by) +
';expires=' + expiration.toUTCString();
$('ul.comment-ul').each(function(index, ul) {
var comments = getChildren($(ul), true);
comments = sortComments(comments);
appendComments(comments, $(ul).empty());
});
}
/**
* Function to process a vote when a user clicks an arrow.
*/
function handleVote(link) {
if (!opts.voting) {
showError("You'll need to login to vote.");
return;
}
var id = link.attr('id');
if (!id) {
// Didn't click on one of the voting arrows.
return;
}
// If it is an unvote, the new vote value is 0,
// Otherwise it's 1 for an upvote, or -1 for a downvote.
var value = 0;
if (id.charAt(1) != 'u') {
value = id.charAt(0) == 'u' ? 1 : -1;
}
// The data to be sent to the server.
var d = {
comment_id: id.substring(2),
value: value
};
// Swap the vote and unvote links.
link.hide();
$('#' + id.charAt(0) + (id.charAt(1) == 'u' ? 'v' : 'u') + d.comment_id)
.show();
// The div the comment is displayed in.
var div = $('div#cd' + d.comment_id);
var data = div.data('comment');
// If this is not an unvote, and the other vote arrow has
// already been pressed, unpress it.
if ((d.value !== 0) && (data.vote === d.value * -1)) {
$('#' + (d.value == 1 ? 'd' : 'u') + 'u' + d.comment_id).hide();
$('#' + (d.value == 1 ? 'd' : 'u') + 'v' + d.comment_id).show();
}
// Update the comments rating in the local data.
data.rating += (data.vote === 0) ? d.value : (d.value - data.vote);
data.vote = d.value;
div.data('comment', data);
// Change the rating text.
div.find('.rating:first')
.text(data.rating + ' point' + (data.rating == 1 ? '' : 's'));
// Send the vote information to the server.
$.ajax({
type: "POST",
url: opts.processVoteURL,
data: d,
error: function(request, textStatus, error) {
showError('Oops, there was a problem casting that vote.');
}
});
}
/**
* Open a reply form used to reply to an existing comment.
*/
function openReply(id) {
// Swap out the reply link for the hide link
$('#rl' + id).hide();
$('#cr' + id).show();
// Add the reply li to the children ul.
var div = $(renderTemplate(replyTemplate, {id: id})).hide();
$('#cl' + id)
.prepend(div)
// Setup the submit handler for the reply form.
.find('#rf' + id)
.submit(function(event) {
event.preventDefault();
addComment($('#rf' + id));
closeReply(id);
})
.find('input[type=button]')
.click(function() {
closeReply(id);
});
div.slideDown('fast', function() {
$('#rf' + id).find('textarea').focus();
});
}
/**
* Close the reply form opened with openReply.
*/
function closeReply(id) {
// Remove the reply div from the DOM.
$('#rd' + id).slideUp('fast', function() {
$(this).remove();
});
// Swap out the hide link for the reply link
$('#cr' + id).hide();
$('#rl' + id).show();
}
/**
* Recursively sort a tree of comments using the comp comparator.
*/
function sortComments(comments) {
comments.sort(comp);
$.each(comments, function() {
this.children = sortComments(this.children);
});
return comments;
}
/**
* Get the children comments from a ul. If recursive is true,
* recursively include childrens' children.
*/
function getChildren(ul, recursive) {
var children = [];
ul.children().children("[id^='cd']")
.each(function() {
var comment = $(this).data('comment');
if (recursive)
comment.children = getChildren($(this).find('#cl' + comment.id), true);
children.push(comment);
});
return children;
}
/** Create a div to display a comment in. */
function createCommentDiv(comment) {
if (!comment.displayed && !opts.moderator) {
return $('<div class="moderate">Thank you! Your comment will show up '
+ 'once it is has been approved by a moderator.</div>');
}
// Prettify the comment rating.
comment.pretty_rating = comment.rating + ' point' +
(comment.rating == 1 ? '' : 's');
// Make a class (for displaying not yet moderated comments differently)
comment.css_class = comment.displayed ? '' : ' moderate';
// Create a div for this comment.
var context = $.extend({}, opts, comment);
var div = $(renderTemplate(commentTemplate, context));
// If the user has voted on this comment, highlight the correct arrow.
if (comment.vote) {
var direction = (comment.vote == 1) ? 'u' : 'd';
div.find('#' + direction + 'v' + comment.id).hide();
div.find('#' + direction + 'u' + comment.id).show();
}
if (opts.moderator || comment.text != '[deleted]') {
div.find('a.reply').show();
if (comment.proposal_diff)
div.find('#sp' + comment.id).show();
if (opts.moderator && !comment.displayed)
div.find('#cm' + comment.id).show();
if (opts.moderator || (opts.username == comment.username))
div.find('#dc' + comment.id).show();
}
return div;
}
/**
* A simple template renderer. Placeholders such as <%id%> are replaced
* by context['id'] with items being escaped. Placeholders such as <#id#>
* are not escaped.
*/
function renderTemplate(template, context) {
var esc = $(document.createElement('div'));
function handle(ph, escape) {
var cur = context;
$.each(ph.split('.'), function() {
cur = cur[this];
});
return escape ? esc.text(cur || "").html() : cur;
}
return template.replace(/<([%#])([\w\.]*)\1>/g, function() {
return handle(arguments[2], arguments[1] == '%' ? true : false);
});
}
/** Flash an error message briefly. */
function showError(message) {
$(document.createElement('div')).attr({'class': 'popup-error'})
.append($(document.createElement('div'))
.attr({'class': 'error-message'}).text(message))
.appendTo('body')
.fadeIn("slow")
.delay(2000)
.fadeOut("slow");
}
/** Add a link the user uses to open the comments popup. */
$.fn.comment = function() {
return this.each(function() {
var id = $(this).attr('id').substring(1);
var count = COMMENT_METADATA[id];
var title = count + ' comment' + (count == 1 ? '' : 's');
var image = count > 0 ? opts.commentBrightImage : opts.commentImage;
var addcls = count == 0 ? ' nocomment' : '';
$(this)
.append(
$(document.createElement('a')).attr({
href: '#',
'class': 'sphinx-comment-open' + addcls,
id: 'ao' + id
})
.append($(document.createElement('img')).attr({
src: image,
alt: 'comment',
title: title
}))
.click(function(event) {
event.preventDefault();
show($(this).attr('id').substring(2));
})
)
.append(
$(document.createElement('a')).attr({
href: '#',
'class': 'sphinx-comment-close hidden',
id: 'ah' + id
})
.append($(document.createElement('img')).attr({
src: opts.closeCommentImage,
alt: 'close',
title: 'close'
}))
.click(function(event) {
event.preventDefault();
hide($(this).attr('id').substring(2));
})
);
});
};
var opts = {
processVoteURL: '/_process_vote',
addCommentURL: '/_add_comment',
getCommentsURL: '/_get_comments',
acceptCommentURL: '/_accept_comment',
deleteCommentURL: '/_delete_comment',
commentImage: '/static/_static/comment.png',
closeCommentImage: '/static/_static/comment-close.png',
loadingImage: '/static/_static/ajax-loader.gif',
commentBrightImage: '/static/_static/comment-bright.png',
upArrow: '/static/_static/up.png',
downArrow: '/static/_static/down.png',
upArrowPressed: '/static/_static/up-pressed.png',
downArrowPressed: '/static/_static/down-pressed.png',
voting: false,
moderator: false
};
if (typeof COMMENT_OPTIONS != "undefined") {
opts = jQuery.extend(opts, COMMENT_OPTIONS);
}
var popupTemplate = '\
<div class="sphinx-comments" id="sc<%id%>">\
<p class="sort-options">\
Sort by:\
<a href="#" class="sort-option byrating">best rated</a>\
<a href="#" class="sort-option byascage">newest</a>\
<a href="#" class="sort-option byage">oldest</a>\
</p>\
<div class="comment-header">Comments</div>\
<div class="comment-loading" id="cn<%id%>">\
loading comments... <img src="<%loadingImage%>" alt="" /></div>\
<ul id="cl<%id%>" class="comment-ul"></ul>\
<div id="ca<%id%>">\
<p class="add-a-comment">Add a comment\
(<a href="#" class="comment-markup" id="ab<%id%>">markup</a>):</p>\
<div class="comment-markup-box" id="mb<%id%>">\
reStructured text markup: <i>*emph*</i>, <b>**strong**</b>, \
<tt>``code``</tt>, \
code blocks: <tt>::</tt> and an indented block after blank line</div>\
<form method="post" id="cf<%id%>" class="comment-form" action="">\
<textarea name="comment" cols="80"></textarea>\
<p class="propose-button">\
<a href="#" id="pc<%id%>" class="show-propose-change">\
Propose a change &#9657;\
</a>\
<a href="#" id="hc<%id%>" class="hide-propose-change">\
Propose a change &#9663;\
</a>\
</p>\
<textarea name="proposal" id="pt<%id%>" cols="80"\
spellcheck="false"></textarea>\
<input type="submit" value="Add comment" />\
<input type="hidden" name="node" value="<%id%>" />\
<input type="hidden" name="parent" value="" />\
</form>\
</div>\
</div>';
var commentTemplate = '\
<div id="cd<%id%>" class="sphinx-comment<%css_class%>">\
<div class="vote">\
<div class="arrow">\
<a href="#" id="uv<%id%>" class="vote" title="vote up">\
<img src="<%upArrow%>" />\
</a>\
<a href="#" id="uu<%id%>" class="un vote" title="vote up">\
<img src="<%upArrowPressed%>" />\
</a>\
</div>\
<div class="arrow">\
<a href="#" id="dv<%id%>" class="vote" title="vote down">\
<img src="<%downArrow%>" id="da<%id%>" />\
</a>\
<a href="#" id="du<%id%>" class="un vote" title="vote down">\
<img src="<%downArrowPressed%>" />\
</a>\
</div>\
</div>\
<div class="comment-content">\
<p class="tagline comment">\
<span class="user-id"><%username%></span>\
<span class="rating"><%pretty_rating%></span>\
<span class="delta"><%time.delta%></span>\
</p>\
<div class="comment-text comment"><#text#></div>\
<p class="comment-opts comment">\
<a href="#" class="reply hidden" id="rl<%id%>">reply &#9657;</a>\
<a href="#" class="close-reply" id="cr<%id%>">reply &#9663;</a>\
<a href="#" id="sp<%id%>" class="show-proposal">proposal &#9657;</a>\
<a href="#" id="hp<%id%>" class="hide-proposal">proposal &#9663;</a>\
<a href="#" id="dc<%id%>" class="delete-comment hidden">delete</a>\
<span id="cm<%id%>" class="moderation hidden">\
<a href="#" id="ac<%id%>" class="accept-comment">accept</a>\
</span>\
</p>\
<pre class="proposal" id="pr<%id%>">\
<#proposal_diff#>\
</pre>\
<ul class="comment-children" id="cl<%id%>"></ul>\
</div>\
<div class="clearleft"></div>\
</div>\
</div>';
var replyTemplate = '\
<li>\
<div class="reply-div" id="rd<%id%>">\
<form id="rf<%id%>">\
<textarea name="comment" cols="80"></textarea>\
<input type="submit" value="Add reply" />\
<input type="button" value="Cancel" />\
<input type="hidden" name="parent" value="<%id%>" />\
<input type="hidden" name="node" value="" />\
</form>\
</div>\
</li>';
$(document).ready(function() {
init();
});
})(jQuery);
$(document).ready(function() {
// add comment anchors for all paragraphs that are commentable
$('.sphinx-has-comment').comment();
// highlight search words in search results
$("div.context").each(function() {
var params = $.getQueryParameters();
var terms = (params.q) ? params.q[0].split(/\s+/) : [];
var result = $(this);
$.each(terms, function() {
result.highlightText(this.toLowerCase(), 'highlighted');
});
});
// directly open comment window if requested
var anchor = document.location.hash;
if (anchor.substring(0, 9) == '#comment-') {
$('#ao' + anchor.substring(9)).click();
document.location.hash = '#s' + anchor.substring(9);
}
});

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,514 @@
//
// Copyright (c) 2009 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if _WIN32
#include <windows.h>
#endif
#include <GL/gl.h>
// default font
#include "droidsans_ttf.h"
#define STB_TRUETYPE_IMPLEMENTATION
#define STBTT_malloc(x,u) malloc(x)
#define STBTT_free(x,u) free(x)
#include "stb_truetype.h"
#define HASH_LUT_SIZE 256
#define MAX_ROWS 128
#define MAX_FONTS 4
#define VERT_COUNT (6*128)
#define VERT_STRIDE (sizeof(float)*4)
static unsigned int hashint(unsigned int a)
{
a += ~(a<<15);
a ^= (a>>10);
a += (a<<3);
a ^= (a>>6);
a += ~(a<<11);
a ^= (a>>16);
return a;
}
struct sth_quad
{
float x0,y0,s0,t0;
float x1,y1,s1,t1;
};
struct sth_row
{
short x,y,h;
};
struct sth_glyph
{
unsigned int codepoint;
short size;
int x0,y0,x1,y1;
float xadv,xoff,yoff;
int next;
};
struct sth_font
{
stbtt_fontinfo font;
unsigned char* data;
int datasize;
int freedata; // rute : added flag
struct sth_glyph* glyphs;
int lut[HASH_LUT_SIZE];
int nglyphs;
float ascender;
float descender;
float lineh;
};
struct sth_stash
{
int tw,th;
float itw,ith;
GLuint tex;
struct sth_row rows[MAX_ROWS];
int nrows;
struct sth_font fonts[MAX_FONTS];
float verts[4*VERT_COUNT];
int nverts;
int drawing;
};
// Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
#define UTF8_ACCEPT 0
#define UTF8_REJECT 1
static const unsigned char utf8d[] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
};
static unsigned int decutf8(unsigned int* state, unsigned int* codep, unsigned int byte)
{
unsigned int type = utf8d[byte];
*codep = (*state != UTF8_ACCEPT) ?
(byte & 0x3fu) | (*codep << 6) :
(0xff >> type) & (byte);
*state = utf8d[256 + *state*16 + type];
return *state;
}
struct sth_stash* sth_create(int cachew, int cacheh)
{
struct sth_stash* stash;
// Allocate memory for the font stash.
stash = (struct sth_stash*)malloc(sizeof(struct sth_stash));
if (stash == NULL) goto error;
memset(stash,0,sizeof(struct sth_stash));
// Create texture for the cache.
stash->tw = cachew;
stash->th = cacheh;
stash->itw = 1.0f/cachew;
stash->ith = 1.0f/cacheh;
glGenTextures(1, &stash->tex);
if (!stash->tex) goto error;
glBindTexture(GL_TEXTURE_2D, stash->tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, stash->tw,stash->th, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
return stash;
error:
if (stash != NULL)
free(stash);
return NULL;
}
int sth_add_font(struct sth_stash* stash, int idx, const char* path)
{
FILE* fp = 0;
int i, ascent, descent, fh, lineGap;
struct sth_font* fnt;
if (idx < 0 || idx >= MAX_FONTS) return 0;
fnt = &stash->fonts[idx];
if (fnt->data)
free(fnt->data);
if (fnt->glyphs)
free(fnt->glyphs);
memset(fnt,0,sizeof(struct sth_font));
// Init hash lookup.
for (i = 0; i < HASH_LUT_SIZE; ++i) fnt->lut[i] = -1;
if (path != NULL) {
// Read in the font data.
fp = fopen(path, "rb");
if (!fp) goto error;
fseek(fp,0,SEEK_END);
fnt->datasize = (int)ftell(fp);
fseek(fp,0,SEEK_SET);
fnt->data = (unsigned char*)malloc(fnt->datasize);
fnt->freedata = 1;
if (fnt->data == NULL) goto error;
fread(fnt->data, 1, fnt->datasize, fp);
fclose(fp);
fp = 0;
} else {
fnt->data = &droidsans_ttf[0];
fnt->freedata = 0;
}
// Init stb_truetype
if (!stbtt_InitFont(&fnt->font, fnt->data, 0)) goto error;
// Store normalized line height. The real line height is got
// by multiplying the lineh by font size.
stbtt_GetFontVMetrics(&fnt->font, &ascent, &descent, &lineGap);
fh = ascent - descent;
fnt->ascender = (float)ascent / (float)fh;
fnt->descender = (float)descent / (float)fh;
fnt->lineh = (float)(fh + lineGap) / (float)fh;
return 1;
error:
if (fnt->freedata && fnt->data) free(fnt->data);
if (fnt->glyphs) free(fnt->glyphs);
memset(fnt,0,sizeof(struct sth_font));
if (fp) fclose(fp);
return 0;
}
static struct sth_glyph* get_glyph(struct sth_stash* stash, struct sth_font* fnt, unsigned int codepoint, short isize)
{
int i,g,advance,lsb,x0,y0,x1,y1,gw,gh;
float scale;
struct sth_glyph* glyph;
unsigned char* bmp;
unsigned int h;
float size = isize/10.0f;
int rh;
struct sth_row* br;
// Find code point and size.
h = hashint(codepoint) & (HASH_LUT_SIZE-1);
i = fnt->lut[h];
while (i != -1)
{
if (fnt->glyphs[i].codepoint == codepoint && fnt->glyphs[i].size == isize)
return &fnt->glyphs[i];
i = fnt->glyphs[i].next;
}
// Could not find glyph, create it.
scale = stbtt_ScaleForPixelHeight(&fnt->font, size);
g = stbtt_FindGlyphIndex(&fnt->font, codepoint);
stbtt_GetGlyphHMetrics(&fnt->font, g, &advance, &lsb);
stbtt_GetGlyphBitmapBox(&fnt->font, g, scale,scale, &x0,&y0,&x1,&y1);
gw = x1-x0;
gh = y1-y0;
// Find row where the glyph can be fit.
br = NULL;
rh = (gh+7) & ~7;
for (i = 0; i < stash->nrows; ++i)
{
if (stash->rows[i].h == rh && stash->rows[i].x+gw+1 <= stash->tw)
br = &stash->rows[i];
}
// If no row found, add new.
if (br == NULL)
{
short py = 0;
// Check that there is enough space.
if (stash->nrows)
{
py = stash->rows[stash->nrows-1].y + stash->rows[stash->nrows-1].h+1;
if (py+rh > stash->th)
return 0;
}
// Init and add row
br = &stash->rows[stash->nrows];
br->x = 0;
br->y = py;
br->h = rh;
stash->nrows++;
}
// Alloc space for new glyph.
fnt->nglyphs++;
fnt->glyphs = realloc(fnt->glyphs, fnt->nglyphs*sizeof(struct sth_glyph));
if (!fnt->glyphs) return 0;
// Init glyph.
glyph = &fnt->glyphs[fnt->nglyphs-1];
memset(glyph, 0, sizeof(struct sth_glyph));
glyph->codepoint = codepoint;
glyph->size = isize;
glyph->x0 = br->x;
glyph->y0 = br->y;
glyph->x1 = glyph->x0+gw;
glyph->y1 = glyph->y0+gh;
glyph->xadv = scale * advance;
glyph->xoff = (float)x0;
glyph->yoff = (float)y0;
glyph->next = 0;
// Advance row location.
br->x += gw+1;
// Insert char to hash lookup.
glyph->next = fnt->lut[h];
fnt->lut[h] = fnt->nglyphs-1;
// Rasterize
bmp = (unsigned char*)malloc(gw*gh);
if (bmp)
{
stbtt_MakeGlyphBitmap(&fnt->font, bmp, gw,gh,gw, scale,scale, g);
// Update texture
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
glTexSubImage2D(GL_TEXTURE_2D, 0, glyph->x0,glyph->y0, gw,gh, GL_ALPHA,GL_UNSIGNED_BYTE,bmp);
free(bmp);
}
return glyph;
}
static int get_quad(struct sth_stash* stash, struct sth_font* fnt, unsigned int codepoint, short isize, float* x, float* y, struct sth_quad* q)
{
int rx,ry;
struct sth_glyph* glyph = get_glyph(stash, fnt, codepoint, isize);
if (!glyph) return 0;
rx = floorf(*x + glyph->xoff);
ry = floorf(*y - glyph->yoff);
q->x0 = rx;
q->y0 = ry;
q->x1 = rx + glyph->x1 - glyph->x0;
q->y1 = ry - glyph->y1 + glyph->y0;
q->s0 = (glyph->x0) * stash->itw;
q->t0 = (glyph->y0) * stash->ith;
q->s1 = (glyph->x1) * stash->itw;
q->t1 = (glyph->y1) * stash->ith;
*x += glyph->xadv;
return 1;
}
static float* setv(float* v, float x, float y, float s, float t)
{
v[0] = x;
v[1] = y;
v[2] = s;
v[3] = t;
return v+4;
}
static void flush_draw(struct sth_stash* stash)
{
if (stash->nverts == 0)
return;
glBindTexture(GL_TEXTURE_2D, stash->tex);
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FLOAT, VERT_STRIDE, stash->verts);
glTexCoordPointer(2, GL_FLOAT, VERT_STRIDE, stash->verts+2);
glDrawArrays(GL_TRIANGLES, 0, stash->nverts);
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
stash->nverts = 0;
}
void sth_begin_draw(struct sth_stash* stash)
{
if (stash == NULL) return;
if (stash->drawing)
flush_draw(stash);
stash->drawing = 1;
}
void sth_end_draw(struct sth_stash* stash)
{
if (stash == NULL) return;
if (!stash->drawing) return;
/*
// Debug dump.
if (stash->nverts+6 < VERT_COUNT)
{
float x = 500, y = 100;
float* v = &stash->verts[stash->nverts*4];
v = setv(v, x, y, 0, 0);
v = setv(v, x+stash->tw, y, 1, 0);
v = setv(v, x+stash->tw, y+stash->th, 1, 1);
v = setv(v, x, y, 0, 0);
v = setv(v, x+stash->tw, y+stash->th, 1, 1);
v = setv(v, x, y+stash->th, 0, 1);
stash->nverts += 6;
}
*/
flush_draw(stash);
stash->drawing = 0;
}
int sth_draw_text(struct sth_stash* stash,
int idx, float size,
float x, float y,
const char* s, float* dx)
{
unsigned int codepoint;
unsigned int state = 0;
struct sth_quad q;
short isize = (short)(size*10.0f);
float* v;
struct sth_font* fnt;
if (stash == NULL) return 0;
if (!stash->tex) return 0;
if (idx < 0 || idx >= MAX_FONTS) return 0;
fnt = &stash->fonts[idx];
if (!fnt->data) return 0;
for (; *s; ++s)
{
if (decutf8(&state, &codepoint, *(unsigned char*)s)) continue;
if (stash->nverts+6 >= VERT_COUNT)
flush_draw(stash);
if (!get_quad(stash, fnt, codepoint, isize, &x, &y, &q)) continue;
v = &stash->verts[stash->nverts*4];
v = setv(v, q.x0, q.y0, q.s0, q.t0);
v = setv(v, q.x1, q.y0, q.s1, q.t0);
v = setv(v, q.x1, q.y1, q.s1, q.t1);
v = setv(v, q.x0, q.y0, q.s0, q.t0);
v = setv(v, q.x1, q.y1, q.s1, q.t1);
v = setv(v, q.x0, q.y1, q.s0, q.t1);
stash->nverts += 6;
}
if (dx) *dx = x;
return 1;
}
void sth_dim_text(struct sth_stash* stash,
int idx, float size,
const char* s,
float* minx, float* miny, float* maxx, float* maxy)
{
unsigned int codepoint;
unsigned int state = 0;
struct sth_quad q;
short isize = (short)(size*10.0f);
struct sth_font* fnt;
float x = 0, y = 0;
if (stash == NULL) return;
if (!stash->tex) return;
if (idx < 0 || idx >= MAX_FONTS) return;
fnt = &stash->fonts[idx];
if (!fnt->data) return;
*minx = *maxx = x;
*miny = *maxy = y;
for (; *s; ++s)
{
if (decutf8(&state, &codepoint, *(unsigned char*)s)) continue;
if (!get_quad(stash, fnt, codepoint, isize, &x, &y, &q)) continue;
if (q.x0 < *minx) *minx = q.x0;
if (q.x1 > *maxx) *maxx = q.x1;
if (q.y1 < *miny) *miny = q.y1;
if (q.y0 > *maxy) *maxy = q.y0;
}
}
void sth_vmetrics(struct sth_stash* stash,
int idx, float size,
float* ascender, float* descender, float* lineh)
{
if (stash == NULL) return;
if (!stash->tex) return;
if (idx < 0 || idx >= MAX_FONTS) return;
if (!stash->fonts[idx].data) return;
if (ascender)
*ascender = stash->fonts[idx].ascender*size;
if (descender)
*descender = stash->fonts[idx].descender*size;
if (lineh)
*lineh = stash->fonts[idx].lineh*size;
}
void sth_delete(struct sth_stash* stash)
{
int i;
if (!stash) return;
if (stash->tex) glDeleteTextures(1,&stash->tex);
for (i = 0; i < MAX_FONTS; ++i)
{
if (stash->fonts[i].glyphs)
free(stash->fonts[i].glyphs);
if (stash->fonts[i].freedata && stash->fonts[i].data)
free(stash->fonts[i].data);
}
free(stash);
}

View file

@ -0,0 +1,50 @@
//
// Copyright (c) 2009 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
#ifndef FONTSTASH_H
#define FONTSTASH_H
#ifdef __cplusplus
extern "C" {
#endif
struct sth_stash* sth_create(int cachew, int cacheh);
int sth_add_font(struct sth_stash*, int idx, const char* path);
void sth_begin_draw(struct sth_stash* stash);
void sth_end_draw(struct sth_stash* stash);
int sth_draw_text(struct sth_stash* stash,
int idx, float size,
float x, float y, const char* string, float* dx);
void sth_dim_text(struct sth_stash* stash, int idx, float size, const char* string,
float* minx, float* miny, float* maxx, float* maxy);
void sth_vmetrics(struct sth_stash* stash,
int idx, float size,
float* ascender, float* descender, float * lineh);
void sth_delete(struct sth_stash* stash);
#ifdef __cplusplus
}
#endif
#endif // FONTSTASH_H

768
gltools/@contrib/imgui.cpp Normal file
View file

@ -0,0 +1,768 @@
//
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
// Copyright (c) 2011 Mario 'rlyeh' Rodriguez
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
#include <stdio.h>
#include <string.h>
#define _USE_MATH_DEFINES
#include <math.h>
#include "imgui.h"
#ifdef _MSC_VER
#include <stdarg.h>
#define snprintf c99_snprintf
inline int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap)
{
int count = -1;
if (size != 0)
count = _vsnprintf_s(str, size, _TRUNCATE, format, ap);
if (count == -1)
count = _vscprintf(format, ap);
return count;
}
inline int c99_snprintf(char* str, size_t size, const char* format, ...)
{
int count;
va_list ap;
va_start(ap, format);
count = c99_vsnprintf(str, size, format, ap);
va_end(ap);
return count;
}
#endif // _MSC_VER
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static const unsigned TEXT_POOL_SIZE = 8000;
static char g_textPool[TEXT_POOL_SIZE];
static unsigned g_textPoolSize = 0;
static const char* allocText(const char* text)
{
unsigned len = strlen(text)+1;
if (g_textPoolSize + len >= TEXT_POOL_SIZE)
return 0;
char* dst = &g_textPool[g_textPoolSize];
memcpy(dst, text, len);
g_textPoolSize += len;
return dst;
}
static const unsigned GFXCMD_QUEUE_SIZE = 5000;
static imguiGfxCmd g_gfxCmdQueue[GFXCMD_QUEUE_SIZE];
static unsigned g_gfxCmdQueueSize = 0;
static void resetGfxCmdQueue()
{
g_gfxCmdQueueSize = 0;
g_textPoolSize = 0;
}
static void addGfxCmdScissor(int x, int y, int w, int h)
{
if (g_gfxCmdQueueSize >= GFXCMD_QUEUE_SIZE)
return;
imguiGfxCmd& cmd = g_gfxCmdQueue[g_gfxCmdQueueSize++];
cmd.type = IMGUI_GFXCMD_SCISSOR;
cmd.flags = x < 0 ? 0 : 1; // on/off flag.
cmd.col = 0;
cmd.rect.x = (short)x;
cmd.rect.y = (short)y;
cmd.rect.w = (short)w;
cmd.rect.h = (short)h;
}
static void addGfxCmdRect(float x, float y, float w, float h, unsigned int color)
{
if (g_gfxCmdQueueSize >= GFXCMD_QUEUE_SIZE)
return;
imguiGfxCmd& cmd = g_gfxCmdQueue[g_gfxCmdQueueSize++];
cmd.type = IMGUI_GFXCMD_RECT;
cmd.flags = 0;
cmd.col = color;
cmd.rect.x = (short)(x*8.0f);
cmd.rect.y = (short)(y*8.0f);
cmd.rect.w = (short)(w*8.0f);
cmd.rect.h = (short)(h*8.0f);
cmd.rect.r = 0;
}
static void addGfxCmdLine(float x0, float y0, float x1, float y1, float r, unsigned int color)
{
if (g_gfxCmdQueueSize >= GFXCMD_QUEUE_SIZE)
return;
imguiGfxCmd& cmd = g_gfxCmdQueue[g_gfxCmdQueueSize++];
cmd.type = IMGUI_GFXCMD_LINE;
cmd.flags = 0;
cmd.col = color;
cmd.line.x0 = (short)(x0*8.0f);
cmd.line.y0 = (short)(y0*8.0f);
cmd.line.x1 = (short)(x1*8.0f);
cmd.line.y1 = (short)(y1*8.0f);
cmd.line.r = (short)(r*8.0f);
}
static void addGfxCmdRoundedRect(float x, float y, float w, float h, float r, unsigned int color)
{
if (g_gfxCmdQueueSize >= GFXCMD_QUEUE_SIZE)
return;
imguiGfxCmd& cmd = g_gfxCmdQueue[g_gfxCmdQueueSize++];
cmd.type = IMGUI_GFXCMD_RECT;
cmd.flags = 0;
cmd.col = color;
cmd.rect.x = (short)(x*8.0f);
cmd.rect.y = (short)(y*8.0f);
cmd.rect.w = (short)(w*8.0f);
cmd.rect.h = (short)(h*8.0f);
cmd.rect.r = (short)(r*8.0f);
}
static void addGfxCmdTriangle(int x, int y, int w, int h, int flags, unsigned int color)
{
if (g_gfxCmdQueueSize >= GFXCMD_QUEUE_SIZE)
return;
imguiGfxCmd& cmd = g_gfxCmdQueue[g_gfxCmdQueueSize++];
cmd.type = IMGUI_GFXCMD_TRIANGLE;
cmd.flags = (char)flags;
cmd.col = color;
cmd.rect.x = (short)(x*8.0f);
cmd.rect.y = (short)(y*8.0f);
cmd.rect.w = (short)(w*8.0f);
cmd.rect.h = (short)(h*8.0f);
}
static void addGfxCmdText(int x, int y, int align, const char* text, unsigned int color)
{
if (g_gfxCmdQueueSize >= GFXCMD_QUEUE_SIZE)
return;
imguiGfxCmd& cmd = g_gfxCmdQueue[g_gfxCmdQueueSize++];
cmd.type = IMGUI_GFXCMD_TEXT;
cmd.flags = 0;
cmd.col = color;
cmd.text.x = (short)x;
cmd.text.y = (short)y;
cmd.text.align = (short)align;
cmd.text.text = allocText(text);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct GuiState
{
GuiState() :
left(false), leftPressed(false), leftReleased(false),
mx(-1), my(-1), scroll(0),
active(0), hot(0), hotToBe(0), isHot(false), isActive(false), wentActive(false),
dragX(0), dragY(0), dragOrig(0), widgetX(0), widgetY(0), widgetW(100),
insideCurrentScroll(false), areaId(0), widgetId(0)
{
}
bool left;
bool leftPressed, leftReleased;
int mx,my;
int scroll;
unsigned int active;
unsigned int hot;
unsigned int hotToBe;
bool isHot;
bool isActive;
bool wentActive;
int dragX, dragY;
float dragOrig;
int widgetX, widgetY, widgetW;
bool insideCurrentScroll;
unsigned int areaId;
unsigned int widgetId;
};
static GuiState g_state;
inline bool anyActive()
{
return g_state.active != 0;
}
inline bool anyHot() // @rlyeh: new method
{
return g_state.hot != 0;
}
inline bool isActive(unsigned int id)
{
return g_state.active == id;
}
inline bool isHot(unsigned int id)
{
return g_state.hot == id;
}
inline bool inRect(int x, int y, int w, int h, bool checkScroll = true)
{
return (!checkScroll || g_state.insideCurrentScroll) && g_state.mx >= x && g_state.mx <= x+w && g_state.my >= y && g_state.my <= y+h;
}
inline void clearInput()
{
g_state.leftPressed = false;
g_state.leftReleased = false;
g_state.scroll = 0;
}
inline void clearActive()
{
g_state.active = 0;
// mark all UI for this frame as processed
clearInput();
}
inline void setActive(unsigned int id)
{
g_state.active = id;
g_state.wentActive = true;
}
inline void setHot(unsigned int id)
{
g_state.hotToBe = id;
}
static bool buttonLogic(unsigned int id, bool over)
{
bool res = false;
// process down
if (!anyActive())
{
if (over)
setHot(id);
if (isHot(id) && g_state.leftPressed)
setActive(id);
}
// if button is active, then react on left up
if (isActive(id))
{
g_state.isActive = true;
if (over)
setHot(id);
if (g_state.leftReleased)
{
if (isHot(id))
res = true;
clearActive();
}
}
if (isHot(id))
g_state.isHot = true;
return res;
}
static void updateInput(int mx, int my, unsigned char mbut, int scroll)
{
bool left = (mbut & IMGUI_MBUT_LEFT) != 0;
g_state.mx = mx;
g_state.my = my;
g_state.leftPressed = !g_state.left && left;
g_state.leftReleased = g_state.left && !left;
g_state.left = left;
g_state.scroll = scroll;
}
bool imguiAnyActive() // added by rute
{
return g_state.active != 0;
}
void imguiBeginFrame(int mx, int my, unsigned char mbut, int scroll)
{
updateInput(mx,my,mbut,scroll);
g_state.hot = g_state.hotToBe;
g_state.hotToBe = 0;
g_state.wentActive = false;
g_state.isActive = false;
g_state.isHot = false;
g_state.widgetX = 0;
g_state.widgetY = 0;
g_state.widgetW = 0;
g_state.areaId = 1;
g_state.widgetId = 1;
resetGfxCmdQueue();
}
void imguiEndFrame()
{
clearInput();
}
const imguiGfxCmd* imguiGetRenderQueue()
{
return g_gfxCmdQueue;
}
int imguiGetRenderQueueSize()
{
return g_gfxCmdQueueSize;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static const int BUTTON_HEIGHT = 20;
static const int SLIDER_HEIGHT = 20;
static const int SLIDER_MARKER_WIDTH = 10;
static const int CHECK_SIZE = 8;
static const int DEFAULT_SPACING = 4;
static const int TEXT_HEIGHT = 8;
static const int SCROLL_AREA_PADDING = 6;
static const int INDENT_SIZE = 16;
static const int AREA_HEADER = 28;
static int g_scrollTop = 0;
static int g_scrollBottom = 0;
static int g_scrollRight = 0;
static int g_scrollAreaTop = 0;
static int* g_scrollVal = 0;
static int g_focusTop = 0;
static int g_focusBottom = 0;
static unsigned int g_scrollId = 0;
static bool g_insideScrollArea = false;
bool imguiBeginScrollArea(const char* name, int x, int y, int w, int h, int* scroll)
{
g_state.areaId++;
g_state.widgetId = 0;
g_scrollId = (g_state.areaId<<16) | g_state.widgetId;
g_state.widgetX = x + SCROLL_AREA_PADDING;
g_state.widgetY = y+h-AREA_HEADER + (*scroll);
g_state.widgetW = w - SCROLL_AREA_PADDING*4;
g_scrollTop = y-AREA_HEADER+h;
g_scrollBottom = y+SCROLL_AREA_PADDING;
g_scrollRight = x+w - SCROLL_AREA_PADDING*3;
g_scrollVal = scroll;
g_scrollAreaTop = g_state.widgetY;
g_focusTop = y-AREA_HEADER;
g_focusBottom = y-AREA_HEADER+h;
g_insideScrollArea = inRect(x, y, w, h, false);
g_state.insideCurrentScroll = g_insideScrollArea;
addGfxCmdRoundedRect((float)x, (float)y, (float)w, (float)h, 6, imguiRGBA(0,0,0,192));
addGfxCmdText(x+AREA_HEADER/2, y+h-AREA_HEADER/2-TEXT_HEIGHT/2, IMGUI_ALIGN_LEFT, name, imguiRGBA(255,255,255,128));
addGfxCmdScissor(x+SCROLL_AREA_PADDING, y+SCROLL_AREA_PADDING, w-SCROLL_AREA_PADDING*4, h-AREA_HEADER-SCROLL_AREA_PADDING);
return g_insideScrollArea;
}
void imguiEndScrollArea()
{
// Disable scissoring.
addGfxCmdScissor(-1,-1,-1,-1);
// Draw scroll bar
int x = g_scrollRight+SCROLL_AREA_PADDING/2;
int y = g_scrollBottom;
int w = SCROLL_AREA_PADDING*2;
int h = g_scrollTop - g_scrollBottom;
int stop = g_scrollAreaTop;
int sbot = g_state.widgetY;
int sh = stop - sbot; // The scrollable area height.
float barHeight = (float)h/(float)sh;
if (barHeight < 1)
{
float barY = (float)(y - sbot)/(float)sh;
if (barY < 0) barY = 0;
if (barY > 1) barY = 1;
// Handle scroll bar logic.
unsigned int hid = g_scrollId;
int hx = x;
int hy = y + (int)(barY*h);
int hw = w;
int hh = (int)(barHeight*h);
const int range = h - (hh-1);
bool over = inRect(hx, hy, hw, hh);
buttonLogic(hid, over);
if (isActive(hid))
{
float u = (float)(hy-y) / (float)range;
if (g_state.wentActive)
{
g_state.dragY = g_state.my;
g_state.dragOrig = u;
}
if (g_state.dragY != g_state.my)
{
u = g_state.dragOrig + (g_state.my - g_state.dragY) / (float)range;
if (u < 0) u = 0;
if (u > 1) u = 1;
*g_scrollVal = (int)((1-u) * (sh - h));
}
}
// BG
addGfxCmdRoundedRect((float)x, (float)y, (float)w, (float)h, (float)w/2-1, imguiRGBA(0,0,0,196));
// Bar
if (isActive(hid))
addGfxCmdRoundedRect((float)hx, (float)hy, (float)hw, (float)hh, (float)w/2-1, imguiRGBA(255,196,0,196));
else
addGfxCmdRoundedRect((float)hx, (float)hy, (float)hw, (float)hh, (float)w/2-1, isHot(hid) ? imguiRGBA(255,196,0,96) : imguiRGBA(255,255,255,64));
// Handle mouse scrolling.
if (g_insideScrollArea) // && !anyActive())
{
if (g_state.scroll)
{
*g_scrollVal += 20*g_state.scroll;
if (*g_scrollVal < 0) *g_scrollVal = 0;
if (*g_scrollVal > (sh - h)) *g_scrollVal = (sh - h);
}
}
}
g_state.insideCurrentScroll = false;
}
bool imguiBeginArea(const char* name, int x, int y, int w, int h)
{
g_state.areaId++;
g_state.widgetId = 0;
g_scrollId = (g_state.areaId<<16) | g_state.widgetId;
g_state.widgetX = x + DEFAULT_SPACING;
g_state.widgetY = y + h - AREA_HEADER;
g_state.widgetW = w - DEFAULT_SPACING;
g_scrollTop = y + h - AREA_HEADER;
g_scrollBottom = y+DEFAULT_SPACING;
g_scrollRight = x+w - 2*DEFAULT_SPACING;
g_scrollAreaTop = g_state.widgetY;
g_focusTop = y-AREA_HEADER;
g_focusBottom = y-AREA_HEADER+h;
g_insideScrollArea = inRect(x, y, w, h, false);
g_state.insideCurrentScroll = g_insideScrollArea;
addGfxCmdRoundedRect((float)x, (float)y, (float)w, (float)h, 6, imguiRGBA(0,0,0,192));
addGfxCmdText(x+AREA_HEADER/2, y+h-AREA_HEADER/2-TEXT_HEIGHT/2, IMGUI_ALIGN_LEFT, name, imguiRGBA(255,255,255,128));
addGfxCmdScissor(x, y, w, h-AREA_HEADER);
addGfxCmdScissor(x+DEFAULT_SPACING, y+DEFAULT_SPACING, w-2*DEFAULT_SPACING, h-AREA_HEADER-DEFAULT_SPACING);
return g_insideScrollArea;
}
void imguiEndArea()
{
// Disable scissoring.
addGfxCmdScissor(-1,-1,-1,-1);
g_state.insideCurrentScroll = false;
}
bool imguiButton(const char* text, bool enabled, int x, int y, int w, int h)
{
g_state.widgetId++;
unsigned int id = (g_state.areaId<<16) | g_state.widgetId;
bool floating = false;
if (x == -1) {
x = g_state.widgetX;
} else {
x += g_state.widgetX;
}
if (y == -1) {
y = g_state.widgetY - BUTTON_HEIGHT;
} else {
floating = true;
y = g_scrollTop - y;
}
if (w == -1)
w = g_state.widgetW;
if (h == -1)
h = BUTTON_HEIGHT;
if (!floating)
g_state.widgetY -= h + DEFAULT_SPACING;
bool over = enabled && inRect(x, y, w, h);
bool res = buttonLogic(id, over);
addGfxCmdRoundedRect((float)x, (float)y, (float)w, (float)h, (float)BUTTON_HEIGHT/2-1, imguiRGBA(128,128,128, isActive(id)?196:96));
if (enabled)
addGfxCmdText(x+h/2, y+h/2-TEXT_HEIGHT/2, IMGUI_ALIGN_LEFT, text, isHot(id) ? imguiRGBA(255,196,0,255) : imguiRGBA(255,255,255,200));
else
addGfxCmdText(x+h/2, y+h/2-TEXT_HEIGHT/2, IMGUI_ALIGN_LEFT, text, imguiRGBA(128,128,128,200));
return res;
}
bool imguiItem(const char* text, bool enabled)
{
g_state.widgetId++;
unsigned int id = (g_state.areaId<<16) | g_state.widgetId;
int x = g_state.widgetX;
int y = g_state.widgetY - BUTTON_HEIGHT;
int w = g_state.widgetW;
int h = BUTTON_HEIGHT;
g_state.widgetY -= BUTTON_HEIGHT + DEFAULT_SPACING;
bool over = enabled && inRect(x, y, w, h);
bool res = buttonLogic(id, over);
if (isHot(id))
addGfxCmdRoundedRect((float)x, (float)y, (float)w, (float)h, 2.0f, imguiRGBA(255,196,0,isActive(id)?196:96));
if (enabled)
addGfxCmdText(x+BUTTON_HEIGHT/2, y+BUTTON_HEIGHT/2-TEXT_HEIGHT/2, IMGUI_ALIGN_LEFT, text, imguiRGBA(255,255,255,200));
else
addGfxCmdText(x+BUTTON_HEIGHT/2, y+BUTTON_HEIGHT/2-TEXT_HEIGHT/2, IMGUI_ALIGN_LEFT, text, imguiRGBA(128,128,128,200));
return res;
}
bool imguiCheck(const char* text, bool checked, bool enabled)
{
g_state.widgetId++;
unsigned int id = (g_state.areaId<<16) | g_state.widgetId;
int x = g_state.widgetX;
int y = g_state.widgetY - BUTTON_HEIGHT;
int w = g_state.widgetW;
int h = BUTTON_HEIGHT;
g_state.widgetY -= BUTTON_HEIGHT + DEFAULT_SPACING;
bool over = enabled && inRect(x, y, w, h);
bool res = buttonLogic(id, over);
const int cx = x+BUTTON_HEIGHT/2-CHECK_SIZE/2;
const int cy = y+BUTTON_HEIGHT/2-CHECK_SIZE/2;
addGfxCmdRoundedRect((float)cx-3, (float)cy-3, (float)CHECK_SIZE+6, (float)CHECK_SIZE+6, 4, imguiRGBA(128,128,128, isActive(id)?196:96));
if (checked)
{
if (enabled)
addGfxCmdRoundedRect((float)cx, (float)cy, (float)CHECK_SIZE, (float)CHECK_SIZE, (float)CHECK_SIZE/2-1, imguiRGBA(255,255,255,isActive(id)?255:200));
else
addGfxCmdRoundedRect((float)cx, (float)cy, (float)CHECK_SIZE, (float)CHECK_SIZE, (float)CHECK_SIZE/2-1, imguiRGBA(128,128,128,200));
}
if (enabled)
addGfxCmdText(x+BUTTON_HEIGHT, y+BUTTON_HEIGHT/2-TEXT_HEIGHT/2, IMGUI_ALIGN_LEFT, text, isHot(id) ? imguiRGBA(255,196,0,255) : imguiRGBA(255,255,255,200));
else
addGfxCmdText(x+BUTTON_HEIGHT, y+BUTTON_HEIGHT/2-TEXT_HEIGHT/2, IMGUI_ALIGN_LEFT, text, imguiRGBA(128,128,128,200));
return res;
}
bool imguiCollapse(const char* text, const char* subtext, bool checked, bool enabled)
{
g_state.widgetId++;
unsigned int id = (g_state.areaId<<16) | g_state.widgetId;
int x = g_state.widgetX;
int y = g_state.widgetY - BUTTON_HEIGHT;
int w = g_state.widgetW;
int h = BUTTON_HEIGHT;
g_state.widgetY -= BUTTON_HEIGHT; // + DEFAULT_SPACING;
const int cx = x+BUTTON_HEIGHT/2-CHECK_SIZE/2;
const int cy = y+BUTTON_HEIGHT/2-CHECK_SIZE/2;
bool over = enabled && inRect(x, y, w, h);
bool res = buttonLogic(id, over);
if (checked)
addGfxCmdTriangle(cx, cy, CHECK_SIZE, CHECK_SIZE, 2, imguiRGBA(255,255,255,isActive(id)?255:200));
else
addGfxCmdTriangle(cx, cy, CHECK_SIZE, CHECK_SIZE, 1, imguiRGBA(255,255,255,isActive(id)?255:200));
if (enabled)
addGfxCmdText(x+BUTTON_HEIGHT, y+BUTTON_HEIGHT/2-TEXT_HEIGHT/2, IMGUI_ALIGN_LEFT, text, isHot(id) ? imguiRGBA(255,196,0,255) : imguiRGBA(255,255,255,200));
else
addGfxCmdText(x+BUTTON_HEIGHT, y+BUTTON_HEIGHT/2-TEXT_HEIGHT/2, IMGUI_ALIGN_LEFT, text, imguiRGBA(128,128,128,200));
if (subtext)
addGfxCmdText(x+w-BUTTON_HEIGHT/2, y+BUTTON_HEIGHT/2-TEXT_HEIGHT/2, IMGUI_ALIGN_RIGHT, subtext, imguiRGBA(255,255,255,128));
return res;
}
void imguiLabel(const char* text)
{
int x = g_state.widgetX;
int y = g_state.widgetY - BUTTON_HEIGHT;
g_state.widgetY -= BUTTON_HEIGHT;
addGfxCmdText(x, y+BUTTON_HEIGHT/2-TEXT_HEIGHT/2, IMGUI_ALIGN_LEFT, text, imguiRGBA(255,255,255,255));
}
void imguiValue(const char* text)
{
const int x = g_state.widgetX;
const int y = g_state.widgetY - BUTTON_HEIGHT;
const int w = g_state.widgetW;
g_state.widgetY -= BUTTON_HEIGHT;
addGfxCmdText(x+w-BUTTON_HEIGHT/2, y+BUTTON_HEIGHT/2-TEXT_HEIGHT/2, IMGUI_ALIGN_RIGHT, text, imguiRGBA(255,255,255,200));
}
bool imguiSlider(const char* text, float* val, float vmin, float vmax, float vinc, bool enabled)
{
g_state.widgetId++;
unsigned int id = (g_state.areaId<<16) | g_state.widgetId;
int x = g_state.widgetX;
int y = g_state.widgetY - BUTTON_HEIGHT;
int w = g_state.widgetW;
int h = SLIDER_HEIGHT;
g_state.widgetY -= SLIDER_HEIGHT + DEFAULT_SPACING;
addGfxCmdRoundedRect((float)x, (float)y, (float)w, (float)h, 4.0f, imguiRGBA(0,0,0,128));
const int range = w - SLIDER_MARKER_WIDTH;
float u = (*val - vmin) / (vmax-vmin);
if (u < 0) u = 0;
if (u > 1) u = 1;
int m = (int)(u * range);
bool over = enabled && inRect(x+m, y, SLIDER_MARKER_WIDTH, SLIDER_HEIGHT);
bool res = buttonLogic(id, over);
bool valChanged = false;
if (isActive(id))
{
if (g_state.wentActive)
{
g_state.dragX = g_state.mx;
g_state.dragOrig = u;
}
if (g_state.dragX != g_state.mx)
{
u = g_state.dragOrig + (float)(g_state.mx - g_state.dragX) / (float)range;
if (u < 0) u = 0;
if (u > 1) u = 1;
*val = vmin + u*(vmax-vmin);
*val = floorf(*val/vinc+0.5f)*vinc; // Snap to vinc
m = (int)(u * range);
valChanged = true;
}
}
if (isActive(id))
addGfxCmdRoundedRect((float)(x+m), (float)y, (float)SLIDER_MARKER_WIDTH, (float)SLIDER_HEIGHT, 4.0f, imguiRGBA(255,255,255,255));
else
addGfxCmdRoundedRect((float)(x+m), (float)y, (float)SLIDER_MARKER_WIDTH, (float)SLIDER_HEIGHT, 4.0f, isHot(id) ? imguiRGBA(255,196,0,128) : imguiRGBA(255,255,255,64));
// TODO: fix this, take a look at 'nicenum'.
int digits = (int)(ceilf(log10f(vinc)));
char fmt[16];
snprintf(fmt, 16, "%%.%df", digits >= 0 ? 0 : -digits);
char msg[128];
snprintf(msg, 128, fmt, *val);
if (enabled)
{
addGfxCmdText(x+SLIDER_HEIGHT/2, y+SLIDER_HEIGHT/2-TEXT_HEIGHT/2, IMGUI_ALIGN_LEFT, text, isHot(id) ? imguiRGBA(255,196,0,255) : imguiRGBA(255,255,255,200));
addGfxCmdText(x+w-SLIDER_HEIGHT/2, y+SLIDER_HEIGHT/2-TEXT_HEIGHT/2, IMGUI_ALIGN_RIGHT, msg, isHot(id) ? imguiRGBA(255,196,0,255) : imguiRGBA(255,255,255,200));
}
else
{
addGfxCmdText(x+SLIDER_HEIGHT/2, y+SLIDER_HEIGHT/2-TEXT_HEIGHT/2, IMGUI_ALIGN_LEFT, text, imguiRGBA(128,128,128,200));
addGfxCmdText(x+w-SLIDER_HEIGHT/2, y+SLIDER_HEIGHT/2-TEXT_HEIGHT/2, IMGUI_ALIGN_RIGHT, msg, imguiRGBA(128,128,128,200));
}
return res || valChanged;
}
void imguiIndent()
{
g_state.widgetX += INDENT_SIZE;
g_state.widgetW -= INDENT_SIZE;
}
void imguiUnindent()
{
g_state.widgetX -= INDENT_SIZE;
g_state.widgetW += INDENT_SIZE;
}
void imguiSeparator()
{
g_state.widgetY -= DEFAULT_SPACING*3;
}
void imguiSeparatorLine()
{
int x = g_state.widgetX;
int y = g_state.widgetY - DEFAULT_SPACING*2;
int w = g_state.widgetW;
int h = 1;
g_state.widgetY -= DEFAULT_SPACING*4;
addGfxCmdRect((float)x, (float)y, (float)w, (float)h, imguiRGBA(255,255,255,32));
}
void imguiDrawText(int x, int y, int align, const char* text, unsigned int color)
{
addGfxCmdText(x, y, align, text, color);
}
void imguiDrawLine(float x0, float y0, float x1, float y1, float r, unsigned int color)
{
addGfxCmdLine(x0, y0, x1, y1, r, color);
}
void imguiDrawRect(float x, float y, float w, float h, unsigned int color)
{
addGfxCmdRect(x, y, w, h, color);
}
void imguiDrawRoundedRect(float x, float y, float w, float h, float r, unsigned int color)
{
addGfxCmdRoundedRect(x, y, w, h, r, color);
}

115
gltools/@contrib/imgui.h Normal file
View file

@ -0,0 +1,115 @@
//
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
#ifndef IMGUI_H
#define IMGUI_H
enum imguiMouseButton
{
IMGUI_MBUT_LEFT = 0x01,
IMGUI_MBUT_RIGHT = 0x02,
};
enum imguiTextAlign
{
IMGUI_ALIGN_LEFT,
IMGUI_ALIGN_CENTER,
IMGUI_ALIGN_RIGHT,
};
inline unsigned int imguiRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a=255)
{
return (r) | (g << 8) | (b << 16) | (a << 24);
}
bool imguiAnyActive();
void imguiBeginFrame(int mx, int my, unsigned char mbut, int scroll);
void imguiEndFrame();
bool imguiBeginScrollArea(const char* name, int x, int y, int w, int h, int* scroll);
void imguiEndScrollArea();
bool imguiBeginArea(const char* name, int x, int y, int w, int h);
void imguiEndArea();
bool imguiButton(const char* text, bool enabled, int x = -1, int y = -1,
int w = -1, int h = -1);
bool imguiItem(const char* text, bool enabled = true);
bool imguiCheck(const char* text, bool checked, bool enabled = true);
bool imguiCollapse(const char* text, const char* subtext, bool checked, bool enabled = true);
void imguiLabel(const char* text);
void imguiValue(const char* text);
bool imguiSlider(const char* text, float* val, float vmin, float vmax, float vinc, bool enabled = true);
void imguiIndent();
void imguiUnindent();
void imguiSeparator();
void imguiSeparatorLine();
void imguiDrawText(int x, int y, int align, const char* text, unsigned int color);
void imguiDrawLine(float x0, float y0, float x1, float y1, float r, unsigned int color);
void imguiDrawRoundedRect(float x, float y, float w, float h, float r, unsigned int color);
void imguiDrawRect(float x, float y, float w, float h, unsigned int color);
// Pull render interface.
enum imguiGfxCmdType
{
IMGUI_GFXCMD_RECT,
IMGUI_GFXCMD_TRIANGLE,
IMGUI_GFXCMD_LINE,
IMGUI_GFXCMD_TEXT,
IMGUI_GFXCMD_SCISSOR,
};
struct imguiGfxRect
{
short x,y,w,h,r;
};
struct imguiGfxText
{
short x,y,align;
const char* text;
};
struct imguiGfxLine
{
short x0,y0,x1,y1,r;
};
struct imguiGfxCmd
{
char type;
char flags;
char pad[2];
unsigned int col;
union
{
imguiGfxLine line;
imguiGfxRect rect;
imguiGfxText text;
};
};
const imguiGfxCmd* imguiGetRenderQueue();
int imguiGetRenderQueueSize();
#endif // IMGUI_H

View file

@ -0,0 +1,375 @@
//
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
#define _USE_MATH_DEFINES
#include <stdio.h>
#include <math.h>
#include "imgui.h"
#include "fontstash.h"
#include "GLTools.h"
// Some math headers don't have PI defined.
static const float PI = 3.14159265f;
static const unsigned TEMP_COORD_COUNT = 100;
static float g_tempCoords[TEMP_COORD_COUNT*2];
static float g_tempNormals[TEMP_COORD_COUNT*2];
static const int CIRCLE_VERTS = 8*4;
static float g_circleVerts[CIRCLE_VERTS*2];
inline unsigned int RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
{
return (r) | (g << 8) | (b << 16) | (a << 24);
}
static void drawPolygon(const float* coords, unsigned numCoords, float r, unsigned int col)
{
if (numCoords > TEMP_COORD_COUNT) numCoords = TEMP_COORD_COUNT;
for (unsigned i = 0, j = numCoords-1; i < numCoords; j=i++)
{
const float* v0 = &coords[j*2];
const float* v1 = &coords[i*2];
float dx = v1[0] - v0[0];
float dy = v1[1] - v0[1];
float d = sqrtf(dx*dx+dy*dy);
if (d > 0)
{
d = 1.0f/d;
dx *= d;
dy *= d;
}
g_tempNormals[j*2+0] = dy;
g_tempNormals[j*2+1] = -dx;
}
for (unsigned i = 0, j = numCoords-1; i < numCoords; j=i++)
{
float dlx0 = g_tempNormals[j*2+0];
float dly0 = g_tempNormals[j*2+1];
float dlx1 = g_tempNormals[i*2+0];
float dly1 = g_tempNormals[i*2+1];
float dmx = (dlx0 + dlx1) * 0.5f;
float dmy = (dly0 + dly1) * 0.5f;
float dmr2 = dmx*dmx + dmy*dmy;
if (dmr2 > 0.000001f)
{
float scale = 1.0f / dmr2;
if (scale > 10.0f) scale = 10.0f;
dmx *= scale;
dmy *= scale;
}
g_tempCoords[i*2+0] = coords[i*2+0]+dmx*r;
g_tempCoords[i*2+1] = coords[i*2+1]+dmy*r;
}
unsigned int colTrans = RGBA(col&0xff, (col>>8)&0xff, (col>>16)&0xff, 0);
glBegin(GL_TRIANGLES);
glColor4ubv((GLubyte*)&col);
for (unsigned i = 0, j = numCoords-1; i < numCoords; j=i++)
{
glVertex2fv(&coords[i*2]);
glVertex2fv(&coords[j*2]);
glColor4ubv((GLubyte*)&colTrans);
glVertex2fv(&g_tempCoords[j*2]);
glVertex2fv(&g_tempCoords[j*2]);
glVertex2fv(&g_tempCoords[i*2]);
glColor4ubv((GLubyte*)&col);
glVertex2fv(&coords[i*2]);
}
glColor4ubv((GLubyte*)&col);
for (unsigned i = 2; i < numCoords; ++i)
{
glVertex2fv(&coords[0]);
glVertex2fv(&coords[(i-1)*2]);
glVertex2fv(&coords[i*2]);
}
glEnd();
}
static void drawRect(float x, float y, float w, float h, float fth, unsigned int col)
{
float verts[4*2] =
{
x+0.5f, y+0.5f,
x+w-0.5f, y+0.5f,
x+w-0.5f, y+h-0.5f,
x+0.5f, y+h-0.5f,
};
drawPolygon(verts, 4, fth, col);
}
static void drawRoundedRect(float x, float y, float w, float h, float r, float fth, unsigned int col)
{
const unsigned n = CIRCLE_VERTS/4;
float verts[(n+1)*4*2];
const float* cverts = g_circleVerts;
float* v = verts;
for (unsigned i = 0; i <= n; ++i)
{
*v++ = x+w-r + cverts[i*2]*r;
*v++ = y+h-r + cverts[i*2+1]*r;
}
for (unsigned i = n; i <= n*2; ++i)
{
*v++ = x+r + cverts[i*2]*r;
*v++ = y+h-r + cverts[i*2+1]*r;
}
for (unsigned i = n*2; i <= n*3; ++i)
{
*v++ = x+r + cverts[i*2]*r;
*v++ = y+r + cverts[i*2+1]*r;
}
for (unsigned i = n*3; i < n*4; ++i)
{
*v++ = x+w-r + cverts[i*2]*r;
*v++ = y+r + cverts[i*2+1]*r;
}
*v++ = x+w-r + cverts[0]*r;
*v++ = y+r + cverts[1]*r;
drawPolygon(verts, (n+1)*4, fth, col);
}
static void drawLine(float x0, float y0, float x1, float y1, float r, float fth, unsigned int col)
{
float dx = x1-x0;
float dy = y1-y0;
float d = sqrtf(dx*dx+dy*dy);
if (d > 0.0001f)
{
d = 1.0f/d;
dx *= d;
dy *= d;
}
float nx = dy;
float ny = -dx;
float verts[4*2];
r -= fth;
r *= 0.5f;
if (r < 0.01f) r = 0.01f;
dx *= r;
dy *= r;
nx *= r;
ny *= r;
verts[0] = x0-dx-nx;
verts[1] = y0-dy-ny;
verts[2] = x0-dx+nx;
verts[3] = y0-dy+ny;
verts[4] = x1+dx+nx;
verts[5] = y1+dy+ny;
verts[6] = x1+dx-nx;
verts[7] = y1+dy-ny;
drawPolygon(verts, 4, fth, col);
}
void imguiRenderGLInit(void)
{
for (int i = 0; i < CIRCLE_VERTS; ++i)
{
float a = (float)i/(float)CIRCLE_VERTS * PI*2;
g_circleVerts[i*2+0] = cosf(a);
g_circleVerts[i*2+1] = sinf(a);
}
}
static void drawText(float x, float y, const char *text, int align, unsigned int col)
{
float minx, miny, maxx, maxy, dx, hsize;
if (!_fonts) return;
if (align != IMGUI_ALIGN_LEFT) {
// adjust for alignment
sth_dim_text(_fonts, 0, 15.0f, text, &minx, &miny, &maxx, &maxy);
hsize = maxx - minx;
if (align == IMGUI_ALIGN_CENTER)
x -= hsize/2;
else if (align == IMGUI_ALIGN_RIGHT)
x -= hsize;
}
glColor4ub(col&0xff, (col>>8)&0xff, (col>>16)&0xff, (col>>24)&0xff);
sth_begin_draw(_fonts);
sth_draw_text(_fonts, 0, 15.0f, x, y, text, &dx);
sth_end_draw(_fonts);
}
/*
static void drawText(float x, float y, const char *text, int align, unsigned int col)
{
if (!g_ftex) return;
if (!text) return;
if (align == IMGUI_ALIGN_CENTER)
x -= getTextLength(g_cdata, text)/2;
else if (align == IMGUI_ALIGN_RIGHT)
x -= getTextLength(g_cdata, text);
glColor4ub(col&0xff, (col>>8)&0xff, (col>>16)&0xff, (col>>24)&0xff);
glEnable(GL_TEXTURE_2D);
// assume orthographic projection with units = screen pixels, origin at top left
glBindTexture(GL_TEXTURE_2D, g_ftex);
glBegin(GL_TRIANGLES);
const float ox = x;
while (*text)
{
int c = (unsigned char)*text;
if (c == '\t')
{
for (int i = 0; i < 4; ++i)
{
if (x < g_tabStops[i]+ox)
{
x = g_tabStops[i]+ox;
break;
}
}
}
else if (c >= 32 && c < 128)
{
stbtt_aligned_quad q;
getBakedQuad(g_cdata, 512,512, c-32, &x,&y,&q);
glTexCoord2f(q.s0, q.t0);
glVertex2f(q.x0, q.y0);
glTexCoord2f(q.s1, q.t1);
glVertex2f(q.x1, q.y1);
glTexCoord2f(q.s1, q.t0);
glVertex2f(q.x1, q.y0);
glTexCoord2f(q.s0, q.t0);
glVertex2f(q.x0, q.y0);
glTexCoord2f(q.s0, q.t1);
glVertex2f(q.x0, q.y1);
glTexCoord2f(q.s1, q.t1);
glVertex2f(q.x1, q.y1);
}
++text;
}
glEnd();
glDisable(GL_TEXTURE_2D);
}
*/
void imguiRenderGLDraw()
{
const imguiGfxCmd* q = imguiGetRenderQueue();
int nq = imguiGetRenderQueueSize();
const float s = 1.0f/8.0f;
glDisable(GL_SCISSOR_TEST);
for (int i = 0; i < nq; ++i)
{
const imguiGfxCmd& cmd = q[i];
if (cmd.type == IMGUI_GFXCMD_RECT)
{
if (cmd.rect.r == 0)
{
drawRect((float)cmd.rect.x*s+0.5f, (float)cmd.rect.y*s+0.5f,
(float)cmd.rect.w*s-1, (float)cmd.rect.h*s-1,
1.0f, cmd.col);
}
else
{
drawRoundedRect((float)cmd.rect.x*s+0.5f, (float)cmd.rect.y*s+0.5f,
(float)cmd.rect.w*s-1, (float)cmd.rect.h*s-1,
(float)cmd.rect.r*s, 1.0f, cmd.col);
}
}
else if (cmd.type == IMGUI_GFXCMD_LINE)
{
drawLine(cmd.line.x0*s, cmd.line.y0*s, cmd.line.x1*s, cmd.line.y1*s, cmd.line.r*s, 1.0f, cmd.col);
}
else if (cmd.type == IMGUI_GFXCMD_TRIANGLE)
{
if (cmd.flags == 1)
{
const float verts[3*2] =
{
(float)cmd.rect.x*s+0.5f, (float)cmd.rect.y*s+0.5f,
(float)cmd.rect.x*s+0.5f+(float)cmd.rect.w*s-1, (float)cmd.rect.y*s+0.5f+(float)cmd.rect.h*s/2-0.5f,
(float)cmd.rect.x*s+0.5f, (float)cmd.rect.y*s+0.5f+(float)cmd.rect.h*s-1,
};
drawPolygon(verts, 3, 1.0f, cmd.col);
}
if (cmd.flags == 2)
{
const float verts[3*2] =
{
(float)cmd.rect.x*s+0.5f, (float)cmd.rect.y*s+0.5f+(float)cmd.rect.h*s-1,
(float)cmd.rect.x*s+0.5f+(float)cmd.rect.w*s/2-0.5f, (float)cmd.rect.y*s+0.5f,
(float)cmd.rect.x*s+0.5f+(float)cmd.rect.w*s-1, (float)cmd.rect.y*s+0.5f+(float)cmd.rect.h*s-1,
};
drawPolygon(verts, 3, 1.0f, cmd.col);
}
if (cmd.flags == 3) // @rlyeh new rotation: left
{
const float verts[3*2] =
{
(float)cmd.rect.x*s+0.5f+(float)cmd.rect.w*s-1, (float)cmd.rect.y*s+0.5f,
(float)cmd.rect.x*s+0.5f+(float)cmd.rect.w*s-1, (float)cmd.rect.y*s+0.5f+(float)cmd.rect.h*s-1,
(float)cmd.rect.x*s+0.5f, (float)cmd.rect.y*s+0.5f+(float)cmd.rect.h*s/2-0.5f,
};
drawPolygon(verts, 3, 1.0f, cmd.col);
}
}
else if (cmd.type == IMGUI_GFXCMD_TEXT)
{
drawText(cmd.text.x, cmd.text.y, cmd.text.text, cmd.text.align, cmd.col);
}
else if (cmd.type == IMGUI_GFXCMD_SCISSOR)
{
if (cmd.flags)
{
glEnable(GL_SCISSOR_TEST);
glScissor(cmd.rect.x, cmd.rect.y, cmd.rect.w, cmd.rect.h);
}
else
{
glDisable(GL_SCISSOR_TEST);
}
}
}
glDisable(GL_SCISSOR_TEST);
}

View file

@ -0,0 +1,25 @@
//
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
#ifndef IMGUI_RENDER_GL_H
#define IMGUI_RENDER_GL_H
void imguiRenderGLInit();
void imguiRenderGLDraw();
#endif // IMGUI_RENDER_GL_H

View file

@ -0,0 +1,2 @@
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"

View file

@ -0,0 +1,511 @@
/* stbiw-0.92 - public domain - http://nothings.org/stb/stb_image_write.h
writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010
no warranty implied; use at your own risk
Before including,
#define STB_IMAGE_WRITE_IMPLEMENTATION
in the file that you want to have the implementation.
ABOUT:
This header file is a library for writing images to C stdio. It could be
adapted to write to memory or a general streaming interface; let me know.
The PNG output is not optimal; it is 20-50% larger than the file
written by a decent optimizing implementation. This library is designed
for source code compactness and simplicitly, not optimal image file size
or run-time performance.
USAGE:
There are three functions, one for each image file format:
int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
Each function returns 0 on failure and non-0 on success.
The functions create an image file defined by the parameters. The image
is a rectangle of pixels stored from left-to-right, top-to-bottom.
Each pixel contains 'comp' channels of data stored interleaved with 8-bits
per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is
monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall.
The *data pointer points to the first byte of the top-left-most pixel.
For PNG, "stride_in_bytes" is the distance in bytes from the first byte of
a row of pixels to the first byte of the next row of pixels.
PNG creates output files with the same number of components as the input.
The BMP and TGA formats expand Y to RGB in the file format. BMP does not
output alpha.
PNG supports writing rectangles of data even when the bytes storing rows of
data are not consecutive in memory (e.g. sub-rectangles of a larger image),
by supplying the stride between the beginning of adjacent rows. The other
formats do not. (Thus you cannot write a native-format BMP through the BMP
writer, both because it is in BGR order and because it may have padding
at the end of the line.)
*/
#ifndef INCLUDE_STB_IMAGE_WRITE_H
#define INCLUDE_STB_IMAGE_WRITE_H
#ifdef __cplusplus
extern "C" {
#endif
extern int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
extern int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
extern int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
#ifdef __cplusplus
}
#endif
#endif//INCLUDE_STB_IMAGE_WRITE_H
#ifdef STB_IMAGE_WRITE_IMPLEMENTATION
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
typedef unsigned int stbiw_uint32;
typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
static void writefv(FILE *f, const char *fmt, va_list v)
{
while (*fmt) {
switch (*fmt++) {
case ' ': break;
case '1': { unsigned char x = (unsigned char) va_arg(v, int); fputc(x,f); break; }
case '2': { int x = va_arg(v,int); unsigned char b[2];
b[0] = (unsigned char) x; b[1] = (unsigned char) (x>>8);
fwrite(b,2,1,f); break; }
case '4': { stbiw_uint32 x = va_arg(v,int); unsigned char b[4];
b[0]=(unsigned char)x; b[1]=(unsigned char)(x>>8);
b[2]=(unsigned char)(x>>16); b[3]=(unsigned char)(x>>24);
fwrite(b,4,1,f); break; }
default:
assert(0);
return;
}
}
}
static void write3(FILE *f, unsigned char a, unsigned char b, unsigned char c)
{
unsigned char arr[3];
arr[0] = a, arr[1] = b, arr[2] = c;
fwrite(arr, 3, 1, f);
}
static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad)
{
unsigned char bg[3] = { 255, 0, 255}, px[3];
stbiw_uint32 zero = 0;
int i,j,k, j_end;
if (y <= 0)
return;
if (vdir < 0)
j_end = -1, j = y-1;
else
j_end = y, j = 0;
for (; j != j_end; j += vdir) {
for (i=0; i < x; ++i) {
unsigned char *d = (unsigned char *) data + (j*x+i)*comp;
if (write_alpha < 0)
fwrite(&d[comp-1], 1, 1, f);
switch (comp) {
case 1:
case 2: write3(f, d[0],d[0],d[0]);
break;
case 4:
if (!write_alpha) {
// composite against pink background
for (k=0; k < 3; ++k)
px[k] = bg[k] + ((d[k] - bg[k]) * d[3])/255;
write3(f, px[1-rgb_dir],px[1],px[1+rgb_dir]);
break;
}
/* FALLTHROUGH */
case 3:
write3(f, d[1-rgb_dir],d[1],d[1+rgb_dir]);
break;
}
if (write_alpha > 0)
fwrite(&d[comp-1], 1, 1, f);
}
fwrite(&zero,scanline_pad,1,f);
}
}
static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, int comp, void *data, int alpha, int pad, const char *fmt, ...)
{
FILE *f;
if (y < 0 || x < 0) return 0;
f = fopen(filename, "wb");
if (f) {
va_list v;
va_start(v, fmt);
writefv(f, fmt, v);
va_end(v);
write_pixels(f,rgb_dir,vdir,x,y,comp,data,alpha,pad);
fclose(f);
}
return f != NULL;
}
int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
{
int pad = (-x*3) & 3;
return outfile(filename,-1,-1,x,y,comp,(void *) data,0,pad,
"11 4 22 4" "4 44 22 444444",
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
}
int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
{
int has_alpha = !(comp & 1);
return outfile(filename, -1,-1, x, y, comp, (void *) data, has_alpha, 0,
"111 221 2222 11", 0,0,2, 0,0,0, 0,0,x,y, 24+8*has_alpha, 8*has_alpha);
}
// stretchy buffer; stbi__sbpush() == vector<>::push_back() -- stbi__sbcount() == vector<>::size()
#define stbi__sbraw(a) ((int *) (a) - 2)
#define stbi__sbm(a) stbi__sbraw(a)[0]
#define stbi__sbn(a) stbi__sbraw(a)[1]
#define stbi__sbneedgrow(a,n) ((a)==0 || stbi__sbn(a)+n >= stbi__sbm(a))
#define stbi__sbmaybegrow(a,n) (stbi__sbneedgrow(a,(n)) ? stbi__sbgrow(a,n) : 0)
#define stbi__sbgrow(a,n) stbi__sbgrowf((void **) &(a), (n), sizeof(*(a)))
#define stbi__sbpush(a, v) (stbi__sbmaybegrow(a,1), (a)[stbi__sbn(a)++] = (v))
#define stbi__sbcount(a) ((a) ? stbi__sbn(a) : 0)
#define stbi__sbfree(a) ((a) ? free(stbi__sbraw(a)),0 : 0)
static void *stbi__sbgrowf(void **arr, int increment, int itemsize)
{
int m = *arr ? 2*stbi__sbm(*arr)+increment : increment+1;
void *p = realloc(*arr ? stbi__sbraw(*arr) : 0, itemsize * m + sizeof(int)*2);
assert(p);
if (p) {
if (!*arr) ((int *) p)[1] = 0;
*arr = (void *) ((int *) p + 2);
stbi__sbm(*arr) = m;
}
return *arr;
}
static unsigned char *stbi__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
{
while (*bitcount >= 8) {
stbi__sbpush(data, (unsigned char) *bitbuffer);
*bitbuffer >>= 8;
*bitcount -= 8;
}
return data;
}
static int stbi__zlib_bitrev(int code, int codebits)
{
int res=0;
while (codebits--) {
res = (res << 1) | (code & 1);
code >>= 1;
}
return res;
}
static unsigned int stbi__zlib_countm(unsigned char *a, unsigned char *b, int limit)
{
int i;
for (i=0; i < limit && i < 258; ++i)
if (a[i] != b[i]) break;
return i;
}
static unsigned int stbi__zhash(unsigned char *data)
{
stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
return hash;
}
#define stbi__zlib_flush() (out = stbi__zlib_flushf(out, &bitbuf, &bitcount))
#define stbi__zlib_add(code,codebits) \
(bitbuf |= (code) << bitcount, bitcount += (codebits), stbi__zlib_flush())
#define stbi__zlib_huffa(b,c) stbi__zlib_add(stbi__zlib_bitrev(b,c),c)
// default huffman tables
#define stbi__zlib_huff1(n) stbi__zlib_huffa(0x30 + (n), 8)
#define stbi__zlib_huff2(n) stbi__zlib_huffa(0x190 + (n)-144, 9)
#define stbi__zlib_huff3(n) stbi__zlib_huffa(0 + (n)-256,7)
#define stbi__zlib_huff4(n) stbi__zlib_huffa(0xc0 + (n)-280,8)
#define stbi__zlib_huff(n) ((n) <= 143 ? stbi__zlib_huff1(n) : (n) <= 255 ? stbi__zlib_huff2(n) : (n) <= 279 ? stbi__zlib_huff3(n) : stbi__zlib_huff4(n))
#define stbi__zlib_huffb(n) ((n) <= 143 ? stbi__zlib_huff1(n) : stbi__zlib_huff2(n))
#define stbi__ZHASH 16384
unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
{
static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 };
static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 };
static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 };
static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 };
unsigned int bitbuf=0;
int i,j, bitcount=0;
unsigned char *out = NULL;
unsigned char **hash_table[stbi__ZHASH]; // 64KB on the stack!
if (quality < 5) quality = 5;
stbi__sbpush(out, 0x78); // DEFLATE 32K window
stbi__sbpush(out, 0x5e); // FLEVEL = 1
stbi__zlib_add(1,1); // BFINAL = 1
stbi__zlib_add(1,2); // BTYPE = 1 -- fixed huffman
for (i=0; i < stbi__ZHASH; ++i)
hash_table[i] = NULL;
i=0;
while (i < data_len-3) {
// hash next 3 bytes of data to be compressed
int h = stbi__zhash(data+i)&(stbi__ZHASH-1), best=3;
unsigned char *bestloc = 0;
unsigned char **hlist = hash_table[h];
int n = stbi__sbcount(hlist);
for (j=0; j < n; ++j) {
if (hlist[j]-data > i-32768) { // if entry lies within window
int d = stbi__zlib_countm(hlist[j], data+i, data_len-i);
if (d >= best) best=d,bestloc=hlist[j];
}
}
// when hash table entry is too long, delete half the entries
if (hash_table[h] && stbi__sbn(hash_table[h]) == 2*quality) {
memcpy(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
stbi__sbn(hash_table[h]) = quality;
}
stbi__sbpush(hash_table[h],data+i);
if (bestloc) {
// "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal
h = stbi__zhash(data+i+1)&(stbi__ZHASH-1);
hlist = hash_table[h];
n = stbi__sbcount(hlist);
for (j=0; j < n; ++j) {
if (hlist[j]-data > i-32767) {
int e = stbi__zlib_countm(hlist[j], data+i+1, data_len-i-1);
if (e > best) { // if next match is better, bail on current match
bestloc = NULL;
break;
}
}
}
}
if (bestloc) {
int d = data+i - bestloc; // distance back
assert(d <= 32767 && best <= 258);
for (j=0; best > lengthc[j+1]-1; ++j);
stbi__zlib_huff(j+257);
if (lengtheb[j]) stbi__zlib_add(best - lengthc[j], lengtheb[j]);
for (j=0; d > distc[j+1]-1; ++j);
stbi__zlib_add(stbi__zlib_bitrev(j,5),5);
if (disteb[j]) stbi__zlib_add(d - distc[j], disteb[j]);
i += best;
} else {
stbi__zlib_huffb(data[i]);
++i;
}
}
// write out final bytes
for (;i < data_len; ++i)
stbi__zlib_huffb(data[i]);
stbi__zlib_huff(256); // end of block
// pad with 0 bits to byte boundary
while (bitcount)
stbi__zlib_add(0,1);
for (i=0; i < stbi__ZHASH; ++i)
(void) stbi__sbfree(hash_table[i]);
{
// compute adler32 on input
unsigned int i=0, s1=1, s2=0, blocklen = data_len % 5552;
int j=0;
while (j < data_len) {
for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1;
s1 %= 65521, s2 %= 65521;
j += blocklen;
blocklen = 5552;
}
stbi__sbpush(out, (unsigned char) (s2 >> 8));
stbi__sbpush(out, (unsigned char) s2);
stbi__sbpush(out, (unsigned char) (s1 >> 8));
stbi__sbpush(out, (unsigned char) s1);
}
*out_len = stbi__sbn(out);
// make returned pointer freeable
memmove(stbi__sbraw(out), out, *out_len);
return (unsigned char *) stbi__sbraw(out);
}
unsigned int stbi__crc32(unsigned char *buffer, int len)
{
static unsigned int crc_table[256];
unsigned int crc = ~0u;
int i,j;
if (crc_table[1] == 0)
for(i=0; i < 256; i++)
for (crc_table[i]=i, j=0; j < 8; ++j)
crc_table[i] = (crc_table[i] >> 1) ^ (crc_table[i] & 1 ? 0xedb88320 : 0);
for (i=0; i < len; ++i)
crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
return ~crc;
}
#define stbi__wpng4(o,a,b,c,d) ((o)[0]=(unsigned char)(a),(o)[1]=(unsigned char)(b),(o)[2]=(unsigned char)(c),(o)[3]=(unsigned char)(d),(o)+=4)
#define stbi__wp32(data,v) stbi__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
#define stbi__wptag(data,s) stbi__wpng4(data, s[0],s[1],s[2],s[3])
static void stbi__wpcrc(unsigned char **data, int len)
{
unsigned int crc = stbi__crc32(*data - len - 4, len+4);
stbi__wp32(*data, crc);
}
static unsigned char stbi__paeth(int a, int b, int c)
{
int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);
if (pa <= pb && pa <= pc) return (unsigned char) a;
if (pb <= pc) return (unsigned char) b;
return (unsigned char) c;
}
unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
{
int ctype[5] = { -1, 0, 4, 2, 6 };
unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
unsigned char *out,*o, *filt, *zlib;
signed char *line_buffer;
int i,j,k,p,zlen;
if (stride_bytes == 0)
stride_bytes = x * n;
filt = (unsigned char *) malloc((x*n+1) * y); if (!filt) return 0;
line_buffer = (signed char *) malloc(x * n); if (!line_buffer) { free(filt); return 0; }
for (j=0; j < y; ++j) {
static int mapping[] = { 0,1,2,3,4 };
static int firstmap[] = { 0,1,0,5,6 };
int *mymap = j ? mapping : firstmap;
int best = 0, bestval = 0x7fffffff;
for (p=0; p < 2; ++p) {
for (k= p?best:0; k < 5; ++k) {
int type = mymap[k],est=0;
unsigned char *z = pixels + stride_bytes*j;
for (i=0; i < n; ++i)
switch (type) {
case 0: line_buffer[i] = z[i]; break;
case 1: line_buffer[i] = z[i]; break;
case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break;
case 4: line_buffer[i] = (signed char) (z[i] - stbi__paeth(0,z[i-stride_bytes],0)); break;
case 5: line_buffer[i] = z[i]; break;
case 6: line_buffer[i] = z[i]; break;
}
for (i=n; i < x*n; ++i) {
switch (type) {
case 0: line_buffer[i] = z[i]; break;
case 1: line_buffer[i] = z[i] - z[i-n]; break;
case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break;
case 4: line_buffer[i] = z[i] - stbi__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break;
case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break;
case 6: line_buffer[i] = z[i] - stbi__paeth(z[i-n], 0,0); break;
}
}
if (p) break;
for (i=0; i < x*n; ++i)
est += abs((signed char) line_buffer[i]);
if (est < bestval) { bestval = est; best = k; }
}
}
// when we get here, best contains the filter type, and line_buffer contains the data
filt[j*(x*n+1)] = (unsigned char) best;
memcpy(filt+j*(x*n+1)+1, line_buffer, x*n);
}
free(line_buffer);
zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory
free(filt);
if (!zlib) return 0;
// each tag requires 12 bytes of overhead
out = (unsigned char *) malloc(8 + 12+13 + 12+zlen + 12);
if (!out) return 0;
*out_len = 8 + 12+13 + 12+zlen + 12;
o=out;
memcpy(o,sig,8); o+= 8;
stbi__wp32(o, 13); // header length
stbi__wptag(o, "IHDR");
stbi__wp32(o, x);
stbi__wp32(o, y);
*o++ = 8;
*o++ = (unsigned char) ctype[n];
*o++ = 0;
*o++ = 0;
*o++ = 0;
stbi__wpcrc(&o,13);
stbi__wp32(o, zlen);
stbi__wptag(o, "IDAT");
memcpy(o, zlib, zlen); o += zlen; free(zlib);
stbi__wpcrc(&o, zlen);
stbi__wp32(o,0);
stbi__wptag(o, "IEND");
stbi__wpcrc(&o,0);
assert(o == out + *out_len);
return out;
}
int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
{
FILE *f;
int len;
unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
if (!png) return 0;
f = fopen(filename, "wb");
if (!f) { free(png); return 0; }
fwrite(png, 1, len, f);
fclose(f);
free(png);
return 1;
}
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
/* Revision history
0.92 (2010-08-01)
casts to unsigned char to fix warnings
0.91 (2010-07-17)
first public release
0.90 first internal release
*/

File diff suppressed because it is too large Load diff

11
gltools/@docs/conf.py Normal file
View file

@ -0,0 +1,11 @@
source_suffix = '.rst'
master_doc = 'index'
project = 'gltools'
copyright = '2012, Runar Tenfjord'
extensions = ['sphinx.ext.autodoc']
autodoc_docstring_signature = True
autodoc_member_order = 'groupwise'
html_style = 'default.css'
htmlhelp_basename = 'gltoolsdoc'

122
gltools/@include/GLTools.h Normal file
View file

@ -0,0 +1,122 @@
// Copyright 2012 by Runar Tenfjord, Tenko as.
// See LICENSE.txt for details on conditions.
#ifndef GLTOOLS_H
#define GLTOOLS_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <GLFW/glfw3.h>
#include <GL/glext.h>
#define GLEXTPROCSIZE 27
#define VERTEXBUFFERATTRIBSIZE 8
extern char errorMessage[256];
void setErrorMessage(const char *err);
// opengl error check
int glCheck();
// opengl font
extern struct sth_stash *_fonts;
int initText(void);
int beginText(void);
int endText(void);
int drawText(int idx, float size, float x, float y, const char *text, float *dx);
/* OpenGL 2.1 function pointers */
extern int isGLExtLoaded;
static PFNGLACTIVETEXTUREPROC pglActiveTexture = NULL;
static PFNGLGENBUFFERSPROC pglGenBuffers = NULL;
static PFNGLDELETEBUFFERSPROC pglDeleteBuffers = NULL;
static PFNGLCREATESHADERPROC pglCreateShader = NULL;
static PFNGLSHADERSOURCEPROC pglShaderSource = NULL;
static PFNGLCOMPILESHADERPROC pglCompileShader = NULL;
static PFNGLGETSHADERIVPROC pglGetShaderiv = NULL;
static PFNGLGETSHADERINFOLOGPROC pglGetShaderInfoLog = NULL;
static PFNGLDELETESHADERPROC pglDeleteShader = NULL;
static PFNGLCREATEPROGRAMPROC pglCreateProgram = NULL;
static PFNGLATTACHSHADERPROC pglAttachShader = NULL;
static PFNGLLINKPROGRAMPROC pglLinkProgram = NULL;
static PFNGLUSEPROGRAMPROC pglUseProgram = NULL;
static PFNGLGETPROGRAMIVPROC pglGetProgramiv = NULL;
static PFNGLGETPROGRAMINFOLOGPROC pglGetProgramInfoLog = NULL;
static PFNGLDELETEPROGRAMPROC pglDeleteProgram = NULL;
static PFNGLGETUNIFORMLOCATIONPROC pglGetUniformLocation = NULL;
static PFNGLUNIFORM1IPROC pglUniform1i = NULL;
static PFNGLUNIFORM1FPROC pglUniform1f = NULL;
static PFNGLUNIFORM4FPROC pglUniform4f = NULL;
static PFNGLUNIFORMMATRIX4FVPROC pglUniformMatrix4fv = NULL;
static PFNGLGETATTRIBLOCATIONPROC pglGetAttribLocation = NULL;
static PFNGLBUFFERDATAPROC pglBufferData = NULL;
static PFNGLBINDBUFFERPROC pglBindBuffer = NULL;
static PFNGLBUFFERSUBDATAPROC pglBufferSubData = NULL;
static PFNGLGETBUFFERPARAMETERIVPROC pglGetBufferParameteriv = NULL;
static PFNGLENABLEVERTEXATTRIBARRAYPROC pglEnableVertexAttribArray = NULL;
static PFNGLVERTEXATTRIBPOINTERPROC pglVertexAttribPointer = NULL;
int initGLExt(void);
class TextureRect2D {
public:
GLuint m_id;
GLuint m_width;
GLuint m_height;
GLuint m_depth;
TextureRect2D(int width, int height, int depth, void *data);
~TextureRect2D();
void blit(float x, float y);
void copy(GLenum mode);
};
struct ClientBufferAttrib {
int enabled;
GLenum type;
GLenum dataType;
GLint dataTypeSize;
GLsizei stride;
const GLvoid *pointer;
};
class ClientBuffer {
public:
GLuint m_id;
GLenum m_target;
bool m_loaded;
ClientBufferAttrib m_attrib[VERTEXBUFFERATTRIBSIZE];
ClientBuffer(GLenum target);
~ClientBuffer();
void bind();
void unBind();
int setDataType(GLenum type, GLenum dataType, GLenum dataTypeSize,
GLsizei stride, const uintptr_t pointer);
int loadData(const GLvoid *data, GLsizeiptr size, GLintptr offset = 0,
GLenum usage = GL_STATIC_DRAW);
};
class ShaderProgram {
public:
GLuint m_id;
GLuint m_vertex_id;
GLuint m_fragment_id;
ShaderProgram();
~ShaderProgram();
bool isValid();
void begin();
void end();
GLint attribLocation(const GLchar *name);
int loadUniform1i(const char *name, const GLint value);
int loadUniform1f(const char *name, const GLfloat value);
int loadUniform4f(const char *name, const GLfloat v0, const GLfloat v1,
const GLfloat v2, const GLfloat v3);
int loadUniformMatrix4vf(const char *name, const GLfloat *value, GLsizei count = 1);
int build(const char* vertex_src = NULL, const char* fragment_src = NULL);
private:
static const char* default_vertex_shader;
static const char* default_fragment_shader;
};
#endif

View file

@ -0,0 +1,61 @@
# -*- coding: utf-8 -*-
cdef extern from "GLTools.h":
ctypedef unsigned int GLenum
ctypedef unsigned char GLboolean
ctypedef unsigned int GLbitfield
ctypedef signed char GLbyte
ctypedef short GLshort
ctypedef int GLint
ctypedef int GLsizei
ctypedef unsigned char GLubyte
ctypedef unsigned short GLushort
ctypedef unsigned int GLuint
ctypedef float GLfloat
ctypedef float GLclampf
ctypedef double GLdouble
ctypedef double GLclampd
ctypedef void GLvoid
ctypedef ssize_t GLintptr
ctypedef ssize_t GLsizeiptr
char errorMessage[256]
int glCheck()
int stbi_write_png(char *filename, int w, int h, int comp, void *data, int stride_in_bytes)
int c_initText "initText"()
int c_beginText "beginText"()
int c_endText "endText"()
int c_drawText "drawText"(int idx, float size, float x, float y, char *text, float *dx)
int isGLExtLoaded
int c_initGLExt "initGLExt"()
cdef cppclass c_TextureRect2D "TextureRect2D":
GLuint m_width
GLuint m_height
GLuint m_depth
c_TextureRect2D(int width, int height, int depth, void *data)
void blit(float x, float y)
void copy(GLenum mode)
cdef cppclass c_ClientBuffer "ClientBuffer":
c_ClientBuffer(GLenum target)
void bind()
void unBind()
int setDataType(GLenum type, GLenum dataType, GLenum dataTypeSize,
GLsizei stride, size_t pointer)
int loadData(GLvoid *data, GLsizeiptr size, GLintptr offset, GLenum usage)
cdef cppclass c_ShaderProgram "ShaderProgram":
c_ShaderProgram()
bint isValid()
void begin()
void end()
GLint attribLocation(char *name)
int loadUniform1i(char *name, GLint value)
int loadUniform1f(char *name, GLfloat value)
int loadUniform4f(char *name, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)
int loadUniformMatrix4vf(char *name, GLfloat *value, GLsizei count)
int build(char *vertex_src, char *fragment_src)

View file

@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
cdef extern from "stb_image_write.h":
int stbi_write_png(char *filename, int w, int h, int comp, void *data, int stride_in_bytes)

285
gltools/@include/glLib.pxd Normal file
View file

@ -0,0 +1,285 @@
# -*- coding: utf-8 -*-
cdef extern from "GLFW/glfw3.h":
ctypedef unsigned int GLenum
ctypedef unsigned char GLboolean
ctypedef unsigned int GLbitfield
ctypedef signed char GLbyte
ctypedef short GLshort
ctypedef int GLint
ctypedef int GLsizei
ctypedef unsigned char GLubyte
ctypedef unsigned short GLushort
ctypedef unsigned int GLuint
ctypedef float GLfloat
ctypedef float GLclampf
ctypedef double GLdouble
ctypedef double GLclampd
ctypedef void GLvoid
void glBlendFunc(GLenum sfactor, GLenum dfactor)
void glClear(GLbitfield mask)
void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
void glClearDepth(GLclampd depth)
void glDepthFunc(GLenum func)
void glColor4ub(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha )
void glDisable(GLenum cap)
void glDrawArrays(GLenum mode, GLint first, GLsizei count)
void glDrawElements(GLenum mode, GLsizei count, GLenum type, GLvoid *indices)
void glEnable(GLenum cap)
void glGetIntegerv(GLenum pname, GLint *params)
void glHint(GLenum target, GLenum mode)
void glPointSize(GLfloat size)
void glLineWidth(GLfloat width)
void glLightf(GLenum light, GLenum pname, GLfloat param)
void glLightfv(GLenum light, GLenum pname, GLfloat *params )
void glLightModeli(GLenum pname, GLint param)
void glLightModelfv(GLenum pname, GLfloat *params)
void glLoadIdentity()
void glLoadMatrixd(GLdouble *m)
void glMaterialfv(GLenum face, GLenum pname, GLfloat *params)
void glMatrixMode(GLenum mode)
void glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar)
void glPixelStorei(GLenum pname, GLint param)
void glPolygonMode(GLenum face, GLenum mode)
void glPolygonOffset(GLfloat factor, GLfloat units)
void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels)
void glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
cdef enum:
# Boolean values
GL_FALSE
GL_TRUE
# DataType
GL_BYTE
GL_UNSIGNED_BYTE
GL_SHORT
GL_UNSIGNED_SHORT
GL_INT
GL_UNSIGNED_INT
GL_FLOAT
GL_2_BYTES
GL_3_BYTES
GL_4_BYTES
GL_DOUBLE
# BeginMode
GL_POINTS
GL_LINES
GL_LINE_LOOP
GL_LINE_STRIP
GL_TRIANGLES
GL_TRIANGLE_STRIP
GL_TRIANGLE_FAN
GL_QUADS
GL_QUAD_STRIP
GL_POLYGON
# AlphaFunction
GL_NEVER
GL_LESS
GL_EQUAL
GL_LEQUAL
GL_GREATER
GL_NOTEQUAL
GL_GEQUAL
GL_ALWAYS
# AttribMask
GL_CURRENT_BIT
GL_POINT_BIT
GL_LINE_BIT
GL_POLYGON_BIT
GL_POLYGON_STIPPLE_BIT
GL_PIXEL_MODE_BIT
GL_LIGHTING_BIT
GL_FOG_BIT
GL_DEPTH_BUFFER_BIT
GL_ACCUM_BUFFER_BIT
GL_STENCIL_BUFFER_BIT
GL_VIEWPORT_BIT
GL_TRANSFORM_BIT
GL_ENABLE_BIT
GL_COLOR_BUFFER_BIT
GL_HINT_BIT
GL_EVAL_BIT
GL_LIST_BIT
GL_TEXTURE_BIT
GL_SCISSOR_BIT
GL_ALL_ATTRIB_BITS
# Vertex Arrays
GL_VERTEX_ARRAY
GL_NORMAL_ARRAY
GL_COLOR_ARRAY
GL_INDEX_ARRAY
GL_TEXTURE_COORD_ARRAY
GL_EDGE_FLAG_ARRAY
# BlendingFactorDest
GL_ZERO
GL_ONE
GL_SRC_COLOR
GL_ONE_MINUS_SRC_COLOR
GL_SRC_ALPHA
GL_ONE_MINUS_SRC_ALPHA
GL_DST_ALPHA
GL_ONE_MINUS_DST_ALPHA
# BlendingFactorSrc
GL_DST_COLOR
GL_ONE_MINUS_DST_COLOR
GL_SRC_ALPHA_SATURATE
# DrawBufferMode
GL_NONE
GL_FRONT_LEFT
GL_FRONT_RIGHT
GL_BACK_LEFT
GL_BACK_RIGHT
GL_FRONT
GL_BACK
GL_LEFT
GL_RIGHT
GL_FRONT_AND_BACK
GL_AUX0
GL_AUX1
GL_AUX2
GL_AUX3
GL_CW
GL_CCW
# ErrorCode
GL_NO_ERROR
GL_INVALID_ENUM
GL_INVALID_VALUE
GL_INVALID_OPERATION
GL_STACK_OVERFLOW
GL_STACK_UNDERFLOW
GL_OUT_OF_MEMORY
# GetTarget
GL_POLYGON_MODE
GL_POLYGON_SMOOTH
GL_POLYGON_STIPPLE
GL_FRONT_FACE
GL_SHADE_MODEL
GL_COLOR_MATERIAL_FACE
GL_COLOR_MATERIAL_PARAMETER
GL_COLOR_MATERIAL
GL_DEPTH_RANGE
GL_DEPTH_TEST
GL_DEPTH_WRITEMASK
GL_DEPTH_CLEAR_VALUE
GL_DEPTH_FUNC
GL_MATRIX_MODE
GL_NORMALIZE
GL_VIEWPORT
GL_MODELVIEW_MATRIX
GL_PROJECTION_MATRIX
GL_TEXTURE_MATRIX
GL_ALPHA_TEST
GL_ALPHA_TEST_FUNC
GL_ALPHA_TEST_REF
GL_DITHER
GL_BLEND_DST
GL_BLEND_SRC
GL_BLEND
GL_LOGIC_OP_MODE
GL_INDEX_LOGIC_OP
GL_COLOR_LOGIC_OP
GL_AUX_BUFFERS
GL_DRAW_BUFFER
GL_READ_BUFFER
GL_SCISSOR_BOX
GL_SCISSOR_TEST
GL_INDEX_CLEAR_VALUE
GL_INDEX_WRITEMASK
GL_COLOR_CLEAR_VALUE
GL_COLOR_WRITEMASK
GL_INDEX_MODE
GL_RGBA_MODE
GL_DOUBLEBUFFER
GL_STEREO
GL_RENDER_MODE
GL_SUBPIXEL_BITS
GL_INDEX_BITS
GL_RED_BITS
GL_GREEN_BITS
GL_BLUE_BITS
GL_ALPHA_BITS
GL_DEPTH_BITS
GL_STENCIL_BITS
GL_CULL_FACE
# Hints
GL_PERSPECTIVE_CORRECTION_HINT
GL_POINT_SMOOTH_HINT
GL_LINE_SMOOTH_HINT
GL_POLYGON_SMOOTH_HINT
GL_FOG_HINT
GL_DONT_CARE
GL_FASTEST
GL_NICEST
# Ligthing & Material
GL_AMBIENT
GL_DIFFUSE
GL_SPECULAR
GL_SHININESS
GL_EMISSION
GL_POSITION
GL_SPOT_DIRECTION
GL_SPOT_EXPONENT
GL_SPOT_CUTOFF
GL_AMBIENT_AND_DIFFUSE
GL_COLOR_INDEXES
GL_LIGHTING
GL_LIGHT0
GL_LIGHT1
GL_LIGHT2
GL_LIGHT3
GL_LIGHT4
GL_LIGHT5
GL_LIGHT6
GL_LIGHT7
GL_LIGHT_MODEL_TWO_SIDE
GL_LIGHT_MODEL_LOCAL_VIEWER
GL_LIGHT_MODEL_AMBIENT
# MatrixMode
GL_MODELVIEW
GL_PROJECTION
GL_TEXTURE
# Lines
GL_LINE_SMOOTH
# PolygonMode
GL_POINT
GL_LINE
GL_FILL
GL_POLYGON_OFFSET_LINE
GL_POLYGON_OFFSET_FILL
# ShadingModel
GL_FLAT
GL_SMOOTH
# Images
GL_RGB
GL_RGBA
GL_PACK_ALIGNMENT
# Texture mapping
GL_TEXTURE_1D
GL_TEXTURE_2D
# glext.h
GL_MULTISAMPLE
GL_STATIC_DRAW
GL_ARRAY_BUFFER
GL_ELEMENT_ARRAY_BUFFER

View file

@ -0,0 +1,397 @@
# -*- coding: utf-8 -*-
cdef extern from "GLFW/glfw3.h":
cdef enum:
GLFW_VERSION_MAJOR
GLFW_VERSION_MINOR
GLFW_VERSION_REVISION
# Key and button state/action definitions
GLFW_RELEASE
GLFW_PRESS
# Printable keys
GLFW_KEY_SPACE
GLFW_KEY_APOSTROPHE
GLFW_KEY_COMMA
GLFW_KEY_MINUS
GLFW_KEY_PERIOD
GLFW_KEY_SLASH
GLFW_KEY_0
GLFW_KEY_1
GLFW_KEY_2
GLFW_KEY_3
GLFW_KEY_4
GLFW_KEY_5
GLFW_KEY_6
GLFW_KEY_7
GLFW_KEY_8
GLFW_KEY_9
GLFW_KEY_SEMICOLON
GLFW_KEY_EQUAL
GLFW_KEY_A
GLFW_KEY_B
GLFW_KEY_C
GLFW_KEY_D
GLFW_KEY_E
GLFW_KEY_F
GLFW_KEY_G
GLFW_KEY_H
GLFW_KEY_I
GLFW_KEY_J
GLFW_KEY_K
GLFW_KEY_L
GLFW_KEY_M
GLFW_KEY_N
GLFW_KEY_O
GLFW_KEY_P
GLFW_KEY_Q
GLFW_KEY_R
GLFW_KEY_S
GLFW_KEY_T
GLFW_KEY_U
GLFW_KEY_V
GLFW_KEY_W
GLFW_KEY_X
GLFW_KEY_Y
GLFW_KEY_Z
GLFW_KEY_LEFT_BRACKET
GLFW_KEY_BACKSLASH
GLFW_KEY_RIGHT_BRACKET
GLFW_KEY_GRAVE_ACCENT
GLFW_KEY_WORLD_1
GLFW_KEY_WORLD_2
# Function keys
GLFW_KEY_ESCAPE
GLFW_KEY_ENTER
GLFW_KEY_TAB
GLFW_KEY_BACKSPACE
GLFW_KEY_INSERT
GLFW_KEY_DELETE
GLFW_KEY_RIGHT
GLFW_KEY_LEFT
GLFW_KEY_DOWN
GLFW_KEY_UP
GLFW_KEY_PAGE_UP
GLFW_KEY_PAGE_DOWN
GLFW_KEY_HOME
GLFW_KEY_END
GLFW_KEY_CAPS_LOCK
GLFW_KEY_SCROLL_LOCK
GLFW_KEY_NUM_LOCK
GLFW_KEY_PRINT_SCREEN
GLFW_KEY_PAUSE
GLFW_KEY_F1
GLFW_KEY_F2
GLFW_KEY_F3
GLFW_KEY_F4
GLFW_KEY_F5
GLFW_KEY_F6
GLFW_KEY_F7
GLFW_KEY_F8
GLFW_KEY_F9
GLFW_KEY_F10
GLFW_KEY_F11
GLFW_KEY_F12
GLFW_KEY_F13
GLFW_KEY_F14
GLFW_KEY_F15
GLFW_KEY_F16
GLFW_KEY_F17
GLFW_KEY_F18
GLFW_KEY_F19
GLFW_KEY_F20
GLFW_KEY_F21
GLFW_KEY_F22
GLFW_KEY_F23
GLFW_KEY_F24
GLFW_KEY_F25
GLFW_KEY_KP_0
GLFW_KEY_KP_1
GLFW_KEY_KP_2
GLFW_KEY_KP_3
GLFW_KEY_KP_4
GLFW_KEY_KP_5
GLFW_KEY_KP_6
GLFW_KEY_KP_7
GLFW_KEY_KP_8
GLFW_KEY_KP_9
GLFW_KEY_KP_DECIMAL
GLFW_KEY_KP_DIVIDE
GLFW_KEY_KP_MULTIPLY
GLFW_KEY_KP_SUBTRACT
GLFW_KEY_KP_ADD
GLFW_KEY_KP_ENTER
GLFW_KEY_KP_EQUAL
GLFW_KEY_LEFT_SHIFT
GLFW_KEY_LEFT_CONTROL
GLFW_KEY_LEFT_ALT
GLFW_KEY_LEFT_SUPER
GLFW_KEY_RIGHT_SHIFT
GLFW_KEY_RIGHT_CONTROL
GLFW_KEY_RIGHT_ALT
GLFW_KEY_RIGHT_SUPER
GLFW_KEY_MENU
GLFW_KEY_LAST
# Modifiers
GLFW_MOD_SHIFT
GLFW_MOD_CONTROL
GLFW_MOD_ALT
GLFW_MOD_SUPER
# Mouse button definitions
GLFW_MOUSE_BUTTON_1
GLFW_MOUSE_BUTTON_2
GLFW_MOUSE_BUTTON_3
GLFW_MOUSE_BUTTON_4
GLFW_MOUSE_BUTTON_5
GLFW_MOUSE_BUTTON_6
GLFW_MOUSE_BUTTON_7
GLFW_MOUSE_BUTTON_8
GLFW_MOUSE_BUTTON_LAST
# Mouse button aliases
GLFW_MOUSE_BUTTON_LEFT
GLFW_MOUSE_BUTTON_RIGHT
GLFW_MOUSE_BUTTON_MIDDLE
# Joystick identifiers
GLFW_JOYSTICK_1
GLFW_JOYSTICK_2
GLFW_JOYSTICK_3
GLFW_JOYSTICK_4
GLFW_JOYSTICK_5
GLFW_JOYSTICK_6
GLFW_JOYSTICK_7
GLFW_JOYSTICK_8
GLFW_JOYSTICK_9
GLFW_JOYSTICK_10
GLFW_JOYSTICK_11
GLFW_JOYSTICK_12
GLFW_JOYSTICK_13
GLFW_JOYSTICK_14
GLFW_JOYSTICK_15
GLFW_JOYSTICK_16
GLFW_JOYSTICK_LAST
# glfwGetWindowParam tokens
GLFW_ACTIVE
GLFW_ICONIFIED
GLFW_CLOSE_REQUESTED
GLFW_OPENGL_REVISION
# glfwWindowHint tokens
GLFW_RED_BITS
GLFW_GREEN_BITS
GLFW_BLUE_BITS
GLFW_ALPHA_BITS
GLFW_DEPTH_BITS
GLFW_STENCIL_BITS
GLFW_REFRESH_RATE
GLFW_ACCUM_RED_BITS
GLFW_ACCUM_GREEN_BITS
GLFW_ACCUM_BLUE_BITS
GLFW_ACCUM_ALPHA_BITS
GLFW_AUX_BUFFERS
GLFW_STEREO
GLFW_FSAA_SAMPLES
# The following constants are used with both glfwGetWindowParam
# and glfwWindowHint
GLFW_CLIENT_API
GLFW_OPENGL_FORWARD_COMPAT
GLFW_OPENGL_DEBUG_CONTEXT
GLFW_OPENGL_PROFILE
GLFW_OPENGL_ROBUSTNESS
GLFW_RESIZABLE
GLFW_VISIBLE
# GLFW_CLIENT_API tokens
GLFW_OPENGL_API
GLFW_OPENGL_ES_API
# GLFW_OPENGL_ROBUSTNESS mode tokens
GLFW_OPENGL_NO_ROBUSTNESS
GLFW_OPENGL_NO_RESET_NOTIFICATION
GLFW_OPENGL_LOSE_CONTEXT_ON_RESET
# GLFW_OPENGL_PROFILE bit tokens
GLFW_OPENGL_NO_PROFILE
GLFW_OPENGL_CORE_PROFILE
GLFW_OPENGL_COMPAT_PROFILE
# glfwGetInputMode/glfwSetInputMode tokens
GLFW_CURSOR_MODE
GLFW_STICKY_KEYS
GLFW_STICKY_MOUSE_BUTTONS
GLFW_SYSTEM_KEYS
GLFW_KEY_REPEAT
# GLFW_CURSOR_MODE values
GLFW_CURSOR_NORMAL
GLFW_CURSOR_HIDDEN
GLFW_CURSOR_CAPTURED
# glfwGetJoystickParam tokens
GLFW_PRESENT
GLFW_AXES
GLFW_BUTTONS
# glfwGetError/glfwErrorString tokens
GLFW_NO_ERROR
GLFW_NOT_INITIALIZED
GLFW_NO_CURRENT_CONTEXT
GLFW_INVALID_ENUM
GLFW_INVALID_VALUE
GLFW_OUT_OF_MEMORY
GLFW_OPENGL_UNAVAILABLE
GLFW_VERSION_UNAVAILABLE
GLFW_PLATFORM_ERROR
GLFW_WINDOW_NOT_ACTIVE
GLFW_FORMAT_UNAVAILABLE
# Gamma ramps
GLFW_GAMMA_RAMP_SIZE
# OpenGL function pointer type
ctypedef void (*GLFWglproc)()
# Monitor handle type
cdef struct GLFWmonitor:
pass
# Window handle type
cdef struct GLFWwindow:
pass
# Function pointer types
ctypedef void (* GLFWerrorfun)(int,char*)
ctypedef void (* GLFWwindowsizefun)(GLFWwindow *,int,int)
ctypedef int (* GLFWwindowclosefun)(GLFWwindow *)
ctypedef void (* GLFWwindowrefreshfun)(GLFWwindow *)
ctypedef void (* GLFWwindowfocusfun)(GLFWwindow *,int)
ctypedef void (* GLFWwindowiconifyfun)(GLFWwindow *,int)
ctypedef void (* GLFWmousebuttonfun)(GLFWwindow *,int,int)
ctypedef void (* GLFWcursorposfun)(GLFWwindow *,double,double)
ctypedef void (* GLFWcursorenterfun)(GLFWwindow *,int)
ctypedef void (* GLFWscrollfun)(GLFWwindow *,double,double)
ctypedef void (* GLFWkeyfun)(GLFWwindow *,int,int,int,int)
ctypedef void (* GLFWcharfun)(GLFWwindow *,int)
ctypedef void (* GLFWmonitorfun)(c_GLFWmonitor,int)
# The video mode structure used by glfwGetVideoModes
cdef struct _GLFWvidmode:
int width
int height
int redBits
int blueBits
int greenBits
int refreshRate
ctypedef _GLFWvidmode GLFWvidmode
# Gamma ramp
cdef struct _GLFWgammaramp:
unsigned short* red
unsigned short* green
unsigned short* blue
unsigned int size
ctypedef _GLFWgammaramp GLFWgammaramp
# Initialization, termination and version querying
int glfwInit()
void glfwTerminate()
void glfwGetVersion(int* major, int* minor, int* rev)
char* glfwGetVersionString()
# Error handling
int glfwGetError()
char* glfwErrorString(int error)
void glfwSetErrorCallback(GLFWerrorfun cbfun)
# Monitor handling
GLFWmonitor *glfwGetMonitors(int* count)
GLFWmonitor *glfwGetPrimaryMonitor()
void glfwGetMonitorPos(GLFWmonitor *monitor, int* xpos, int* ypos)
void glfwGetMonitorPhysicalSize(GLFWmonitor *monitor, int* width, int* height)
char* glfwGetMonitorName(GLFWmonitor *monitor)
GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun)
# Video mode functions
GLFWvidmode* glfwGetVideoModes(int* count)
const GLFWvidmode* glfwGetVideoMode(GLFWmonitor *monitor)
# Gamma ramp functions
void glfwSetGamma(GLFWmonitor *monitor, float gamma)
GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor *monitor)
void glfwSetGammaRamp(GLFWmonitor *monitor, GLFWgammaramp* ramp)
# Window handling
void glfwDefaultWindowHints()
void glfwWindowHint(int target, int hint)
GLFWwindow * glfwCreateWindow(int width, int height, char* title, GLFWmonitor *monitor, GLFWwindow * share)
int glfwWindowShouldClose(GLFWwindow * window)
void glfwSetWindowShouldClose(GLFWwindow * window, int value)
void glfwDestroyWindow(GLFWwindow * window)
void glfwSetWindowTitle(GLFWwindow * window, char* title)
void glfwGetWindowSize(GLFWwindow * window, int* width, int* height)
void glfwSetWindowSize(GLFWwindow * window, int width, int height)
void glfwGetWindowPos(GLFWwindow * window, int* xpos, int* ypos)
void glfwSetWindowPos(GLFWwindow * window, int xpos, int ypos)
void glfwIconifyWindow(GLFWwindow * window)
void glfwRestoreWindow(GLFWwindow * window)
void glfwShowWindow(GLFWwindow * window)
void glfwHideWindow(GLFWwindow * window)
GLFWmonitor *glfwGetWindowMonitor(GLFWwindow * window)
int glfwGetWindowParam(GLFWwindow * window, int param)
void glfwSetWindowUserPointer(GLFWwindow * window, void* pointer)
void* glfwGetWindowUserPointer(GLFWwindow * window)
void glfwSetWindowSizeCallback(GLFWwindow * window, GLFWwindowsizefun cbfun)
void glfwSetWindowCloseCallback(GLFWwindow * window, GLFWwindowclosefun cbfun)
void glfwSetWindowRefreshCallback(GLFWwindow * window, GLFWwindowrefreshfun cbfun)
void glfwSetWindowFocusCallback(GLFWwindow * window, GLFWwindowfocusfun cbfun)
void glfwSetWindowIconifyCallback(GLFWwindow * window, GLFWwindowiconifyfun cbfun)
# Event handling
void glfwPollEvents()
void glfwWaitEvents()
# Input handling
int glfwGetInputMode(GLFWwindow * window, int mode)
void glfwSetInputMode(GLFWwindow * window, int mode, int value)
int glfwGetKey(GLFWwindow * window, int key)
int glfwGetMouseButton(GLFWwindow * window, int button)
void glfwGetCursorPos(GLFWwindow * window, double* xpos, double* ypos)
void glfwSetCursorPos(GLFWwindow * window, double xpos, double ypos)
void glfwGetScrollOffset(GLFWwindow * window, double* xoffset, double* yoffset)
void glfwSetKeyCallback(GLFWwindow * window, GLFWkeyfun cbfun)
void glfwSetCharCallback(GLFWwindow * window, GLFWcharfun cbfun)
void glfwSetMouseButtonCallback(GLFWwindow * window, GLFWmousebuttonfun cbfun)
void glfwSetCursorPosCallback(GLFWwindow * window, GLFWcursorposfun cbfun)
void glfwSetCursorEnterCallback(GLFWwindow * window, GLFWcursorenterfun cbfun)
void glfwSetScrollCallback(GLFWwindow * window, GLFWscrollfun cbfun)
# Joystick input
int glfwGetJoystickParam(int joy, int param)
int glfwGetJoystickAxes(int joy, float* axes, int numaxes)
int glfwGetJoystickButtons(int joy, unsigned char* buttons, int numbuttons)
# Clipboard
void glfwSetClipboardString(GLFWwindow * window, char* string)
char* glfwGetClipboardString(GLFWwindow * window)
# Time
double glfwGetTime()
void glfwSetTime(double time)
# OpenGL support
void glfwMakeContextCurrent(GLFWwindow * window)
GLFWwindow * glfwGetCurrentContext()
void glfwSwapBuffers(GLFWwindow * window)
void glfwSwapInterval(int interval)
int glfwExtensionSupported(char* extension)
GLFWglproc glfwGetProcAddress(char* procname)
void glfwCopyContext(GLFWwindow * src, GLFWwindow * dst, unsigned long mask)

View file

@ -0,0 +1,44 @@
cdef extern from "imguiRenderGL.h":
bint imguiRenderGLInit()
void imguiRenderGLDraw()
cdef extern from "imgui.h":
cdef enum imguiMouseButton:
IMGUI_MBUT_LEFT
IMGUI_MBUT_RIGHT
cdef enum imguiTextAlign:
IMGUI_ALIGN_LEFT
IMGUI_ALIGN_CENTER
IMGUI_ALIGN_RIGHT
unsigned int imguiRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
bint imguiAnyActive()
void imguiBeginFrame(int mx, int my, unsigned char mbut, int scroll)
void imguiEndFrame()
bint imguiBeginScrollArea(char* name, int x, int y, int w, int h, int* scroll)
void imguiEndScrollArea()
bint imguiBeginArea(char* name, int x, int y, int w, int h)
void imguiEndArea()
void imguiIndent()
void imguiUnindent()
void imguiSeparator()
void imguiSeparatorLine()
bint imguiButton(char* text, bint enabled, int x, int y, int w, int h)
bint imguiItem(char* text, bint enabled)
bint imguiCheck(char* text, bint checked, bint enabled)
bint imguiCollapse(char* text, char* subtext, bint checked, bint enabled)
void imguiLabel(char* text)
void imguiValue(char* text)
bint imguiSlider(char* text, float* val, float vmin, float vmax, float vinc, bint enabled)
void imguiDrawText(int x, int y, int align, char* text, unsigned int color)
void imguiDrawLine(float x0, float y0, float x1, float y1, float r, unsigned int color)
void imguiDrawRoundedRect(float x, float y, float w, float h, float r, unsigned int color)
void imguiDrawRect(float x, float y, float w, float h, unsigned int color)

View file

@ -0,0 +1,88 @@
# -*- coding: utf-8 -*-
#
# This file is part of gltools - See LICENSE.txt
#
cdef class ClientBuffer:
'''
Abstraction of OpenGL vertex buffer
The class initialize a single buffer object.
The target argument is either gl.ARRAY_BUFFER
or gl.ELEMENT_ARRAY_BUFFER.
'''
def __init__(self, target = GL_ARRAY_BUFFER):
if not isGLExtLoaded:
raise GLError('OpenGL 2.1 function pointers not found')
self.thisptr = new c_ClientBuffer(target)
if not glCheck():
raise GLError(errorMessage)
def __dealloc__(self):
cdef c_ClientBuffer *tmp
if self.thisptr != NULL:
tmp = <c_ClientBuffer *>self.thisptr
del tmp
def __str__(self):
return "ClientBuffer%s" % repr(self)
def __repr__(self):
return "()"
cpdef bind(self):
'''
Bind the buffer object and possible set the attribute pointers
ig the target is gl.ARRAY_BUFFER and the datatype is defined
'''
cdef c_ClientBuffer *buf = <c_ClientBuffer *>self.thisptr
buf.bind()
cpdef unBind(self):
'''
Unbind the buffer object
'''
cdef c_ClientBuffer *buf = <c_ClientBuffer *>self.thisptr
buf.unBind()
cpdef setDataType(self, int type, int dataType, int dataTypeSize,
int stride, size_t pointer):
'''
Set datatye for data in buffer. Only makes sense when
target is gl.ARRAY_BUFFER.
:type: gl.VERTEX_ARRAY, gl.NORMAL_ARRAY or gl.COLOR_ARRAY.
:dataType: gl.FLOAT, gl.INT etc.
:dataTypeSize: size of datatype.
:stride: stride between data
:pointer: pointer into buffer object (offser from index 0)
example::
buffer.setDataType(gl.VERTEX_ARRAY, gl.FLOAT, 3, 0, 0)
'''
cdef c_ClientBuffer *buf = <c_ClientBuffer *>self.thisptr
if not buf.setDataType(type, dataType, dataTypeSize, stride, pointer):
raise GLError(errorMessage)
cdef cloadData(self, void *data, ssize_t size, ssize_t offset, int usage):
cdef c_ClientBuffer *buf = <c_ClientBuffer *>self.thisptr
if not buf.loadData(data, size, offset, usage):
raise GLError(errorMessage)
cpdef loadData(self, data, ssize_t size, ssize_t offset = 0, int usage = GL_STATIC_DRAW):
'''
Upload data to client side buffer. Passing None
for data will reserve capacity.
:data: None, or any python python object with buffer interface
:size: size of data to upload.
:offset: offset into buffer object
'''
if data is None:
self.cloadData(NULL, size, offset, usage)
else:
self.cloadData(getVoidPtr(data), size, offset, usage)

246
gltools/@src/Color.pxi Normal file
View file

@ -0,0 +1,246 @@
# -*- coding: utf-8 -*-
#
# This file is part of gltools - See LICENSE.txt
#
cdef class ColorRGBA:
'''
RGBA color with components stored as unsigned
bytes.
'''
def __init__(self, GLubyte red = 255, GLubyte green = 255, GLubyte blue = 255,
GLubyte alpha = 255):
self.red = red
self.green = green
self.blue = blue
self.alpha = alpha
def __str__(self):
return "ColorRGBA%s" % repr(self)
def __repr__(self):
args = self.red, self.green, self.blue, self.alpha
return "(red=%d, green=%d, blue=%d, alpha=%d)" % args
def __len__(self):
return 4
def __getitem__(self, int key):
if key == 0:
return self.red
elif key == 1:
return self.green
elif key == 2:
return self.blue
elif key == 3:
return self.alpha
raise IndexError('index out of range')
def __mul__(double factor, ColorRGBA rhs):
'''
Scale color components and leaves alpha unchanged
'''
cdef ColorRGBA ret = ColorRGBA.__new__(ColorRGBA)
if factor < 0.:
raise GLError('factor < 0.')
ret.red = <unsigned char>fmin(255, factor*rhs.red)
ret.green = <unsigned char>fmin(255, factor*rhs.green)
ret.blue = <unsigned char>fmin(255, factor*rhs.blue)
ret.alpha = rhs.alpha
return ret
cpdef ColorRGBA copy(self, int red = -1, int green = -1, int blue = -1, alpha = -1):
'''
Create copy with optional changes.
'''
cdef ColorRGBA ret = ColorRGBA.__new__(ColorRGBA)
ret.red = self.red
ret.green = self.green
ret.blue = self.blue
ret.alpha = self.alpha
if red >= 0 and red < 256:
ret.red = red
if green >= 0 and green < 256:
ret.green = green
if blue >= 0 and blue < 256:
ret.blue = blue
if alpha >= 0 and alpha < 256:
ret.alpha = alpha
return ret
cpdef unsigned toInt(self):
'''
Pack color to a single unsigned int
'''
return self.alpha << 24 | self.blue << 16 | self.green << 8 | self.red
cpdef fromInt(self, unsigned int value):
'''
Unpack color from unsigned int
'''
self.red = value & 0x000000FF
self.green = (value & 0x0000FF00) >> 8
self.blue = (value & 0x00FF0000) >> 16
self.alpha = (value & 0xFF000000) >> 24
cpdef tuple toFloatVector(self):
'''
Return color as float normalized [0.0 - 1.0]
'''
return (self.red / 255., self.green / 255., self.blue / 255., self.alpha / 255.)
cdef setFloatVector(self, float *vec):
vec[0] = self.red / 255.
vec[1] = self.green / 255.
vec[2] = self.blue / 255.
vec[3] = self.alpha / 255.
WHITE = ColorRGBA(255,255,255,255)
BLACK = ColorRGBA(0,0,0,255)
cdef class Material:
'''
Abstraction of OpenGL material
'''
def __init__(self, int mode = GL_FRONT_AND_BACK, **kwargs):
self.mode = mode
self.shininess = -1.
for name, value in kwargs.iteritems():
if name in {'ambient','diffuse','specular','emissive','shininess'}:
setattr(self, name, value)
else:
raise GLError("attribute '%s' not known")
def __str__(self):
return "Material%s" % repr(self)
def __repr__(self):
return "()"
cpdef enable(self):
'''
Set OpenGL material state
'''
cdef float mat[4]
cdef int i
if not self.ambient is None:
self.ambient.setFloatVector(mat)
glMaterialfv(self.mode, GL_AMBIENT, mat)
if not self.diffuse is None:
self.diffuse.setFloatVector(mat)
glMaterialfv(self.mode, GL_DIFFUSE, mat)
if not self.specular is None:
self.specular.setFloatVector(mat)
glMaterialfv(self.mode, GL_SPECULAR, mat)
if not self.emissive is None:
self.emissive.setFloatVector(mat)
glMaterialfv(self.mode, GL_EMISSION, mat)
if self.shininess > 0:
mat[0] = fmin(fmax(0., self.shininess), 128)
glMaterialfv(self.mode, GL_SHININESS, mat)
cpdef AmbientLight(ColorRGBA col):
'''
Set global ambient light color.
'''
cdef float c_col[4]
col.setFloatVector(c_col)
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, c_col)
cdef class Light:
'''
Abstraction of OpenGL light
'''
def __init__(self, int index = 0, Material material = None,
Point position = None, directional = True,
Vector direction = None):
if index == 0:
self.index = GL_LIGHT0
elif index == 1:
self.index = GL_LIGHT1
elif index == 2:
self.index = GL_LIGHT2
elif index == 3:
self.index = GL_LIGHT3
elif index == 4:
self.index = GL_LIGHT4
elif index == 5:
self.index = GL_LIGHT5
elif index == 6:
self.index = GL_LIGHT6
elif index == 7:
self.index = GL_LIGHT7
else:
raise GLError('Light index out of range (0-7)')
self.material = material
self.position = position
self.directional = directional
self.direction = direction
def __str__(self):
return "Light%s" % repr(self)
def __repr__(self):
return "()"
cpdef enable(self):
'''
Enable light and set OpenGL state
'''
cdef float mat[4]
glEnable(self.index)
if not self.material.ambient is None:
self.material.ambient.setFloatVector(mat)
glLightfv(self.index, GL_AMBIENT, mat)
if not self.material.diffuse is None:
self.material.diffuse.setFloatVector(mat)
glLightfv(self.index, GL_DIFFUSE, mat)
if not self.material.specular is None:
self.material.specular.setFloatVector(mat)
glLightfv(self.index, GL_SPECULAR, mat)
if self.directional:
mat[3] = 0.
else:
mat[3] = 1.
if not self.direction is None:
mat[0], mat[1], mat[2] = self.direction
else:
mat[0], mat[1], mat[2] = 0., 0., -1.
glLightfv(self.index, GL_SPOT_DIRECTION, mat)
if not self.position is None:
mat[0], mat[1], mat[2] = self.position
else:
mat[0], mat[1], mat[2] = 0., 0., 0.
glLightfv(self.index, GL_POSITION, mat)
glLightf(self.index, GL_SPOT_CUTOFF, 180.)
glLightf(self.index, GL_SPOT_EXPONENT, 0.)
cpdef disable(self):
'''
Disable light
'''
glDisable(self.index)

262
gltools/@src/Constants.pxi Normal file
View file

@ -0,0 +1,262 @@
# -*- coding: utf-8 -*-
class ACTION:
RELEASE = GLFW_RELEASE
PRESS = GLFW_PRESS
class KEY:
SPACE = GLFW_KEY_SPACE
APOSTROPHE = GLFW_KEY_APOSTROPHE
COMMA = GLFW_KEY_COMMA
MINUS = GLFW_KEY_MINUS
PERIOD = GLFW_KEY_PERIOD
SLASH = GLFW_KEY_SLASH
ZERO = GLFW_KEY_0
ONE = GLFW_KEY_1
TWO = GLFW_KEY_2
THREE = GLFW_KEY_3
FOUR = GLFW_KEY_4
FIVE = GLFW_KEY_5
SIX = GLFW_KEY_6
SEVEN = GLFW_KEY_7
EIGHT = GLFW_KEY_8
NINE = GLFW_KEY_9
SEMICOLON = GLFW_KEY_SEMICOLON
EQUAL = GLFW_KEY_EQUAL
A = GLFW_KEY_A
B = GLFW_KEY_B
C = GLFW_KEY_C
D = GLFW_KEY_D
E = GLFW_KEY_E
F = GLFW_KEY_F
G = GLFW_KEY_G
H = GLFW_KEY_H
I = GLFW_KEY_I
J = GLFW_KEY_J
K = GLFW_KEY_K
L = GLFW_KEY_L
M = GLFW_KEY_M
N = GLFW_KEY_N
O = GLFW_KEY_O
P = GLFW_KEY_P
Q = GLFW_KEY_Q
R = GLFW_KEY_R
S = GLFW_KEY_S
T = GLFW_KEY_T
U = GLFW_KEY_U
V = GLFW_KEY_V
W = GLFW_KEY_W
X = GLFW_KEY_X
Y = GLFW_KEY_Y
Z = GLFW_KEY_Z
LEFT_BRACKET = GLFW_KEY_LEFT_BRACKET
BACKSLASH = GLFW_KEY_BACKSLASH
RIGHT_BRACKET = GLFW_KEY_RIGHT_BRACKET
SPACE = GLFW_KEY_SPACE
ESCAPE = GLFW_KEY_ESCAPE
ENTER = GLFW_KEY_ENTER
TAB = GLFW_KEY_TAB
BACKSPACE = GLFW_KEY_BACKSPACE
INSERT = GLFW_KEY_INSERT
DELETE = GLFW_KEY_DELETE
RIGHT = GLFW_KEY_RIGHT
LEFT = GLFW_KEY_LEFT
DOWN = GLFW_KEY_DOWN
UP = GLFW_KEY_UP
PAGE_UP = GLFW_KEY_PAGE_UP
PAGE_DOWN = GLFW_KEY_PAGE_DOWN
HOME = GLFW_KEY_HOME
END = GLFW_KEY_END
CAPS_LOCK = GLFW_KEY_CAPS_LOCK
SCROLL_LOCK = GLFW_KEY_SCROLL_LOCK
NUM_LOCK = GLFW_KEY_NUM_LOCK
PRINT_SCREEN = GLFW_KEY_PRINT_SCREEN
PAUSE = GLFW_KEY_PAUSE
F1 = GLFW_KEY_F1
F2 = GLFW_KEY_F2
F3 = GLFW_KEY_F3
F4 = GLFW_KEY_F4
F5 = GLFW_KEY_F5
F6 = GLFW_KEY_F6
F7 = GLFW_KEY_F7
F8 = GLFW_KEY_F8
F9 = GLFW_KEY_F9
F10 = GLFW_KEY_F10
F11 = GLFW_KEY_F11
F12 = GLFW_KEY_F12
LEFT_SHIFT = GLFW_KEY_LEFT_SHIFT
LEFT_CONTROL = GLFW_KEY_LEFT_CONTROL
LEFT_ALT = GLFW_KEY_LEFT_ALT
RIGHT_SHIFT = GLFW_KEY_RIGHT_SHIFT
RIGHT_CONTROL = GLFW_KEY_RIGHT_CONTROL
RIGHT_ALT = GLFW_KEY_RIGHT_ALT
class MOD:
SHIFT = GLFW_MOD_SHIFT
CONTROL = GLFW_MOD_CONTROL
ALT = GLFW_MOD_ALT
SUPER = GLFW_MOD_SUPER
class MOUSE:
LEFT = GLFW_MOUSE_BUTTON_LEFT
RIGHT = GLFW_MOUSE_BUTTON_RIGHT
MIDDLE = GLFW_MOUSE_BUTTON_MIDDLE
# AlphaFunction
NEVER = GL_NEVER
LESS = GL_LESS
EQUAL = GL_EQUAL
LEQUAL = GL_LEQUAL
GREATER = GL_GREATER
NOTEQUAL = GL_NOTEQUAL
GEQUAL = GL_GEQUAL
ALWAYS = GL_ALWAYS
# AttribMask
CURRENT_BIT = GL_CURRENT_BIT
POINT_BIT = GL_POINT_BIT
LINE_BIT = GL_LINE_BIT
POLYGON_BIT = GL_POLYGON_BIT
POLYGON_STIPPLE_BIT = GL_POLYGON_STIPPLE_BIT
PIXEL_MODE_BIT = GL_PIXEL_MODE_BIT
LIGHTING_BIT = GL_LIGHTING_BIT
FOG_BIT = GL_FOG_BIT
DEPTH_BUFFER_BIT = GL_DEPTH_BUFFER_BIT
ACCUM_BUFFER_BIT = GL_ACCUM_BUFFER_BIT
STENCIL_BUFFER_BIT = GL_STENCIL_BUFFER_BIT
VIEWPORT_BIT = GL_VIEWPORT_BIT
TRANSFORM_BIT = GL_TRANSFORM_BIT
ENABLE_BIT = GL_ENABLE_BIT
COLOR_BUFFER_BIT = GL_COLOR_BUFFER_BIT
HINT_BIT = GL_HINT_BIT
EVAL_BIT = GL_EVAL_BIT
LIST_BIT = GL_LIST_BIT
TEXTURE_BIT = GL_TEXTURE_BIT
SCISSOR_BIT = GL_SCISSOR_BIT
ALL_ATTRIB_BITS = GL_ALL_ATTRIB_BITS
# BeginMode
POINTS = GL_POINTS
LINES = GL_LINES
LINE_LOOP = GL_LINE_LOOP
LINE_STRIP = GL_LINE_STRIP
TRIANGLES = GL_TRIANGLES
TRIANGLE_STRIP = GL_TRIANGLE_STRIP
TRIANGLE_FAN = GL_TRIANGLE_FAN
QUADS = GL_QUADS
QUAD_STRIP = GL_QUAD_STRIP
POLYGON = GL_POLYGON
# Vertex Arrays
VERTEX_ARRAY = GL_VERTEX_ARRAY
NORMAL_ARRAY = GL_NORMAL_ARRAY
COLOR_ARRAY = GL_COLOR_ARRAY
INDEX_ARRAY = GL_INDEX_ARRAY
TEXTURE_COORD_ARRAY = GL_TEXTURE_COORD_ARRAY
EDGE_FLAG_ARRAY = GL_EDGE_FLAG_ARRAY
# BlendingFactorDest
ZERO = GL_ZERO
ONE = GL_ONE
SRC_COLOR = GL_SRC_COLOR
ONE_MINUS_SRC_COLOR = GL_ONE_MINUS_SRC_COLOR
SRC_ALPHA = GL_SRC_ALPHA
ONE_MINUS_SRC_ALPHA = GL_ONE_MINUS_SRC_ALPHA
DST_ALPHA = GL_DST_ALPHA
ONE_MINUS_DST_ALPHA = GL_ONE_MINUS_DST_ALPHA
# BlendingFactorSrc
DST_COLOR = GL_DST_COLOR
ONE_MINUS_DST_COLOR = GL_ONE_MINUS_DST_COLOR
SRC_ALPHA_SATURATE = GL_SRC_ALPHA_SATURATE
# Boolean values
FALSE = GL_FALSE
TRUE = GL_TRUE
BYTE = GL_BYTE
UNSIGNED_BYTE = GL_UNSIGNED_BYTE
SHORT = GL_SHORT
UNSIGNED_SHORT = GL_UNSIGNED_SHORT
INT = GL_INT
UNSIGNED_INT = GL_UNSIGNED_INT
FLOAT = GL_FLOAT
DOUBLE = GL_DOUBLE
# DrawBufferMode
NONE = GL_NONE
FRONT_LEFT = GL_FRONT_LEFT
FRONT_RIGHT = GL_FRONT_RIGHT
BACK_LEFT = GL_BACK_LEFT
BACK_RIGHT = GL_BACK_RIGHT
FRONT = GL_FRONT
BACK = GL_BACK
LEFT = GL_LEFT
RIGHT = GL_RIGHT
FRONT_AND_BACK = GL_FRONT_AND_BACK
AUX0 = GL_AUX0
AUX1 = GL_AUX1
AUX2 = GL_AUX2
AUX3 = GL_AUX3
CW = GL_CW
CCW = GL_CCW
# GetTarget
DEPTH_TEST = GL_DEPTH_TEST
BLEND = GL_BLEND
DITHER = GL_DITHER
CULL_FACE = GL_CULL_FACE
# MatrixMode
MODELVIEW = GL_MODELVIEW
PROJECTION = GL_PROJECTION
TEXTURE = GL_TEXTURE
# Lines
LINE_SMOOTH = GL_LINE_SMOOTH
# PolygonMode
POINT = GL_POINT
LINE = GL_LINE
FILL = GL_FILL
POLYGON_OFFSET_LINE = GL_POLYGON_OFFSET_LINE
POLYGON_OFFSET_FILL = GL_POLYGON_OFFSET_FILL
# ShadingModel
FLAT = GL_FLAT
SMOOTH = GL_SMOOTH
# Hints
PERSPECTIVE_CORRECTION_HINT = GL_PERSPECTIVE_CORRECTION_HINT
POINT_SMOOTH_HINT = GL_POINT_SMOOTH_HINT
LINE_SMOOTH_HINT = GL_LINE_SMOOTH_HINT
POLYGON_SMOOTH_HINT = GL_POLYGON_SMOOTH_HINT
FOG_HINT = GL_FOG_HINT
DONT_CARE = GL_DONT_CARE
FASTEST = GL_FASTEST
NICEST = GL_NICEST
# Lighting
LIGHTING = GL_LIGHTING
LIGHT0 = GL_LIGHT0
LIGHT1 = GL_LIGHT1
LIGHT2 = GL_LIGHT2
LIGHT3 = GL_LIGHT3
LIGHT4 = GL_LIGHT4
LIGHT5 = GL_LIGHT5
LIGHT6 = GL_LIGHT6
LIGHT7 = GL_LIGHT7
LIGHT_MODEL_TWO_SIDE = GL_LIGHT_MODEL_TWO_SIDE
# Images
RGB = GL_RGB
RGBA = GL_RGBA
# Texture
TEXTURE_2D = GL_TEXTURE_2D
# glext.h
MULTISAMPLE = GL_MULTISAMPLE
STATIC_DRAW = GL_STATIC_DRAW
ARRAY_BUFFER = GL_ARRAY_BUFFER
ELEMENT_ARRAY_BUFFER = GL_ELEMENT_ARRAY_BUFFER

260
gltools/@src/GL.pxi Normal file
View file

@ -0,0 +1,260 @@
# -*- coding: utf-8 -*-
#
# This file is part of gltools - See LICENSE.txt
#
from glLib cimport *
# init OpenGL function pointers
cpdef InitGLExt():
'''
Initialize OpenGL 2.1 extension
Raise GLError if extensions not found
'''
if not c_initGLExt():
raise GLError(errorMessage)
cpdef int Check():
'''
Check for OpenGL errors.
Raises GLError.
'''
if not glCheck():
raise GLError(errorMessage)
cpdef BlendFunc(unsigned int sfactor, unsigned int dfactor):
'''
Specify pixel arithmetic
:sfactor: Specifies how the red, green, blue, and alpha source blending
factors are computed. The initial value is GL_ONE.
:dfactor: Specifies how the red, green, blue, and alpha destination
blending factors are computed. gl.ONE_MINUS_SRC_COLOR etc.
'''
glBlendFunc(sfactor, dfactor)
cpdef Clear(unsigned int mask):
'''
Clear selected buffers to preset values.
:mask: bit flags are gl.COLOR_BUFFER_BIT, gl.DEPTH_BUFFER_BIT, and
gl.STENCIL_BUFFER_BIT
'''
glClear(mask)
cpdef ClearColor(ColorRGBA col):
'''
Specify clear values for the color buffers
'''
glClearColor(col.red / 255., col.green / 255., col.blue / 255., col.alpha / 255.)
cpdef ClearDepth(double depth):
'''
Specify the clear value for the depth buffer
'''
glClearDepth(depth)
cpdef DepthFunc(int func):
'''
Specify the value used for depth buffer comparisons
'''
glDepthFunc(func)
cpdef Color(ColorRGBA col):
'''
Sets the current color.
'''
glColor4ub(col.red, col.green, col.blue, col.alpha )
cpdef Disable(unsigned int cap):
'''
Disable server-side GL capabilities
'''
glDisable(cap)
cpdef DrawArrays(unsigned int mode, int first, int count):
'''
Render primitives from array data
:mode: Primitive type gl.POINTS, gl.LINE_STRIP, etc.
:first: Specifies the starting index in the enabled arrays.
:count: Specifies the number of indices to be rendered.
'''
glDrawArrays(mode, first, count)
cpdef DrawElements(unsigned int mode, int count, int type, indices):
'''
Render primitives from array data with indices.
:mode: Primitive type gl.POINTS, gl.LINE_STRIP, etc.
:count: Specifies the number of indices to be rendered.
:type: Indices data type. One of gl.UNSIGNED_BYTE, gl.UNSIGNED_SHORT, or
gl.UNSIGNED_INT
:indices: Either a python object with valid buffer interface or and
integer as a pointer into a already bound ClientBuffer of
element array type.
'''
cdef int offset
try:
offset = indices
glDrawElements(mode, count, type, <void *>offset)
except TypeError:
glDrawElements(mode, count, type, getVoidPtr(indices))
cpdef Enable(unsigned int cap):
'''
Enable server-side GL capabilities
'''
glEnable(cap)
cpdef Hint(int target, int mode):
'''
specify implementation-specific hints
'''
glHint(target, mode)
cpdef PointSize(float width):
'''
Specify the diameter of rasterized points
'''
glPointSize(width)
cpdef LineWidth(float width):
'''
Specify the width of rasterized lines
'''
glLineWidth(width)
cpdef LightModeli(int pname, int param):
'''
Sets lighting model parameters.
Example::
gl.LightModeli(gl.LIGHT_MODEL_TWO_SIDE, gl.TRUE)
'''
glLightModeli(pname, param)
cpdef LoadIdentity():
'''
Replace the current matrix with the identity matrix
'''
glLoadIdentity()
cpdef LoadMatrixd(Transform tr):
'''
Replace the current matrix with given matrix.
'''
cdef double cm[16]
# col 1
cm[0] = tr.m[0][0]
cm[1] = tr.m[1][0]
cm[2] = tr.m[2][0]
cm[3] = tr.m[3][0]
# col 2
cm[4] = tr.m[0][1]
cm[5] = tr.m[1][1]
cm[6] = tr.m[2][1]
cm[7] = tr.m[3][1]
# col 3
cm[8] = tr.m[0][2]
cm[9] = tr.m[1][2]
cm[10] = tr.m[2][2]
cm[11] = tr.m[3][2]
# col 4
cm[12] = tr.m[0][3]
cm[13] = tr.m[1][3]
cm[14] = tr.m[2][3]
cm[15] = tr.m[3][3]
glLoadMatrixd(cm)
cpdef MatrixMode(unsigned int mode):
'''
Specify which matrix is the current matrix
:mode: gl.MODELVIEW, gl.PROJECTION, or gl.TEXTURE
'''
glMatrixMode(mode)
cpdef Ortho(double left, double right, double bottom, double top, double zNear,
double zFar):
'''
Multiply the current matrix with an orthographic matrix
:left: Specify the coordinates for the left vertical clipping plane.
:right: Specify the coordinates for the vertical clipping plane.
:bottom: Specify the coordinates for the bottom horizontal clipping plane.
:top: Specify the coordinates for the top horizontal clipping plane.
:zNear: Specify the distances to the nearer clipping plane.
:zFar: Specify the distances to the farther depth clipping plane.
'''
glOrtho(left, right, bottom, top, zNear, zFar)
cpdef PolygonMode(unsigned int face, unsigned int mode):
'''
Select a polygon rasterization mode
Example::
gl.PolygonMode(gl.FRONT_AND_BACK, gl.FILL)
'''
glPolygonMode(face, mode)
cpdef PolygonOffset(float factor, float units):
'''
Set the scale and units used to calculate depth values
:factor: Specifies a scale factor that is used to create a variable depth
offset for each polygon.
:units: Is multiplied by an implementation-specific value to create a
constant depth offset.
'''
glPolygonOffset(factor, units)
cpdef ColorRGBA ReadPixel(int x, int y):
'''
Read a sigle pixel from the frame buffer.
'''
cdef unsigned char pixel[4]
cdef ColorRGBA ret = ColorRGBA.__new__(ColorRGBA)
glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel)
ret.red = pixel[0]
ret.green = pixel[1]
ret.blue = pixel[2]
ret.alpha = pixel[3]
return ret
cpdef ReadPixels(int x, int y, Image img):
'''
Read a block of pixels from the frame buffer
'''
cdef GLenum format
if img.bytesPerPixel == 3:
format = GL_RGB
else:
format = GL_RGBA
glPixelStorei(GL_PACK_ALIGNMENT, 1)
glReadPixels(x, y, img.width, img.height, format, GL_UNSIGNED_BYTE, img._buffer)
cpdef Viewport(int x, int y, int width, int height):
'''
Set the viewport
:x: x coordiante of lower left corner.
:y: y coordiante of lower left corner.
:width: viewport width
:height: viewport height
'''
glViewport(x, y, width, height)

419
gltools/@src/GLFW.pxi Normal file
View file

@ -0,0 +1,419 @@
# -*- coding: utf-8 -*-
from glfwLib cimport *
cpdef Init():
'''
Initialize GLFW.
Raise GLError on failure
'''
if not glfwInit():
raise GLError('failed to initialize glfw')
cpdef Terminate():
'''
Terminate GLFW
'''
glfwTerminate()
# event handling
cpdef PollEvents():
'''
Process pending events and return
'''
glfwPollEvents()
cpdef WaitEvents():
'''
Wait for events
'''
glfwWaitEvents()
# timer functions
cpdef double GetTime():
'''
Get current time since call to Init as float value
'''
Init()
return glfwGetTime()
cpdef SetTime(double time):
'''
Sets current time
'''
Init()
glfwSetTime(time)
# gamma value
cpdef SetGamma(Window window, float gamma):
'''
Set gamma value
'''
Init()
glfwSetGamma(glfwGetWindowMonitor(<GLFWwindow *>window.thisptr), gamma)
# get desktop size
cpdef tuple GetDesktopSize(Window window):
'''
Return desktop size
'''
cdef GLFWvidmode *vidmode
Init()
vidmode = glfwGetVideoMode(glfwGetWindowMonitor(<GLFWwindow *>window.thisptr))
return vidmode.width, vidmode.height
cdef class Window:
'''
GLFW based window
If width and height are not set then the window is
sized to the current desktop size
'''
def __init__(self, int width = -1, int height = -1, title = None,
bint fullscreen = False):
cdef GLFWvidmode *vidmode
cdef char *c_title
# Initialise GLFW
if not glfwInit():
raise GLError('failed to initialize glfw')
# set window hints
glfwWindowHint(GLFW_RED_BITS, 8)
glfwWindowHint(GLFW_GREEN_BITS, 8)
glfwWindowHint(GLFW_BLUE_BITS, 8)
glfwWindowHint(GLFW_ALPHA_BITS, 8)
glfwWindowHint(GLFW_DEPTH_BITS, 24)
glfwWindowHint(GLFW_STENCIL_BITS, 8)
# open window
if width < 0 or height < 0:
# default to desktop size
vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor())
width, height = vidmode.width, vidmode.height
glfwWindowHint(GLFW_RED_BITS, vidmode.redBits)
glfwWindowHint(GLFW_GREEN_BITS, vidmode.greenBits)
glfwWindowHint(GLFW_BLUE_BITS, vidmode.blueBits)
# decode to UTF-8
if title is None:
title = ''
bytetext = unicode(title).encode('UTF-8','ignore')
c_title = bytetext
self.thisptr = glfwCreateWindow(width, height, c_title, glfwGetPrimaryMonitor(), NULL)
if self.thisptr == NULL:
raise GLError('failed to open window')
# Set pointer back to this class for callbacks
glfwSetWindowUserPointer(<GLFWwindow *>self.thisptr, <void *>self)
# Set callback functions
glfwSetWindowSizeCallback(<GLFWwindow *>self.thisptr, cb_onSize)
glfwSetWindowRefreshCallback(<GLFWwindow *>self.thisptr, cb_onRefresh)
glfwSetCursorPosCallback(<GLFWwindow *>self.thisptr, cb_onCursorPos)
glfwSetMouseButtonCallback(<GLFWwindow *>self.thisptr, cb_onMouseButton)
glfwSetKeyCallback(<GLFWwindow *>self.thisptr, cb_onKey)
glfwSetCharCallback(<GLFWwindow *>self.thisptr, cb_onChar)
glfwSetWindowCloseCallback(<GLFWwindow *>self.thisptr, cb_onClose)
glfwSetWindowFocusCallback(<GLFWwindow *>self.thisptr, cb_onFocus)
glfwSetCursorEnterCallback(<GLFWwindow *>self.thisptr, cb_onEnter)
glfwSetScrollCallback(<GLFWwindow *>self.thisptr, cb_onScroll)
glfwSetWindowIconifyCallback(<GLFWwindow *>self.thisptr, cb_onIconify)
# Get window size (may be different than the requested size)
glfwGetWindowSize(<GLFWwindow *>self.thisptr, &width, &height);
self.onSize(width, max(1, height))
def __dealloc__(self):
glfwTerminate()
cpdef setTitle(self, title):
'''
Set window title
'''
cdef char *c_title
# decode to UTF-8
bytetext = unicode(title).encode('UTF-8','ignore')
c_title = bytetext
glfwSetWindowTitle(<GLFWwindow *>self.thisptr, c_title)
cpdef tuple getSize(self):
'''
Get window size
'''
cdef int width, height
glfwGetWindowSize(<GLFWwindow *>self.thisptr, &width, &height)
return width, height
cpdef setSize(self, int width, int height):
'''
Set window size
'''
if width <= 0 or height <= 0:
raise GLError('window size not valid')
glfwSetWindowSize(<GLFWwindow *>self.thisptr, width, height)
cpdef setClipboard(self, content):
'''
Set clipboard text
'''
glfwSetClipboardString(<GLFWwindow *>self.thisptr, content)
cpdef getClipboard(self):
'''
Get clipboard text
'''
cdef const_char *content = glfwGetClipboardString(<GLFWwindow *>self.thisptr)
return content
cpdef iconify(self):
'''
Iconify window
'''
glfwIconifyWindow(<GLFWwindow *>self.thisptr)
cpdef restore(self):
'''
Restore window from iconification
'''
glfwRestoreWindow(<GLFWwindow *>self.thisptr)
cpdef show(self):
'''
Show window
'''
glfwShowWindow(<GLFWwindow *>self.thisptr)
cpdef hide(self):
'''
Hide window
'''
glfwHideWindow(<GLFWwindow *>self.thisptr)
cpdef close(self):
'''
Stop main loop and close window
'''
self.running = False
glfwDestroyWindow(<GLFWwindow *>self.thisptr)
glfwTerminate()
cpdef makeContextCurrent(self):
'''
Make window openGL context current
'''
glfwMakeContextCurrent(<GLFWwindow *>self.thisptr)
cpdef swapBuffers(self):
'''
Swap front and back buffers
'''
glfwSwapBuffers(<GLFWwindow *>self.thisptr)
cpdef mainLoop(self):
'''
Run main loop.
The main loops waits for events. Mouse move events are special
handled to avoid to quick update.
'''
# keep waiting for events until running is False
cdef double x, y, lastX, lastY
cdef double t
glfwSetCursorPosCallback(<GLFWwindow *>self.thisptr, NULL)
glfwGetCursorPos(<GLFWwindow *>self.thisptr, &lastX, &lastY)
self.running = True
while True:
# Wait for new events
glfwWaitEvents()
# Avoid to quick update due to mouse move
glfwGetCursorPos(<GLFWwindow *>self.thisptr, &x, &y)
if x != lastX or y != lastY:
# in mouse move
t = glfwGetTime()
while True and self.running:
glfwWaitEvents()
if glfwGetTime() - t > .025:
break
glfwGetCursorPos(<GLFWwindow *>self.thisptr, &x, &y)
self.onCursorPos(x, y)
lastX, lastY = x, y
if not self.error is None:
error = self.error
self.error = None
raise error
if not self.running:
break
cpdef onSize(self, int w, int h):
'''
Callback when size changes
'''
pass
cpdef onRefresh(self):
'''
Callback when refresh of content is requested
'''
pass
cpdef onCursorPos(self, double x, double y):
'''
Callback on change of mouse cursor position
'''
pass
cpdef onMouseButton(self, int button, int action):
'''
Callback on mouse button press or release
'''
pass
cpdef onKey(self, int key, int scancode, int action, int mods):
'''
Callback on key press or relase.
'''
pass
cpdef onChar(self, ch):
'''
Callback non-special key pressed
'''
pass
cpdef onFocus(self, int status):
'''
Callback on windows focus change
'''
pass
cpdef onEnter(self, int status):
'''
Callback on mouse pointer enter/leave event
'''
pass
cpdef onScroll(self, double dx, double dy):
'''
Callback on mouse scroll wheel
'''
pass
cpdef onIconify(self, int status):
'''
Callback on iconify status change
'''
pass
cpdef bint onClose(self):
'''
Callback on close request.
'''
return False
# callback functions
cdef void cb_onSize(GLFWwindow *window, int w, int h):
cdef Window self = <Window>glfwGetWindowUserPointer(window)
try:
self.onSize(w, max(1, h))
except Exception as err:
self.error = err
cdef void cb_onRefresh(GLFWwindow *window):
cdef Window self = <Window>glfwGetWindowUserPointer(window)
try:
self.onRefresh()
except Exception as err:
self.error = err
cdef void cb_onCursorPos(GLFWwindow *window, double x, double y):
cdef Window self = <Window>glfwGetWindowUserPointer(window)
try:
self.onCursorPos(x, y)
except Exception as err:
self.error = err
cdef void cb_onMouseButton(GLFWwindow *window, int button, int action):
cdef Window self = <Window>glfwGetWindowUserPointer(window)
try:
self.onMouseButton(button, action)
except Exception as err:
self.error = err
cdef void cb_onKey(GLFWwindow *window, int key, int scancode, int action, int mods):
cdef Window self = <Window>glfwGetWindowUserPointer(window)
try:
self.onKey(key, scancode, action, mods)
except Exception as err:
self.error = err
cdef void cb_onChar(GLFWwindow *window, int ch):
cdef Window self = <Window>glfwGetWindowUserPointer(window)
cdef char st[2]
st[0] = <char>(ch & 0xff)
st[1] = 0
try:
self.onChar(st.decode('UTF-8', 'ignore'))
except Exception as err:
self.error = err
cdef void cb_onFocus(GLFWwindow *window, int status):
cdef Window self = <Window>glfwGetWindowUserPointer(window)
try:
self.onFocus(status)
except Exception as err:
self.error = err
cdef void cb_onEnter(GLFWwindow *window, int status):
cdef Window self = <Window>glfwGetWindowUserPointer(window)
self.onEnter(status)
cdef void cb_onScroll(GLFWwindow *window, double dx, double dy):
cdef Window self = <Window>glfwGetWindowUserPointer(window)
try:
self.onScroll(dx, dy)
except Exception as err:
self.error = err
cdef void cb_onIconify(GLFWwindow *window, int status):
cdef Window self = <Window>glfwGetWindowUserPointer(window)
try:
self.onIconify(status)
except Exception as err:
self.error = err
cdef int cb_onClose(GLFWwindow *window):
cdef Window self = <Window>glfwGetWindowUserPointer(window)
cdef int ret
try:
ret = self.onClose()
except Exception as err:
self.error = err
if ret:
self.running = False
return ret

553
gltools/@src/GLTools.cpp Normal file
View file

@ -0,0 +1,553 @@
#include "GLTools.h"
#include "fontstash.h"
#include <Python.h>
// error handling
char errorMessage[256];
void setErrorMessage(const char *err) {
strncpy(errorMessage, err, 255);
}
int glCheck() {
switch(glGetError()) {
case GL_NO_ERROR:
return 1;
case GL_INVALID_ENUM:
setErrorMessage("GL_INVALID_ENUM");
break;
case GL_INVALID_VALUE:
setErrorMessage("GL_INVALID_VALUE");
break;
case GL_INVALID_OPERATION:
setErrorMessage("GL_INVALID_OPERATION");
break;
case GL_INVALID_FRAMEBUFFER_OPERATION:
setErrorMessage("GL_INVALID_FRAMEBUFFER_OPERATION");
break;
case GL_OUT_OF_MEMORY:
setErrorMessage("GL_OUT_OF_MEMORY");
break;
default:
setErrorMessage("GL_UNKNOWN");
break;
}
return 0;
}
// load font
struct sth_stash *_fonts;
void destroyFont(void)
{
sth_delete(_fonts);
_fonts = NULL;
}
int initFont(void)
{
_fonts = sth_create(512,512);
if (!_fonts) {
setErrorMessage("failed to initialize font structure");
printf("failed to initialize font structure\n");
return 0;
}
atexit(destroyFont);
if (!sth_add_font(_fonts, 0, NULL)) {
setErrorMessage("failed to initialize default font");
printf("failed to initialize default font\n");
return 0;
}
return 1;
}
int initText(void)
{
if (!_fonts) {
if (!initFont())
return 0;
}
return 1;
}
int beginText(void)
{
if (!_fonts) {
if (!initFont())
return 0;
}
sth_begin_draw(_fonts);
return 1;
}
int endText(void)
{
if (!_fonts) {
if (!initFont())
return 0;
}
sth_end_draw(_fonts);
return 1;
}
int drawText(int idx, float size, float x, float y, const char *text, float *dx)
{
if (!_fonts) {
if (!initFont())
return 0;
}
if (!sth_draw_text(_fonts, idx, size, x, y, text, dx)) {
setErrorMessage("failed to draw text string");
return 0;
}
return 1;
}
// opengl 2.1 extensions
#define GLEXTPROCSIZE 28
int isGLExtLoaded = 0;
int initGLExt(void)
{
// OpenGL 2.1 functions
int status = 0;
pglActiveTexture = (PFNGLACTIVETEXTUREPROC) glfwGetProcAddress("glActiveTexture");
if (pglActiveTexture) status++;
pglCreateShader = (PFNGLCREATESHADERPROC) glfwGetProcAddress("glCreateShader");
if (pglCreateShader) status++;
pglShaderSource = (PFNGLSHADERSOURCEPROC) glfwGetProcAddress("glShaderSource");
if (pglShaderSource) status++;
pglCompileShader = (PFNGLCOMPILESHADERPROC) glfwGetProcAddress("glCompileShader");
if (pglCompileShader) status++;
pglGetShaderiv = (PFNGLGETSHADERIVPROC) glfwGetProcAddress("glGetShaderiv");
if (pglGetShaderiv) status++;
pglGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) glfwGetProcAddress("glGetShaderInfoLog");
if (pglGetShaderInfoLog) status++;
pglDeleteShader = (PFNGLDELETESHADERPROC) glfwGetProcAddress("glDeleteShader");
if (pglDeleteShader) status++;
pglCreateProgram = (PFNGLCREATEPROGRAMPROC) glfwGetProcAddress("glCreateProgram");
if (pglCreateProgram) status++;
pglAttachShader = (PFNGLATTACHSHADERPROC) glfwGetProcAddress("glAttachShader");
if (pglAttachShader) status++;
pglLinkProgram = (PFNGLLINKPROGRAMPROC) glfwGetProcAddress("glLinkProgram");
if (pglLinkProgram) status++;
pglUseProgram = (PFNGLUSEPROGRAMPROC) glfwGetProcAddress("glUseProgram");
if (pglUseProgram) status++;
pglGetProgramiv = (PFNGLGETPROGRAMIVPROC) glfwGetProcAddress("glGetProgramiv");
if (pglGetProgramiv) status++;
pglGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) glfwGetProcAddress("glGetProgramInfoLog");
if (pglGetProgramInfoLog) status++;
pglDeleteProgram = (PFNGLDELETEPROGRAMPROC) glfwGetProcAddress("glDeleteProgram");
if (pglDeleteProgram) status++;
pglGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) glfwGetProcAddress("glGetUniformLocation");
if (pglGetUniformLocation) status++;
pglUniform1i = (PFNGLUNIFORM1IPROC) glfwGetProcAddress("glUniform1i");
if (pglUniform1i) status++;
pglUniform1f = (PFNGLUNIFORM1FPROC) glfwGetProcAddress("glUniform1f");
if (pglUniform1f) status++;
pglUniform4f = (PFNGLUNIFORM4FPROC) glfwGetProcAddress("glUniform4f");
if (pglUniform4f) status++;
pglUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC) glfwGetProcAddress("glUniformMatrix4fv");
if (pglUniformMatrix4fv) status++;
pglGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC) glfwGetProcAddress("glGetAttribLocation");
if (pglGetAttribLocation) status++;
pglGenBuffers = (PFNGLGENBUFFERSPROC) glfwGetProcAddress("glGenBuffers");
if (pglGenBuffers) status++;
pglDeleteBuffers = (PFNGLDELETEBUFFERSPROC) glfwGetProcAddress("glDeleteBuffers");
if (pglDeleteBuffers) status++;
pglBindBuffer = (PFNGLBINDBUFFERPROC) glfwGetProcAddress("glBindBuffer");
if (pglBindBuffer) status++;
pglBufferData = (PFNGLBUFFERDATAPROC) glfwGetProcAddress("glBufferData");
if (pglBufferData) status++;
pglBufferSubData = (PFNGLBUFFERSUBDATAPROC) glfwGetProcAddress("glBufferSubData");
if (pglBufferSubData) status++;
pglGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC) glfwGetProcAddress("glGetBufferParameteriv");
if (pglGetBufferParameteriv) status++;
pglEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC) glfwGetProcAddress("glEnableVertexAttribArray");
if (pglEnableVertexAttribArray) status++;
pglVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC) glfwGetProcAddress("glVertexAttribPointer");
if (pglVertexAttribPointer) status++;
if (status != GLEXTPROCSIZE) {
setErrorMessage("Failed to load OpenGL 2.1 function pointers");
return 0;
}
isGLExtLoaded = 1;
return 1;
}
// opengl texture rectangle
TextureRect2D::TextureRect2D(int width, int height, int depth, void *data = NULL) {
GLint iformat, format;
m_width = width;
m_height = height;
m_depth = depth;
if (depth == 4) {
iformat = GL_RGBA8;
format = GL_RGBA;
} else {
iformat = GL_RGB8;
format = GL_RGB;
}
glGenTextures(1, &m_id);
glBindTexture(GL_TEXTURE_RECTANGLE, m_id);
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
if (!data) {
char *colorBits = new char[width * height * depth];
memset(colorBits, 0, width * height * depth);
glTexImage2D(GL_TEXTURE_RECTANGLE, 0, format, width, height, 0,
format, GL_UNSIGNED_BYTE, colorBits);
delete[] colorBits;
} else {
glTexImage2D(GL_TEXTURE_RECTANGLE, 0, format, width, height, 0,
format, GL_UNSIGNED_BYTE, data);
}
glBindTexture(GL_TEXTURE_RECTANGLE, 0);
}
TextureRect2D::~TextureRect2D() {
glDeleteTextures(1, &m_id);
}
void TextureRect2D::blit(float x, float y) {
glEnable(GL_TEXTURE_RECTANGLE);
pglActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_RECTANGLE, m_id);
glColor3ub(255,255,255);
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
glVertex3f(x, y, 0);
glTexCoord2f(m_width, 0);
glVertex3f(x + m_width, y, 0);
glTexCoord2f(m_width, m_height);
glVertex3f(x + m_width, y + m_height, 0);
glTexCoord2f(0, m_height);
glVertex3f(x, y + m_height, 0);
glEnd();
glBindTexture(GL_TEXTURE_RECTANGLE, 0);
glDisable(GL_TEXTURE_RECTANGLE);
}
void TextureRect2D::copy(GLenum mode = GL_BACK) {
glReadBuffer(mode);
glEnable(GL_TEXTURE_RECTANGLE);
pglActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_RECTANGLE, m_id);
glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE,0,0,0,0,0,m_width, m_height);
glBindTexture(GL_TEXTURE_RECTANGLE, 0);
glDisable(GL_TEXTURE_RECTANGLE);
}
// opengl buffer interface
ClientBuffer::ClientBuffer(GLenum target = GL_ARRAY_BUFFER) {
pglGenBuffers(1, &m_id);
m_target = target;
m_loaded = false;
for (unsigned i = 0; i < VERTEXBUFFERATTRIBSIZE; i++) {
m_attrib[i].enabled = 0;
}
}
ClientBuffer::~ClientBuffer() {
pglDeleteBuffers(1, &m_id);
}
void ClientBuffer::bind() {
pglBindBuffer(m_target, m_id);
if (m_target != GL_ARRAY_BUFFER)
return;
for (unsigned i = 0; i < VERTEXBUFFERATTRIBSIZE; i++) {
ClientBufferAttrib *attr = &m_attrib[i];
if(m_attrib[i].enabled) {
glEnableClientState(attr->type);
if (attr->type == GL_VERTEX_ARRAY) {
glVertexPointer(attr->dataTypeSize, attr->dataType,
attr->stride, attr->pointer);
} else if (attr->type == GL_NORMAL_ARRAY) {
glNormalPointer(attr->dataType, attr->stride, attr->pointer);
} else if (attr->type == GL_COLOR_ARRAY) {
glColorPointer(attr->dataTypeSize, attr->dataType,
attr->stride, attr->pointer);
}
}
}
}
void ClientBuffer::unBind() {
if (m_target == GL_ARRAY_BUFFER) {
for (unsigned i = 0; i < VERTEXBUFFERATTRIBSIZE; i++) {
if(m_attrib[i].enabled) {
glDisableClientState(m_attrib[i].type);
}
}
} else {
glDisableClientState(GL_INDEX_ARRAY);
}
pglBindBuffer(m_target, 0);
}
int ClientBuffer::setDataType(GLenum type, GLenum dataType, GLenum dataTypeSize,
GLsizei stride, const uintptr_t pointer) {
int idx;
switch (type)
{
case GL_VERTEX_ARRAY:
{
idx = 0;
break;
}
case GL_COLOR_ARRAY:
{
idx = 1;
break;
}
case GL_NORMAL_ARRAY:
{
idx = 2;
break;
}
default:
{
setErrorMessage("Failed to allocate memory for buffer");
return 0;
}
}
m_attrib[idx].enabled = 1;
m_attrib[idx].type = type;
m_attrib[idx].dataType = dataType;
m_attrib[idx].dataTypeSize = dataTypeSize;
m_attrib[idx].stride = stride;
m_attrib[idx].pointer = (void*)pointer;
return 1;
}
int ClientBuffer::loadData(const GLvoid *data, GLsizeiptr size,
GLintptr offset, GLenum usage) {
int bufferSize = 0;
if (!m_loaded) {
pglBindBuffer(m_target, m_id);
pglBufferData(m_target, size, data, usage);
pglGetBufferParameteriv(m_target, GL_BUFFER_SIZE_ARB, &bufferSize);
pglBindBuffer(m_target, 0);
if (bufferSize != size) {
setErrorMessage("Failed to allocate memory for buffer");
return 0;
}
m_loaded = true;
} else {
pglBindBuffer(m_target, m_id);
pglBufferSubData(m_target, offset, size, data);
pglBindBuffer(m_target, 0);
}
return 1;
}
// opengl shader program interface
ShaderProgram::ShaderProgram() {
m_id = 0u;
m_vertex_id = 0u;
m_fragment_id = 0u;
}
ShaderProgram::~ShaderProgram() {
if (m_vertex_id) pglDeleteShader(m_vertex_id);
if (m_fragment_id) pglDeleteShader(m_fragment_id);
if (m_id) pglDeleteProgram(m_id);
}
bool ShaderProgram::isValid() {
return (m_id != 0u && m_vertex_id != 0u && m_fragment_id != 0u);
}
void ShaderProgram::begin() {
pglUseProgram(m_id);
}
void ShaderProgram::end() {
pglUseProgram(0);
}
GLint ShaderProgram::attribLocation(const GLchar *name) {
GLint uloc = pglGetAttribLocation(m_id, name);
if (uloc == -1) {
setErrorMessage("Failed to find attrib variable");
return -1;
}
return uloc;
}
int ShaderProgram::loadUniform1i(const char *name, const GLint value) {
GLint uloc = pglGetUniformLocation(m_id, name);
if (uloc == -1) {
setErrorMessage("Failed to find uniform variable");
return 0;
}
pglUniform1i(uloc, value);
return 1;
}
int ShaderProgram::loadUniform1f(const char *name, const GLfloat value) {
GLint uloc = pglGetUniformLocation(m_id, name);
if (uloc == -1) {
setErrorMessage("Failed to find uniform variable");
return 0;
}
pglUniform1f(uloc, value);
return 1;
}
int ShaderProgram::loadUniform4f(const char *name, const GLfloat v0, const GLfloat v1,
const GLfloat v2, const GLfloat v3) {
GLint uloc = pglGetUniformLocation(m_id, name);
if (uloc == -1) {
setErrorMessage("Failed to find uniform variable");
return 0;
}
pglUniform4f(uloc, v0, v1, v2, v3);
return 1;
}
int ShaderProgram::loadUniformMatrix4vf(const char *name, const GLfloat *value,
GLsizei count) {
GLint uloc = pglGetUniformLocation(m_id, name);
if (uloc == -1) {
setErrorMessage("Failed to find uniform variable");
return 0;
}
pglUniformMatrix4fv(uloc, count, GL_FALSE, value);
return 1;
}
int ShaderProgram::build(const char* vertex_src,
const char* fragment_src) {
GLint status;
GLsizei log_length;
char info_log[256];
if (!vertex_src) vertex_src = default_vertex_shader;
if (!fragment_src) fragment_src = default_fragment_shader;
// build vertex shader
m_vertex_id = pglCreateShader(GL_VERTEX_SHADER);
if (m_vertex_id == 0u) {
setErrorMessage("Failed to create vertex shader");
return 0;
}
pglShaderSource(m_vertex_id, 1, (const GLchar**)&vertex_src, NULL);
pglCompileShader(m_vertex_id);
pglGetShaderiv(m_vertex_id, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE)
{
pglGetShaderInfoLog(m_vertex_id, sizeof(info_log), &log_length,info_log);
setErrorMessage(info_log);
return 0;
}
// build fragment shader
m_fragment_id = pglCreateShader(GL_FRAGMENT_SHADER);
if (m_fragment_id == 0u) {
setErrorMessage("Failed to create fragment shader");
return 0;
}
pglShaderSource(m_fragment_id, 1, (const GLchar**)&fragment_src, NULL);
pglCompileShader(m_fragment_id);
pglGetShaderiv(m_fragment_id, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE)
{
pglGetShaderInfoLog(m_fragment_id, sizeof(info_log), &log_length,info_log);
setErrorMessage(info_log);
return 0;
}
// create program and link shaders
m_id = pglCreateProgram();
if (m_id == 0u) {
setErrorMessage("Failed to create program");
return 0;
}
pglAttachShader(m_id, m_vertex_id);
pglAttachShader(m_id, m_fragment_id);
pglLinkProgram(m_id);
pglGetProgramiv(m_id, GL_LINK_STATUS, &status);
if (status != GL_TRUE)
{
pglGetShaderInfoLog(m_id, 8192, &log_length,info_log);
setErrorMessage(info_log);
return 0;
}
return 1;
}
const char* ShaderProgram::default_vertex_shader =
"#version 130\n"
"void main()\n"
"{\n"
" gl_FrontColor = gl_Color;\n"
" gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n"
"}\n";
const char* ShaderProgram::default_fragment_shader =
"#version 130\n"
"void main()\n"
"{\n"
" gl_FragColor = gl_Color;\n"
"}\n";

96
gltools/@src/Image.pxi Normal file
View file

@ -0,0 +1,96 @@
# -*- coding: utf-8 -*-
#
# This file is part of gltools - See LICENSE.txt
#
from ImageLib cimport *
cdef class Image:
'''
Image buffer containing either an RGB/RGBA 8bit
channel image.
:width: image width
:height: image height
:format: gl.RGB or gl.RGBA
'''
def __init__(self, int width, int height, int format):
cdef int bytesPerPixel
self.width = width
self.height = height
if format == GL_RGB:
self.bytesPerPixel = 3
elif format == GL_RGBA:
self.bytesPerPixel = 4
else:
raise GLError('Image format not supported')
self._buffer = <unsigned char *>malloc(width * height * self.bytesPerPixel * sizeof(unsigned char))
if self._buffer == NULL:
raise MemoryError('Could not allocate memory')
def __dealloc__(self):
if not self._buffer == NULL:
free(self._buffer)
def __getbuffer__(self, Py_buffer* buffer, int flags):
self.__shape[0] = self.width * self.height * self.bytesPerPixel
self.__strides[0] = 1
buffer.buf = <void *>self._buffer
buffer.obj = self
buffer.len = self.width * self.height * self.bytesPerPixel
buffer.readonly = 0
buffer.format = <char*>"B"
buffer.ndim = 1
buffer.shape = <Py_ssize_t *>&self.__shape[0]
buffer.strides = <Py_ssize_t *>&self.__strides[0]
buffer.suboffsets = NULL
buffer.itemsize = sizeof(unsigned char)
buffer.internal = NULL
def __releasebuffer__(self, Py_buffer* buffer):
pass
def __len__(self):
return self.width * self.height * self.bytesPerPixel
cpdef flipY(self):
'''
Flip inplace the image in the vertical direction
'''
cdef unsigned char *pixels = self._buffer
cdef int x, y, i, swapY, offset, swapOffset
for y in range(self.height/ 2):
swapY = self.height - y - 1
for x in range(self.width):
offset = self.bytesPerPixel * (x + y * self.width)
swapOffset = self.bytesPerPixel * (x + swapY * self.width)
# Swap R, G and B or A of the 2 pixels
for i in range(self.bytesPerPixel):
pixels[swapOffset + i], pixels[offset + i] = pixels[offset + i], pixels[swapOffset + i]
cpdef writePNG(self, filename, int stride = 0):
'''
Write image to PNG file. Note that the file
will be overwritten if not locked.
:filename: image file name
:stride: stride into buffer
Raises GLError on failure.
'''
cdef char *c_filename
bytetext = unicode(filename).encode('UTF-8','ignore')
c_filename = bytetext
if not stbi_write_png(c_filename, self.width, self.height, self.bytesPerPixel,
self._buffer, stride):
raise GLError("failed to write to PNG '%s'" % filename)

View file

@ -0,0 +1,381 @@
# -*- coding: utf-8 -*-
#
# This file is part of gltools - See LICENSE.txt
#
cdef class ShaderProgram:
'''
Class to encapsulate compiled GLSL shaders
'''
def __init__(self):
if not isGLExtLoaded:
raise GLError('OpenGL 2.1 function pointers not found')
self.thisptr = new c_ShaderProgram()
def __dealloc__(self):
cdef c_ShaderProgram *tmp
if self.thisptr != NULL:
tmp = <c_ShaderProgram *>self.thisptr
del tmp
def __str__(self):
return "ShaderProgram%s" % repr(self)
def __repr__(self):
return "()"
cpdef bint isValid(self):
'''
Return status
'''
cdef c_ShaderProgram *prog = <c_ShaderProgram *>self.thisptr
return prog.isValid()
cpdef begin(self):
'''
Set program as current
'''
cdef c_ShaderProgram *prog = <c_ShaderProgram *>self.thisptr
prog.begin()
cpdef end(self):
'''
Unset program. This will enable the fixed openGL pipeline
'''
cdef c_ShaderProgram *prog = <c_ShaderProgram *>self.thisptr
prog.end()
cpdef loadUniform1i(self, char *name, int value):
'''
Load named uniform integer value
'''
cdef c_ShaderProgram *prog = <c_ShaderProgram *>self.thisptr
if not prog.loadUniform1i(name, value):
raise GLError(errorMessage)
cpdef loadUniform1f(self, char *name, float value):
'''
Load named uniform float value
'''
cdef c_ShaderProgram *prog = <c_ShaderProgram *>self.thisptr
if not prog.loadUniform1f(name, value):
raise GLError(errorMessage)
cpdef loadUniform4f(self, char *name, float v0, float v1, float v2, float v3):
'''
Load named uniform float vector
'''
cdef c_ShaderProgram *prog = <c_ShaderProgram *>self.thisptr
if not prog.loadUniform4f(name, v0, v1, v2, v3):
raise GLError(errorMessage)
cpdef loadUniformMatrix4vf(self, char *name, float [::1] value, int count = 1):
'''
Load named uniform matrix value
'''
cdef c_ShaderProgram *prog = <c_ShaderProgram *>self.thisptr
if not prog.loadUniformMatrix4vf(name, &value[0], count):
raise GLError(errorMessage)
cpdef build(self, vertex_src = None, fragment_src = None):
'''
Compile program source. If no argument is given the
default program simulating the fixed pipeline is
loaded.
Raises GLError if failed.
'''
cdef c_ShaderProgram *prog = <c_ShaderProgram *>self.thisptr
cdef int ret
if vertex_src is None and fragment_src is None:
ret = prog.build(NULL,NULL)
else:
if not isinstance(vertex_src, bytes):
vertex_src = vertex_src.encode('ascii')
if not isinstance(fragment_src, bytes):
fragment_src = fragment_src.encode('ascii')
ret = prog.build(vertex_src, fragment_src)
if not ret:
raise GLError(errorMessage)
@classmethod
def flat(cls):
cdef ShaderProgram ret = ShaderProgram()
ret.build(GLSL_VERTEX_FLAT, GLSL_FRAG_FLAT)
return ret
@classmethod
def pongDiffuse(cls, int lights):
cdef ShaderProgram ret = ShaderProgram()
if lights < 1 or lights > 8:
raise GLError('lights must be between 1 and 8')
INIT = "#define MAX_LIGHTS %d" % lights
FRAG_SRC = b"\n".join((INIT.encode('ascii'), GLSL_FRAG_PONG_COMMON, GLSL_FRAG_PONG_DIFFUSE))
ret.build(GLSL_VERTEX_PONG, FRAG_SRC)
return ret
@classmethod
def pongSpecular(cls, int lights):
cdef ShaderProgram ret = ShaderProgram()
if lights < 1 or lights > 8:
raise GLError('lights must be between 1 and 8')
INIT = "#define MAX_LIGHTS %d" % lights
FRAG_SRC = b"\n".join((INIT.encode('ascii'), GLSL_FRAG_PONG_COMMON, GLSL_FRAG_PONG_SPECULAR))
ret.build(GLSL_VERTEX_PONG, FRAG_SRC)
return ret
# simple flat shader for overlay & background
cdef char *GLSL_VERTEX_FLAT = \
"""
varying vec4 col;
void main(void)
{
col = gl_Color;
gl_Position = ftransform();
}
"""
cdef char *GLSL_FRAG_FLAT = \
"""
varying vec4 col;
void main (void)
{
gl_FragColor = col;
}
"""
# two sided per-pixel phong shader
# ref: http://www.gamedev.net/page/resources/_/technical/opengl/creating-a-glsl-library-r2428
cdef char *GLSL_VERTEX_PONG = \
"""
varying vec3 normal;
varying vec3 vertex;
void main()
{
// Calculate the normal
normal = normalize(gl_NormalMatrix * gl_Normal);
// Transform the vertex position to eye space
vertex = vec3(gl_ModelViewMatrix * gl_Vertex);
gl_Position = ftransform();
}
"""
cdef char *GLSL_FRAG_PONG_COMMON = \
"""
varying vec3 normal;
varying vec3 vertex;
float calculateAttenuation(in int i, in float dist)
{
return(1.0 / (gl_LightSource[i].constantAttenuation +
gl_LightSource[i].linearAttenuation * dist +
gl_LightSource[i].quadraticAttenuation * dist * dist));
}
void directionalLight(in int i, in vec3 N, in float shininess,
inout vec4 ambient, inout vec4 diffuse, inout vec4 specular)
{
vec3 L = normalize(gl_LightSource[i].position.xyz);
float nDotL = dot(N, L);
if (nDotL > 0.0)
{
vec3 H = gl_LightSource[i].halfVector.xyz;
float pf = pow(max(dot(N,H), 0.0), shininess);
diffuse += gl_LightSource[i].diffuse * nDotL;
specular += gl_LightSource[i].specular * pf;
}
ambient += gl_LightSource[i].ambient;
}
void pointLight(in int i, in vec3 N, in vec3 V, in float shininess,
inout vec4 ambient, inout vec4 diffuse, inout vec4 specular)
{
vec3 D = gl_LightSource[i].position.xyz - V;
vec3 L = normalize(D);
float dist = length(D);
float attenuation = calculateAttenuation(i, dist);
float nDotL = dot(N,L);
if (nDotL > 0.0)
{
vec3 E = normalize(-V);
vec3 R = reflect(-L, N);
float pf = pow(max(dot(R,E), 0.0), shininess);
diffuse += gl_LightSource[i].diffuse * attenuation * nDotL;
specular += gl_LightSource[i].specular * attenuation * pf;
}
ambient += gl_LightSource[i].ambient * attenuation;
}
void spotLight(in int i, in vec3 N, in vec3 V, in float shininess,
inout vec4 ambient, inout vec4 diffuse, inout vec4 specular)
{
vec3 D = gl_LightSource[i].position.xyz - V;
vec3 L = normalize(D);
float dist = length(D);
float attenuation = calculateAttenuation(i, dist);
float nDotL = dot(N,L);
if (nDotL > 0.0)
{
float spotEffect = dot(normalize(gl_LightSource[i].spotDirection), -L);
if (spotEffect > gl_LightSource[i].spotCosCutoff)
{
attenuation *= pow(spotEffect, gl_LightSource[i].spotExponent);
vec3 E = normalize(-V);
vec3 R = reflect(-L, N);
float pf = pow(max(dot(R,E), 0.0), shininess);
diffuse += gl_LightSource[i].diffuse * attenuation * nDotL;
specular += gl_LightSource[i].specular * attenuation * pf;
}
}
ambient += gl_LightSource[i].ambient * attenuation;
}
void calculateLighting(in vec3 N, in vec3 V, in float shininess,
inout vec4 ambient, inout vec4 diffuse, inout vec4 specular)
{
// Just loop through each light, and add
// its contributions to the color of the pixel.
for (int i = 0; i < MAX_LIGHTS - 1; i++)
{
if (gl_LightSource[i].position.w == 0.0)
directionalLight(i, N, shininess, ambient, diffuse, specular);
else if (gl_LightSource[i].spotCutoff == 180.0)
pointLight(i, N, V, shininess, ambient, diffuse, specular);
else
spotLight(i, N, V, shininess, ambient, diffuse, specular);
}
}
"""
cdef char *GLSL_FRAG_PONG_SPECULAR = \
"""
void main()
{
// Normalize the normal. A varying variable CANNOT
// be modified by a fragment shader. So a new variable
// needs to be created.
vec3 n = normalize(normal);
vec4 ambient, diffuse, specular, color;
// Initialize the contributions.
ambient = vec4(0.0);
diffuse = vec4(0.0);
specular = vec4(0.0);
// In this case the built in uniform gl_MaxLights is used
// to denote the number of lights. A better option may be passing
// in the number of lights as a uniform or replacing the current
// value with a smaller value.
calculateLighting(n, vertex, gl_FrontMaterial.shininess,
ambient, diffuse, specular);
color = gl_FrontLightModelProduct.sceneColor +
(ambient * gl_FrontMaterial.ambient) +
(diffuse * gl_FrontMaterial.diffuse) +
(specular * gl_FrontMaterial.specular);
// Re-initialize the contributions for the back
// pass over the lights
ambient = vec4(0.0);
diffuse = vec4(0.0);
specular = vec4(0.0);
// Now caculate the back contribution. All that needs to be
// done is to flip the normal.
calculateLighting(-n, vertex, gl_BackMaterial.shininess,
ambient, diffuse, specular);
color += gl_BackLightModelProduct.sceneColor +
(ambient * gl_BackMaterial.ambient) +
(diffuse * gl_BackMaterial.diffuse) +
(specular * gl_BackMaterial.specular);
color = clamp(color, 0.0, 1.0);
gl_FragColor = color;
}
"""
cdef char *GLSL_FRAG_PONG_DIFFUSE = \
"""
void main()
{
// Normalize the normal. A varying variable CANNOT
// be modified by a fragment shader. So a new variable
// needs to be created.
vec3 n = normalize(normal);
vec4 ambient, diffuse, specular, color;
// Initialize the contributions.
ambient = vec4(0.0);
diffuse = vec4(0.0);
specular = vec4(0.0);
// In this case the built in uniform gl_MaxLights is used
// to denote the number of lights. A better option may be passing
// in the number of lights as a uniform or replacing the current
// value with a smaller value.
calculateLighting(n, vertex, gl_FrontMaterial.shininess,
ambient, diffuse, specular);
color = gl_FrontLightModelProduct.sceneColor +
(ambient * gl_FrontMaterial.ambient) +
(diffuse * gl_FrontMaterial.diffuse);
// Re-initialize the contributions for the back
// pass over the lights
ambient = vec4(0.0);
diffuse = vec4(0.0);
specular = vec4(0.0);
// Now caculate the back contribution. All that needs to be
// done is to flip the normal.
calculateLighting(-n, vertex, gl_BackMaterial.shininess,
ambient, diffuse, specular);
color += gl_BackLightModelProduct.sceneColor +
(ambient * gl_BackMaterial.ambient) +
(diffuse * gl_BackMaterial.diffuse);
color = clamp(color, 0.0, 1.0);
gl_FragColor = color;
}
"""

38
gltools/@src/Text.pxi Normal file
View file

@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
#
# This file is part of gltools - See LICENSE.txt
#
cpdef BeginText():
'''
Start text drawing
'''
if not c_beginText():
raise GLError(errorMessage)
cpdef float DrawText(size, float x, float y, text):
'''
Draw text
:size: font size
:x: x coordinate
:y: y coordinate
:text: text (must encode to UTF-8)
'''
cdef float dx
cdef char *c_str
bytetext = unicode(text).encode('UTF-8','ignore')
c_str = bytetext
if not c_drawText(0, size, x, y, c_str, &dx):
raise GLError(errorMessage)
return dx
cpdef EndText():
'''
Finish text drawing. This will flush any pending text
drawing operations.
'''
if not c_endText():
raise GLError(errorMessage)

52
gltools/@src/Texture.pxi Normal file
View file

@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
#
# This file is part of gltools - See LICENSE.txt
#
cdef class TextureRect2D:
'''
Abstraction of OpenGL 2d rectangular texture used
for keeping a buffer of the screen content.
'''
def __init__(self, int width, int height, int depth = 3):
self.thisptr = new c_TextureRect2D(width, height, depth, NULL)
if not glCheck():
raise GLError(errorMessage)
def __dealloc__(self):
cdef c_TextureRect2D *tmp
if self.thisptr != NULL:
tmp = <c_TextureRect2D *>self.thisptr
del tmp
def __str__(self):
return "TextureRect2D%s" % repr(self)
def __repr__(self):
cdef c_TextureRect2D *tex = <c_TextureRect2D *>self.thisptr
args = tex.m_width, tex.m_height, tex.m_depth
return "(width = %d, height = %d, depth = %d)" % args
cpdef blit(self, float x = 0., float y = 0.):
'''
Blit content of the texture to the back buffer.
'''
cdef c_TextureRect2D *tex = <c_TextureRect2D *>self.thisptr
tex.blit(x, y)
cpdef copy(self, int mode = GL_BACK):
'''
Copy buffer content to texture.
'''
cdef c_TextureRect2D *tex = <c_TextureRect2D *>self.thisptr
tex.copy(mode)
@classmethod
def fromImage(cls, Image img):
'''
Create texture from existing image
'''
cpdef TextureRect2D ret = TextureRect2D.__new__(TextureRect2D)
ret.thisptr = new c_TextureRect2D(img.width, img.height, img.bytesPerPixel, img._buffer)
return ret

228
gltools/@src/UI.pxi Normal file
View file

@ -0,0 +1,228 @@
# -*- coding: utf-8 -*-
from imguiLib cimport *
cdef class UI:
'''
Draw UI elements
'''
def __init__(self):
self.scrollIdx = 0
imguiRenderGLInit()
if not c_initText():
raise GLError(errorMessage)
cpdef bint anyActive(self):
'''
Return true if any ui element is active
'''
return imguiAnyActive()
cpdef flush(self):
'''
Flush drawing pipeline
'''
self.scrollIdx = 0
imguiRenderGLDraw()
cpdef beginFrame(self, int mx, int my, char mbut, int scroll):
'''
Start frame
'''
if mbut == GLFW_MOUSE_BUTTON_LEFT:
mbut = IMGUI_MBUT_LEFT
elif mbut == GLFW_MOUSE_BUTTON_RIGHT:
mbut = IMGUI_MBUT_RIGHT
elif mbut == -1:
mbut = 0
imguiBeginFrame(mx, my, mbut, scroll)
cpdef endFrame(self):
'''
End frame
'''
imguiEndFrame()
cpdef bint beginScrollArea(self, name, int x, int y, int w, int h):
'''
Begin scroll area
Up to 10 scroll areas can be used, but not nested.
'''
cdef char *c_name
cdef bint ret
bytetext = unicode(name).encode('UTF-8','ignore')
c_name = bytetext
ret = imguiBeginScrollArea(c_name, x, y, w, h, &self.scroll[self.scrollIdx])
self.scrollIdx += 1
if self.scrollIdx >= 10:
raise GLError('Only 10 scrool areas supported')
return ret
cpdef endScrollArea(self):
'''
End scroll area
'''
imguiEndScrollArea()
cpdef bint beginArea(self, name, int x, int y, int w, int h):
'''
Begin fixed area
'''
cdef char *c_name
bytetext = unicode(name).encode('UTF-8','ignore')
c_name = bytetext
return imguiBeginArea(c_name, x, y, w, h)
cpdef endArea(self):
'''
End fixed area
'''
imguiEndArea()
cpdef indent(self):
'''
Indent current x position
'''
imguiIndent()
cpdef unindent(self):
'''
Unindent current x position
'''
imguiUnindent()
cpdef separator(self):
'''
Add horisontal separator space
'''
imguiSeparator()
cpdef separatorLine(self):
'''
Add horisontal separator line
'''
imguiSeparatorLine()
cpdef bint button(self, text, bint enabled, int x = -1, int y = -1,
int w = -1, int h = -1):
'''
Button element
'''
cdef char *c_text
bytetext = unicode(text).encode('UTF-8','ignore')
c_text = bytetext
return imguiButton(c_text, enabled, x, y, w, h)
cpdef bint item(self, text, bint enabled):
'''
Item element
'''
cdef char *c_text
bytetext = unicode(text).encode('UTF-8','ignore')
c_text = bytetext
return imguiItem(c_text, enabled)
cpdef bint check(self, text, bint checked, bint enabled):
'''
Check box element
'''
cdef char *c_text
bytetext = unicode(text).encode('UTF-8','ignore')
c_text = bytetext
return imguiCheck(c_text, checked, enabled)
cpdef bint collapse(self, text, subtext, bint checked, bint enabled):
'''
Collapse element
'''
cdef char *c_text, *c_subtext
bytetext = unicode(text).encode('UTF-8','ignore')
c_text = bytetext
bytetext = unicode(subtext).encode('UTF-8','ignore')
c_subtext = bytetext
return imguiCollapse(c_text, c_subtext, checked, enabled)
cpdef label(self, text):
'''
Text label (left aligned)
'''
cdef char *c_text
bytetext = unicode(text).encode('UTF-8','ignore')
c_text = bytetext
imguiLabel(c_text)
cpdef value(self, text):
'''
Text label (right aligned)
'''
cdef char *c_text
bytetext = unicode(text).encode('UTF-8','ignore')
c_text = bytetext
imguiValue(c_text)
cpdef float slider(self, text, float val, float vmin, float vmax,
float vinc, bint enabled):
'''
Horisontal slider
'''
cdef float c_val = val
cdef char *c_text
bytetext = unicode(text).encode('UTF-8','ignore')
c_text = bytetext
imguiSlider(c_text, &c_val, vmin, vmax, vinc, enabled)
return c_val
cpdef drawText(self, int x, int y, int align, text, ColorRGBA color):
'''
Draw text
'''
cdef char *c_text
bytetext = unicode(text).encode('UTF-8','ignore')
c_text = bytetext
imguiDrawText(x, y, align, c_text, color.toInt())
cpdef drawLine(self, float x0, float y0, float x1, float y1, float r, ColorRGBA color):
'''
Draw single line
'''
imguiDrawLine(x0, y0, x1, y1, r, color.toInt())
cpdef drawRoundedRect(self, float x, float y, float w, float h, float r, ColorRGBA color):
'''
Draw rounded rectangle
'''
imguiDrawRoundedRect(x, y, w, h, r, color.toInt())
cpdef drawRect(self, float x, float y, float w, float h, ColorRGBA color):
'''
Draw rectangle
'''
imguiDrawRect(x, y, w, h, color.toInt())

View file

@ -0,0 +1,99 @@
# -*- coding: utf-8 -*-
#
# This file is part of gltools - See LICENSE.txt
#
# general imports
IF UNAME_SYSNAME == "Windows":
ctypedef unsigned int uintptr_t
ELSE:
from libc.stdint cimport uintptr_t
cdef extern from *:
ctypedef char const_char "const char"
from libc.stdlib cimport malloc, free
from libc.math cimport fabs, copysign
from libc.math cimport M_PI, sqrt, sin, cos, tan
cimport cpython.array
cdef inline double fmax(double a, double b):
if a < b:
return b
return a
cdef inline double fmin(double a, double b):
if a > b:
return b
return a
# utility to get pointer from memoryview
cdef void *getVoidPtr(arr):
cdef double [::1] d_view
cdef float [::1] f_view
cdef long [::1] l_view
cdef int [::1] i_view
cdef unsigned int [::1] I_view
cdef char [::1] b_view
cdef unsigned char [::1] B_view
cdef void *ptr
try:
d_view = arr
except ValueError:
pass
else:
ptr = <void *>(&d_view[0])
return ptr
try:
f_view = arr
except ValueError:
pass
else:
ptr = <void *>(&f_view[0])
return ptr
try:
l_view = arr
except ValueError:
pass
else:
ptr = <void *>(&l_view[0])
return ptr
try:
i_view = arr
except ValueError:
pass
else:
ptr = <void *>(&i_view[0])
return ptr
try:
I_view = arr
except ValueError:
pass
else:
ptr = <void *>(&I_view[0])
return ptr
try:
b_view = arr
except ValueError:
pass
else:
ptr = <void *>(&b_view[0])
return ptr
try:
B_view = arr
except ValueError:
pass
else:
ptr = <void *>(&B_view[0])
return ptr
raise TypeError('no valid array type found')

172
gltools/gltools.pxd Normal file
View file

@ -0,0 +1,172 @@
# -*- coding: utf-8 -*-
#
# This file is part of gltools - See LICENSE.txt
#
from geotools cimport Point, Vector, Transform
cdef class ColorRGBA:
cdef public unsigned char red
cdef public unsigned char green
cdef public unsigned char blue
cdef public unsigned char alpha
cpdef ColorRGBA copy(self, int red = ?, int green = ?, int blue = ?, alpha = ?)
cpdef unsigned toInt(self)
cpdef fromInt(self, unsigned int value)
cpdef tuple toFloatVector(self)
cdef setFloatVector(self, float *vec)
cdef class Material:
cdef public ColorRGBA ambient
cdef public ColorRGBA diffuse
cdef public ColorRGBA specular
cdef public ColorRGBA emissive
cdef public float shininess
cdef readonly int mode
cpdef enable(self)
cpdef AmbientLight(ColorRGBA col)
cdef class Light:
cdef public Material material
cdef public Point position
cdef public bint directional
cdef public Vector direction
cdef readonly int index
cpdef enable(self)
cpdef disable(self)
cdef class TextureRect2D:
cdef void *thisptr
cpdef blit(self, float x = ?, float y = ?)
cpdef copy(self, int mode = ?)
cdef class ClientBuffer:
cdef void *thisptr
cpdef bind(self)
cpdef unBind(self)
cpdef setDataType(self, int type, int dataType, int dataTypeSize,
int stride, size_t pointer)
cdef cloadData(self, void *data, ssize_t size, ssize_t offset, int usage)
cpdef loadData(self, data, ssize_t size, ssize_t offset = ?, int usage = ?)
cpdef Init()
cpdef Terminate()
cpdef double GetTime()
cpdef SetTime(double time)
cpdef SetGamma(Window window, float gamma)
cpdef tuple GetDesktopSize(Window window)
cdef class Window:
cdef void *thisptr
cdef public bint running
cdef object error
cpdef setTitle(self, title)
cpdef tuple getSize(self)
cpdef setSize(self, int width, int height)
cpdef setClipboard(self, content)
cpdef getClipboard(self)
cpdef iconify(self)
cpdef restore(self)
cpdef show(self)
cpdef hide(self)
cpdef close(self)
cpdef makeContextCurrent(self)
cpdef swapBuffers(self)
cpdef mainLoop(self)
cpdef onSize(self, int w, int h)
cpdef onRefresh(self)
cpdef onCursorPos(self, double x, double y)
cpdef onMouseButton(self, int button, int action)
cpdef onKey(self, int key, int scancode, int action, int mods)
cpdef onChar(self, ch)
cpdef onFocus(self, int status)
cpdef onEnter(self, int status)
cpdef onScroll(self, double dx, double dy)
cpdef onIconify(self, int status)
cpdef bint onClose(self)
cdef class ShaderProgram:
cdef void *thisptr
cpdef bint isValid(self)
cpdef begin(self)
cpdef end(self)
cpdef loadUniform1i(self, char *name, int value)
cpdef loadUniform1f(self, char *name, float value)
cpdef loadUniform4f(self, char *name, float v0, float v1, float v2, float v3)
cpdef loadUniformMatrix4vf(self, char *name, float [::1] value, int count = ?)
cpdef build(self, vertex_src = ?, fragment_src = ?)
cpdef BeginText()
cpdef float DrawText(size, float x, float y, text)
cpdef EndText()
cdef class UI:
cdef int scroll[10]
cdef int scrollIdx
cpdef bint anyActive(self)
cpdef flush(self)
cpdef beginFrame(self, int mx, int my, char mbut, int scroll)
cpdef endFrame(self)
cpdef bint beginScrollArea(self, name, int x, int y, int w, int h)
cpdef endScrollArea(self)
cpdef bint beginArea(self, name, int x, int y, int w, int h)
cpdef endArea(self)
cpdef indent(self)
cpdef unindent(self)
cpdef separator(self)
cpdef separatorLine(self)
cpdef bint button(self, text, bint enabled, int x = ?, int y = ?,
int w = ?, int h = ?)
cpdef bint item(self, text, bint enabled)
cpdef bint check(self, text, bint checked, bint enabled)
cpdef bint collapse(self, text, subtext, bint checked, bint enabled)
cpdef label(self, text)
cpdef value(self, text)
cpdef float slider(self, text, float val, float vmin, float vmax,
float vinc, bint enabled)
cpdef drawText(self, int x, int y, int align, text, ColorRGBA color)
cpdef drawLine(self, float x0, float y0, float x1, float y1, float r, ColorRGBA color)
cpdef drawRoundedRect(self, float x, float y, float w, float h, float r, ColorRGBA color)
cpdef drawRect(self, float x, float y, float w, float h, ColorRGBA color)
cdef class Image:
cdef unsigned char *_buffer
cdef readonly int width
cdef readonly int height
cdef readonly int bytesPerPixel
# buffer interface
cdef Py_ssize_t __shape[1]
cdef Py_ssize_t __strides[1]
cdef __cythonbufferdefaults__ = {"ndim": 1, "mode": "c"}
cpdef flipY(self)
cpdef writePNG(self, filename, int stride = ?)
cpdef InitGLExt()
cpdef int Check()
cpdef BlendFunc(unsigned int sfactor, unsigned int dfactor)
cpdef Clear(unsigned int mask)
cpdef ClearColor(ColorRGBA col)
cpdef ClearDepth(double depth)
cpdef DepthFunc(int func)
cpdef Color(ColorRGBA col)
cpdef Disable(unsigned int cap)
cpdef DrawArrays(unsigned int mode, int first, int count)
cpdef DrawElements(unsigned int mode, int count, int type, indices)
cpdef Enable(unsigned int cap)
cpdef Hint(int target, int mode)
cpdef PointSize(float width)
cpdef LineWidth(float width)
cpdef LightModeli(int pname, int param)
cpdef LoadIdentity()
cpdef LoadMatrixd(Transform tr)
cpdef MatrixMode(unsigned int mode)
cpdef Ortho(double left, double right, double bottom, double top, double zNear,
double zFar)
cpdef PolygonMode(unsigned int face, unsigned int mode)
cpdef PolygonOffset(float factor, float units)
cpdef ColorRGBA ReadPixel(int x, int y)
cpdef ReadPixels(int x, int y, Image img)
cpdef Viewport(int x, int y, int width, int height)

28
gltools/gltools.pyx Normal file
View file

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
#cython: embedsignature=True
#
# This file is part of gltools - See LICENSE.txt
#
import sys
if sys.hexversion > 0x03000000:
unicode = str
from geotools cimport *
from GLToolsLib cimport *
class GLError(Exception):
pass
include "Config.pxi"
include "Utilities.pxi"
include "Constants.pxi"
include "GLFW.pxi"
include "Color.pxi"
include "Image.pxi"
include "GL.pxi"
include "ClientBuffer.pxi"
include "ShaderProgram.pxi"
include "Text.pxi"
include "Texture.pxi"
include "UI.pxi"

341
gltools/test.py Normal file
View file

@ -0,0 +1,341 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
import sys
import math
import array
import geotools as geo
import gltools as gl
# cube
# v6----- v5
# /| /|
# v1------v0|
# | | | |
# | |v7---|-|v4
# |/ |/
# v2------v3
vertices = array.array('f',(
1, 1, 1, -1, 1, 1, -1,-1, 1, 1,-1, 1, # v0,v1,v2,v3 (front)
1, 1, 1, 1,-1, 1, 1,-1,-1, 1, 1,-1, # v0,v3,v4,v5 (right)
1, 1, 1, 1, 1,-1, -1, 1,-1, -1, 1, 1, # v0,v5,v6,v1 (top)
-1, 1, 1, -1, 1,-1, -1,-1,-1, -1,-1, 1, # v1,v6,v7,v2 (left)
-1,-1,-1, 1,-1,-1, 1,-1, 1, -1,-1, 1, # v7,v4,v3,v2 (bottom)
1,-1,-1, -1,-1,-1, -1, 1,-1, 1, 1,-1, # v4,v7,v6,v5 (back)
))
normals = array.array('f',(
0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, # v0,v1,v2,v3 (front)
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, # v0,v3,v4,v5 (right)
0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, # v0,v5,v6,v1 (top)
-1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, # v1,v6,v7,v2 (left)
0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, # v7,v4,v3,v2 (bottom)
0, 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, # v4,v7,v6,v5 (back)
))
colors = array.array('f',(
1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, # v0,v1,v2,v3 (front)
1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, # v0,v3,v4,v5 (right)
1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, # v0,v5,v6,v1 (top)
1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, # v1,v6,v7,v2 (left)
0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, # v7,v4,v3,v2 (bottom)
0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, # v4,v7,v6,v5 (back)
))
indices = array.array('B',(
0, 1, 2, 2, 3, 0, # front
4, 5, 6, 6, 7, 4, # right
8, 9,10, 10,11, 8, # top
12,13,14, 14,15,12, # left
16,17,18, 18,19,16, # bottom
20,21,22, 22,23,20, # back
))
class MainWindow(gl.Window):
def __init__(self, width, height, title):
self.initialized = False
self.cam = geo.Camera()
self.near = geo.Point(-2.,-2.,-2.)
self.far = geo.Point(2.,2.,2.)
self.lastPos = 0,0
self.mouseCenter = geo.Point()
self.uiScroll = 0
self.currentButton = -1
gl.Window.__init__(self, width, height, title)
self.projectionMatrix = geo.Transform()
self.modelviewMatrix = geo.Transform()
def onSetup(self):
self.ui = gl.UI()
gl.ClearColor(gl.ColorRGBA(38,38,102,255))
gl.ClearDepth(1.)
gl.InitGLExt()
# Material & lights
mat = self.mat = gl.Material(
ambient = gl.ColorRGBA(80,80,80,255),
diffuse = gl.ColorRGBA(45,45,45,255),
specular = gl.ColorRGBA(255,255,255,255),
shininess = 100.,
)
lightMat = gl.Material(
diffuse = gl.ColorRGBA(255,255,55,255),
ambient = gl.ColorRGBA(55,55,25,255),
specular = gl.ColorRGBA(255,255,255,255)
)
light0 = self.light0 = gl.Light(
0,
lightMat,
geo.Point(0.,50.,100.),
)
light1 = self.light1 = gl.Light(
1,
lightMat,
geo.Point(50.,0.,-100.),
)
light2 = self.light2 = gl.Light(
2,
lightMat,
geo.Point(0.,-50.,0.),
)
# GLSL
glsl = self.program = gl.ShaderProgram.pongDiffuse(3)
# mesh
fsize = vertices.itemsize
buffer = self.buffer = gl.ClientBuffer()
buffer.loadData(None, (len(vertices) + len(normals))*fsize)
offset = 0
size = len(vertices)*fsize
buffer.setDataType(gl.VERTEX_ARRAY, gl.FLOAT, 3, 0, 0)
buffer.loadData(vertices, size, offset) # copy vertices starting from 0 offest
offset += size
size = len(normals)*fsize
buffer.setDataType(gl.NORMAL_ARRAY, gl.FLOAT, 3, 0, offset)
buffer.loadData(normals, size, offset) # copy normals after vertices
offset += size
# index buffer
idxbuffer = self.idxbuffer = gl.ClientBuffer(gl.ELEMENT_ARRAY_BUFFER)
idxbuffer.loadData(indices, len(indices)*indices.itemsize)
def onSize(self, w, h):
#print('onSize ', w, h)
self.width, self.height = w - 1, h - 1
if self.width > 1 and self.height > 1:
# Adjust frustum to viewport aspect
frustum_aspect = float(self.width) / self.height
self.cam.setFrustumAspect(frustum_aspect)
self.cam.setViewportSize(self.width, self.height)
self.makeContextCurrent()
gl.Viewport(0, 0, self.width, self.height)
# initialize
if not self.initialized:
self.onSetup()
self.cam.zoomExtents(self.near, self.far)
self.initialized = True
def insideUI(self, x, y):
y = self.height - y
if x >= 10 and x <= 210:
if y >= self.height - 260 and y <= self.height - 10:
return True
if x >= 10 and x <= 210:
if y >= 10 and y <= self.height - 300:
return True
return False
def onRefresh(self):
#print('onRefresh')
if not self.running:
return
ui = self.ui
glsl = self.program
x, y = self.lastPos
w, h = self.width, self.height
self.makeContextCurrent()
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
gl.Enable(gl.DEPTH_TEST)
gl.Enable(gl.MULTISAMPLE)
gl.Enable(gl.DITHER)
gl.Disable(gl.BLEND)
gl.Disable(gl.CULL_FACE)
gl.PolygonMode(gl.FRONT_AND_BACK, gl.FILL)
gl.LightModeli(gl.LIGHT_MODEL_TWO_SIDE, gl.TRUE)
gl.MatrixMode(gl.PROJECTION)
self.projectionMatrix.cameraToClip(self.cam)
gl.LoadMatrixd(self.projectionMatrix)
gl.MatrixMode(gl.MODELVIEW)
self.modelviewMatrix.worldToCamera(self.cam)
gl.LoadMatrixd(self.modelviewMatrix)
gl.Enable(gl.LIGHTING)
self.light0.enable()
self.light1.enable()
self.light2.enable()
self.mat.enable()
glsl.begin()
self.buffer.bind()
self.idxbuffer.bind()
gl.DrawElements(gl.TRIANGLES, 36, gl.UNSIGNED_BYTE, 0)
self.buffer.unBind()
self.idxbuffer.unBind()
glsl.end()
# draw font overlay
gl.Disable(gl.DEPTH_TEST)
gl.Disable(gl.LIGHTING)
gl.Disable(gl.DITHER)
gl.Enable(gl.BLEND)
gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
gl.MatrixMode(gl.PROJECTION)
gl.LoadIdentity()
gl.Ortho(0,self.width,0,self.height,-1,1)
gl.MatrixMode(gl.MODELVIEW)
gl.LoadIdentity()
scroll = self.uiScroll
if scroll:
self.uiScroll = 0
ui.beginFrame(x,h - y,self.currentButton,scroll)
ui.beginScrollArea("Scroll Area", 10, 10, 200, h-300)
ui.label('Label test')
ui.value(u'Value æøå')
ui.separatorLine()
ui.item('Item 1', True)
ui.indent()
ui.item('Item 2', False)
ui.separator()
ui.item('Item 3', True)
ui.unindent()
if ui.button("Button 1", True):
print('Button 1 pressed')
ui.button("Button 2", False)
ui.separator()
ui.check("Check 1", True, True)
ui.check("Check 2", False, True)
ui.check("Check 3", False, False)
ui.separatorLine()
ui.slider('Slider 1', 5, 0, 10, 1, True)
ui.slider('Slider 2', 5, 0, 10, 1, False)
ui.separatorLine()
ui.collapse('Text line', 'Sub text line', True, True)
ui.collapse('Text line', 'Sub text line', False, True)
ui.endScrollArea()
ui.beginArea("Fixed Area", 10, h - 260, 200, 250)
ui.label('Message')
if ui.button("OK", True, 5, 210, 40):
print('Button OK pressed')
ui.endArea()
ui.endFrame()
ui.flush()
gl.Enable(gl.DEPTH_TEST)
self.swapBuffers()
def onCursorPos(self, x, y):
width, height = self.width, self.height
lastx,lasty = self.lastPos
cam = self.cam
ui = self.insideUI(x, y)
update = False
if not ui and self.currentButton == gl.MOUSE.LEFT:
# rotate view
dx = x - lastx
dy = y - lasty
cam.rotateDeltas(dx, dy, target = self.mouseCenter)
update = True
elif not ui and self.currentButton == gl.MOUSE.RIGHT:
# pan view
cam.pan(lastx, lasty, x, y, target = self.mouseCenter)
update = True
#print('onCursorPos ', x, y)
self.lastPos = x, y
if ui or update:
self.onRefresh()
def onMouseButton(self, button, action):
#print('onMouseButton ', button, action)
if action == gl.ACTION.PRESS:
if button in {gl.MOUSE.LEFT, gl.MOUSE.RIGHT}:
# temporary rotation center to avoid exponential increase
self.mouseCenter.set(self.cam.target)
self.currentButton = button
else:
self.currentButton = -1
self.onRefresh()
def onKey(self, key, scancode, action, mods):
#print('onKey ', key, action)
if key == gl.KEY.ESCAPE:
self.running = False
elif key == gl.KEY.F:
self.cam.zoomExtents(self.near, self.far)
self.onRefresh()
elif key == gl.KEY.F1:
self.makeContextCurrent()
img = gl.Image(self.width, self.height, gl.RGBA)
gl.ReadPixels(0, 0, img)
img.flipY()
img.writePNG('screenshot01.png')
def onScroll(self, scx, scy):
x, y = self.lastPos
self.uiScroll = -int(scy)
if not self.insideUI(x, y):
delta = 1e-4*scy
dx = delta*self.width
dy = delta*self.height
self.cam.zoomFactor(1. + max(dx,dy), (x, y))
self.onRefresh()
def onClose(self):
#print('onClose')
return True
win = MainWindow(800, 600, title = u'title')
win.mainLoop()

View file

@ -1,184 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Overview &mdash; gltools documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="gltools documentation" href="#" />
<link rel="next" title="GLTools" href="content.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="content.html" title="GLTools"
accesskey="N">next</a> |</li>
<li><a href="#">gltools documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div class="section" id="overview">
<h1>Overview<a class="headerlink" href="#overview" title="Permalink to this headline"></a></h1>
<p><strong>gltools</strong> is library for quickly creating OpenGL based
application in Python/Cython with support for:</p>
<blockquote>
<div><ul class="simple">
<li>Access to vertex buffers and GLSL shaders</li>
<li>Access to truetype fonts</li>
<li>Windows handling through GLFW</li>
<li>Simple GUI controls</li>
</ul>
</div></blockquote>
<p>OpenGL version 2.1 is targeted which should be available
in most computers these days, even in a laptop&#8217;s integrated
graphics.</p>
<p>The license is GPL v2.</p>
</div>
<div class="section" id="building">
<h1>Building<a class="headerlink" href="#building" title="Permalink to this headline"></a></h1>
<blockquote>
<div><ul class="simple">
<li>Python 2.7/3.x and Cython 0.17 or later.</li>
<li>The <a class="reference external" href="http://github.com/tenko/geotools">geotools</a> library.</li>
<li><a class="reference external" href="http://github.com/elmindreda/glfw">GLFW</a> v3.0 (not released, must be build from GIT repo)</li>
<li>OpenGL headers</li>
</ul>
</div></blockquote>
<p>Prebuild installers are available on the <a class="reference external" href="http://pypi.python.org/pypi/gltools">pypi</a> site
for the Windows platform.</p>
<p>For Linux build scripts are available for ArchLinux in the <a class="reference external" href="https://aur.archlinux.org/packages/?O=0&amp;K=gltools">AUR</a>
repository. These could be adapted to other Linux distros.</p>
<p>Note that currently I can not find a way to install the required
Cython &#8216;pxd&#8217; files with distutils and this file has to be copied
manually.</p>
</div>
<div class="section" id="history">
<h1>History<a class="headerlink" href="#history" title="Permalink to this headline"></a></h1>
<blockquote>
<div><ul class="simple">
<li>v0.1.1 : Added missing files and fix building against GLFW3 trunk.</li>
</ul>
</div></blockquote>
</div>
<div class="section" id="api-docs">
<h1>API Docs<a class="headerlink" href="#api-docs" title="Permalink to this headline"></a></h1>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="content.html">GLTools</a><ul>
<li class="toctree-l2"><a class="reference internal" href="content.html#colorrgba">ColorRGBA</a></li>
<li class="toctree-l2"><a class="reference internal" href="content.html#material">Material</a></li>
<li class="toctree-l2"><a class="reference internal" href="content.html#light">Light</a></li>
<li class="toctree-l2"><a class="reference internal" href="content.html#image">Image</a></li>
<li class="toctree-l2"><a class="reference internal" href="content.html#texturerect2d">TextureRect2D</a></li>
<li class="toctree-l2"><a class="reference internal" href="content.html#clientbuffer">ClientBuffer</a></li>
<li class="toctree-l2"><a class="reference internal" href="content.html#shaderprogram">ShaderProgram</a></li>
<li class="toctree-l2"><a class="reference internal" href="content.html#glfw">GLFW</a></li>
<li class="toctree-l2"><a class="reference internal" href="content.html#window">Window</a></li>
<li class="toctree-l2"><a class="reference internal" href="content.html#ui">UI</a></li>
<li class="toctree-l2"><a class="reference internal" href="content.html#glfw-constants">GLFW Constants</a></li>
<li class="toctree-l2"><a class="reference internal" href="content.html#opengl">OpenGL</a></li>
<li class="toctree-l2"><a class="reference internal" href="content.html#opengl-constants">OpenGL Constants</a></li>
</ul>
</li>
</ul>
</div>
</div>
<div class="section" id="indices-and-tables">
<h1>Indices and tables<a class="headerlink" href="#indices-and-tables" title="Permalink to this headline"></a></h1>
<ul class="simple">
<li><a class="reference internal" href="genindex.html"><em>Index</em></a></li>
<li><a class="reference internal" href="py-modindex.html"><em>Module Index</em></a></li>
<li><a class="reference internal" href="search.html"><em>Search Page</em></a></li>
</ul>
</div>
</div>
</div>
</div>
<div class="sphinxsidebar">
<div class="sphinxsidebarwrapper">
<h3><a href="#">Table Of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Overview</a></li>
<li><a class="reference internal" href="#building">Building</a></li>
<li><a class="reference internal" href="#history">History</a></li>
<li><a class="reference internal" href="#api-docs">API Docs</a><ul>
</ul>
</li>
<li><a class="reference internal" href="#indices-and-tables">Indices and tables</a></li>
</ul>
<h4>Next topic</h4>
<p class="topless"><a href="content.html"
title="next chapter">GLTools</a></p>
<h3>This Page</h3>
<ul class="this-page-menu">
<li><a href="_sources/index.txt"
rel="nofollow">Show Source</a></li>
</ul>
<div id="searchbox" style="display: none">
<h3>Quick search</h3>
<form class="search" action="search.html" method="get">
<input type="text" name="q" />
<input type="submit" value="Go" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
<p class="searchtip" style="font-size: 90%">
Enter search terms or a module, class or function name.
</p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="content.html" title="GLTools"
>next</a> |</li>
<li><a href="#">gltools documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
&copy; Copyright 2012, Runar Tenfjord.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
</div>
</body>
</html>

Binary file not shown.

View file

@ -1,99 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Search &mdash; gltools documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/searchtools.js"></script>
<link rel="top" title="gltools documentation" href="index.html" />
<script type="text/javascript">
jQuery(function() { Search.loadIndex("searchindex.js"); });
</script>
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li><a href="index.html">gltools documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<h1 id="search-documentation">Search</h1>
<div id="fallback" class="admonition warning">
<script type="text/javascript">$('#fallback').hide();</script>
<p>
Please activate JavaScript to enable the search
functionality.
</p>
</div>
<p>
From here you can search these documents. Enter your search
words into the box below and click "search". Note that the search
function will automatically search for all of the words. Pages
containing fewer words won't appear in the result list.
</p>
<form action="" method="get">
<input type="text" name="q" value="" />
<input type="submit" value="search" />
<span id="search-progress" style="padding-left: 10px"></span>
</form>
<div id="search-results">
</div>
</div>
</div>
</div>
<div class="sphinxsidebar">
<div class="sphinxsidebarwrapper">
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li><a href="index.html">gltools documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
&copy; Copyright 2012, Runar Tenfjord.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
</div>
</body>
</html>

File diff suppressed because one or more lines are too long

135
setup_build.py Normal file
View file

@ -0,0 +1,135 @@
#!/usr/bin/python2
# -*- coding: utf-8 -*-
#
# This file is part of gltools - See LICENSE.txt
#
import sys
import os
import glob
from distutils.core import setup
from distutils.extension import Extension
try:
from Cython.Distutils import build_ext
except ImportError:
print >>sys.stderr, "Cython is required to build geotools"
sys.exit(1)
#sys.argv.append('build_ext')
#sys.argv.extend(['sdist','--formats=gztar,zip'])
#sys.argv.append('bdist_wininst')
# create config file
sys.dont_write_bytecode = True
import version
CONFIG = 'gltools/@src/Config.pxi'
if not os.path.exists(CONFIG) and 'sdist' not in sys.argv:
with open(CONFIG, 'w') as fh:
fh.write("__version__ = '%s'\n" % version.STRING)
args = version.MAJOR, version.MINOR, version.BUILD
fh.write("__version_info__ = (%d,%d,%d)\n" % args)
# platform specific settings
OBJECTS, LIBS, LINK_ARGS, COMPILE_ARGS = [],[],[],[]
if sys.platform == 'win32':
LIBS.append('OPENGL32')
LIBS.append('glfw3')
LIBS.append('user32')
LIBS.append('gdi32')
OBJECTS.append('glfw3.lib')
elif sys.platform == 'msys':
LIBS.append('OPENGL32')
LIBS.append('glfw3dll')
COMPILE_ARGS.append("-fpermissive")
elif sys.platform == 'darwin':
LINK_ARGS.extend(['-framework', 'OpenGL', '-arch', 'x86_64'])
COMPILE_ARGS.extend(['-arch', 'x86_64'])
LIBS.append('glfw')
else:
LIBS.append('GL')
LIBS.append('glfw')
COMPILE_ARGS.append("-fpermissive")
classifiers = '''\
Development Status :: 4 - Beta
Environment :: MacOS X
Environment :: Win32 (MS Windows)
Environment :: X11 Applications
Intended Audience :: Science/Research
License :: OSI Approved :: GNU General Public License v2 (GPLv2)
Operating System :: OS Independent
Programming Language :: Cython
Topic :: Scientific/Engineering :: Visualization
'''
SRC = [
"gltools/gltools.pyx",
"gltools/@src/GLTools.cpp",
"gltools/@contrib/fontstash.c",
"gltools/@contrib/stb_image_write.c",
"gltools/@contrib/imgui.cpp",
"gltools/@contrib/imguiRenderGL.cpp"
]
DEP = \
["gltools/gltools.pxd",] + \
glob.glob("gltools/@src/*.pxi") + \
glob.glob("gltools/@src/*.cpp") + \
glob.glob("gltools/@include/*.pxd") + \
glob.glob("gltools/@include/*.h")
try:
setup(
name = 'gltools',
version = version.STRING,
description = 'Library to create OpenGL based applications',
long_description = \
'''**gltools** is library for quickly creating OpenGL based
application in Python/Cython with support for:
* Access to vertex buffers and GLSL shaders
* Access to truetype fonts
* Windows handling through GLFW
* Saving framebuffer content to PNG file.
* Simple GUI controls
**History**
* v0.1.1 : Added missing files in source distribution
''',
classifiers = [value for value in classifiers.split("\n") if value],
author='Runar Tenfjord',
author_email = 'runar.tenfjord@gmail.com',
license = 'GPLv2',
download_url='http://pypi.python.org/pypi/gltools/',
url = 'http://github.com/tenko/gltools',
platforms = ['any'],
requires = ['geotools'],
ext_modules=[
Extension("gltools",
sources = SRC,
depends = DEP,
include_dirs = ['gltools/@include','gltools/@src',
'gltools/@contrib'],
library_dirs = ['gltools'],
libraries = LIBS,
extra_link_args = LINK_ARGS,
extra_compile_args = COMPILE_ARGS,
extra_objects = OBJECTS,
language="c++"
),
],
cmdclass = {'build_ext': build_ext},
packages=[''],
package_dir={'': 'gltools'},
package_data={'': ['*.pxd']},
)
except:
print('Traceback\n:%s\n' % str(sys.exc_info()[-2]))
sys.exit(1)

32
setup_docs.py Normal file
View file

@ -0,0 +1,32 @@
#!/usr/bin/python2
# -*- coding: utf-8 -*-
#
# This file is part of gltools - See LICENSE.txt
#
import sys
import os
from distutils.core import setup
from sphinx.setup_command import BuildDoc
cmdclass = {'build_sphinx': BuildDoc}
name = 'gltools'
version = '0.1'
release = '0.1.0'
try:
setup(
name = name,
author = 'Runar Tenfjord',
version = release,
cmdclass = cmdclass,
command_options = {
'build_sphinx': {
'builder': ('setup_docs.py', 'html'),
}
},
)
except:
print('Traceback\n:%s\n' % str(sys.exc_info()[-2]))
sys.exit(1)

5
version.py Normal file
View file

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
MAJOR = 0
MINOR = 2
BUILD = 1
STRING = "%d.%d.%d" % (MAJOR,MINOR,BUILD)