first commit
commit
f255ae1922
|
@ -0,0 +1,7 @@
|
|||
* text=auto
|
||||
|
||||
*.sln text eol=crlf
|
||||
*.vcproj text eol=crlf
|
||||
*.vcxproj text eol=crlf
|
||||
*.vcxproj text eol=crlf
|
||||
*.vcxproj.filters text eol=crlf
|
|
@ -0,0 +1,36 @@
|
|||
*.exe
|
||||
*.dll
|
||||
|
||||
/other/
|
||||
Release_MD/
|
||||
Release/
|
||||
Debug/
|
||||
x64/
|
||||
ipch/
|
||||
|
||||
tags
|
||||
*.swp
|
||||
*.dat
|
||||
*.clbin
|
||||
*.log
|
||||
*.tlog
|
||||
*.sdf
|
||||
*.opensdf
|
||||
*.xml
|
||||
*.ipch
|
||||
*.css
|
||||
*.xslt
|
||||
*.aps
|
||||
*.suo
|
||||
*.ncb
|
||||
*.user
|
||||
*.o
|
||||
*.obj
|
||||
*.pdb
|
||||
*.res
|
||||
*.manifest
|
||||
*.dep
|
||||
*.zip
|
||||
*.lnk
|
||||
*.chm
|
||||
*~
|
|
@ -0,0 +1,674 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. 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
|
||||
them 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 prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. 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.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey 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;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If 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 convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU 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 that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
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.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
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.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
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
|
||||
state 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program 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, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU 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. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
|
@ -0,0 +1,166 @@
|
|||
|
||||
What is OBS?
|
||||
|
||||
This project is a rewrite of what was formerly known as "Open Broadcaster
|
||||
Software", software originally designed for recording and streaming live
|
||||
video content, efficiently.
|
||||
|
||||
|
||||
What's the goal of rewriting OBS?
|
||||
|
||||
- Make it multiplatform. Use multiplatform libraries/functions/classes where
|
||||
possible to allow this. Multi-platform support was one of the primary
|
||||
reasons for the rewrite. This also means using a UI toolkit will be
|
||||
necessary for user interface. It also means allowing the use of OpenGL as
|
||||
well as Direct3D.
|
||||
|
||||
- Separate the application from the core, allowing custom user interfaces and
|
||||
custom appliction of the core if desired, and easier extending of the user
|
||||
interface.
|
||||
|
||||
- Simplify complex systems to not only make it easier to use, but easier to
|
||||
maintain.
|
||||
|
||||
- Write a better core API, and design the entire system to be modular.
|
||||
|
||||
- Now that we have much more experience, improve the overall design of all
|
||||
the subsystems/API, and minimize/eliminate design flaws. Make it so we can
|
||||
do all the things we've had trouble with before, such as custom outputs,
|
||||
multiple outputs at once, better handling of inputs, custom services.
|
||||
|
||||
- Make a better/cleaner code base, use better coding standards, use standard
|
||||
libraries where possible (not just STL and C standard library, but also
|
||||
things like ffmpeg as well), and improve maintainability of the project as a
|
||||
whole.
|
||||
|
||||
- Implement a new API-independent shader/effect system allowing better and
|
||||
easier shaders usage and customization without having to duplicate shader
|
||||
code.
|
||||
|
||||
- Better device support. Again, I didn't know what I was getting into when
|
||||
I originally started writing code for devices. It evolved into a totally
|
||||
convoluted mess. I would have improved the existing device plugin code, but
|
||||
it was just all so fundamentally bad and flawed that it would have been
|
||||
detrimental to progression to continue working on it rather than rewrite it.
|
||||
|
||||
|
||||
What was wrong with the original OBS?
|
||||
|
||||
The original OBS was rewritten not because it was bad, at least in terms of
|
||||
optimization. Optimization and graphics are things I love. However, there
|
||||
were some serious problems with the code and design that were deep and
|
||||
fundamental, which prevented myself and other developers from being able to
|
||||
improve/extend the application or add new features very easily.
|
||||
|
||||
First, the design flaws:
|
||||
|
||||
- The original OBS was completely and hopelessly hard-coded for windows,
|
||||
and only windows. It was just totally impossible to use it on other
|
||||
systems.
|
||||
|
||||
- All the sub-systems were written before I really knew what I was getting
|
||||
into. When I started the project, I didn't really fully comprehend the
|
||||
scope of what I would need or how to properly design the project. My
|
||||
design and plans for the application were just to write something that
|
||||
would "stream games and a webcam, with things like overlays and such."
|
||||
This turned out fine for most casual gamers and streamers (and very
|
||||
successful), but left anyone wanting to do anything more advanced left
|
||||
massively wanting.
|
||||
|
||||
- Subsystems and core functionalities intermingled in such a way that it
|
||||
was a nightmare to get proper custom functionality out of it. Things
|
||||
like QSV had to be meshed in with the main encoding loop, and it just
|
||||
made things a nightmare to deal with. Custom outputs were nigh
|
||||
impossible.
|
||||
|
||||
- The API was poorly designed because most of it came after I originally
|
||||
wrote the application, it was more of an afterthought, and plugin API
|
||||
would routinely break for plugin developers due to changing C++
|
||||
interfaces (one of the reasons the core is now C).
|
||||
|
||||
- API was intermeshed with the main executable. The OBSApi DLL was
|
||||
nothing more than basically this mutant growth upon OBS.exe that allowed
|
||||
plugin developers to barely write plugins, but all the important API
|
||||
code was actually stored in the executable. Navigation was a total mess.
|
||||
|
||||
- The graphics subsystem, while not bad, was incomplete, and though far
|
||||
easier to use than bare D3D, wasn't ideal, and was hard-coded for D3D
|
||||
specifically.
|
||||
|
||||
- The devices and audio code was poor, I had no idea what I was getting into
|
||||
when I started writing them in. I did not realize beforehand all the
|
||||
device-specific quirks that each device/system could have. Some devices
|
||||
had bad timing and quirks that I never aniticipated while writing them.
|
||||
I struggled with devices, and my original design for the audio subsystem
|
||||
for example morphed over and over into an abomination that, though works,
|
||||
is basically this giant duct-taped zombie monster.
|
||||
|
||||
- Shaders were difficult to customize because they had to be duplicated if
|
||||
you wanted slightly different functionality that required more than just
|
||||
changing shader constants.
|
||||
|
||||
- Oriantation of sources was fixed, and required special code for each
|
||||
source to do any custom modification of rotation/position/scale/etc.
|
||||
This is one of those fundamental flaws that I look back on and regret, as
|
||||
it was a stupid idea from the beginning. I originally thought I could
|
||||
get more accurate source position/sizes, but it just turned out to be
|
||||
totally bad. Should have been matrices from the beginning just like with
|
||||
a regular 3D engine.
|
||||
|
||||
Second, the coding flaws:
|
||||
|
||||
- The coding style was inconsistent.
|
||||
|
||||
- C++98, C-Style C++, there was no exception usage, no STL. C++ used
|
||||
poorly.
|
||||
|
||||
- Not Invented Here Syndrome everywhere. Custom string functions/classes,
|
||||
custom templates, custom everything everywhere. To be fair, it was all
|
||||
hand-me-down code from the early 2000s that I had become used to, but
|
||||
that was no excuse -- C-standard libraries and the STL should have been
|
||||
used from the beginning over anything else. That doesn't mean to say
|
||||
that using custom stuff is always bad, but doing it to the extent I did
|
||||
definitely was. Made it horrible to maintain as well, required extra
|
||||
knowledge for plugin developers and anyone messing with the code.
|
||||
|
||||
- Giant monolithic classes everywhere, the main OBS class was paricularly
|
||||
bad in this regard. This meant navigation was a nightmare, and no one
|
||||
really knew where to go or where to add/change things.
|
||||
|
||||
- Giant monolithic functions everywhere. This was particularly bad
|
||||
because it meant that functions became harder to debug and harder to
|
||||
keep track of what was going on in any particular function at any given
|
||||
time. These large functions, though not inefficient, were delicate and
|
||||
easily breakable. (See OBS::MainCaptureLoop for a nightmarish example,
|
||||
or the listbox subclass window procedure in WindowStuff.cpp)
|
||||
|
||||
- Very large file sizes with everything clumped up into single files (for
|
||||
another particularly nightmarish example, see WindowStuff.cpp)
|
||||
|
||||
- Bad formatting. Code could go beyond 200 columns in some cases, making
|
||||
it very unpleasant to read with many editors. Spaces instead of tabs,
|
||||
K&R mixed with allman (which was admittedly my fault).
|
||||
|
||||
|
||||
New (actual) coding guidelines
|
||||
|
||||
- For the C code (especially in the core), guidelines are pretty strict K&R,
|
||||
kernel style. See the linux kernel "CodingStyle" document for more
|
||||
information. That particular coding style guideline is for more than just
|
||||
style, it actually helps produce a better overall code base.
|
||||
|
||||
- For C++ code, I still use CamelCase instead of all_lowercase just because
|
||||
I prefer it that way, it feels right with C++ for some reason. It also
|
||||
helps make it distinguishable from C code.
|
||||
|
||||
- I've started using 8-column tabs for almost everything -- I really
|
||||
personally like it over 4-column tabs. I feel that 8-column tabs are very
|
||||
helpful in preventing large amounts of indentation. A self-imposed
|
||||
limitation, if you will. I also use actual tabs now, instead of spaces.
|
||||
Also, I feel that the K&R style looks much better/cleaner when viewed with
|
||||
8-column tabs.
|
||||
|
||||
- Preferred maximum columns: 80. I've also been doing this because in
|
||||
combination with 8-column tabs, it further prevents large/bad functions
|
||||
with high indentation. Another self-imposed limitation. Also, it makes
|
||||
for much cleaner viewing in certain editors that wrap (like vim).
|
|
@ -0,0 +1,12 @@
|
|||
SRCPATH=.
|
||||
CC=gcc
|
||||
CCDEP=gcc
|
||||
CFLAGS=-std=gnu99 -I$(SRCPATH)
|
||||
CXXFLAGS=-std=c++11 -I$(SRCPATH)
|
||||
#CPPFLAGS=-Wall -msse2 -O3 -ffast-math -fomit-frame-pointer
|
||||
CPPFLAGS=-Wall -msse2 -g
|
||||
LD=gcc -o
|
||||
LDFLAGS=-shared
|
||||
OBJ=o
|
||||
SOEXT=dll
|
||||
EXT=.exe
|
|
@ -0,0 +1,200 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef GS_D3D11EXPORTS_H
|
||||
#define GS_D3D11EXPORTS_H
|
||||
|
||||
#include "util/c99defs.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
EXPORT device_t device_create(struct gs_init_data *data);
|
||||
EXPORT void device_destroy(device_t device);
|
||||
EXPORT swapchain_t device_create_swapchain(device_t device,
|
||||
struct gs_init_data *data);
|
||||
EXPORT void device_resize(device_t device, uint32_t x, uint32_t y);
|
||||
EXPORT void device_getsize(device_t device, uint32_t *x, uint32_t *y);
|
||||
EXPORT uint32_t device_getwidth(device_t device);
|
||||
EXPORT uint32_t device_getheight(device_t device);
|
||||
EXPORT texture_t device_create_texture(device_t device, uint32_t width,
|
||||
uint32_t height, enum gs_color_format color_format, void *data,
|
||||
uint32_t flags);
|
||||
EXPORT texture_t device_create_cubetexture(device_t device, uint32_t size,
|
||||
enum gs_color_format color_format, void *data[6],
|
||||
uint32_t flags);
|
||||
EXPORT texture_t device_create_volumetexture(device_t device, uint32_t width,
|
||||
uint32_t height, uint32_t depth,
|
||||
enum gs_color_format color_format, void *data, uint32_t flags);
|
||||
EXPORT zstencil_t device_create_zstencil(device_t device, uint32_t width,
|
||||
uint32_t height, enum gs_zstencil_format format);
|
||||
EXPORT stagesurf_t device_create_stagesurface(device_t device, uint32_t width,
|
||||
uint32_t height, enum gs_color_format color_format);
|
||||
EXPORT samplerstate_t device_create_samplerstate(device_t device,
|
||||
struct gs_sampler_info *info);
|
||||
EXPORT shader_t device_create_vertexshader(device_t device,
|
||||
const char *shader, const char *file,
|
||||
char **error_string);
|
||||
EXPORT shader_t device_create_pixelshader(device_t device,
|
||||
const char *shader, const char *file,
|
||||
char **error_string);
|
||||
EXPORT vertbuffer_t device_create_vertexbuffer(device_t device,
|
||||
struct vb_data *data, uint32_t flags);
|
||||
EXPORT indexbuffer_t device_create_indexbuffer(device_t device,
|
||||
enum gs_index_type type, void *indices, size_t num,
|
||||
uint32_t flags);
|
||||
EXPORT enum gs_texture_type device_gettexturetype(device_t device,
|
||||
texture_t texture);
|
||||
EXPORT void device_load_vertexbuffer(device_t device, vertbuffer_t vertbuffer);
|
||||
EXPORT void device_load_indexbuffer(device_t device, indexbuffer_t indexbuffer);
|
||||
EXPORT void device_load_texture(device_t device, texture_t tex, int unit);
|
||||
EXPORT void device_load_cubetexture(device_t device, texture_t cubetex,
|
||||
int unit);
|
||||
EXPORT void device_load_volumetexture(device_t device, texture_t voltex,
|
||||
int unit);
|
||||
EXPORT void device_load_samplerstate(device_t device,
|
||||
samplerstate_t samplerstate, int unit);
|
||||
EXPORT void device_load_vertexshader(device_t device, shader_t vertshader);
|
||||
EXPORT void device_load_pixelshader(device_t device, shader_t pixelshader);
|
||||
EXPORT void device_load_defaultsamplerstate(device_t device, bool b_3d,
|
||||
int unit);
|
||||
EXPORT shader_t device_getvertexshader(device_t device);
|
||||
EXPORT shader_t device_getpixelshader(device_t device);
|
||||
EXPORT texture_t device_getrendertarget(device_t device);
|
||||
EXPORT zstencil_t device_getzstenciltarget(device_t device);
|
||||
EXPORT void device_setrendertarget(device_t device, texture_t tex,
|
||||
zstencil_t zstencil);
|
||||
EXPORT void device_setcuberendertarget(device_t device, texture_t cubetex,
|
||||
int side, zstencil_t zstencil);
|
||||
EXPORT void device_copy_texture(device_t device, texture_t dst, texture_t src);
|
||||
EXPORT void device_stage_texture(device_t device, stagesurf_t dst,
|
||||
texture_t src);
|
||||
EXPORT void device_beginscene(device_t device);
|
||||
EXPORT void device_draw(device_t device, enum gs_draw_mode draw_mode,
|
||||
uint32_t start_vert, uint32_t num_verts);
|
||||
EXPORT void device_endscene(device_t device);
|
||||
EXPORT void device_load_swapchain(device_t device, swapchain_t swapchain);
|
||||
EXPORT void device_clear(device_t device, uint32_t clear_flags,
|
||||
struct vec4 *color, float depth, uint8_t stencil);
|
||||
EXPORT void device_present(device_t device);
|
||||
EXPORT void device_setcullmode(device_t device, enum gs_cull_mode mode);
|
||||
EXPORT enum gs_cull_mode device_getcullmode(device_t device);
|
||||
EXPORT void device_enable_blending(device_t device, bool enable);
|
||||
EXPORT void device_enable_depthtest(device_t device, bool enable);
|
||||
EXPORT void device_enable_stenciltest(device_t device, bool enable);
|
||||
EXPORT void device_enable_stencilwrite(device_t device, bool enable);
|
||||
EXPORT void device_enable_color(device_t device, bool red, bool blue,
|
||||
bool green, bool alpha);
|
||||
EXPORT void device_blendfunction(device_t device, enum gs_blend_type src,
|
||||
enum gs_blend_type dest);
|
||||
EXPORT void device_depthfunction(device_t device, enum gs_depth_test test);
|
||||
EXPORT void device_stencilfunction(device_t device, enum gs_stencil_side side,
|
||||
enum gs_depth_test test);
|
||||
EXPORT void device_stencilop(device_t device, enum gs_stencil_side side,
|
||||
enum gs_stencil_op fail, enum gs_stencil_op zfail,
|
||||
enum gs_stencil_op zpass);
|
||||
EXPORT void device_enable_fullscreen(device_t device, bool enable);
|
||||
EXPORT int device_fullscreen_enabled(device_t device);
|
||||
EXPORT void device_setdisplaymode(device_t device,
|
||||
const struct gs_display_mode *mode);
|
||||
EXPORT void device_getdisplaymode(device_t device,
|
||||
struct gs_display_mode *mode);
|
||||
EXPORT void device_setcolorramp(device_t device, float gamma, float brightness,
|
||||
float contrast);
|
||||
EXPORT void device_setviewport(device_t device, int x, int y, int width,
|
||||
int height);
|
||||
EXPORT void device_getviewport(device_t device, struct gs_rect *rect);
|
||||
EXPORT void device_setscissorrect(device_t device, struct gs_rect *rect);
|
||||
EXPORT void device_ortho(device_t device, float left, float right,
|
||||
float top, float bottom, float znear, float zfar);
|
||||
EXPORT void device_frustum(device_t device, float left, float right,
|
||||
float top, float bottom, float znear, float zfar);
|
||||
EXPORT void device_perspective(device_t device, float fovy, float aspect,
|
||||
float znear, float zfar);
|
||||
EXPORT void device_set_view_matrix(device_t device, struct matrix3 *mat);
|
||||
EXPORT void device_projection_push(device_t device);
|
||||
EXPORT void device_projection_pop(device_t device);
|
||||
|
||||
EXPORT void swapchain_destroy(swapchain_t swapchain);
|
||||
|
||||
EXPORT void texture_destroy(texture_t tex);
|
||||
EXPORT uint32_t texture_getwidth(texture_t tex);
|
||||
EXPORT uint32_t texture_getheight(texture_t tex);
|
||||
EXPORT enum gs_color_format texture_getcolorformat(texture_t tex);
|
||||
EXPORT bool texture_map(texture_t tex, void **ptr, uint32_t *byte_width);
|
||||
EXPORT void texture_unmap(texture_t tex);
|
||||
|
||||
EXPORT void cubetexture_destroy(texture_t cubetex);
|
||||
EXPORT uint32_t cubetexture_getsize(texture_t cubetex);
|
||||
EXPORT enum gs_color_format cubetexture_getcolorformat(texture_t cubetex);
|
||||
|
||||
EXPORT void volumetexture_destroy(texture_t voltex);
|
||||
EXPORT uint32_t volumetexture_getwidth(texture_t voltex);
|
||||
EXPORT uint32_t volumetexture_getheight(texture_t voltex);
|
||||
EXPORT uint32_t volumetexture_getdepth(texture_t voltex);
|
||||
EXPORT enum gs_color_format volumetexture_getcolorformat(texture_t voltex);
|
||||
|
||||
EXPORT void stagesurface_destroy(stagesurf_t stagesurf);
|
||||
EXPORT uint32_t stagesurface_getwidth(stagesurf_t stagesurf);
|
||||
EXPORT uint32_t stagesurface_getheight(stagesurf_t stagesurf);
|
||||
EXPORT enum gs_color_format stagesurface_getcolorformat(stagesurf_t stagesurf);
|
||||
EXPORT bool stagesurface_map(stagesurf_t stagesurf, const void **data,
|
||||
uint32_t *byte_width);
|
||||
EXPORT void stagesurface_unmap(stagesurf_t stagesurf);
|
||||
|
||||
EXPORT void zstencil_destroy(zstencil_t zstencil);
|
||||
|
||||
EXPORT void samplerstate_destroy(samplerstate_t samplerstate);
|
||||
|
||||
EXPORT void vertexbuffer_destroy(vertbuffer_t vertbuffer);
|
||||
EXPORT void vertexbuffer_flush(vertbuffer_t vertbuffer, bool rebuild);
|
||||
EXPORT struct vb_data *vertexbuffer_getdata(vertbuffer_t vertbuffer);
|
||||
|
||||
EXPORT void indexbuffer_destroy(indexbuffer_t indexbuffer);
|
||||
EXPORT void indexbuffer_flush(indexbuffer_t indexbuffer);
|
||||
EXPORT void *indexbuffer_getdata(indexbuffer_t indexbuffer);
|
||||
EXPORT size_t indexbuffer_numindices(indexbuffer_t indexbuffer);
|
||||
EXPORT enum gs_index_type indexbuffer_gettype(indexbuffer_t indexbuffer);
|
||||
|
||||
EXPORT void shader_destroy(shader_t shader);
|
||||
EXPORT int shader_numparams(shader_t shader);
|
||||
EXPORT sparam_t shader_getparambyidx(shader_t shader, int param);
|
||||
EXPORT sparam_t shader_getparambyname(shader_t shader, const char *name);
|
||||
EXPORT void shader_getparaminfo(shader_t shader, sparam_t param,
|
||||
struct shader_param_info *info);
|
||||
EXPORT sparam_t shader_getviewprojmatrix(shader_t shader);
|
||||
EXPORT sparam_t shader_getworldmatrix(shader_t shader);
|
||||
EXPORT void shader_setbool(shader_t shader, sparam_t param, bool val);
|
||||
EXPORT void shader_setfloat(shader_t shader, sparam_t param, float val);
|
||||
EXPORT void shader_setint(shader_t shader, sparam_t param, int val);
|
||||
EXPORT void shader_setmatrix3(shader_t shader, sparam_t param,
|
||||
const struct matrix3 *val);
|
||||
EXPORT void shader_setmatrix4(shader_t shader, sparam_t param,
|
||||
const struct matrix4 *val);
|
||||
EXPORT void shader_setvec2(shader_t shader, sparam_t param,
|
||||
const struct vec2 *val);
|
||||
EXPORT void shader_setvec3(shader_t shader, sparam_t param,
|
||||
const struct vec3 *val);
|
||||
EXPORT void shader_setvec4(shader_t shader, sparam_t param,
|
||||
const struct vec4 *val);
|
||||
EXPORT void shader_settexture(shader_t shader, sparam_t param, texture_t val);
|
||||
EXPORT void shader_setval(shader_t shader, sparam_t param, const void *val,
|
||||
size_t size);
|
||||
EXPORT void shader_setdefault(shader_t shader, sparam_t param);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,54 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "GS_D3D11SubSystem.hpp"
|
||||
|
||||
void gs_index_buffer::InitBuffer()
|
||||
{
|
||||
D3D11_BUFFER_DESC bd;
|
||||
D3D11_SUBRESOURCE_DATA srd;
|
||||
HRESULT hr;
|
||||
|
||||
memset(&bd, 0, sizeof(bd));
|
||||
memset(&srd, 0, sizeof(srd));
|
||||
|
||||
bd.Usage = dynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT;
|
||||
bd.CPUAccessFlags = dynamic ? D3D11_CPU_ACCESS_WRITE : 0;
|
||||
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
|
||||
bd.ByteWidth = UINT(indexSize * num);
|
||||
srd.pSysMem = indices.data;
|
||||
|
||||
hr = device->device->CreateBuffer(&bd, &srd, indexBuffer.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create buffer", hr);
|
||||
}
|
||||
|
||||
gs_index_buffer::gs_index_buffer(device_t device, enum gs_index_type type,
|
||||
void *indices, size_t num, uint32_t flags)
|
||||
: device (device),
|
||||
type (type),
|
||||
indices (indices),
|
||||
num (num),
|
||||
dynamic ((flags & GS_DYNAMIC) != 0)
|
||||
{
|
||||
switch (type) {
|
||||
case GS_UNSIGNED_SHORT: indexSize = 2; break;
|
||||
case GS_UNSIGNED_LONG: indexSize = 4; break;
|
||||
}
|
||||
|
||||
InitBuffer();
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "GS_D3D11SubSystem.hpp"
|
||||
#include "graphics/vec4.h"
|
||||
|
||||
const D3D11_TEXTURE_ADDRESS_MODE convertAddressMode[] =
|
||||
{
|
||||
D3D11_TEXTURE_ADDRESS_CLAMP,
|
||||
D3D11_TEXTURE_ADDRESS_WRAP,
|
||||
D3D11_TEXTURE_ADDRESS_MIRROR,
|
||||
D3D11_TEXTURE_ADDRESS_BORDER,
|
||||
D3D11_TEXTURE_ADDRESS_MIRROR_ONCE
|
||||
};
|
||||
|
||||
const D3D11_FILTER convertFilter[] =
|
||||
{
|
||||
D3D11_FILTER_MIN_MAG_MIP_LINEAR,
|
||||
D3D11_FILTER_MIN_MAG_MIP_POINT,
|
||||
D3D11_FILTER_ANISOTROPIC,
|
||||
D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR,
|
||||
D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT,
|
||||
D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR,
|
||||
D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT,
|
||||
D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR,
|
||||
D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT
|
||||
};
|
||||
|
||||
gs_sampler_state::gs_sampler_state(device_t device, gs_sampler_info *info)
|
||||
: device (device),
|
||||
info (*info)
|
||||
{
|
||||
D3D11_SAMPLER_DESC sd;
|
||||
HRESULT hr;
|
||||
vec4 v4;
|
||||
|
||||
memset(&sd, 0, sizeof(sd));
|
||||
sd.AddressU = convertAddressMode[(uint32_t)info->address_u];
|
||||
sd.AddressV = convertAddressMode[(uint32_t)info->address_v];
|
||||
sd.AddressW = convertAddressMode[(uint32_t)info->address_w];
|
||||
sd.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
|
||||
sd.Filter = convertFilter[(uint32_t)info->filter];
|
||||
sd.MaxAnisotropy = info->max_anisotropy;
|
||||
sd.MaxLOD = FLT_MAX;
|
||||
|
||||
vec4_from_rgba(&v4, info->border_color);
|
||||
memcpy(sd.BorderColor, v4.ptr, sizeof(v4));
|
||||
|
||||
hr = device->device->CreateSamplerState(&sd, state.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create sampler state", hr);
|
||||
}
|
|
@ -0,0 +1,338 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "GS_D3D11SubSystem.hpp"
|
||||
#include "GS_D3D11ShaderProcessor.hpp"
|
||||
#include "graphics/vec2.h"
|
||||
#include "graphics/vec3.h"
|
||||
#include "graphics/matrix3.h"
|
||||
#include "graphics/matrix4.h"
|
||||
|
||||
void gs_vertex_shader::GetBuffersExpected(
|
||||
const vector<D3D11_INPUT_ELEMENT_DESC> &inputs)
|
||||
{
|
||||
for (size_t i = 0; i < inputs.size(); i++) {
|
||||
const D3D11_INPUT_ELEMENT_DESC &input = inputs[i];
|
||||
if (strcmp(input.SemanticName, "NORMAL") == 0)
|
||||
hasNormals = true;
|
||||
else if (strcmp(input.SemanticName, "TANGENT") == 0)
|
||||
hasTangents = true;
|
||||
else if (strcmp(input.SemanticName, "COLOR") == 0)
|
||||
hasColors = true;
|
||||
else if (strcmp(input.SemanticName, "TEXCOORD") == 0)
|
||||
nTexUnits++;
|
||||
}
|
||||
}
|
||||
|
||||
gs_vertex_shader::gs_vertex_shader(device_t device, const char *file,
|
||||
const char *shaderString)
|
||||
: gs_shader (device, SHADER_VERTEX),
|
||||
hasNormals (false),
|
||||
hasColors (false),
|
||||
hasTangents (false),
|
||||
nTexUnits (0)
|
||||
{
|
||||
vector<D3D11_INPUT_ELEMENT_DESC> inputs;
|
||||
ShaderProcessor processor(device);
|
||||
ComPtr<ID3D10Blob> shaderBlob;
|
||||
string outputString;
|
||||
HRESULT hr;
|
||||
|
||||
processor.Process(shaderString, file);
|
||||
processor.BuildString(outputString);
|
||||
processor.BuildParams(params);
|
||||
processor.BuildInputLayout(inputs);
|
||||
GetBuffersExpected(inputs);
|
||||
BuildConstantBuffer();
|
||||
|
||||
Compile(outputString.c_str(), file, "vs_4_0", shaderBlob.Assign());
|
||||
|
||||
hr = device->device->CreateVertexShader(shaderBlob->GetBufferPointer(),
|
||||
shaderBlob->GetBufferSize(), NULL, shader.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create vertex shader", hr);
|
||||
|
||||
hr = device->device->CreateInputLayout(inputs.data(),
|
||||
(UINT)inputs.size(), shaderBlob->GetBufferPointer(),
|
||||
shaderBlob->GetBufferSize(), layout.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create input layout", hr);
|
||||
|
||||
viewProj = shader_getparambyname(this, "ViewProj");
|
||||
world = shader_getparambyname(this, "World");
|
||||
}
|
||||
|
||||
gs_pixel_shader::gs_pixel_shader(device_t device, const char *file,
|
||||
const char *shaderString)
|
||||
: gs_shader(device, SHADER_PIXEL)
|
||||
{
|
||||
ShaderProcessor processor(device);
|
||||
ComPtr<ID3D10Blob> shaderBlob;
|
||||
string outputString;
|
||||
HRESULT hr;
|
||||
|
||||
processor.Process(shaderString, file);
|
||||
processor.BuildString(outputString);
|
||||
processor.BuildParams(params);
|
||||
processor.BuildSamplers(samplers);
|
||||
BuildConstantBuffer();
|
||||
|
||||
Compile(outputString.c_str(), file, "ps_4_0", shaderBlob.Assign());
|
||||
|
||||
hr = device->device->CreatePixelShader(shaderBlob->GetBufferPointer(),
|
||||
shaderBlob->GetBufferSize(), NULL, shader.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create vertex shader", hr);
|
||||
}
|
||||
|
||||
void gs_shader::BuildConstantBuffer()
|
||||
{
|
||||
for (size_t i = 0; i < params.size(); i++) {
|
||||
shader_param ¶m = params[i];
|
||||
switch (param.type) {
|
||||
case SHADER_PARAM_BOOL:
|
||||
case SHADER_PARAM_INT:
|
||||
case SHADER_PARAM_FLOAT: constantSize += sizeof(float); break;
|
||||
case SHADER_PARAM_VEC2: constantSize += sizeof(vec2); break;
|
||||
case SHADER_PARAM_VEC3: constantSize += sizeof(float)*3; break;
|
||||
case SHADER_PARAM_VEC4: constantSize += sizeof(vec4); break;
|
||||
case SHADER_PARAM_MATRIX3X3:
|
||||
constantSize += sizeof(float)*3*3;
|
||||
break;
|
||||
case SHADER_PARAM_MATRIX4X4:
|
||||
constantSize += sizeof(float)*4*4;
|
||||
}
|
||||
}
|
||||
|
||||
if (constantSize) {
|
||||
D3D11_BUFFER_DESC bd;
|
||||
HRESULT hr;
|
||||
|
||||
memset(&bd, 0, sizeof(bd));
|
||||
bd.ByteWidth = (constantSize+15)&0xFFFFFFF0; /* align */
|
||||
bd.Usage = D3D11_USAGE_DYNAMIC;
|
||||
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||
bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
|
||||
hr = device->device->CreateBuffer(&bd, NULL,
|
||||
constants.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create constant buffer", hr);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < params.size(); i++)
|
||||
shader_setdefault(this, ¶ms[i]);
|
||||
}
|
||||
|
||||
void gs_shader::Compile(const char *shaderString, const char *file,
|
||||
const char *target, ID3D10Blob **shader)
|
||||
{
|
||||
ComPtr<ID3D10Blob> errorsBlob;
|
||||
HRESULT hr;
|
||||
|
||||
if (!shaderString)
|
||||
throw "No shader string specified";
|
||||
|
||||
hr = D3DCompile(shaderString, strlen(shaderString), file, NULL, NULL,
|
||||
"main", target,
|
||||
D3D10_SHADER_OPTIMIZATION_LEVEL1, 0,
|
||||
shader, errorsBlob.Assign());
|
||||
if (FAILED(hr)) {
|
||||
if (errorsBlob != NULL && errorsBlob->GetBufferSize())
|
||||
throw ShaderError(errorsBlob, hr);
|
||||
else
|
||||
throw HRError("Failed to compile shader", hr);
|
||||
}
|
||||
}
|
||||
|
||||
inline void gs_shader::UpdateParam(vector<uint8_t> &constData,
|
||||
shader_param ¶m, bool &upload)
|
||||
{
|
||||
if (param.type != SHADER_PARAM_TEXTURE) {
|
||||
if (!param.curValue.size())
|
||||
throw "Not all shader parameters were set";
|
||||
|
||||
constData.insert(constData.end(),
|
||||
param.curValue.begin(),
|
||||
param.curValue.end());
|
||||
|
||||
if (param.changed) {
|
||||
upload = true;
|
||||
param.changed = false;
|
||||
}
|
||||
} else if (param.curValue.size() == sizeof(texture_t)) {
|
||||
texture_t tex;
|
||||
memcpy(&tex, param.curValue.data(), sizeof(texture_t));
|
||||
device_load_texture(device, tex, param.textureID);
|
||||
}
|
||||
}
|
||||
|
||||
void gs_shader::UploadParams()
|
||||
{
|
||||
vector<uint8_t> constData;
|
||||
bool upload = false;
|
||||
|
||||
constData.reserve(constantSize);
|
||||
|
||||
for (size_t i = 0; i < params.size(); i++)
|
||||
UpdateParam(constData, params[i], upload);
|
||||
|
||||
if (constData.size() != constantSize)
|
||||
throw "Invalid constant data size given to shader";
|
||||
|
||||
if (upload) {
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
HRESULT hr;
|
||||
|
||||
hr = device->context->Map(constants, 0, D3D11_MAP_WRITE_DISCARD,
|
||||
0, &map);
|
||||
if (FAILED(hr))
|
||||
throw HRError("Could not lock constant buffer", hr);
|
||||
|
||||
memcpy(map.pData, constData.data(), constData.size());
|
||||
device->context->Unmap(constants, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void shader_destroy(shader_t shader)
|
||||
{
|
||||
delete shader;
|
||||
}
|
||||
|
||||
int shader_numparams(shader_t shader)
|
||||
{
|
||||
return (int)shader->params.size();
|
||||
}
|
||||
|
||||
sparam_t shader_getparambyidx(shader_t shader, int param)
|
||||
{
|
||||
return &shader->params[param];
|
||||
}
|
||||
|
||||
sparam_t shader_getparambyname(shader_t shader, const char *name)
|
||||
{
|
||||
for (size_t i = 0; i < shader->params.size(); i++) {
|
||||
shader_param ¶m = shader->params[i];
|
||||
if (strcmp(param.name.c_str(), name) == 0)
|
||||
return ¶m;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void shader_getparaminfo(shader_t shader, sparam_t param,
|
||||
struct shader_param_info *info)
|
||||
{
|
||||
if (!param || !shader)
|
||||
return;
|
||||
|
||||
info->name = param->name.c_str();
|
||||
info->type = param->type;
|
||||
}
|
||||
|
||||
sparam_t shader_getviewprojmatrix(shader_t shader)
|
||||
{
|
||||
if (shader->type != SHADER_VERTEX)
|
||||
return NULL;
|
||||
|
||||
return static_cast<gs_vertex_shader*>(shader)->viewProj;
|
||||
}
|
||||
|
||||
sparam_t shader_getworldmatrix(shader_t shader)
|
||||
{
|
||||
if (shader->type != SHADER_VERTEX)
|
||||
return NULL;
|
||||
|
||||
return static_cast<gs_vertex_shader*>(shader)->world;
|
||||
}
|
||||
|
||||
static inline void shader_setval_inline(gs_shader *shader, shader_param *param,
|
||||
const void *data, size_t size)
|
||||
{
|
||||
assert(param);
|
||||
if (!param)
|
||||
return;
|
||||
|
||||
bool size_changed = param->curValue.size() != size;
|
||||
if (size_changed)
|
||||
param->curValue.resize(size);
|
||||
|
||||
if (size_changed || memcmp(param->curValue.data(), data, size) != 0) {
|
||||
memcpy(param->curValue.data(), data, size);
|
||||
param->changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
void shader_setbool(shader_t shader, sparam_t param, bool val)
|
||||
{
|
||||
shader_setval_inline(shader, param, &val, sizeof(bool));
|
||||
}
|
||||
|
||||
void shader_setfloat(shader_t shader, sparam_t param, float val)
|
||||
{
|
||||
shader_setval_inline(shader, param, &val, sizeof(float));
|
||||
}
|
||||
|
||||
void shader_setint(shader_t shader, sparam_t param, int val)
|
||||
{
|
||||
shader_setval_inline(shader, param, &val, sizeof(int));
|
||||
}
|
||||
|
||||
void shader_setmatrix3(shader_t shader, sparam_t param,
|
||||
const struct matrix3 *val)
|
||||
{
|
||||
shader_setval_inline(shader, param, val, sizeof(matrix3));
|
||||
}
|
||||
|
||||
void shader_setmatrix4(shader_t shader, sparam_t param,
|
||||
const struct matrix4 *val)
|
||||
{
|
||||
shader_setval_inline(shader, param, val, sizeof(matrix4));
|
||||
}
|
||||
|
||||
void shader_setvec2(shader_t shader, sparam_t param, const struct vec2 *val)
|
||||
{
|
||||
shader_setval_inline(shader, param, val, sizeof(vec2));
|
||||
}
|
||||
|
||||
void shader_setvec3(shader_t shader, sparam_t param, const struct vec3 *val)
|
||||
{
|
||||
shader_setval_inline(shader, param, val, sizeof(float) * 3);
|
||||
}
|
||||
|
||||
void shader_setvec4(shader_t shader, sparam_t param, const struct vec4 *val)
|
||||
{
|
||||
shader_setval_inline(shader, param, val, sizeof(vec4));
|
||||
}
|
||||
|
||||
void shader_settexture(shader_t shader, sparam_t param, texture_t val)
|
||||
{
|
||||
shader_setval_inline(shader, param, &val, sizeof(texture_t));
|
||||
}
|
||||
|
||||
void shader_setval(shader_t shader, sparam_t param, const void *val,
|
||||
size_t size)
|
||||
{
|
||||
shader_setval_inline(shader, param, val, size);
|
||||
}
|
||||
|
||||
void shader_setdefault(shader_t shader, sparam_t param)
|
||||
{
|
||||
if (param->defaultValue.size())
|
||||
shader_setval_inline(shader, param, param->defaultValue.data(),
|
||||
param->defaultValue.size());
|
||||
}
|
|
@ -0,0 +1,236 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "GS_D3D11SubSystem.hpp"
|
||||
#include "GS_D3D11ShaderProcessor.hpp"
|
||||
|
||||
#include <sstream>
|
||||
using namespace std;
|
||||
|
||||
static const char *semanticInputNames[] =
|
||||
{"POSITION", "NORMAL", "COLOR", "TANGENT", "TEXCOORD"};
|
||||
static const char *semanticOutputNames[] =
|
||||
{"SV_Position", "NORMAL", "COLOR", "TANGENT", "TEXCOORD"};
|
||||
|
||||
static const char *ConvertSemanticName(const char *name)
|
||||
{
|
||||
const size_t num = sizeof(semanticInputNames) / sizeof(const char*);
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
if (strcmp(name, semanticInputNames[i]) == 0)
|
||||
return semanticOutputNames[i];
|
||||
}
|
||||
|
||||
throw "Unknown Semantic Name";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void GetSemanticInfo(shader_var *var, const char *&name,
|
||||
uint32_t &index)
|
||||
{
|
||||
const char *mapping = var->mapping;
|
||||
const char *indexStr = mapping;
|
||||
|
||||
while (*indexStr && !isdigit(*indexStr))
|
||||
indexStr++;
|
||||
index = (*indexStr) ? strtol(indexStr, NULL, 10) : 0;
|
||||
|
||||
string nameStr;
|
||||
nameStr.assign(mapping, indexStr-mapping);
|
||||
name = ConvertSemanticName(nameStr.c_str());
|
||||
}
|
||||
|
||||
static void AddInputLayoutVar(shader_var *var,
|
||||
vector<D3D11_INPUT_ELEMENT_DESC> &layout)
|
||||
{
|
||||
D3D11_INPUT_ELEMENT_DESC ied;
|
||||
const char *semanticName;
|
||||
uint32_t semanticIndex;
|
||||
|
||||
GetSemanticInfo(var, semanticName, semanticIndex);
|
||||
|
||||
memset(&ied, 0, sizeof(ied));
|
||||
ied.SemanticName = semanticName;
|
||||
ied.SemanticIndex = semanticIndex;
|
||||
ied.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
|
||||
if (strcmp(var->mapping, "COLOR") == 0) {
|
||||
ied.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
|
||||
} else if (strcmp(var->mapping, "POSITION") == 0 ||
|
||||
strcmp(var->mapping, "NORMAL") == 0 ||
|
||||
strcmp(var->mapping, "TANGENT") == 0) {
|
||||
ied.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
|
||||
|
||||
} else if (astrcmp_n(var->mapping, "TEXCOORD", 8) == 0) {
|
||||
/* type is always a 'float' type */
|
||||
switch (var->type[5]) {
|
||||
case 0: ied.Format = DXGI_FORMAT_R32_FLOAT; break;
|
||||
case '2': ied.Format = DXGI_FORMAT_R32G32_FLOAT; break;
|
||||
case '3':
|
||||
case '4': ied.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; break;
|
||||
}
|
||||
}
|
||||
|
||||
layout.push_back(ied);
|
||||
}
|
||||
|
||||
static inline bool SetSlot(vector<D3D11_INPUT_ELEMENT_DESC> &layout,
|
||||
const char *name, uint32_t index, uint32_t &slotIdx)
|
||||
{
|
||||
for (size_t i = 0; i < layout.size(); i++) {
|
||||
D3D11_INPUT_ELEMENT_DESC &input = layout[i];
|
||||
if (input.SemanticIndex == index &&
|
||||
strcmpi(input.SemanticName, name) == 0) {
|
||||
layout[i].InputSlot = slotIdx++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void BuildInputLayoutFromVars(shader_parser *parser, darray *vars,
|
||||
vector<D3D11_INPUT_ELEMENT_DESC> &layout)
|
||||
{
|
||||
shader_var *array = (shader_var*)vars->array;
|
||||
|
||||
for (size_t i = 0; i < vars->num; i++) {
|
||||
shader_var *var = array+i;
|
||||
|
||||
if (var->mapping) {
|
||||
AddInputLayoutVar(var, layout);
|
||||
} else {
|
||||
shader_struct *st = shader_parser_getstruct(parser,
|
||||
var->type);
|
||||
if (st)
|
||||
BuildInputLayoutFromVars(parser, &st->vars.da,
|
||||
layout);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the input slot value for each semantic, however we do it in
|
||||
* a specific order so that it will always match the vertex buffer's
|
||||
* sub-buffer order (points-> normals-> colors-> tangents-> uvcoords)
|
||||
*/
|
||||
uint32_t slot = 0;
|
||||
SetSlot(layout, "SV_Position", 0, slot);
|
||||
SetSlot(layout, "NORMAL", 0, slot);
|
||||
SetSlot(layout, "COLOR", 0, slot);
|
||||
SetSlot(layout, "TANGENT", 0, slot);
|
||||
|
||||
uint32_t index = 0;
|
||||
while (SetSlot(layout, "TEXCOORD", index++, slot));
|
||||
}
|
||||
|
||||
void ShaderProcessor::BuildInputLayout(
|
||||
vector<D3D11_INPUT_ELEMENT_DESC> &layout)
|
||||
{
|
||||
shader_func *func = shader_parser_getfunc(&parser, "main");
|
||||
if (!func)
|
||||
throw "Failed to find 'main' shader function";
|
||||
|
||||
BuildInputLayoutFromVars(&parser, &func->params.da, layout);
|
||||
}
|
||||
|
||||
shader_param::shader_param(shader_var &var, uint32_t &texCounter)
|
||||
: type (get_shader_param_type(var.type)),
|
||||
name (var.name),
|
||||
textureID (texCounter),
|
||||
arrayCount (var.array_count),
|
||||
changed (false)
|
||||
{
|
||||
defaultValue.resize(var.default_val.num);
|
||||
memcpy(defaultValue.data(), var.default_val.array, var.default_val.num);
|
||||
|
||||
if (type == SHADER_PARAM_TEXTURE)
|
||||
texCounter++;
|
||||
else
|
||||
textureID = 0;
|
||||
}
|
||||
|
||||
static inline void AddParam(shader_var &var, vector<shader_param> ¶ms,
|
||||
uint32_t &texCounter)
|
||||
{
|
||||
if (var.var_type != SHADER_VAR_UNIFORM ||
|
||||
strcmp(var.type, "sampler") == 0)
|
||||
return;
|
||||
|
||||
params.push_back(shader_param(var, texCounter));
|
||||
}
|
||||
|
||||
void ShaderProcessor::BuildParams(vector<shader_param> ¶ms)
|
||||
{
|
||||
uint32_t texCounter = 0;
|
||||
|
||||
for (size_t i = 0; i < parser.params.num; i++)
|
||||
AddParam(parser.params.array[i], params, texCounter);
|
||||
}
|
||||
|
||||
static inline void AddSampler(device_t device, shader_sampler &sampler,
|
||||
vector<ShaderSampler> &samplers)
|
||||
{
|
||||
gs_sampler_info si;
|
||||
shader_sampler_convert(&sampler, &si);
|
||||
samplers.push_back(ShaderSampler(sampler.name, device, &si));
|
||||
}
|
||||
|
||||
void ShaderProcessor::BuildSamplers(vector<ShaderSampler> &samplers)
|
||||
{
|
||||
for (size_t i = 0; i < parser.samplers.num; i++)
|
||||
AddSampler(device, parser.samplers.array[i], samplers);
|
||||
}
|
||||
|
||||
void ShaderProcessor::BuildString(string &outputString)
|
||||
{
|
||||
stringstream output;
|
||||
cf_token *token = cf_preprocessor_gettokens(&parser.cfp.pp);
|
||||
while (token->type != CFTOKEN_NONE) {
|
||||
/* cheaply just replace specific tokens */
|
||||
if (strref_cmp(&token->str, "POSITION") == 0)
|
||||
output << "SV_Position";
|
||||
else if (strref_cmp(&token->str, "TARGET") == 0)
|
||||
output << "SV_Target";
|
||||
else if (strref_cmp(&token->str, "texture2d") == 0)
|
||||
output << "Texture2D";
|
||||
else if (strref_cmp(&token->str, "texture3d") == 0)
|
||||
output << "Texture3D";
|
||||
else if (strref_cmp(&token->str, "texture_cube") == 0)
|
||||
output << "TextureCube";
|
||||
else if (strref_cmp(&token->str, "sampler_state") == 0)
|
||||
output << "SamplerState";
|
||||
else
|
||||
output.write(token->str.array, token->str.len);
|
||||
|
||||
token++;
|
||||
}
|
||||
|
||||
outputString = move(output.str());
|
||||
}
|
||||
|
||||
void ShaderProcessor::Process(const char *shader_string, const char *file)
|
||||
{
|
||||
if (!shader_parse(&parser, shader_string, file)) {
|
||||
char *str = error_data_buildstring(&parser.cfp.error_list);
|
||||
if (str) {
|
||||
blog(LOG_WARNING, "Shader parser errors/warnings:\n"
|
||||
"%s\n", str);
|
||||
bfree(str);
|
||||
}
|
||||
throw "Failed to parse shader";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "graphics/shader-parser.h"
|
||||
|
||||
struct ShaderParser : shader_parser {
|
||||
inline ShaderParser() {shader_parser_init(this);}
|
||||
inline ~ShaderParser() {shader_parser_free(this);}
|
||||
};
|
||||
|
||||
struct ShaderProcessor {
|
||||
device_t device;
|
||||
ShaderParser parser;
|
||||
|
||||
void BuildInputLayout(vector<D3D11_INPUT_ELEMENT_DESC> &inputs);
|
||||
void BuildParams(vector<shader_param> ¶ms);
|
||||
void BuildSamplers(vector<ShaderSampler> &samplers);
|
||||
void BuildString(string &outputString);
|
||||
void Process(const char *shader_string, const char *file);
|
||||
|
||||
inline ShaderProcessor(device_t device) : device(device)
|
||||
{
|
||||
}
|
||||
};
|
|
@ -0,0 +1,44 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "GS_D3D11SubSystem.hpp"
|
||||
|
||||
gs_stage_surface::gs_stage_surface(device_t device, uint32_t width,
|
||||
uint32_t height, gs_color_format colorFormat)
|
||||
: device (device),
|
||||
width (width),
|
||||
height (height),
|
||||
format (colorFormat),
|
||||
dxgiFormat (ConvertGSTextureFormat(colorFormat))
|
||||
{
|
||||
D3D11_TEXTURE2D_DESC td;
|
||||
HRESULT hr;
|
||||
|
||||
memset(&td, 0, sizeof(td));
|
||||
td.Width = width;
|
||||
td.Height = height;
|
||||
td.MipLevels = 1;
|
||||
td.ArraySize = 1;
|
||||
td.Format = dxgiFormat;
|
||||
td.SampleDesc.Count = 1;
|
||||
td.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
td.Usage = D3D11_USAGE_STAGING;
|
||||
|
||||
hr = device->device->CreateTexture2D(&td, NULL, texture.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create 2D texture", hr);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,642 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <windows.h>
|
||||
#include <dxgi.h>
|
||||
#include <d3d11.h>
|
||||
#include <d3dcompiler.h>
|
||||
|
||||
#include "util/base.h"
|
||||
#include "graphics/matrix4.h"
|
||||
#include "graphics/graphics.h"
|
||||
#include "util/windows/ComPtr.hpp"
|
||||
#include "util/windows/HRError.hpp"
|
||||
|
||||
struct shader_var;
|
||||
struct shader_sampler;
|
||||
struct gs_vertex_shader;
|
||||
|
||||
#include "GS_D3D11Exports.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/*
|
||||
* Just to clarify, all structs, and all public. These are exporting only
|
||||
* via encapsulated C bindings, not C++ bindings, so the whole concept of
|
||||
* "public" and "private" does not matter at all for this subproject.
|
||||
*/
|
||||
|
||||
#define MAX_TEXTURES 8
|
||||
|
||||
static inline uint32_t GetWinVer()
|
||||
{
|
||||
OSVERSIONINFO ovi;
|
||||
ovi.dwOSVersionInfoSize = sizeof(ovi);
|
||||
GetVersionEx(&ovi);
|
||||
|
||||
return (ovi.dwMajorVersion << 8) | (ovi.dwMinorVersion);
|
||||
}
|
||||
|
||||
static inline uint32_t GetFormatBPP(gs_color_format format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case GS_A8: return 1;
|
||||
case GS_R8: return 1;
|
||||
case GS_RGBA: return 4;
|
||||
case GS_BGRX: return 4;
|
||||
case GS_BGRA: return 4;
|
||||
case GS_R10G10B10A2: return 4;
|
||||
case GS_RGBA16: return 8;
|
||||
case GS_R16: return 2;
|
||||
case GS_RGBA16F: return 8;
|
||||
case GS_RGBA32F: return 16;
|
||||
case GS_RG16F: return 4;
|
||||
case GS_RG32F: return 8;
|
||||
case GS_R16F: return 2;
|
||||
case GS_R32F: return 4;
|
||||
case GS_DXT1: return 0;
|
||||
case GS_DXT3: return 0;
|
||||
case GS_DXT5: return 0;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline DXGI_FORMAT ConvertGSTextureFormat(gs_color_format format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case GS_A8: return DXGI_FORMAT_A8_UNORM;
|
||||
case GS_R8: return DXGI_FORMAT_R8_UNORM;
|
||||
case GS_RGBA: return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
case GS_BGRX: return DXGI_FORMAT_B8G8R8X8_UNORM;
|
||||
case GS_BGRA: return DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
case GS_R10G10B10A2: return DXGI_FORMAT_R10G10B10A2_UNORM;
|
||||
case GS_RGBA16: return DXGI_FORMAT_R16G16B16A16_UNORM;
|
||||
case GS_R16: return DXGI_FORMAT_R16_UNORM;
|
||||
case GS_RGBA16F: return DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
case GS_RGBA32F: return DXGI_FORMAT_R32G32B32A32_FLOAT;
|
||||
case GS_RG16F: return DXGI_FORMAT_R16G16_FLOAT;
|
||||
case GS_RG32F: return DXGI_FORMAT_R32G32_FLOAT;
|
||||
case GS_R16F: return DXGI_FORMAT_R16_FLOAT;
|
||||
case GS_R32F: return DXGI_FORMAT_R32_FLOAT;
|
||||
case GS_DXT1: return DXGI_FORMAT_BC1_UNORM;
|
||||
case GS_DXT3: return DXGI_FORMAT_BC2_UNORM;
|
||||
case GS_DXT5: return DXGI_FORMAT_BC3_UNORM;
|
||||
default: return DXGI_FORMAT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static inline DXGI_FORMAT ConvertGSZStencilFormat(gs_zstencil_format format)
|
||||
{
|
||||
switch (format) {
|
||||
case GS_Z16: return DXGI_FORMAT_D16_UNORM;
|
||||
case GS_Z24_S8: return DXGI_FORMAT_D24_UNORM_S8_UINT;
|
||||
case GS_Z32F: return DXGI_FORMAT_D32_FLOAT;
|
||||
case GS_Z32F_S8X24: return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
|
||||
default: return DXGI_FORMAT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static inline D3D11_COMPARISON_FUNC ConvertGSDepthTest(gs_depth_test test)
|
||||
{
|
||||
switch (test) {
|
||||
default:
|
||||
case GS_NEVER: return D3D11_COMPARISON_NEVER;
|
||||
case GS_LESS: return D3D11_COMPARISON_LESS;
|
||||
case GS_LEQUAL: return D3D11_COMPARISON_LESS_EQUAL;
|
||||
case GS_EQUAL: return D3D11_COMPARISON_EQUAL;
|
||||
case GS_GEQUAL: return D3D11_COMPARISON_GREATER_EQUAL;
|
||||
case GS_GREATER: return D3D11_COMPARISON_GREATER;
|
||||
case GS_NOTEQUAL: return D3D11_COMPARISON_NOT_EQUAL;
|
||||
case GS_ALWAYS: return D3D11_COMPARISON_ALWAYS;
|
||||
}
|
||||
}
|
||||
|
||||
static inline D3D11_STENCIL_OP ConvertGSStencilOp(gs_stencil_op op)
|
||||
{
|
||||
switch (op) {
|
||||
default:
|
||||
case GS_KEEP: return D3D11_STENCIL_OP_KEEP;
|
||||
case GS_ZERO: return D3D11_STENCIL_OP_ZERO;
|
||||
case GS_REPLACE: return D3D11_STENCIL_OP_REPLACE;
|
||||
case GS_INCR: return D3D11_STENCIL_OP_INCR;
|
||||
case GS_DECR: return D3D11_STENCIL_OP_DECR;
|
||||
case GS_INVERT: return D3D11_STENCIL_OP_INVERT;
|
||||
}
|
||||
}
|
||||
|
||||
static inline D3D11_BLEND ConvertGSBlendType(gs_blend_type type)
|
||||
{
|
||||
switch (type) {
|
||||
default:
|
||||
case GS_BLEND_ZERO: return D3D11_BLEND_ZERO;
|
||||
case GS_BLEND_ONE: return D3D11_BLEND_ONE;
|
||||
case GS_BLEND_SRCCOLOR: return D3D11_BLEND_SRC_COLOR;
|
||||
case GS_BLEND_INVSRCCOLOR: return D3D11_BLEND_INV_SRC_COLOR;
|
||||
case GS_BLEND_SRCALPHA: return D3D11_BLEND_SRC_ALPHA;
|
||||
case GS_BLEND_INVSRCALPHA: return D3D11_BLEND_INV_SRC_ALPHA;
|
||||
case GS_BLEND_DSTCOLOR: return D3D11_BLEND_DEST_COLOR;
|
||||
case GS_BLEND_INVDSTCOLOR: return D3D11_BLEND_INV_DEST_COLOR;
|
||||
case GS_BLEND_DSTALPHA: return D3D11_BLEND_DEST_ALPHA;
|
||||
case GS_BLEND_INVDSTALPHA: return D3D11_BLEND_INV_DEST_ALPHA;
|
||||
case GS_BLEND_SRCALPHASAT: return D3D11_BLEND_SRC_ALPHA_SAT;
|
||||
}
|
||||
}
|
||||
|
||||
static inline D3D11_CULL_MODE ConvertGSCullMode(gs_cull_mode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
default:
|
||||
case GS_BACK: return D3D11_CULL_BACK;
|
||||
case GS_FRONT: return D3D11_CULL_FRONT;
|
||||
case GS_NEITHER: return D3D11_CULL_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static inline D3D11_PRIMITIVE_TOPOLOGY ConvertGSTopology(gs_draw_mode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
default:
|
||||
case GS_POINTS: return D3D11_PRIMITIVE_TOPOLOGY_POINTLIST;
|
||||
case GS_LINES: return D3D11_PRIMITIVE_TOPOLOGY_LINELIST;
|
||||
case GS_LINESTRIP: return D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP;
|
||||
case GS_TRIS: return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
case GS_TRISTRIP: return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
|
||||
}
|
||||
}
|
||||
|
||||
/* exception-safe RAII wrapper for vertex buffer data (NOTE: not copy-safe) */
|
||||
struct VBDataPtr {
|
||||
vb_data *data;
|
||||
|
||||
inline VBDataPtr(vb_data *data) : data(data) {}
|
||||
inline ~VBDataPtr() {vbdata_destroy(data);}
|
||||
};
|
||||
|
||||
struct gs_vertex_buffer {
|
||||
ComPtr<ID3D11Buffer> vertexBuffer;
|
||||
ComPtr<ID3D11Buffer> normalBuffer;
|
||||
ComPtr<ID3D11Buffer> colorBuffer;
|
||||
ComPtr<ID3D11Buffer> tangentBuffer;
|
||||
vector<ComPtr<ID3D11Buffer>> uvBuffers;
|
||||
|
||||
device_t device;
|
||||
bool dynamic;
|
||||
VBDataPtr vbd;
|
||||
size_t numVerts;
|
||||
vector<size_t> uvSizes;
|
||||
|
||||
void FlushBuffer(ID3D11Buffer *buffer, void *array,
|
||||
size_t elementSize);
|
||||
|
||||
void MakeBufferList(gs_vertex_shader *shader,
|
||||
vector<ID3D11Buffer*> &buffers,
|
||||
vector<uint32_t> &strides);
|
||||
|
||||
inline void InitBuffer(const size_t elementSize,
|
||||
const size_t numVerts, void *array,
|
||||
ID3D11Buffer **buffer);
|
||||
|
||||
gs_vertex_buffer(device_t device, struct vb_data *data, uint32_t flags);
|
||||
};
|
||||
|
||||
/* exception-safe RAII wrapper for index buffer data (NOTE: not copy-safe) */
|
||||
struct DataPtr {
|
||||
void *data;
|
||||
|
||||
inline DataPtr(void *data) : data(data) {}
|
||||
inline ~DataPtr() {bfree(data);}
|
||||
};
|
||||
|
||||
struct gs_index_buffer {
|
||||
ComPtr<ID3D11Buffer> indexBuffer;
|
||||
device_t device;
|
||||
bool dynamic;
|
||||
gs_index_type type;
|
||||
size_t indexSize;
|
||||
size_t num;
|
||||
DataPtr indices;
|
||||
|
||||
void InitBuffer();
|
||||
|
||||
gs_index_buffer(device_t device, enum gs_index_type type,
|
||||
void *indices, size_t num, uint32_t flags);
|
||||
};
|
||||
|
||||
struct gs_texture {
|
||||
gs_texture_type type;
|
||||
ComPtr<ID3D11ShaderResourceView> shaderRes;
|
||||
gs_device *device;
|
||||
|
||||
inline gs_texture(gs_device *device, gs_texture_type type)
|
||||
: device (device),
|
||||
type (type)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~gs_texture() {}
|
||||
};
|
||||
|
||||
struct gs_texture_2d : gs_texture {
|
||||
ComPtr<ID3D11Texture2D> texture;
|
||||
ComPtr<ID3D11RenderTargetView> renderTarget[6];
|
||||
ComPtr<IDXGISurface1> gdiSurface;
|
||||
|
||||
uint32_t width, height;
|
||||
gs_color_format format;
|
||||
DXGI_FORMAT dxgiFormat;
|
||||
bool isRenderTarget;
|
||||
bool isGDICompatible;
|
||||
bool isDynamic;
|
||||
bool isShared;
|
||||
bool genMipmaps;
|
||||
HANDLE sharedHandle;
|
||||
|
||||
void InitSRD(D3D11_SUBRESOURCE_DATA *srd, void *data);
|
||||
void InitTexture(void *data);
|
||||
void InitResourceView();
|
||||
void InitRenderTargets();
|
||||
|
||||
inline gs_texture_2d()
|
||||
: gs_texture (NULL, GS_TEXTURE_2D),
|
||||
width (0),
|
||||
height (0),
|
||||
format (GS_UNKNOWN),
|
||||
dxgiFormat (DXGI_FORMAT_UNKNOWN),
|
||||
isRenderTarget (false),
|
||||
isGDICompatible (false),
|
||||
isDynamic (false),
|
||||
isShared (false),
|
||||
genMipmaps (false),
|
||||
sharedHandle (NULL)
|
||||
{
|
||||
}
|
||||
|
||||
gs_texture_2d(device_t device, uint32_t width, uint32_t height,
|
||||
gs_color_format colorFormat, void *data,
|
||||
uint32_t flags, bool isCubeMap, bool gdiCompatible,
|
||||
bool shared);
|
||||
};
|
||||
|
||||
struct gs_zstencil_buffer {
|
||||
ComPtr<ID3D11Texture2D> texture;
|
||||
ComPtr<ID3D11DepthStencilView> view;
|
||||
|
||||
gs_device *device;
|
||||
uint32_t width, height;
|
||||
gs_zstencil_format format;
|
||||
DXGI_FORMAT dxgiFormat;
|
||||
|
||||
void InitBuffer();
|
||||
|
||||
inline gs_zstencil_buffer()
|
||||
: device (NULL),
|
||||
width (0),
|
||||
height (0),
|
||||
dxgiFormat (DXGI_FORMAT_UNKNOWN)
|
||||
{
|
||||
}
|
||||
|
||||
gs_zstencil_buffer(device_t device, uint32_t width, uint32_t height,
|
||||
gs_zstencil_format format);
|
||||
};
|
||||
|
||||
struct gs_stage_surface {
|
||||
ComPtr<ID3D11Texture2D> texture;
|
||||
|
||||
gs_device *device;
|
||||
uint32_t width, height;
|
||||
gs_color_format format;
|
||||
DXGI_FORMAT dxgiFormat;
|
||||
|
||||
gs_stage_surface(device_t device, uint32_t width, uint32_t height,
|
||||
gs_color_format colorFormat);
|
||||
};
|
||||
|
||||
struct gs_sampler_state {
|
||||
ComPtr<ID3D11SamplerState> state;
|
||||
device_t device;
|
||||
gs_sampler_info info;
|
||||
|
||||
gs_sampler_state(device_t device, gs_sampler_info *info);
|
||||
};
|
||||
|
||||
struct shader_param {
|
||||
string name;
|
||||
shader_param_type type;
|
||||
|
||||
uint32_t textureID;
|
||||
|
||||
int arrayCount;
|
||||
|
||||
vector<uint8_t> curValue;
|
||||
vector<uint8_t> defaultValue;
|
||||
bool changed;
|
||||
|
||||
shader_param(shader_var &var, uint32_t &texCounter);
|
||||
};
|
||||
|
||||
struct ShaderError {
|
||||
ComPtr<ID3D10Blob> errors;
|
||||
HRESULT hr;
|
||||
|
||||
inline ShaderError(const ComPtr<ID3D10Blob> &errors, HRESULT hr)
|
||||
: errors (errors),
|
||||
hr (hr)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct gs_shader {
|
||||
device_t device;
|
||||
shader_type type;
|
||||
vector<shader_param> params;
|
||||
ComPtr<ID3D11Buffer> constants;
|
||||
size_t constantSize;
|
||||
|
||||
inline void UpdateParam(vector<uint8_t> &constData, shader_param ¶m,
|
||||
bool &upload);
|
||||
void UploadParams();
|
||||
|
||||
void BuildConstantBuffer();
|
||||
void Compile(const char *shaderStr, const char *file,
|
||||
const char *target, ID3D10Blob **shader);
|
||||
|
||||
inline gs_shader(device_t device, shader_type type)
|
||||
: device (device),
|
||||
type (type),
|
||||
constantSize (0)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~gs_shader() {}
|
||||
};
|
||||
|
||||
struct ShaderSampler {
|
||||
string name;
|
||||
gs_sampler_state sampler;
|
||||
|
||||
inline ShaderSampler(const char *name, device_t device,
|
||||
gs_sampler_info *info)
|
||||
: name (name),
|
||||
sampler (device, info)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct gs_vertex_shader : gs_shader {
|
||||
ComPtr<ID3D11VertexShader> shader;
|
||||
ComPtr<ID3D11InputLayout> layout;
|
||||
|
||||
shader_param *world, *viewProj;
|
||||
|
||||
bool hasNormals;
|
||||
bool hasColors;
|
||||
bool hasTangents;
|
||||
uint32_t nTexUnits;
|
||||
|
||||
inline uint32_t NumBuffersExpected() const
|
||||
{
|
||||
uint32_t count = nTexUnits+1;
|
||||
if (hasNormals) count++;
|
||||
if (hasColors) count++;
|
||||
if (hasTangents) count++;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void GetBuffersExpected(const vector<D3D11_INPUT_ELEMENT_DESC> &inputs);
|
||||
|
||||
gs_vertex_shader(device_t device, const char *file,
|
||||
const char *shaderString);
|
||||
};
|
||||
|
||||
struct gs_pixel_shader : gs_shader {
|
||||
ComPtr<ID3D11PixelShader> shader;
|
||||
vector<ShaderSampler> samplers;
|
||||
|
||||
inline void GetSamplerStates(ID3D11SamplerState **states)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < samplers.size(); i++)
|
||||
states[i] = samplers[i].sampler.state;
|
||||
for (; i < MAX_TEXTURES; i++)
|
||||
states[i] = NULL;
|
||||
}
|
||||
|
||||
gs_pixel_shader(device_t device, const char *file,
|
||||
const char *shaderString);
|
||||
};
|
||||
|
||||
struct gs_swap_chain {
|
||||
gs_device *device;
|
||||
uint32_t numBuffers;
|
||||
HWND hwnd;
|
||||
|
||||
gs_texture_2d target;
|
||||
gs_zstencil_buffer zs;
|
||||
ComPtr<IDXGISwapChain> swap;
|
||||
|
||||
void InitTarget(uint32_t cx, uint32_t cy);
|
||||
void InitZStencilBuffer(uint32_t cx, uint32_t cy);
|
||||
void Resize(uint32_t cx, uint32_t cy);
|
||||
void Init(gs_init_data *data);
|
||||
|
||||
inline gs_swap_chain()
|
||||
: device (NULL),
|
||||
numBuffers (0),
|
||||
hwnd (NULL)
|
||||
{
|
||||
}
|
||||
|
||||
gs_swap_chain(gs_device *device, gs_init_data *data);
|
||||
};
|
||||
|
||||
struct BlendState {
|
||||
bool blendEnabled;
|
||||
gs_blend_type srcFactor;
|
||||
gs_blend_type destFactor;
|
||||
|
||||
bool redEnabled;
|
||||
bool greenEnabled;
|
||||
bool blueEnabled;
|
||||
bool alphaEnabled;
|
||||
|
||||
inline BlendState()
|
||||
: blendEnabled (true),
|
||||
srcFactor (GS_BLEND_SRCALPHA),
|
||||
destFactor (GS_BLEND_INVSRCALPHA),
|
||||
redEnabled (true),
|
||||
greenEnabled (true),
|
||||
blueEnabled (true),
|
||||
alphaEnabled (true)
|
||||
{
|
||||
}
|
||||
|
||||
inline BlendState(const BlendState &state)
|
||||
{
|
||||
memcpy(this, &state, sizeof(BlendState));
|
||||
}
|
||||
};
|
||||
|
||||
struct SavedBlendState : BlendState {
|
||||
ComPtr<ID3D11BlendState> state;
|
||||
|
||||
inline SavedBlendState(const BlendState &val) : BlendState(val)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct StencilSide {
|
||||
gs_depth_test test;
|
||||
gs_stencil_op fail;
|
||||
gs_stencil_op zfail;
|
||||
gs_stencil_op zpass;
|
||||
|
||||
inline StencilSide()
|
||||
: test (GS_ALWAYS),
|
||||
fail (GS_KEEP),
|
||||
zfail (GS_KEEP),
|
||||
zpass (GS_KEEP)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct ZStencilState {
|
||||
bool depthEnabled;
|
||||
bool depthWriteEnabled;
|
||||
gs_depth_test depthFunc;
|
||||
|
||||
bool stencilEnabled;
|
||||
bool stencilWriteEnabled;
|
||||
StencilSide stencilFront;
|
||||
StencilSide stencilBack;
|
||||
|
||||
inline ZStencilState()
|
||||
: depthEnabled (true),
|
||||
depthWriteEnabled (true),
|
||||
depthFunc (GS_LESS),
|
||||
stencilEnabled (false),
|
||||
stencilWriteEnabled (true)
|
||||
{
|
||||
}
|
||||
|
||||
inline ZStencilState(const ZStencilState &state)
|
||||
{
|
||||
memcpy(this, &state, sizeof(ZStencilState));
|
||||
}
|
||||
};
|
||||
|
||||
struct SavedZStencilState : ZStencilState {
|
||||
ComPtr<ID3D11DepthStencilState> state;
|
||||
|
||||
inline SavedZStencilState(const ZStencilState &val)
|
||||
: ZStencilState (val)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct RasterState {
|
||||
gs_cull_mode cullMode;
|
||||
bool scissorEnabled;
|
||||
|
||||
inline RasterState()
|
||||
: cullMode (GS_BACK),
|
||||
scissorEnabled (false)
|
||||
{
|
||||
}
|
||||
|
||||
inline RasterState(const RasterState &state)
|
||||
{
|
||||
memcpy(this, &state, sizeof(RasterState));
|
||||
}
|
||||
};
|
||||
|
||||
struct SavedRasterState : RasterState {
|
||||
ComPtr<ID3D11RasterizerState> state;
|
||||
|
||||
inline SavedRasterState(const RasterState &val)
|
||||
: RasterState (val)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct mat4float {
|
||||
float mat[16];
|
||||
};
|
||||
|
||||
struct gs_device {
|
||||
ComPtr<IDXGIFactory1> factory;
|
||||
ComPtr<ID3D11Device> device;
|
||||
ComPtr<ID3D11DeviceContext> context;
|
||||
gs_swap_chain defaultSwap;
|
||||
|
||||
gs_texture_2d *curRenderTarget;
|
||||
gs_zstencil_buffer *curZStencilBuffer;
|
||||
int curRenderSide;
|
||||
gs_texture *curTextures[MAX_TEXTURES];
|
||||
gs_sampler_state *curSamplers[MAX_TEXTURES];
|
||||
gs_vertex_buffer *curVertexBuffer;
|
||||
gs_vertex_shader *curVertexShader;
|
||||
gs_index_buffer *curIndexBuffer;
|
||||
gs_pixel_shader *curPixelShader;
|
||||
gs_swap_chain *curSwapChain;
|
||||
|
||||
bool zstencilStateChanged;
|
||||
bool rasterStateChanged;
|
||||
bool blendStateChanged;
|
||||
ZStencilState zstencilState;
|
||||
RasterState rasterState;
|
||||
BlendState blendState;
|
||||
vector<SavedZStencilState> zstencilStates;
|
||||
vector<SavedRasterState> rasterStates;
|
||||
vector<SavedBlendState> blendStates;
|
||||
ID3D11DepthStencilState *curDepthStencilState;
|
||||
ID3D11RasterizerState *curRasterState;
|
||||
ID3D11BlendState *curBlendState;
|
||||
D3D11_PRIMITIVE_TOPOLOGY curToplogy;
|
||||
|
||||
gs_rect viewport;
|
||||
|
||||
vector<mat4float> projStack;
|
||||
|
||||
matrix4 curProjMatrix;
|
||||
matrix4 curViewMatrix;
|
||||
matrix4 curViewProjMatrix;
|
||||
|
||||
void InitFactory(uint32_t adapterIdx, IDXGIAdapter1 **adapter);
|
||||
void InitDevice(gs_init_data *data, IDXGIAdapter *adapter);
|
||||
|
||||
ID3D11DepthStencilState *AddZStencilState();
|
||||
ID3D11RasterizerState *AddRasterState();
|
||||
ID3D11BlendState *AddBlendState();
|
||||
void UpdateZStencilState();
|
||||
void UpdateRasterState();
|
||||
void UpdateBlendState();
|
||||
|
||||
inline void CopyTex(ID3D11Texture2D *dst, texture_t src);
|
||||
|
||||
void UpdateViewProjMatrix();
|
||||
|
||||
gs_device(gs_init_data *data);
|
||||
};
|
|
@ -0,0 +1,154 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "util/base.h"
|
||||
#include "GS_D3D11SubSystem.hpp"
|
||||
|
||||
static inline bool IsPow2(uint32_t num)
|
||||
{
|
||||
return num >= 2 && (num & (num-1)) == 0;
|
||||
}
|
||||
|
||||
void gs_texture_2d::InitSRD(D3D11_SUBRESOURCE_DATA *srd, void *data)
|
||||
{
|
||||
uint32_t rowSizeBytes = width * GetFormatBPP(format);
|
||||
uint32_t texSizeBytes = rowSizeBytes * height;
|
||||
|
||||
if (type == GS_TEXTURE_2D) {
|
||||
srd->pSysMem = (uint8_t*)data;
|
||||
srd->SysMemPitch = rowSizeBytes;
|
||||
srd->SysMemSlicePitch = texSizeBytes;
|
||||
|
||||
} else { /* GS_TEXTURE_CUBE */
|
||||
void **buffers = (void**)data;
|
||||
for (size_t i = 0; i < 6; i++) {
|
||||
srd[i].pSysMem = buffers[i];
|
||||
srd[i].SysMemPitch = rowSizeBytes;
|
||||
srd[i].SysMemSlicePitch = texSizeBytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gs_texture_2d::InitTexture(void *data)
|
||||
{
|
||||
D3D11_TEXTURE2D_DESC td;
|
||||
D3D11_SUBRESOURCE_DATA srd[6];
|
||||
HRESULT hr;
|
||||
|
||||
memset(&td, 0, sizeof(td));
|
||||
td.Width = width;
|
||||
td.Height = height;
|
||||
td.MipLevels = genMipmaps ? 0 : 1;
|
||||
td.ArraySize = type == GS_TEXTURE_CUBE ? 6 : 1;
|
||||
td.Format = dxgiFormat;
|
||||
td.BindFlags = D3D10_BIND_SHADER_RESOURCE;
|
||||
td.SampleDesc.Count = 1;
|
||||
td.CPUAccessFlags = isDynamic ? D3D11_CPU_ACCESS_WRITE : 0;
|
||||
td.Usage = isDynamic ? D3D11_USAGE_DYNAMIC :
|
||||
D3D11_USAGE_DEFAULT;
|
||||
|
||||
if (type == GS_TEXTURE_CUBE)
|
||||
td.MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE;
|
||||
|
||||
if (isRenderTarget || isGDICompatible)
|
||||
td.BindFlags |= D3D10_BIND_RENDER_TARGET;
|
||||
|
||||
if (data)
|
||||
InitSRD(srd, data);
|
||||
|
||||
hr = device->device->CreateTexture2D(&td, data ? srd : NULL,
|
||||
texture.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create 2D texture", hr);
|
||||
}
|
||||
|
||||
void gs_texture_2d::InitResourceView()
|
||||
{
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC resourceDesc;
|
||||
HRESULT hr;
|
||||
|
||||
memset(&resourceDesc, 0, sizeof(resourceDesc));
|
||||
resourceDesc.Format = dxgiFormat;
|
||||
|
||||
if (type == GS_TEXTURE_CUBE) {
|
||||
resourceDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURECUBE;
|
||||
resourceDesc.TextureCube.MipLevels = genMipmaps ? -1 : 1;
|
||||
} else {
|
||||
resourceDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
|
||||
resourceDesc.Texture2D.MipLevels = genMipmaps ? -1 : 1;
|
||||
}
|
||||
|
||||
hr = device->device->CreateShaderResourceView(texture, &resourceDesc,
|
||||
shaderRes.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create resource view", hr);
|
||||
}
|
||||
|
||||
void gs_texture_2d::InitRenderTargets()
|
||||
{
|
||||
HRESULT hr;
|
||||
if (type == GS_TEXTURE_2D) {
|
||||
hr = device->device->CreateRenderTargetView(texture, NULL,
|
||||
renderTarget[0].Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create render target view",
|
||||
hr);
|
||||
} else {
|
||||
D3D11_RENDER_TARGET_VIEW_DESC rtv;
|
||||
rtv.Format = dxgiFormat;
|
||||
rtv.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
|
||||
rtv.Texture2DArray.MipSlice = 0;
|
||||
rtv.Texture2DArray.ArraySize = 1;
|
||||
|
||||
for (UINT i = 0; i < 6; i++) {
|
||||
rtv.Texture2DArray.FirstArraySlice = i;
|
||||
hr = device->device->CreateRenderTargetView(texture,
|
||||
&rtv, renderTarget[i].Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create cube render "
|
||||
"target view", hr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gs_texture_2d::gs_texture_2d(device_t device, uint32_t width, uint32_t height,
|
||||
gs_color_format colorFormat, void *data, uint32_t flags,
|
||||
bool isCubeMap, bool gdiCompatible, bool shared)
|
||||
: gs_texture (device, isCubeMap ? GS_TEXTURE_CUBE : GS_TEXTURE_2D),
|
||||
width (width),
|
||||
height (height),
|
||||
format (colorFormat),
|
||||
dxgiFormat (ConvertGSTextureFormat(format)),
|
||||
isGDICompatible (gdiCompatible),
|
||||
isShared (shared),
|
||||
isDynamic ((flags & GS_DYNAMIC) != 0),
|
||||
isRenderTarget ((flags & GS_RENDERTARGET) != 0),
|
||||
genMipmaps ((flags & GS_BUILDMIPMAPS) != 0)
|
||||
{
|
||||
if (genMipmaps && (!IsPow2(width) || !IsPow2(height))) {
|
||||
blog(LOG_WARNING, "Cannot generate mipmaps for a "
|
||||
"non-power-of-two texture. Disabling "
|
||||
"mipmaps for this texture.");
|
||||
genMipmaps = false;
|
||||
}
|
||||
|
||||
InitTexture(data);
|
||||
InitResourceView();
|
||||
|
||||
if (isRenderTarget)
|
||||
InitRenderTargets();
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "util/base.h"
|
||||
#include "graphics/vec3.h"
|
||||
#include "GS_D3D11SubSystem.hpp"
|
||||
|
||||
static inline void PushBuffer(vector<ID3D11Buffer*> &buffers,
|
||||
vector<uint32_t> &strides, ID3D11Buffer *buffer,
|
||||
size_t elementSize, const char *name)
|
||||
{
|
||||
if (buffer) {
|
||||
buffers.push_back(buffer);
|
||||
strides.push_back((uint32_t)elementSize);
|
||||
} else {
|
||||
blog(LOG_ERROR, "This vertex shader requires a %s buffer",
|
||||
name);
|
||||
}
|
||||
}
|
||||
|
||||
void gs_vertex_buffer::FlushBuffer(ID3D11Buffer *buffer, void *array,
|
||||
size_t elementSize)
|
||||
{
|
||||
D3D11_MAPPED_SUBRESOURCE msr;
|
||||
HRESULT hr;
|
||||
|
||||
if (FAILED(hr = device->context->Map(buffer, 0,
|
||||
D3D11_MAP_WRITE_DISCARD, 0, &msr)))
|
||||
throw HRError("Failed to map buffer", hr);
|
||||
|
||||
memcpy(msr.pData, array, elementSize * vbd.data->num);
|
||||
device->context->Unmap(buffer, 0);
|
||||
}
|
||||
|
||||
void gs_vertex_buffer::MakeBufferList(gs_vertex_shader *shader,
|
||||
vector<ID3D11Buffer*> &buffers, vector<uint32_t> &strides)
|
||||
{
|
||||
PushBuffer(buffers, strides, vertexBuffer, sizeof(vec3), "point");
|
||||
|
||||
if (shader->hasNormals)
|
||||
PushBuffer(buffers, strides, vertexBuffer, sizeof(vec3),
|
||||
"normal");
|
||||
if (shader->hasColors)
|
||||
PushBuffer(buffers, strides, vertexBuffer, sizeof(vec3),
|
||||
"color");
|
||||
if (shader->hasTangents)
|
||||
PushBuffer(buffers, strides, vertexBuffer, sizeof(vec3),
|
||||
"tangent");
|
||||
if (shader->nTexUnits <= uvBuffers.size()) {
|
||||
for (size_t i = 0; i < shader->nTexUnits; i++) {
|
||||
buffers.push_back(uvBuffers[i]);
|
||||
strides.push_back((uint32_t)uvSizes[i]);
|
||||
}
|
||||
} else {
|
||||
blog(LOG_ERROR, "This vertex shader requires at least %u "
|
||||
"texture buffers.",
|
||||
(uint32_t)shader->nTexUnits);
|
||||
}
|
||||
}
|
||||
|
||||
inline void gs_vertex_buffer::InitBuffer(const size_t elementSize,
|
||||
const size_t numVerts, void *array, ID3D11Buffer **buffer)
|
||||
{
|
||||
D3D11_BUFFER_DESC bd;
|
||||
D3D11_SUBRESOURCE_DATA srd;
|
||||
HRESULT hr;
|
||||
|
||||
memset(&bd, 0, sizeof(bd));
|
||||
memset(&srd, 0, sizeof(srd));
|
||||
|
||||
bd.Usage = dynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT;
|
||||
bd.CPUAccessFlags = dynamic ? D3D11_CPU_ACCESS_WRITE : 0;
|
||||
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
||||
bd.ByteWidth = UINT(elementSize * numVerts);
|
||||
srd.pSysMem = array;
|
||||
|
||||
hr = device->device->CreateBuffer(&bd, &srd, buffer);
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create buffer", hr);
|
||||
}
|
||||
|
||||
gs_vertex_buffer::gs_vertex_buffer(device_t device, struct vb_data *data,
|
||||
uint32_t flags)
|
||||
: device (device),
|
||||
vbd (data),
|
||||
numVerts (data->num),
|
||||
dynamic ((flags & GS_DYNAMIC) != 0)
|
||||
{
|
||||
if (!data->num)
|
||||
throw "Cannot initialize vertex buffer with 0 vertices";
|
||||
if (!data->points)
|
||||
throw "No points specified for vertex buffer";
|
||||
|
||||
InitBuffer(sizeof(vec3), data->num, data->points,
|
||||
vertexBuffer.Assign());
|
||||
|
||||
if (data->normals)
|
||||
InitBuffer(sizeof(vec3), data->num, data->normals,
|
||||
normalBuffer.Assign());
|
||||
|
||||
if (data->tangents)
|
||||
InitBuffer(sizeof(vec3), data->num, data->tangents,
|
||||
tangentBuffer.Assign());
|
||||
|
||||
if (data->colors)
|
||||
InitBuffer(sizeof(uint32_t), data->num, data->colors,
|
||||
colorBuffer.Assign());
|
||||
|
||||
for (size_t i = 0; i < data->num_tex; i++) {
|
||||
struct tvertarray *tverts = data->tvarray+i;
|
||||
|
||||
if (tverts->width != 2 && tverts->width != 4)
|
||||
throw "Invalid texture vertex size specified";
|
||||
if (!tverts->array)
|
||||
throw "No texture vertices specified";
|
||||
|
||||
ComPtr<ID3D11Buffer> buffer;
|
||||
InitBuffer(tverts->width * sizeof(float), data->num,
|
||||
tverts->array, buffer.Assign());
|
||||
|
||||
uvBuffers.push_back(buffer);
|
||||
uvSizes.push_back(tverts->width * sizeof(float));
|
||||
}
|
||||
|
||||
if (!dynamic) {
|
||||
bfree(data);
|
||||
data = NULL;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "GS_D3D11SubSystem.hpp"
|
||||
|
||||
void gs_zstencil_buffer::InitBuffer()
|
||||
{
|
||||
D3D11_TEXTURE2D_DESC td;
|
||||
D3D11_DEPTH_STENCIL_VIEW_DESC dsvd;
|
||||
HRESULT hr;
|
||||
|
||||
memset(&td, 0, sizeof(td));
|
||||
td.Width = width;
|
||||
td.Height = height;
|
||||
td.MipLevels = 1;
|
||||
td.ArraySize = 1;
|
||||
td.Format = dxgiFormat;
|
||||
td.BindFlags = D3D11_BIND_DEPTH_STENCIL;
|
||||
td.SampleDesc.Count = 1;
|
||||
td.Usage = D3D11_USAGE_DEFAULT;
|
||||
|
||||
hr = device->device->CreateTexture2D(&td, NULL, texture.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create depth stencil texture", hr);
|
||||
|
||||
memset(&dsvd, 0, sizeof(dsvd));
|
||||
dsvd.Format = dxgiFormat;
|
||||
dsvd.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
|
||||
|
||||
hr = device->device->CreateDepthStencilView(texture, &dsvd,
|
||||
view.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create depth stencil view", hr);
|
||||
}
|
||||
|
||||
gs_zstencil_buffer::gs_zstencil_buffer(device_t device,
|
||||
uint32_t width, uint32_t height,
|
||||
gs_zstencil_format format)
|
||||
: device (device),
|
||||
width (width),
|
||||
height (height),
|
||||
format (format),
|
||||
dxgiFormat (ConvertGSZStencilFormat(format))
|
||||
{
|
||||
InitBuffer();
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
include ../config.mak
|
||||
|
||||
all: default
|
||||
|
||||
SRCFILES=GS_D3D11SubSystem.cpp \
|
||||
GS_D3D11IndexBuffer.cpp \
|
||||
GS_D3D11Shader.cpp \
|
||||
GS_D3D11ShaderProcessor.cpp \
|
||||
GS_D3D11StageSurf.cpp \
|
||||
GS_D3D11Texture2D.cpp \
|
||||
GS_D3D11VertexBuffer.cpp \
|
||||
GS_D3D11ZStencilBuffer.cpp
|
||||
|
||||
SONAME=../build/libobs-d3d11.$(SOEXT)
|
||||
|
||||
LD=g++ -o
|
||||
|
||||
CPPFLAGS += -iquote $(BASEINC)
|
||||
CPPFLAGS += -iquote ../libobs-graphics/
|
||||
CPPFLAGS += -isystem ./mingw/
|
||||
|
||||
LDFLAGS += -L../build/
|
||||
|
||||
ifdef monolithic
|
||||
LDFLAGS += -lobs
|
||||
else
|
||||
LDFLAGS += -lobs-util -lobs-graphics
|
||||
endif
|
||||
|
||||
.PHONY: all monolithic default clean
|
||||
|
||||
OBJS += $(SRCFILES:%.cpp=%.$(OBJ))
|
||||
|
||||
default: $(SONAME)
|
||||
|
||||
$(SONAME): .depend $(OBJS)
|
||||
$(LD)$@ $(LDFLAGS) $(OBJS)
|
||||
|
||||
.depend:
|
||||
@rm -f .depend
|
||||
@$(foreach SRC, $(addprefix $(SRCPATH)/, $(SRCFILES)), $(CCDEP) \
|
||||
-std=c++11 $(CPPFLAGS) $(SRC) -I$(BASEINC) \
|
||||
-MT $(SRC:$(SRCPATH)/%.cpp=%.$(OBJ)) -MM 1>> .depend;)
|
||||
|
||||
depend: .depend
|
||||
ifneq ($(wildcard .depend),)
|
||||
include .depend
|
||||
endif
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS) $(SONAME) *.a *.lib *.exp *.pdb .depend
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,38 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "axisang.h"
|
||||
#include "quat.h"
|
||||
|
||||
void axisang_from_quat(struct axisang *dst, const struct quat *q)
|
||||
{
|
||||
float len, leni;
|
||||
|
||||
len = q->x*q->x + q->y*q->y + q->z*q->z;
|
||||
if (!close_float(len, 0.0f, EPSILON)) {
|
||||
leni = 1.0f/sqrtf(len);
|
||||
dst->x = q->x * leni;
|
||||
dst->y = q->y * leni;
|
||||
dst->z = q->z * leni;
|
||||
dst->w = acosf(q->w)*2.0f;
|
||||
} else {
|
||||
dst->x = 0.0f;
|
||||
dst->y = 0.0f;
|
||||
dst->z = 0.0f;
|
||||
dst->w = 0.0f;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef AXISANG_H
|
||||
#define AXISANG_H
|
||||
|
||||
#include "../util/c99defs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct quat;
|
||||
|
||||
struct axisang {
|
||||
union {
|
||||
struct {float x, y, z, w;};
|
||||
float ptr[4];
|
||||
};
|
||||
};
|
||||
|
||||
static inline void axisang_zero(struct axisang *dst)
|
||||
{
|
||||
dst->x = 0.0f;
|
||||
dst->y = 0.0f;
|
||||
dst->z = 0.0f;
|
||||
dst->w = 0.0f;
|
||||
}
|
||||
|
||||
static inline void axisang_copy(struct axisang *dst, struct axisang *aa)
|
||||
{
|
||||
dst->x = aa->x;
|
||||
dst->y = aa->y;
|
||||
dst->z = aa->z;
|
||||
dst->w = aa->w;
|
||||
}
|
||||
|
||||
static inline void axisang_set(struct axisang *dst, float x, float y, float z,
|
||||
float w)
|
||||
{
|
||||
dst->x = x;
|
||||
dst->y = y;
|
||||
dst->z = z;
|
||||
dst->w = w;
|
||||
}
|
||||
|
||||
EXPORT void axisang_from_quat(struct axisang *dst, const struct quat *q);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
/* TODO: C++ math wrappers */
|
|
@ -0,0 +1,263 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "bounds.h"
|
||||
#include "matrix3.h"
|
||||
#include "plane.h"
|
||||
|
||||
void bounds_move(struct bounds *dst, const struct bounds *b,
|
||||
const struct vec3 *v)
|
||||
{
|
||||
vec3_add(&dst->min, &b->min, v);
|
||||
vec3_add(&dst->max, &b->max, v);
|
||||
}
|
||||
|
||||
void bounds_scale(struct bounds *dst, const struct bounds *b,
|
||||
const struct vec3 *v)
|
||||
{
|
||||
vec3_mul(&dst->min, &b->min, v);
|
||||
vec3_mul(&dst->max, &b->max, v);
|
||||
}
|
||||
|
||||
void bounds_merge(struct bounds *dst, const struct bounds *b1,
|
||||
const struct bounds *b2)
|
||||
{
|
||||
vec3_min(&dst->min, &b1->min, &b2->min);
|
||||
vec3_max(&dst->max, &b1->max, &b2->max);
|
||||
}
|
||||
|
||||
void bounds_merge_point(struct bounds *dst, const struct bounds *b,
|
||||
const struct vec3 *v)
|
||||
{
|
||||
vec3_min(&dst->min, &b->min, v);
|
||||
vec3_max(&dst->max, &b->max, v);
|
||||
}
|
||||
|
||||
void bounds_get_point(struct vec3 *dst, const struct bounds *b,
|
||||
unsigned int i)
|
||||
{
|
||||
if (i > 8)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Note:
|
||||
* 0 = min.x,min.y,min.z
|
||||
* 1 = min.x,min.y,MAX.z
|
||||
* 2 = min.x,MAX.y,min.z
|
||||
* 3 = min.x,MAX.y,MAX.z
|
||||
* 4 = MAX.x,min.y,min.z
|
||||
* 5 = MAX.x,min.y,MAX.z
|
||||
|
||||
* 6 = MAX.x,MAX.y,min.z
|
||||
* 7 = MAX.x,MAX.y,MAX.z
|
||||
*/
|
||||
|
||||
if(i > 3) {dst->x = b->max.x; i -= 4;}
|
||||
else {dst->x = b->min.x;}
|
||||
|
||||
if(i > 1) {dst->y = b->max.y; i -= 2;}
|
||||
else {dst->y = b->min.y;}
|
||||
|
||||
dst->z = (i == 1) ? b->max.z : b->min.z;
|
||||
}
|
||||
|
||||
void bounds_get_center(struct vec3 *dst, const struct bounds *b)
|
||||
{
|
||||
vec3_sub(dst, &b->max, &b->min);
|
||||
vec3_mulf(dst, dst, 0.5f);
|
||||
vec3_add(dst, dst, &b->min);
|
||||
}
|
||||
|
||||
void bounds_transform(struct bounds *dst, const struct bounds *b,
|
||||
const struct matrix3 *m)
|
||||
{
|
||||
struct bounds temp;
|
||||
bool b_init = false;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
struct vec3 p;
|
||||
bounds_get_point(&p, b, i);
|
||||
vec3_transform(&p, &p, m);
|
||||
|
||||
if (!b_init) {
|
||||
vec3_copy(&temp.min, &p);
|
||||
vec3_copy(&temp.max, &p);
|
||||
b_init = true;
|
||||
} else {
|
||||
if (p.x < temp.min.x)
|
||||
temp.min.x = p.x;
|
||||
else if(p.x > temp.max.x)
|
||||
temp.max.x = p.x;
|
||||
|
||||
if(p.y < temp.min.y)
|
||||
temp.min.y = p.y;
|
||||
else if(p.y > temp.max.y)
|
||||
temp.max.y = p.y;
|
||||
|
||||
if(p.z < temp.min.z)
|
||||
temp.min.z = p.z;
|
||||
else if(p.z > temp.max.z)
|
||||
temp.max.z = p.z;
|
||||
}
|
||||
}
|
||||
|
||||
bounds_copy(dst, &temp);
|
||||
}
|
||||
|
||||
bool bounds_intersection_ray(const struct bounds *b, const struct vec3 *orig,
|
||||
const struct vec3 *dir, float *t)
|
||||
{
|
||||
float t_max = M_INFINITE;
|
||||
float t_min = -M_INFINITE;
|
||||
struct vec3 center, max_offset, box_offset;
|
||||
int i;
|
||||
|
||||
bounds_get_center(¢er, b);
|
||||
vec3_sub(&max_offset, &b->max, ¢er);
|
||||
vec3_sub(&box_offset, ¢er, orig);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
float e = box_offset.ptr[i];
|
||||
float f = dir->ptr[i];
|
||||
|
||||
if (fabsf(f) > 0.0f) {
|
||||
float fi = 1.0f/f;
|
||||
float t1 = (e+max_offset.ptr[i])*fi;
|
||||
float t2 = (e-max_offset.ptr[i])*fi;
|
||||
if (t1 > t2) {
|
||||
if (t2 > t_min) t_min = t2;
|
||||
if (t1 < t_max) t_max = t1;
|
||||
} else {
|
||||
if (t1 > t_min) t_min = t1;
|
||||
if (t2 < t_max) t_max = t2;
|
||||
}
|
||||
if (t_min > t_max)
|
||||
return false;
|
||||
if (t_max < 0.0f)
|
||||
return false;
|
||||
} else if ((-e - max_offset.ptr[i]) > 0.0f ||
|
||||
(-e + max_offset.ptr[i]) < 0.0f) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
*t = (t_min > 0.0f) ? t_min : t_max;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bounds_intersection_line(const struct bounds *b, const struct vec3 *p1,
|
||||
const struct vec3 *p2, float *t)
|
||||
{
|
||||
struct vec3 dir;
|
||||
float length;
|
||||
|
||||
vec3_sub(&dir, p2, p1);
|
||||
length = vec3_len(&dir);
|
||||
if (length <= TINY_EPSILON)
|
||||
return false;
|
||||
|
||||
vec3_mulf(&dir, &dir, 1.0f/length);
|
||||
|
||||
if (!bounds_intersection_ray(b, p1, &dir, t))
|
||||
return false;
|
||||
|
||||
*t /= length;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bounds_plane_test(const struct bounds *b, const struct plane *p)
|
||||
{
|
||||
struct vec3 vmin, vmax;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (p->dir.ptr[i] >= 0.0f) {
|
||||
vmin.ptr[i] = b->min.ptr[i];
|
||||
vmax.ptr[i] = b->max.ptr[i];
|
||||
} else {
|
||||
vmin.ptr[i] = b->max.ptr[i];
|
||||
vmax.ptr[i] = b->min.ptr[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (vec3_plane_dist(&vmin, p) > 0.0f)
|
||||
return BOUNDS_OUTSIDE;
|
||||
|
||||
if (vec3_plane_dist(&vmax, p) >= 0.0f)
|
||||
return BOUNDS_PARTIAL;
|
||||
|
||||
return BOUNDS_INSIDE;
|
||||
}
|
||||
|
||||
bool bounds_under_plane(const struct bounds *b, const struct plane *p)
|
||||
{
|
||||
struct vec3 vmin;
|
||||
|
||||
vmin.x = (p->dir.x < 0.0f) ? b->max.x : b->min.x;
|
||||
vmin.y = (p->dir.y < 0.0f) ? b->max.y : b->min.y;
|
||||
vmin.z = (p->dir.z < 0.0f) ? b->max.z : b->min.z;
|
||||
|
||||
return (vec3_dot(&vmin, &p->dir) <= p->dist);
|
||||
}
|
||||
|
||||
bool bounds_intersects(const struct bounds *b, const struct bounds *test,
|
||||
float epsilon)
|
||||
{
|
||||
return ((b->min.x - test->max.x) <= epsilon) &&
|
||||
((test->min.x - b->max.x) <= epsilon) &&
|
||||
((b->min.y - test->max.y) <= epsilon) &&
|
||||
((test->min.y - b->max.y) <= epsilon) &&
|
||||
((b->min.z - test->max.z) <= epsilon) &&
|
||||
((test->min.z - b->max.z) <= epsilon);
|
||||
}
|
||||
|
||||
bool bounds_intersects_obb(const struct bounds *b, const struct bounds *test,
|
||||
const struct matrix3 *m, float epsilon)
|
||||
{
|
||||
struct bounds b_tr, test_tr;
|
||||
struct matrix3 m_inv;
|
||||
|
||||
matrix3_transpose(&m_inv, m);
|
||||
|
||||
bounds_transform(&b_tr, b, m);
|
||||
bounds_transform(&test_tr, test, &m_inv);
|
||||
|
||||
return bounds_intersects(b, &test_tr, epsilon) &&
|
||||
bounds_intersects(&b_tr, test, epsilon);
|
||||
}
|
||||
|
||||
static inline float vec3or_offset_len(const struct bounds *b,
|
||||
const struct vec3 *v)
|
||||
{
|
||||
struct vec3 temp1, temp2;
|
||||
vec3_sub(&temp1, &b->max, &b->min);
|
||||
vec3_abs(&temp2, v);
|
||||
return vec3_dot(&temp1, &temp2);
|
||||
}
|
||||
|
||||
float bounds_min_dist(const struct bounds *b, const struct plane *p)
|
||||
{
|
||||
struct vec3 center;
|
||||
float vec_len = vec3or_offset_len(b, &p->dir) * 0.5f;
|
||||
float center_dist;
|
||||
|
||||
bounds_get_center(¢er, b);
|
||||
center_dist = vec3_plane_dist(¢er, p);
|
||||
|
||||
return p->dist + center_dist - vec_len;
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef BOUNDS_H
|
||||
#define BOUNDS_H
|
||||
|
||||
#include "math-defs.h"
|
||||
#include "vec3.h"
|
||||
|
||||
/*
|
||||
* Axis Aligned Bounding Box
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BOUNDS_MAX_X 1
|
||||
#define BOUNDS_MAX_Y 2
|
||||
#define BOUNDS_MAX_Z 4
|
||||
|
||||
#define BOUNDS_OUTSIDE 1
|
||||
#define BOUNDS_INSIDE 2
|
||||
#define BOUNDS_PARTIAL 3
|
||||
|
||||
struct bounds {
|
||||
struct vec3 min, max;
|
||||
};
|
||||
|
||||
static inline void bounds_zero(struct bounds *dst)
|
||||
{
|
||||
vec3_zero(&dst->min);
|
||||
vec3_zero(&dst->max);
|
||||
}
|
||||
|
||||
static inline void bounds_copy(struct bounds *dst, const struct bounds *b)
|
||||
{
|
||||
vec3_copy(&dst->min, &b->min);
|
||||
vec3_copy(&dst->max, &b->max);
|
||||
}
|
||||
|
||||
EXPORT void bounds_move(struct bounds *dst, const struct bounds *b,
|
||||
const struct vec3 *v);
|
||||
|
||||
EXPORT void bounds_scale(struct bounds *dst, const struct bounds *b,
|
||||
const struct vec3 *v);
|
||||
|
||||
EXPORT void bounds_merge(struct bounds *dst, const struct bounds *b1,
|
||||
const struct bounds *b2);
|
||||
EXPORT void bounds_merge_point(struct bounds *dst, const struct bounds *b,
|
||||
const struct vec3 *v);
|
||||
|
||||
EXPORT void bounds_get_point(struct vec3 *dst, const struct bounds *b,
|
||||
unsigned int i);
|
||||
EXPORT void bounds_get_center(struct vec3 *dst, const struct bounds *b);
|
||||
|
||||
/**
|
||||
* Note: transforms as OBB, then converts back to AABB, which can result in
|
||||
* the actual size becoming larger than it originally was.
|
||||
*/
|
||||
EXPORT void bounds_transform(struct bounds *dst, const struct bounds *b,
|
||||
const struct matrix3 *m);
|
||||
|
||||
EXPORT bool bounds_intersection_ray(const struct bounds *b,
|
||||
const struct vec3 *orig, const struct vec3 *dir, float *t);
|
||||
EXPORT bool bounds_intersection_line(const struct bounds *b,
|
||||
const struct vec3 *p1, const struct vec3 *p2, float *t);
|
||||
|
||||
EXPORT bool bounds_plane_test(const struct bounds *b, const struct plane *p);
|
||||
EXPORT bool bounds_under_plane(const struct bounds *b,
|
||||
const struct plane *p);
|
||||
|
||||
static inline bool bounds_inside(const struct bounds *b,
|
||||
const struct bounds *test)
|
||||
{
|
||||
return test->min.x >= b->min.x &&
|
||||
test->min.y >= b->min.y &&
|
||||
test->min.z >= b->min.z &&
|
||||
test->max.x <= b->max.x &&
|
||||
test->max.y <= b->max.y &&
|
||||
test->max.z <= b->max.z;
|
||||
}
|
||||
|
||||
static inline bool bounds_vec3_inside(const struct bounds *b,
|
||||
const struct vec3 *v)
|
||||
{
|
||||
return v->x >= (b->min.x-EPSILON) &&
|
||||
v->x <= (b->max.x+EPSILON) &&
|
||||
v->y >= (b->min.y-EPSILON) &&
|
||||
v->y <= (b->max.y+EPSILON) &&
|
||||
v->z >= (b->min.z-EPSILON) &&
|
||||
v->z <= (b->max.z+EPSILON);
|
||||
}
|
||||
|
||||
EXPORT bool bounds_intersects(const struct bounds *b,
|
||||
const struct bounds *test, float epsilon);
|
||||
EXPORT bool bounds_intersects_obb(const struct bounds *b,
|
||||
const struct bounds *test, const struct matrix3 *m,
|
||||
float epsilon);
|
||||
|
||||
static inline bool bounds_intersects_ray(const struct bounds *b,
|
||||
const struct vec3 *orig, const struct vec3 *dir)
|
||||
{
|
||||
float t;
|
||||
return bounds_intersection_ray(b, orig, dir, &t);
|
||||
}
|
||||
|
||||
static inline bool bounds_intersects_line(const struct bounds *b,
|
||||
const struct vec3 *p1, const struct vec3 *p2)
|
||||
{
|
||||
float t;
|
||||
return bounds_intersection_line(b, p1, p2, &t);
|
||||
}
|
||||
|
||||
EXPORT float bounds_min_dist(const struct bounds *b, const struct plane *p);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,285 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef EFFECT_PARSER_H
|
||||
#define EFFECT_PARSER_H
|
||||
|
||||
#include "../util/darray.h"
|
||||
#include "../util/cf-parser.h"
|
||||
#include "graphics.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct dstr;
|
||||
|
||||
/*
|
||||
* The effect parser takes an effect file and converts it into individual
|
||||
* shaders for each technique's pass. It automatically writes all dependent
|
||||
* structures/functions/parameters to the shader and builds shader text for
|
||||
* each shader component of each pass.
|
||||
*/
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* effect parser var data */
|
||||
|
||||
struct ep_var {
|
||||
char *type, *name, *mapping;
|
||||
bool uniform;
|
||||
};
|
||||
|
||||
static inline void ep_var_init(struct ep_var *epv)
|
||||
{
|
||||
memset(epv, 0, sizeof(struct ep_var));
|
||||
}
|
||||
|
||||
static inline void ep_var_free(struct ep_var *epv)
|
||||
{
|
||||
bfree(epv->type);
|
||||
bfree(epv->name);
|
||||
bfree(epv->mapping);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* effect parser param data */
|
||||
|
||||
struct ep_param {
|
||||
char *type, *name;
|
||||
DARRAY(uint8_t) default_val;
|
||||
DARRAY(char*) properties;
|
||||
struct effect_param *param;
|
||||
bool is_const, is_property, is_texture, written;
|
||||
int writeorder, array_count;
|
||||
};
|
||||
|
||||
extern void ep_param_writevar(struct dstr *dst, struct darray *use_params);
|
||||
|
||||
static inline void ep_param_init(struct ep_param *epp,
|
||||
char *type, char *name,
|
||||
bool is_property, bool is_const)
|
||||
{
|
||||
epp->type = type;
|
||||
epp->name = name;
|
||||
epp->is_property = is_property;
|
||||
epp->is_const = is_const;
|
||||
epp->is_texture = (astrcmp_n(epp->type, "texture", 7) == 0);
|
||||
epp->written = false;
|
||||
epp->writeorder = false;
|
||||
epp->array_count = 0;
|
||||
da_init(epp->default_val);
|
||||
da_init(epp->properties);
|
||||
}
|
||||
|
||||
static inline void ep_param_free(struct ep_param *epp)
|
||||
{
|
||||
bfree(epp->type);
|
||||
bfree(epp->name);
|
||||
da_free(epp->default_val);
|
||||
da_free(epp->properties);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* effect parser struct data */
|
||||
|
||||
struct ep_struct {
|
||||
char *name;
|
||||
DARRAY(struct ep_var) vars; /* struct ep_var */
|
||||
bool written;
|
||||
};
|
||||
|
||||
static inline bool ep_struct_mapped(struct ep_struct *eps)
|
||||
{
|
||||
if (eps->vars.num > 0)
|
||||
return eps->vars.array[0].mapping != NULL;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void ep_struct_init(struct ep_struct *eps)
|
||||
{
|
||||
memset(eps, 0, sizeof(struct ep_struct));
|
||||
}
|
||||
|
||||
static inline void ep_struct_free(struct ep_struct *eps)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
bfree(eps->name);
|
||||
for (i = 0; i < eps->vars.num; i++)
|
||||
ep_var_free(eps->vars.array+i);
|
||||
da_free(eps->vars);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* effect parser sampler data */
|
||||
|
||||
struct ep_sampler {
|
||||
char *name;
|
||||
DARRAY(char*) states;
|
||||
DARRAY(char*) values;
|
||||
|
||||
bool written;
|
||||
};
|
||||
|
||||
static inline void ep_sampler_init(struct ep_sampler *eps)
|
||||
{
|
||||
memset(eps, 0, sizeof(struct ep_sampler));
|
||||
}
|
||||
|
||||
static inline void ep_sampler_free(struct ep_sampler *eps)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < eps->states.num; i++)
|
||||
bfree(eps->states.array[i]);
|
||||
for (i = 0; i < eps->values.num; i++)
|
||||
bfree(eps->values.array[i]);
|
||||
|
||||
bfree(eps->name);
|
||||
da_free(eps->states);
|
||||
da_free(eps->values);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* effect parser pass data */
|
||||
|
||||
struct ep_pass {
|
||||
char *name;
|
||||
DARRAY(struct cf_token) vertex_program;
|
||||
DARRAY(struct cf_token) fragment_program;
|
||||
struct effect_pass *pass;
|
||||
};
|
||||
|
||||
static inline void ep_pass_init(struct ep_pass *epp)
|
||||
{
|
||||
memset(epp, 0, sizeof(struct ep_pass));
|
||||
}
|
||||
|
||||
static inline void ep_pass_free(struct ep_pass *epp)
|
||||
{
|
||||
bfree(epp->name);
|
||||
da_free(epp->vertex_program);
|
||||
da_free(epp->fragment_program);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* effect parser technique data */
|
||||
|
||||
struct ep_technique {
|
||||
char *name;
|
||||
DARRAY(struct ep_pass) passes; /* struct ep_pass */
|
||||
};
|
||||
|
||||
static inline void ep_technique_init(struct ep_technique *ept)
|
||||
{
|
||||
memset(ept, 0, sizeof(struct ep_technique));
|
||||
}
|
||||
|
||||
static inline void ep_technique_free(struct ep_technique *ept)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < ept->passes.num; i++)
|
||||
ep_pass_free(ept->passes.array+i);
|
||||
|
||||
bfree(ept->name);
|
||||
da_free(ept->passes);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* effect parser function data */
|
||||
|
||||
struct ep_func {
|
||||
char *name, *ret_type, *mapping;
|
||||
struct dstr contents;
|
||||
DARRAY(struct ep_var) param_vars;
|
||||
DARRAY(const char*) func_deps;
|
||||
DARRAY(const char*) struct_deps;
|
||||
DARRAY(const char*) param_deps;
|
||||
DARRAY(const char*) sampler_deps;
|
||||
bool written;
|
||||
};
|
||||
|
||||
static inline void ep_func_init(struct ep_func *epf, char *ret_type,
|
||||
char *name)
|
||||
{
|
||||
memset(epf, 0, sizeof(struct ep_func));
|
||||
epf->name = name;
|
||||
epf->ret_type = ret_type;
|
||||
}
|
||||
|
||||
static inline void ep_func_free(struct ep_func *epf)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < epf->param_vars.num; i++)
|
||||
ep_var_free(epf->param_vars.array+i);
|
||||
|
||||
bfree(epf->name);
|
||||
bfree(epf->ret_type);
|
||||
bfree(epf->mapping);
|
||||
dstr_free(&epf->contents);
|
||||
da_free(epf->param_vars);
|
||||
da_free(epf->func_deps);
|
||||
da_free(epf->struct_deps);
|
||||
da_free(epf->param_deps);
|
||||
da_free(epf->sampler_deps);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
struct effect_parser {
|
||||
effect_t effect;
|
||||
|
||||
DARRAY(struct ep_param) params;
|
||||
DARRAY(struct ep_struct) structs;
|
||||
DARRAY(struct ep_func) funcs;
|
||||
DARRAY(struct ep_sampler) samplers;
|
||||
DARRAY(struct ep_technique) techniques;
|
||||
|
||||
/* internal vars */
|
||||
DARRAY(struct cf_lexer) files;
|
||||
DARRAY(struct cf_token) tokens;
|
||||
struct effect_pass *cur_pass;
|
||||
|
||||
struct cf_parser cfp;
|
||||
};
|
||||
|
||||
static inline void ep_init(struct effect_parser *ep)
|
||||
{
|
||||
da_init(ep->params);
|
||||
da_init(ep->structs);
|
||||
da_init(ep->funcs);
|
||||
da_init(ep->samplers);
|
||||
da_init(ep->techniques);
|
||||
da_init(ep->files);
|
||||
da_init(ep->tokens);
|
||||
|
||||
ep->cur_pass = NULL;
|
||||
cf_parser_init(&ep->cfp);
|
||||
}
|
||||
|
||||
extern void ep_free(struct effect_parser *ep);
|
||||
|
||||
extern bool ep_parse(struct effect_parser *ep, effect_t effect,
|
||||
const char *effect_string, const char *file);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,313 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "effect.h"
|
||||
#include "graphics-internal.h"
|
||||
#include "vec2.h"
|
||||
#include "vec3.h"
|
||||
#include "vec4.h"
|
||||
|
||||
void effect_destroy(effect_t effect)
|
||||
{
|
||||
if (effect) {
|
||||
effect_free(effect);
|
||||
bfree(effect);
|
||||
}
|
||||
}
|
||||
|
||||
technique_t effect_gettechnique(effect_t effect, const char *name)
|
||||
{
|
||||
size_t i;
|
||||
struct effect_technique *array = effect->techniques.array;
|
||||
|
||||
for (i = 0; i < effect->techniques.num; i++) {
|
||||
struct effect_technique *tech = array+i;
|
||||
if (strcmp(tech->name, name) == 0)
|
||||
return tech;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int technique_begin(technique_t tech)
|
||||
{
|
||||
tech->effect->cur_technique = tech;
|
||||
tech->effect->graphics->cur_effect = tech->effect;
|
||||
|
||||
return (int)tech->passes.num;
|
||||
}
|
||||
|
||||
void technique_end(technique_t tech)
|
||||
{
|
||||
struct gs_effect *effect = tech->effect;
|
||||
struct effect_param *params = effect->params.array;
|
||||
size_t i;
|
||||
|
||||
gs_load_vertexshader(NULL);
|
||||
gs_load_pixelshader(NULL);
|
||||
|
||||
tech->effect->cur_technique = NULL;
|
||||
tech->effect->graphics->cur_effect = NULL;
|
||||
|
||||
for (i = 0; i < effect->params.num; i++) {
|
||||
struct effect_param *param = params+i;
|
||||
|
||||
da_free(param->cur_val);
|
||||
param->changed = false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void reset_params(struct darray *shaderparams)
|
||||
{
|
||||
struct pass_shaderparam *params = shaderparams->array;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < shaderparams->num; i++)
|
||||
params[i].eparam->changed = false;
|
||||
}
|
||||
|
||||
static void upload_shader_params(shader_t shader, struct darray *pass_params,
|
||||
bool changed_only)
|
||||
{
|
||||
struct pass_shaderparam *params = pass_params->array;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < pass_params->num; i++) {
|
||||
struct pass_shaderparam *param = params+i;
|
||||
struct effect_param *eparam = param->eparam;
|
||||
sparam_t sparam = param->sparam;
|
||||
|
||||
if (changed_only && !eparam->changed)
|
||||
continue;
|
||||
|
||||
if (!eparam->cur_val.num) {
|
||||
if (eparam->default_val.num)
|
||||
da_copy(eparam->cur_val, eparam->default_val);
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
shader_setval(shader, sparam, eparam->cur_val.array,
|
||||
eparam->cur_val.num);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void upload_parameters(struct gs_effect *effect,
|
||||
bool changed_only)
|
||||
{
|
||||
struct darray *vshader_params, *pshader_params;
|
||||
|
||||
if (!effect->cur_pass)
|
||||
return;
|
||||
|
||||
vshader_params = &effect->cur_pass->vertshader_params.da;
|
||||
pshader_params = &effect->cur_pass->pixelshader_params.da;
|
||||
|
||||
upload_shader_params(effect->cur_pass->vertshader, vshader_params,
|
||||
changed_only);
|
||||
upload_shader_params(effect->cur_pass->pixelshader, pshader_params,
|
||||
changed_only);
|
||||
reset_params(vshader_params);
|
||||
reset_params(pshader_params);
|
||||
}
|
||||
|
||||
void effect_updateparams(effect_t effect)
|
||||
{
|
||||
upload_parameters(effect, true);
|
||||
}
|
||||
|
||||
bool technique_beginpass(technique_t tech, size_t idx)
|
||||
{
|
||||
struct effect_pass *passes;
|
||||
struct effect_pass *cur_pass;
|
||||
|
||||
if (idx >= tech->passes.num)
|
||||
return false;
|
||||
|
||||
passes = tech->passes.array;
|
||||
cur_pass = passes+idx;
|
||||
|
||||
tech->effect->cur_pass = cur_pass;
|
||||
gs_load_vertexshader(cur_pass->vertshader);
|
||||
gs_load_pixelshader(cur_pass->pixelshader);
|
||||
upload_parameters(tech->effect, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool technique_beginpassbyname(technique_t tech,
|
||||
const char *name)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < tech->passes.num; i++) {
|
||||
struct effect_pass *pass = tech->passes.array+i;
|
||||
if (strcmp(pass->name, name) == 0) {
|
||||
technique_beginpass(tech, (int)i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void clear_tex_params(shader_t shader, struct darray *in_params)
|
||||
{
|
||||
struct pass_shaderparam *params = in_params->array;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < in_params->num; i++) {
|
||||
struct pass_shaderparam *param = params+i;
|
||||
struct shader_param_info info;
|
||||
|
||||
shader_getparaminfo(shader, param->sparam, &info);
|
||||
if (info.type == SHADER_PARAM_TEXTURE)
|
||||
shader_settexture(shader, param->sparam, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void technique_endpass(technique_t tech)
|
||||
{
|
||||
struct effect_pass *pass = tech->effect->cur_pass;
|
||||
if (!pass)
|
||||
return;
|
||||
|
||||
clear_tex_params(pass->vertshader, &pass->vertshader_params.da);
|
||||
clear_tex_params(pass->pixelshader, &pass->pixelshader_params.da);
|
||||
tech->effect->cur_pass = NULL;
|
||||
}
|
||||
|
||||
int effect_numparams(effect_t effect)
|
||||
{
|
||||
return (int)effect->params.num;
|
||||
}
|
||||
|
||||
eparam_t effect_getparambyidx(effect_t effect, size_t param)
|
||||
{
|
||||
struct effect_param *params = effect->params.array;
|
||||
|
||||
if (param >= effect->params.num)
|
||||
return NULL;
|
||||
|
||||
return params+param;
|
||||
}
|
||||
|
||||
eparam_t effect_getparambyname(effect_t effect, const char *name)
|
||||
{
|
||||
struct effect_param *params = effect->params.array;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < effect->params.num; i++) {
|
||||
struct effect_param *param = params+i;
|
||||
|
||||
if (strcmp(param->name, name) == 0)
|
||||
return param;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void effect_getparaminfo(effect_t effect, eparam_t param,
|
||||
struct effect_param_info *info)
|
||||
{
|
||||
info->name = param->name;
|
||||
info->type = param->type;
|
||||
}
|
||||
|
||||
eparam_t effect_getviewprojmatrix(effect_t effect)
|
||||
{
|
||||
return effect->view_proj;
|
||||
}
|
||||
|
||||
eparam_t effect_getworldmatrix(effect_t effect)
|
||||
{
|
||||
return effect->world;
|
||||
}
|
||||
|
||||
static inline void effect_setval_inline(effect_t effect, eparam_t param,
|
||||
const void *data, size_t size)
|
||||
{
|
||||
bool size_changed = param->cur_val.num != size;
|
||||
if (size_changed)
|
||||
da_resize(param->cur_val, size);
|
||||
|
||||
if (size_changed || memcmp(param->cur_val.array, data, size) != 0) {
|
||||
memcpy(param->cur_val.array, data, size);
|
||||
param->changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
void effect_setbool(effect_t effect, eparam_t param, bool val)
|
||||
{
|
||||
effect_setval_inline(effect, param, &val, sizeof(bool));
|
||||
}
|
||||
|
||||
void effect_setfloat(effect_t effect, eparam_t param, float val)
|
||||
{
|
||||
effect_setval_inline(effect, param, &val, sizeof(float));
|
||||
}
|
||||
|
||||
void effect_setint(effect_t effect, eparam_t param, int val)
|
||||
{
|
||||
effect_setval_inline(effect, param, &val, sizeof(int));
|
||||
}
|
||||
|
||||
void effect_setmatrix3(effect_t effect, eparam_t param,
|
||||
const struct matrix3 *val)
|
||||
{
|
||||
effect_setval_inline(effect, param, val, sizeof(struct matrix3));
|
||||
}
|
||||
|
||||
void effect_setmatrix4(effect_t effect, eparam_t param,
|
||||
const struct matrix4 *val)
|
||||
{
|
||||
effect_setval_inline(effect, param, val, sizeof(struct matrix4));
|
||||
}
|
||||
|
||||
void effect_setvec2(effect_t effect, eparam_t param,
|
||||
const struct vec2 *val)
|
||||
{
|
||||
effect_setval_inline(effect, param, val, sizeof(struct vec2));
|
||||
}
|
||||
|
||||
void effect_setvec3(effect_t effect, eparam_t param,
|
||||
const struct vec3 *val)
|
||||
{
|
||||
effect_setval_inline(effect, param, val, sizeof(float) * 3);
|
||||
}
|
||||
|
||||
void effect_setvec4(effect_t effect, eparam_t param,
|
||||
const struct vec4 *val)
|
||||
{
|
||||
effect_setval_inline(effect, param, val, sizeof(struct vec4));
|
||||
}
|
||||
|
||||
void effect_settexture(effect_t effect, eparam_t param, texture_t val)
|
||||
{
|
||||
effect_setval_inline(effect, param, &val, sizeof(texture_t));
|
||||
}
|
||||
|
||||
void effect_setval(effect_t effect, eparam_t param, const void *val,
|
||||
size_t size)
|
||||
{
|
||||
effect_setval_inline(effect, param, val, size);
|
||||
}
|
||||
|
||||
void effect_setdefault(effect_t effect, eparam_t param)
|
||||
{
|
||||
effect_setval_inline(effect, param, param->default_val.array,
|
||||
param->default_val.num);
|
||||
}
|
|
@ -0,0 +1,181 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef EFFECT_H
|
||||
#define EFFECT_H
|
||||
|
||||
#include "effect-parser.h"
|
||||
#include "graphics.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Effects introduce a means of bundling together shader text into one
|
||||
* file with shared functions and parameters. This is done because often
|
||||
* shaders must be duplicated when you need to alter minor aspects of the code
|
||||
* that cannot be done via constants. Effects allow developers to easily
|
||||
* switch shaders and set constants that can be used between shaders.
|
||||
*
|
||||
* Effects are built via the effect parser, and shaders are automatically
|
||||
* generated for each technique's pass.
|
||||
*/
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
enum effect_section {
|
||||
EFFECT_PARAM,
|
||||
EFFECT_TECHNIQUE,
|
||||
EFFECT_SAMPLER,
|
||||
EFFECT_PASS
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
struct effect_param {
|
||||
char *name;
|
||||
enum effect_section section;
|
||||
|
||||
enum shader_param_type type;
|
||||
|
||||
bool changed;
|
||||
DARRAY(uint8_t) cur_val;
|
||||
DARRAY(uint8_t) default_val;
|
||||
|
||||
/*char *full_name;
|
||||
float scroller_min, scroller_max, scroller_inc, scroller_mul;*/
|
||||
};
|
||||
|
||||
static inline void effect_param_init(struct effect_param *param)
|
||||
{
|
||||
memset(param, 0, sizeof(struct effect_param));
|
||||
}
|
||||
|
||||
static inline void effect_param_free(struct effect_param *param)
|
||||
{
|
||||
bfree(param->name);
|
||||
//bfree(param->full_name);
|
||||
da_free(param->cur_val);
|
||||
da_free(param->default_val);
|
||||
}
|
||||
|
||||
EXPORT void effect_param_parse_property(eparam_t param,
|
||||
const char *property);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
struct pass_shaderparam {
|
||||
struct effect_param *eparam;
|
||||
sparam_t sparam;
|
||||
};
|
||||
|
||||
struct effect_pass {
|
||||
char *name;
|
||||
enum effect_section section;
|
||||
|
||||
shader_t vertshader;
|
||||
shader_t pixelshader;
|
||||
DARRAY(struct pass_shaderparam) vertshader_params;
|
||||
DARRAY(struct pass_shaderparam) pixelshader_params;
|
||||
};
|
||||
|
||||
static inline void effect_pass_init(struct effect_pass *pass)
|
||||
{
|
||||
memset(pass, 0, sizeof(struct effect_pass));
|
||||
}
|
||||
|
||||
static inline void effect_pass_free(struct effect_pass *pass)
|
||||
{
|
||||
bfree(pass->name);
|
||||
da_free(pass->vertshader_params);
|
||||
da_free(pass->pixelshader_params);
|
||||
shader_destroy(pass->vertshader);
|
||||
shader_destroy(pass->pixelshader);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
struct effect_technique {
|
||||
char *name;
|
||||
enum effect_section section;
|
||||
struct gs_effect *effect;
|
||||
|
||||
DARRAY(struct effect_pass) passes;
|
||||
};
|
||||
|
||||
static inline void effect_technique_init(struct effect_technique *t)
|
||||
{
|
||||
memset(t, 0, sizeof(struct effect_technique));
|
||||
}
|
||||
|
||||
static inline void effect_technique_free(struct effect_technique *t)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < t->passes.num; i++)
|
||||
effect_pass_free(t->passes.array+i);
|
||||
da_free(t->passes);
|
||||
bfree(t->name);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
struct gs_effect {
|
||||
bool processing;
|
||||
char *effect_path, *effect_dir;
|
||||
|
||||
DARRAY(struct effect_param) params;
|
||||
DARRAY(struct effect_technique) techniques;
|
||||
|
||||
struct effect_technique *cur_technique;
|
||||
struct effect_pass *cur_pass;
|
||||
|
||||
eparam_t view_proj, world, scale;
|
||||
graphics_t graphics;
|
||||
};
|
||||
|
||||
static inline void effect_init(effect_t effect)
|
||||
{
|
||||
memset(effect, 0, sizeof(struct gs_effect));
|
||||
}
|
||||
|
||||
static inline void effect_free(effect_t effect)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < effect->params.num; i++)
|
||||
effect_param_free(effect->params.array+i);
|
||||
for (i = 0; i < effect->techniques.num; i++)
|
||||
effect_technique_free(effect->techniques.array+i);
|
||||
|
||||
da_free(effect->params);
|
||||
da_free(effect->techniques);
|
||||
|
||||
bfree(effect->effect_path);
|
||||
bfree(effect->effect_dir);
|
||||
effect->effect_path = NULL;
|
||||
effect->effect_dir = NULL;
|
||||
}
|
||||
|
||||
EXPORT void effect_upload_params(effect_t effect, bool changed_only);
|
||||
EXPORT void effect_upload_shader_params(effect_t effect, shader_t shader,
|
||||
struct darray *pass_params, bool changed_only);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,162 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "../util/base.h"
|
||||
#include "../util/dstr.h"
|
||||
#include "../util/platform.h"
|
||||
#include "graphics-internal.h"
|
||||
|
||||
#define GRAPHICS_IMPORT(func) \
|
||||
do { \
|
||||
exports->func = os_dlsym(module, #func); \
|
||||
if (!exports->func) { \
|
||||
success = false; \
|
||||
blog(LOG_ERROR, "Could not load function '%s' from " \
|
||||
"module '%s'", #func, module_name); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
bool load_graphics_imports(struct gs_exports *exports, void *module,
|
||||
const char *module_name)
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
GRAPHICS_IMPORT(device_create);
|
||||
GRAPHICS_IMPORT(device_destroy);
|
||||
GRAPHICS_IMPORT(device_create_swapchain);
|
||||
GRAPHICS_IMPORT(device_resize);
|
||||
GRAPHICS_IMPORT(device_getsize);
|
||||
GRAPHICS_IMPORT(device_getwidth);
|
||||
GRAPHICS_IMPORT(device_getheight);
|
||||
GRAPHICS_IMPORT(device_create_texture);
|
||||
GRAPHICS_IMPORT(device_create_cubetexture);
|
||||
GRAPHICS_IMPORT(device_create_volumetexture);
|
||||
GRAPHICS_IMPORT(device_create_zstencil);
|
||||
GRAPHICS_IMPORT(device_create_stagesurface);
|
||||
GRAPHICS_IMPORT(device_create_samplerstate);
|
||||
GRAPHICS_IMPORT(device_create_vertexshader);
|
||||
GRAPHICS_IMPORT(device_create_pixelshader);
|
||||
GRAPHICS_IMPORT(device_create_vertexbuffer);
|
||||
GRAPHICS_IMPORT(device_create_indexbuffer);
|
||||
GRAPHICS_IMPORT(device_gettexturetype);
|
||||
GRAPHICS_IMPORT(device_load_vertexbuffer);
|
||||
GRAPHICS_IMPORT(device_load_indexbuffer);
|
||||
GRAPHICS_IMPORT(device_load_texture);
|
||||
GRAPHICS_IMPORT(device_load_samplerstate);
|
||||
GRAPHICS_IMPORT(device_load_vertexshader);
|
||||
GRAPHICS_IMPORT(device_load_pixelshader);
|
||||
GRAPHICS_IMPORT(device_load_defaultsamplerstate);
|
||||
GRAPHICS_IMPORT(device_getvertexshader);
|
||||
GRAPHICS_IMPORT(device_getpixelshader);
|
||||
GRAPHICS_IMPORT(device_getrendertarget);
|
||||
GRAPHICS_IMPORT(device_getzstenciltarget);
|
||||
GRAPHICS_IMPORT(device_setrendertarget);
|
||||
GRAPHICS_IMPORT(device_setcuberendertarget);
|
||||
GRAPHICS_IMPORT(device_copy_texture);
|
||||
GRAPHICS_IMPORT(device_stage_texture);
|
||||
GRAPHICS_IMPORT(device_beginscene);
|
||||
GRAPHICS_IMPORT(device_draw);
|
||||
GRAPHICS_IMPORT(device_load_swapchain);
|
||||
GRAPHICS_IMPORT(device_endscene);
|
||||
GRAPHICS_IMPORT(device_clear);
|
||||
GRAPHICS_IMPORT(device_present);
|
||||
GRAPHICS_IMPORT(device_setcullmode);
|
||||
GRAPHICS_IMPORT(device_getcullmode);
|
||||
GRAPHICS_IMPORT(device_enable_blending);
|
||||
GRAPHICS_IMPORT(device_enable_depthtest);
|
||||
GRAPHICS_IMPORT(device_enable_stenciltest);
|
||||
GRAPHICS_IMPORT(device_enable_stencilwrite);
|
||||
GRAPHICS_IMPORT(device_enable_color);
|
||||
GRAPHICS_IMPORT(device_blendfunction);
|
||||
GRAPHICS_IMPORT(device_depthfunction);
|
||||
GRAPHICS_IMPORT(device_stencilfunction);
|
||||
GRAPHICS_IMPORT(device_stencilop);
|
||||
GRAPHICS_IMPORT(device_enable_fullscreen);
|
||||
GRAPHICS_IMPORT(device_fullscreen_enabled);
|
||||
GRAPHICS_IMPORT(device_setdisplaymode);
|
||||
GRAPHICS_IMPORT(device_getdisplaymode);
|
||||
GRAPHICS_IMPORT(device_setcolorramp);
|
||||
GRAPHICS_IMPORT(device_setviewport);
|
||||
GRAPHICS_IMPORT(device_getviewport);
|
||||
GRAPHICS_IMPORT(device_setscissorrect);
|
||||
GRAPHICS_IMPORT(device_ortho);
|
||||
GRAPHICS_IMPORT(device_frustum);
|
||||
GRAPHICS_IMPORT(device_perspective);
|
||||
GRAPHICS_IMPORT(device_projection_push);
|
||||
GRAPHICS_IMPORT(device_projection_pop);
|
||||
|
||||
GRAPHICS_IMPORT(swapchain_destroy);
|
||||
|
||||
GRAPHICS_IMPORT(texture_destroy);
|
||||
GRAPHICS_IMPORT(texture_getwidth);
|
||||
GRAPHICS_IMPORT(texture_getheight);
|
||||
GRAPHICS_IMPORT(texture_getcolorformat);
|
||||
GRAPHICS_IMPORT(texture_map);
|
||||
GRAPHICS_IMPORT(texture_unmap);
|
||||
|
||||
GRAPHICS_IMPORT(cubetexture_destroy);
|
||||
GRAPHICS_IMPORT(cubetexture_getsize);
|
||||
GRAPHICS_IMPORT(cubetexture_getcolorformat);
|
||||
|
||||
GRAPHICS_IMPORT(volumetexture_destroy);
|
||||
GRAPHICS_IMPORT(volumetexture_getwidth);
|
||||
GRAPHICS_IMPORT(volumetexture_getheight);
|
||||
GRAPHICS_IMPORT(volumetexture_getdepth);
|
||||
GRAPHICS_IMPORT(volumetexture_getcolorformat);
|
||||
|
||||
GRAPHICS_IMPORT(stagesurface_destroy);
|
||||
GRAPHICS_IMPORT(stagesurface_getwidth);
|
||||
GRAPHICS_IMPORT(stagesurface_getheight);
|
||||
GRAPHICS_IMPORT(stagesurface_getcolorformat);
|
||||
GRAPHICS_IMPORT(stagesurface_map);
|
||||
GRAPHICS_IMPORT(stagesurface_unmap);
|
||||
|
||||
GRAPHICS_IMPORT(zstencil_destroy);
|
||||
|
||||
GRAPHICS_IMPORT(samplerstate_destroy);
|
||||
|
||||
GRAPHICS_IMPORT(vertexbuffer_destroy);
|
||||
GRAPHICS_IMPORT(vertexbuffer_flush);
|
||||
GRAPHICS_IMPORT(vertexbuffer_getdata);
|
||||
|
||||
GRAPHICS_IMPORT(indexbuffer_destroy);
|
||||
GRAPHICS_IMPORT(indexbuffer_flush);
|
||||
GRAPHICS_IMPORT(indexbuffer_getdata);
|
||||
GRAPHICS_IMPORT(indexbuffer_numindices);
|
||||
GRAPHICS_IMPORT(indexbuffer_gettype);
|
||||
|
||||
GRAPHICS_IMPORT(shader_destroy);
|
||||
GRAPHICS_IMPORT(shader_numparams);
|
||||
GRAPHICS_IMPORT(shader_getparambyidx);
|
||||
GRAPHICS_IMPORT(shader_getparambyname);
|
||||
GRAPHICS_IMPORT(shader_getparaminfo);
|
||||
GRAPHICS_IMPORT(shader_getviewprojmatrix);
|
||||
GRAPHICS_IMPORT(shader_getworldmatrix);
|
||||
GRAPHICS_IMPORT(shader_setbool);
|
||||
GRAPHICS_IMPORT(shader_setfloat);
|
||||
GRAPHICS_IMPORT(shader_setint);
|
||||
GRAPHICS_IMPORT(shader_setmatrix3);
|
||||
GRAPHICS_IMPORT(shader_setmatrix4);
|
||||
GRAPHICS_IMPORT(shader_setvec2);
|
||||
GRAPHICS_IMPORT(shader_setvec3);
|
||||
GRAPHICS_IMPORT(shader_setvec4);
|
||||
GRAPHICS_IMPORT(shader_settexture);
|
||||
GRAPHICS_IMPORT(shader_setval);
|
||||
GRAPHICS_IMPORT(shader_setdefault);
|
||||
|
||||
return success;
|
||||
}
|
|
@ -0,0 +1,229 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef GRAPHICS_INTERNAL_H
|
||||
#define GRAPHICS_INTERNAL_H
|
||||
|
||||
#include "../util/darray.h"
|
||||
#include "graphics.h"
|
||||
#include "matrix3.h"
|
||||
#include "matrix4.h"
|
||||
|
||||
struct gs_exports {
|
||||
device_t (*device_create)(struct gs_init_data *data);
|
||||
void (*device_destroy)(device_t device);
|
||||
swapchain_t (*device_create_swapchain)(device_t device,
|
||||
struct gs_init_data *data);
|
||||
void (*device_resize)(device_t device, uint32_t x, uint32_t y);
|
||||
void (*device_getsize)(device_t device, uint32_t *x, uint32_t *y);
|
||||
uint32_t (*device_getwidth)(device_t device);
|
||||
uint32_t (*device_getheight)(device_t device);
|
||||
texture_t (*device_create_texture)(device_t device, uint32_t width,
|
||||
uint32_t height, enum gs_color_format color_format,
|
||||
void *data, uint32_t flags);
|
||||
texture_t (*device_create_cubetexture)(device_t device, uint32_t size,
|
||||
enum gs_color_format color_format, void *data[6],
|
||||
uint32_t flags);
|
||||
texture_t (*device_create_volumetexture)(device_t device,
|
||||
uint32_t width, uint32_t height, uint32_t depth,
|
||||
enum gs_color_format color_format, void *data,
|
||||
uint32_t flags);
|
||||
zstencil_t (*device_create_zstencil)(device_t device,
|
||||
uint32_t width, uint32_t height,
|
||||
enum gs_zstencil_format format);
|
||||
stagesurf_t (*device_create_stagesurface)(device_t device,
|
||||
uint32_t width, uint32_t height,
|
||||
enum gs_color_format color_format);
|
||||
samplerstate_t (*device_create_samplerstate)(device_t device,
|
||||
struct gs_sampler_info *info);
|
||||
shader_t (*device_create_vertexshader)(device_t device,
|
||||
const char *shader, const char *file,
|
||||
char **error_string);
|
||||
shader_t (*device_create_pixelshader)(device_t device,
|
||||
const char *shader, const char *file,
|
||||
char **error_string);
|
||||
vertbuffer_t (*device_create_vertexbuffer)(device_t device,
|
||||
struct vb_data *data, uint32_t flags);
|
||||
indexbuffer_t (*device_create_indexbuffer)(device_t device,
|
||||
enum gs_index_type type, void *indices, size_t num,
|
||||
uint32_t flags);
|
||||
enum gs_texture_type (*device_gettexturetype)(device_t device,
|
||||
texture_t texture);
|
||||
void (*device_load_vertexbuffer)(device_t device,
|
||||
vertbuffer_t vertbuffer);
|
||||
void (*device_load_indexbuffer)(device_t device,
|
||||
indexbuffer_t indexbuffer);
|
||||
void (*device_load_texture)(device_t device, texture_t tex, int unit);
|
||||
void (*device_load_samplerstate)(device_t device,
|
||||
samplerstate_t samplerstate, int unit);
|
||||
void (*device_load_vertexshader)(device_t device, shader_t vertshader);
|
||||
void (*device_load_pixelshader)(device_t device, shader_t pixelshader);
|
||||
void (*device_load_defaultsamplerstate)(device_t device, bool b_3d,
|
||||
int unit);
|
||||
shader_t (*device_getvertexshader)(device_t device);
|
||||
shader_t (*device_getpixelshader)(device_t device);
|
||||
texture_t (*device_getrendertarget)(device_t device);
|
||||
zstencil_t (*device_getzstenciltarget)(device_t device);
|
||||
void (*device_setrendertarget)(device_t device, texture_t tex,
|
||||
zstencil_t zstencil);
|
||||
void (*device_setcuberendertarget)(device_t device, texture_t cubetex,
|
||||
int side, zstencil_t zstencil);
|
||||
void (*device_copy_texture)(device_t device, texture_t dst,
|
||||
texture_t src);
|
||||
void (*device_stage_texture)(device_t device, stagesurf_t dst,
|
||||
texture_t src);
|
||||
void (*device_beginscene)(device_t device);
|
||||
void (*device_draw)(device_t device, enum gs_draw_mode draw_mode,
|
||||
uint32_t start_vert, uint32_t num_verts);
|
||||
void (*device_endscene)(device_t device);
|
||||
void (*device_load_swapchain)(device_t device, swapchain_t swaphchain);
|
||||
void (*device_clear)(device_t device, uint32_t clear_flags,
|
||||
struct vec4 *color, float depth, uint8_t stencil);
|
||||
void (*device_present)(device_t device);
|
||||
void (*device_setcullmode)(device_t device, enum gs_cull_mode mode);
|
||||
enum gs_cull_mode (*device_getcullmode)(device_t device);
|
||||
void (*device_enable_blending)(device_t device, bool enable);
|
||||
void (*device_enable_depthtest)(device_t device, bool enable);
|
||||
void (*device_enable_stenciltest)(device_t device, bool enable);
|
||||
void (*device_enable_stencilwrite)(device_t device, bool enable);
|
||||
void (*device_enable_color)(device_t device, bool red, bool blue,
|
||||
bool green, bool alpha);
|
||||
void (*device_blendfunction)(device_t device, enum gs_blend_type src,
|
||||
enum gs_blend_type dest);
|
||||
void (*device_depthfunction)(device_t device, enum gs_depth_test test);
|
||||
void (*device_stencilfunction)(device_t device,
|
||||
enum gs_stencil_side side, enum gs_depth_test test);
|
||||
void (*device_stencilop)(device_t device, enum gs_stencil_side side,
|
||||
enum gs_stencil_op fail, enum gs_stencil_op zfail,
|
||||
enum gs_stencil_op zpass);
|
||||
void (*device_enable_fullscreen)(device_t device, bool enable);
|
||||
int (*device_fullscreen_enabled)(device_t device);
|
||||
void (*device_setdisplaymode)(device_t device,
|
||||
const struct gs_display_mode *mode);
|
||||
void (*device_getdisplaymode)(device_t device,
|
||||
struct gs_display_mode *mode);
|
||||
void (*device_setcolorramp)(device_t device, float gamma,
|
||||
float brightness, float contrast);
|
||||
void (*device_setviewport)(device_t device, int x, int y, int width,
|
||||
int height);
|
||||
void (*device_getviewport)(device_t device, struct gs_rect *rect);
|
||||
void (*device_setscissorrect)(device_t device, struct gs_rect *rect);
|
||||
void (*device_ortho)(device_t device, float left, float right,
|
||||
float top, float bottom, float znear, float zfar);
|
||||
void (*device_frustum)(device_t device, float left, float right,
|
||||
float top, float bottom, float znear, float zfar);
|
||||
void (*device_perspective)(device_t device, float fovy, float aspect,
|
||||
float znear, float zfar);
|
||||
void (*device_projection_push)(device_t device);
|
||||
void (*device_projection_pop)(device_t device);
|
||||
|
||||
void (*swapchain_destroy)(swapchain_t swapchain);
|
||||
|
||||
void (*texture_destroy)(texture_t tex);
|
||||
uint32_t (*texture_getwidth)(texture_t tex);
|
||||
uint32_t (*texture_getheight)(texture_t tex);
|
||||
enum gs_color_format (*texture_getcolorformat)(texture_t tex);
|
||||
bool (*texture_map)(texture_t tex, void **ptr,
|
||||
uint32_t *byte_width);
|
||||
void (*texture_unmap)(texture_t tex);
|
||||
|
||||
void (*cubetexture_destroy)(texture_t cubetex);
|
||||
uint32_t (*cubetexture_getsize)(texture_t cubetex);
|
||||
enum gs_color_format (*cubetexture_getcolorformat)(texture_t cubetex);
|
||||
|
||||
void (*volumetexture_destroy)(texture_t voltex);
|
||||
uint32_t (*volumetexture_getwidth)(texture_t voltex);
|
||||
uint32_t (*volumetexture_getheight)(texture_t voltex);
|
||||
uint32_t (*volumetexture_getdepth)(texture_t voltex);
|
||||
enum gs_color_format (*volumetexture_getcolorformat)(texture_t voltex);
|
||||
|
||||
void (*stagesurface_destroy)(stagesurf_t stagesurf);
|
||||
uint32_t (*stagesurface_getwidth)(stagesurf_t stagesurf);
|
||||
uint32_t (*stagesurface_getheight)(stagesurf_t stagesurf);
|
||||
enum gs_color_format (*stagesurface_getcolorformat)(
|
||||
stagesurf_t stagesurf);
|
||||
bool (*stagesurface_map)(stagesurf_t stagesurf, const void **data,
|
||||
uint32_t *byte_width);
|
||||
void (*stagesurface_unmap)(stagesurf_t stagesurf);
|
||||
|
||||
void (*zstencil_destroy)(zstencil_t zstencil);
|
||||
|
||||
void (*samplerstate_destroy)(samplerstate_t samplerstate);
|
||||
|
||||
void (*vertexbuffer_destroy)(vertbuffer_t vertbuffer);
|
||||
void (*vertexbuffer_flush)(vertbuffer_t vertbuffer, bool rebuild);
|
||||
struct vb_data *(*vertexbuffer_getdata)(vertbuffer_t vertbuffer);
|
||||
|
||||
void (*indexbuffer_destroy)(indexbuffer_t indexbuffer);
|
||||
void (*indexbuffer_flush)(indexbuffer_t indexbuffer);
|
||||
void *(*indexbuffer_getdata)(indexbuffer_t indexbuffer);
|
||||
size_t (*indexbuffer_numindices)(indexbuffer_t indexbuffer);
|
||||
enum gs_index_type (*indexbuffer_gettype)(indexbuffer_t indexbuffer);
|
||||
|
||||
void (*shader_destroy)(shader_t shader);
|
||||
int (*shader_numparams)(shader_t shader);
|
||||
sparam_t (*shader_getparambyidx)(shader_t shader, int param);
|
||||
sparam_t (*shader_getparambyname)(shader_t shader, const char *name);
|
||||
void (*shader_getparaminfo)(shader_t shader, sparam_t param,
|
||||
struct shader_param_info *info);
|
||||
sparam_t (*shader_getviewprojmatrix)(shader_t shader);
|
||||
sparam_t (*shader_getworldmatrix)(shader_t shader);
|
||||
void (*shader_setbool)(shader_t shader, sparam_t param, bool val);
|
||||
void (*shader_setfloat)(shader_t shader, sparam_t param, float val);
|
||||
void (*shader_setint)(shader_t shader, sparam_t param, int val);
|
||||
void (*shader_setmatrix3)(shader_t shader, sparam_t param,
|
||||
const struct matrix3 *val);
|
||||
void (*shader_setmatrix4)(shader_t shader, sparam_t param,
|
||||
const struct matrix4 *val);
|
||||
void (*shader_setvec2)(shader_t shader, sparam_t param,
|
||||
const struct vec2 *val);
|
||||
void (*shader_setvec3)(shader_t shader, sparam_t param,
|
||||
const struct vec3 *val);
|
||||
void (*shader_setvec4)(shader_t shader, sparam_t param,
|
||||
const struct vec4 *val);
|
||||
void (*shader_settexture)(shader_t shader, sparam_t param,
|
||||
texture_t val);
|
||||
void (*shader_setval)(shader_t shader, sparam_t param, const void *val,
|
||||
size_t size);
|
||||
void (*shader_setdefault)(shader_t shader, sparam_t param);
|
||||
};
|
||||
|
||||
struct graphics_subsystem {
|
||||
void *module;
|
||||
device_t device;
|
||||
struct gs_exports exports;
|
||||
|
||||
DARRAY(struct gs_rect) viewport_stack;
|
||||
|
||||
DARRAY(struct matrix3) matrix_stack;
|
||||
size_t cur_matrix;
|
||||
|
||||
struct matrix4 projection;
|
||||
struct gs_effect *cur_effect;
|
||||
|
||||
vertbuffer_t sprite_buffer;
|
||||
|
||||
bool using_immediate;
|
||||
struct vb_data *vbd;
|
||||
vertbuffer_t immediate_vertbuffer;
|
||||
DARRAY(struct vec3) verts;
|
||||
DARRAY(struct vec3) norms;
|
||||
DARRAY(uint32_t) colors;
|
||||
DARRAY(struct vec2) texverts[16];
|
||||
};
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,664 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef GRAPHICS_H
|
||||
#define GRAPHICS_H
|
||||
|
||||
#include "../util/bmem.h"
|
||||
#include "input.h"
|
||||
|
||||
/*
|
||||
* This is an API-independent graphics subsystem wrapper.
|
||||
*
|
||||
* This allows the use of OpenGL and different Direct3D versions through
|
||||
* one shared interface.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct vec2;
|
||||
struct vec3;
|
||||
struct vec4;
|
||||
struct quat;
|
||||
struct axisang;
|
||||
struct plane;
|
||||
struct matrix3;
|
||||
struct matrix4;
|
||||
|
||||
enum gs_draw_mode {
|
||||
GS_POINTS,
|
||||
GS_LINES,
|
||||
GS_LINESTRIP,
|
||||
GS_TRIS,
|
||||
GS_TRISTRIP
|
||||
};
|
||||
|
||||
enum gs_color_format {
|
||||
GS_UNKNOWN,
|
||||
GS_A8,
|
||||
GS_R8,
|
||||
GS_RGBA,
|
||||
GS_BGRX,
|
||||
GS_BGRA,
|
||||
GS_R10G10B10A2,
|
||||
GS_RGBA16,
|
||||
GS_R16,
|
||||
GS_RGBA16F,
|
||||
GS_RGBA32F,
|
||||
GS_RG16F,
|
||||
GS_RG32F,
|
||||
GS_R16F,
|
||||
GS_R32F,
|
||||
GS_DXT1,
|
||||
GS_DXT3,
|
||||
GS_DXT5
|
||||
};
|
||||
|
||||
enum gs_zstencil_format {
|
||||
GS_ZS_NONE,
|
||||
GS_Z16,
|
||||
GS_Z24_S8,
|
||||
GS_Z32F,
|
||||
GS_Z32F_S8X24
|
||||
};
|
||||
|
||||
enum gs_index_type {
|
||||
GS_UNSIGNED_SHORT,
|
||||
GS_UNSIGNED_LONG
|
||||
};
|
||||
|
||||
enum gs_cull_mode {
|
||||
GS_BACK,
|
||||
GS_FRONT,
|
||||
GS_NEITHER
|
||||
};
|
||||
|
||||
enum gs_blend_type {
|
||||
GS_BLEND_ZERO,
|
||||
GS_BLEND_ONE,
|
||||
GS_BLEND_SRCCOLOR,
|
||||
GS_BLEND_INVSRCCOLOR,
|
||||
GS_BLEND_SRCALPHA,
|
||||
GS_BLEND_INVSRCALPHA,
|
||||
GS_BLEND_DSTCOLOR,
|
||||
GS_BLEND_INVDSTCOLOR,
|
||||
GS_BLEND_DSTALPHA,
|
||||
GS_BLEND_INVDSTALPHA,
|
||||
GS_BLEND_SRCALPHASAT
|
||||
};
|
||||
|
||||
enum gs_depth_test {
|
||||
GS_NEVER,
|
||||
GS_LESS,
|
||||
GS_LEQUAL,
|
||||
GS_EQUAL,
|
||||
GS_GEQUAL,
|
||||
GS_GREATER,
|
||||
GS_NOTEQUAL,
|
||||
GS_ALWAYS
|
||||
};
|
||||
|
||||
enum gs_stencil_side {
|
||||
GS_STENCIL_FRONT=1,
|
||||
GS_STENCIL_BACK,
|
||||
GS_STENCIL_BOTH
|
||||
};
|
||||
|
||||
enum gs_stencil_op {
|
||||
GS_KEEP,
|
||||
GS_ZERO,
|
||||
GS_REPLACE,
|
||||
GS_INCR,
|
||||
GS_DECR,
|
||||
GS_INVERT
|
||||
};
|
||||
|
||||
enum gs_cube_sides {
|
||||
GS_POSITIVE_X,
|
||||
GS_NEGATIVE_X,
|
||||
GS_POSITIVE_Y,
|
||||
GS_NEGATIVE_Y,
|
||||
GS_POSITIVE_Z,
|
||||
GS_NEGATIVE_Z
|
||||
};
|
||||
|
||||
enum gs_sample_filter {
|
||||
GS_FILTER_POINT,
|
||||
GS_FILTER_LINEAR,
|
||||
GS_FILTER_ANISOTROPIC,
|
||||
GS_FILTER_MIN_MAG_POINT_MIP_LINEAR,
|
||||
GS_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT,
|
||||
GS_FILTER_MIN_POINT_MAG_MIP_LINEAR,
|
||||
GS_FILTER_MIN_LINEAR_MAG_MIP_POINT,
|
||||
GS_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR,
|
||||
GS_FILTER_MIN_MAG_LINEAR_MIP_POINT,
|
||||
};
|
||||
|
||||
enum gs_address_mode {
|
||||
GS_ADDRESS_CLAMP,
|
||||
GS_ADDRESS_WRAP,
|
||||
GS_ADDRESS_MIRROR,
|
||||
GS_ADDRESS_BORDER,
|
||||
GS_ADDRESS_MIRRORONCE
|
||||
};
|
||||
|
||||
enum gs_texture_type {
|
||||
GS_TEXTURE_2D,
|
||||
GS_TEXTURE_3D,
|
||||
GS_TEXTURE_CUBE
|
||||
};
|
||||
|
||||
struct tvertarray {
|
||||
size_t width;
|
||||
void *array;
|
||||
};
|
||||
|
||||
struct vb_data {
|
||||
size_t num;
|
||||
struct vec3 *points;
|
||||
struct vec3 *normals;
|
||||
struct vec3 *tangents;
|
||||
uint32_t *colors;
|
||||
|
||||
size_t num_tex;
|
||||
struct tvertarray *tvarray;
|
||||
};
|
||||
|
||||
static inline struct vb_data *vbdata_create(void)
|
||||
{
|
||||
struct vb_data *vbd = (struct vb_data*)bmalloc(sizeof(struct vb_data));
|
||||
memset(vbd, 0, sizeof(struct vb_data));
|
||||
return vbd;
|
||||
}
|
||||
|
||||
static inline void vbdata_destroy(struct vb_data *data)
|
||||
{
|
||||
uint32_t i;
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
bfree(data->points);
|
||||
bfree(data->normals);
|
||||
bfree(data->tangents);
|
||||
bfree(data->colors);
|
||||
for (i = 0; i < data->num_tex; i++)
|
||||
bfree(data->tvarray[i].array);
|
||||
bfree(data->tvarray);
|
||||
bfree(data);
|
||||
}
|
||||
|
||||
struct gs_sampler_info {
|
||||
enum gs_sample_filter filter;
|
||||
enum gs_address_mode address_u;
|
||||
enum gs_address_mode address_v;
|
||||
enum gs_address_mode address_w;
|
||||
int max_anisotropy;
|
||||
uint32_t border_color;
|
||||
};
|
||||
|
||||
struct gs_display_mode {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t bits;
|
||||
uint32_t freq;
|
||||
};
|
||||
|
||||
struct gs_rect {
|
||||
int x;
|
||||
int y;
|
||||
int cx;
|
||||
int cy;
|
||||
};
|
||||
|
||||
/* wrapped opaque data types */
|
||||
|
||||
struct gs_texture;
|
||||
struct gs_stage_surface;
|
||||
struct gs_zstencil_buffer;
|
||||
struct gs_vertex_buffer;
|
||||
struct gs_index_buffer;
|
||||
struct gs_sampler_state;
|
||||
struct gs_shader;
|
||||
struct gs_swap_chain;
|
||||
struct gs_texrender;
|
||||
struct shader_param;
|
||||
struct gs_effect;
|
||||
struct effect_technique;
|
||||
struct effect_pass;
|
||||
struct effect_param;
|
||||
struct gs_device;
|
||||
struct graphics_subsystem;
|
||||
|
||||
typedef struct gs_texture *texture_t;
|
||||
typedef struct gs_stage_surface *stagesurf_t;
|
||||
typedef struct gs_zstencil_buffer *zstencil_t;
|
||||
typedef struct gs_vertex_buffer *vertbuffer_t;
|
||||
typedef struct gs_index_buffer *indexbuffer_t;
|
||||
typedef struct gs_sampler_state *samplerstate_t;
|
||||
typedef struct gs_swap_chain *swapchain_t;
|
||||
typedef struct gs_texture_render *texrender_t;
|
||||
typedef struct gs_shader *shader_t;
|
||||
typedef struct shader_param *sparam_t;
|
||||
typedef struct gs_effect *effect_t;
|
||||
typedef struct effect_technique *technique_t;
|
||||
typedef struct effect_param *eparam_t;
|
||||
typedef struct gs_device *device_t;
|
||||
typedef struct graphics_subsystem *graphics_t;
|
||||
|
||||
/* ---------------------------------------------------
|
||||
* shader functions
|
||||
* --------------------------------------------------- */
|
||||
|
||||
enum shader_param_type {
|
||||
SHADER_PARAM_UNKNOWN,
|
||||
SHADER_PARAM_BOOL,
|
||||
SHADER_PARAM_FLOAT,
|
||||
SHADER_PARAM_INT,
|
||||
SHADER_PARAM_STRING,
|
||||
SHADER_PARAM_VEC2,
|
||||
SHADER_PARAM_VEC3,
|
||||
SHADER_PARAM_VEC4,
|
||||
SHADER_PARAM_MATRIX3X3,
|
||||
SHADER_PARAM_MATRIX4X4,
|
||||
SHADER_PARAM_TEXTURE,
|
||||
};
|
||||
|
||||
struct shader_param_info {
|
||||
enum shader_param_type type;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
enum shader_type {
|
||||
SHADER_VERTEX,
|
||||
SHADER_PIXEL,
|
||||
SHADER_GEOMETRY
|
||||
};
|
||||
|
||||
EXPORT void shader_destroy(shader_t shader);
|
||||
|
||||
EXPORT int shader_numparams(shader_t shader);
|
||||
EXPORT sparam_t shader_getparambyidx(shader_t shader, int param);
|
||||
EXPORT sparam_t shader_getparambyname(shader_t shader, const char *name);
|
||||
EXPORT void shader_getparaminfo(shader_t shader, sparam_t param,
|
||||
struct shader_param_info *info);
|
||||
|
||||
EXPORT sparam_t shader_getviewprojmatrix(shader_t shader);
|
||||
EXPORT sparam_t shader_getworldmatrix(shader_t shader);
|
||||
|
||||
EXPORT void shader_setbool(shader_t shader, sparam_t param, bool val);
|
||||
EXPORT void shader_setfloat(shader_t shader, sparam_t param, float val);
|
||||
EXPORT void shader_setint(shader_t shader, sparam_t param, int val);
|
||||
EXPORT void shader_setmatrix3(shader_t shader, sparam_t param,
|
||||
const struct matrix3 *val);
|
||||
EXPORT void shader_setmatrix4(shader_t shader, sparam_t param,
|
||||
const struct matrix4 *val);
|
||||
EXPORT void shader_setvec2(shader_t shader, sparam_t param,
|
||||
const struct vec2 *val);
|
||||
EXPORT void shader_setvec3(shader_t shader, sparam_t param,
|
||||
const struct vec3 *val);
|
||||
EXPORT void shader_setvec4(shader_t shader, sparam_t param,
|
||||
const struct vec4 *val);
|
||||
EXPORT void shader_settexture(shader_t shader, sparam_t param, texture_t val);
|
||||
EXPORT void shader_setval(shader_t shader, sparam_t param, const void *val,
|
||||
size_t size);
|
||||
EXPORT void shader_setdefault(shader_t shader, sparam_t param);
|
||||
|
||||
/* ---------------------------------------------------
|
||||
* effect functions
|
||||
* --------------------------------------------------- */
|
||||
|
||||
/*enum effect_property_type {
|
||||
EFFECT_NONE,
|
||||
EFFECT_BOOL,
|
||||
EFFECT_FLOAT,
|
||||
EFFECT_COLOR,
|
||||
EFFECT_TEXTURE
|
||||
};*/
|
||||
|
||||
struct effect_param_info {
|
||||
const char *name;
|
||||
enum shader_param_type type;
|
||||
|
||||
/* const char *full_name;
|
||||
enum effect_property_type prop_type;
|
||||
|
||||
float min, max, inc, mul; */
|
||||
};
|
||||
|
||||
EXPORT void effect_destroy(effect_t effect);
|
||||
|
||||
EXPORT technique_t effect_gettechnique(effect_t effect, const char *name);
|
||||
|
||||
EXPORT int technique_begin(technique_t technique);
|
||||
EXPORT void technique_end(technique_t technique);
|
||||
EXPORT bool technique_beginpass(technique_t technique, size_t pass);
|
||||
EXPORT bool technique_beginpassbyname(technique_t technique,
|
||||
const char *name);
|
||||
EXPORT void technique_endpass(technique_t technique);
|
||||
|
||||
EXPORT int effect_numparams(effect_t effect);
|
||||
EXPORT eparam_t effect_getparambyidx(effect_t effect, size_t param);
|
||||
EXPORT eparam_t effect_getparambyname(effect_t effect, const char *name);
|
||||
EXPORT void effect_getparaminfo(effect_t effect, eparam_t param,
|
||||
struct effect_param_info *info);
|
||||
|
||||
/** used internally */
|
||||
EXPORT void effect_updateparams(effect_t effect);
|
||||
|
||||
EXPORT eparam_t effect_getviewprojmatrix(effect_t effect);
|
||||
EXPORT eparam_t effect_getworldmatrix(effect_t effect);
|
||||
|
||||
EXPORT void effect_setbool(effect_t effect, eparam_t param, bool val);
|
||||
EXPORT void effect_setfloat(effect_t effect, eparam_t param, float val);
|
||||
EXPORT void effect_setint(effect_t effect, eparam_t param, int val);
|
||||
EXPORT void effect_setmatrix3(effect_t effect, eparam_t param,
|
||||
const struct matrix3 *val);
|
||||
EXPORT void effect_setmatrix4(effect_t effect, eparam_t param,
|
||||
const struct matrix4 *val);
|
||||
EXPORT void effect_setvec2(effect_t effect, eparam_t param,
|
||||
const struct vec2 *val);
|
||||
EXPORT void effect_setvec3(effect_t effect, eparam_t param,
|
||||
const struct vec3 *val);
|
||||
EXPORT void effect_setvec4(effect_t effect, eparam_t param,
|
||||
const struct vec4 *val);
|
||||
EXPORT void effect_settexture(effect_t effect, eparam_t param, texture_t val);
|
||||
EXPORT void effect_setval(effect_t shader, eparam_t param, const void *val,
|
||||
size_t size);
|
||||
EXPORT void effect_setdefault(effect_t effect, eparam_t param);
|
||||
|
||||
/* ---------------------------------------------------
|
||||
* texture render helper functions
|
||||
* --------------------------------------------------- */
|
||||
|
||||
EXPORT texrender_t texrender_create(enum gs_color_format format,
|
||||
enum gs_zstencil_format zsformat);
|
||||
EXPORT void texrender_destroy(texrender_t texrender);
|
||||
EXPORT bool texrender_begin(texrender_t texrender, int cx, int cy);
|
||||
EXPORT void texrender_end(texrender_t texrender);
|
||||
EXPORT void texrender_reset(texrender_t texrender);
|
||||
EXPORT texture_t texrender_gettexture(texrender_t texrender);
|
||||
|
||||
/* ---------------------------------------------------
|
||||
* graphics subsystem
|
||||
* --------------------------------------------------- */
|
||||
|
||||
#define GS_BUILDMIPMAPS (1<<0)
|
||||
#define GS_DYNAMIC (1<<1)
|
||||
#define GS_RENDERTARGET (1<<2)
|
||||
|
||||
/* ---------------- */
|
||||
/* global functions */
|
||||
|
||||
#define GS_SUCCESS 0
|
||||
#define GS_ERROR_MODULENOTFOUND -1
|
||||
#define GS_ERROR_FAIL -2
|
||||
|
||||
struct gs_init_data {
|
||||
#if defined(_WIN32)
|
||||
void *hwnd;
|
||||
#elif defined(__APPLE__)
|
||||
/* TODO */
|
||||
#elif defined(__posix__)
|
||||
/* TODO */
|
||||
#endif
|
||||
uint32_t cx, cy;
|
||||
uint32_t num_backbuffers;
|
||||
enum gs_color_format format;
|
||||
enum gs_zstencil_format zsformat;
|
||||
uint32_t adapter;
|
||||
};
|
||||
|
||||
|
||||
EXPORT int gs_create(graphics_t *graphics, const char *module,
|
||||
struct gs_init_data *data);
|
||||
EXPORT void gs_destroy(graphics_t graphics);
|
||||
|
||||
EXPORT void gs_setcontext(graphics_t graphics);
|
||||
EXPORT graphics_t gs_getcontext(void);
|
||||
|
||||
EXPORT void gs_matrix_push(void);
|
||||
EXPORT void gs_matrix_pop(void);
|
||||
EXPORT void gs_matrix_identity(void);
|
||||
EXPORT void gs_matrix_transpose(void);
|
||||
EXPORT void gs_matrix_set(const struct matrix3 *matrix);
|
||||
EXPORT void gs_matrix_get(struct matrix3 *dst);
|
||||
EXPORT void gs_matrix_mul(const struct matrix3 *matrix);
|
||||
EXPORT void gs_matrix_rotquat(const struct quat *rot);
|
||||
EXPORT void gs_matrix_rotaa(const struct axisang *rot);
|
||||
EXPORT void gs_matrix_translate(const struct vec3 *pos);
|
||||
EXPORT void gs_matrix_scale(const struct vec3 *scale);
|
||||
EXPORT void gs_matrix_rotaa4f(float x, float y, float z, float angle);
|
||||
EXPORT void gs_matrix_translate3f(float x, float y, float z);
|
||||
EXPORT void gs_matrix_scale3f(float x, float y, float z);
|
||||
|
||||
EXPORT void gs_renderstart(bool b_new);
|
||||
EXPORT void gs_renderstop(enum gs_draw_mode mode);
|
||||
EXPORT vertbuffer_t gs_rendersave(void);
|
||||
EXPORT void gs_vertex2f(float x, float y);
|
||||
EXPORT void gs_vertex3f(float x, float y, float z);
|
||||
EXPORT void gs_normal3f(float x, float y, float z);
|
||||
EXPORT void gs_color(uint32_t color);
|
||||
EXPORT void gs_texcoord(float x, float y, int unit);
|
||||
EXPORT void gs_vertex2v(const struct vec2 *v);
|
||||
EXPORT void gs_vertex3v(const struct vec3 *v);
|
||||
EXPORT void gs_normal3v(const struct vec3 *v);
|
||||
EXPORT void gs_color4v(const struct vec4 *v);
|
||||
EXPORT void gs_texcoord2v(const struct vec2 *v, int unit);
|
||||
|
||||
EXPORT input_t gs_getinput(void);
|
||||
EXPORT effect_t gs_geteffect(void);
|
||||
|
||||
EXPORT effect_t gs_create_effect_from_file(const char *file,
|
||||
char **error_string);
|
||||
EXPORT effect_t gs_create_effect(const char *effect_string,
|
||||
const char *filename, char **error_string);
|
||||
|
||||
EXPORT shader_t gs_create_vertexshader_from_file(const char *file,
|
||||
char **error_string);
|
||||
EXPORT shader_t gs_create_pixelshader_from_file(const char *file,
|
||||
char **error_string);
|
||||
|
||||
EXPORT texture_t gs_create_texture_from_file(const char *file,
|
||||
uint32_t flags);
|
||||
EXPORT texture_t gs_create_cubetexture_from_file(const char *flie,
|
||||
uint32_t flags);
|
||||
EXPORT texture_t gs_create_volumetexture_from_file(const char *flie,
|
||||
uint32_t flags);
|
||||
|
||||
EXPORT void gs_draw_sprite(texture_t tex);
|
||||
|
||||
EXPORT void gs_draw_cube_backdrop(texture_t cubetex, const struct quat *rot,
|
||||
float left, float right, float top, float bottom, float znear);
|
||||
|
||||
/** sets the viewport to current swap chain size */
|
||||
EXPORT void gs_resetviewport(void);
|
||||
|
||||
/** sets default screen-sized orthographich mode */
|
||||
EXPORT void gs_set2dmode(void);
|
||||
/** sets default screen-sized perspective mode */
|
||||
EXPORT void gs_set3dmode(double fovy, double znear, double zvar);
|
||||
|
||||
EXPORT void gs_viewport_push(void);
|
||||
EXPORT void gs_viewport_pop(void);
|
||||
|
||||
EXPORT void texture_setimage(texture_t tex, const void *data,
|
||||
uint32_t byte_width);
|
||||
EXPORT void cubetexture_setimage(texture_t cubetex, uint32_t side,
|
||||
const void *data, uint32_t byte_width);
|
||||
|
||||
/* -------------------------- */
|
||||
/* library-specific functions */
|
||||
|
||||
EXPORT swapchain_t gs_create_swapchain(struct gs_init_data *data);
|
||||
|
||||
EXPORT void gs_resize(uint32_t x, uint32_t y);
|
||||
EXPORT void gs_getsize(uint32_t *x, uint32_t *y);
|
||||
EXPORT uint32_t gs_getwidth(void);
|
||||
EXPORT uint32_t gs_getheight(void);
|
||||
|
||||
EXPORT texture_t gs_create_texture(uint32_t width, uint32_t height,
|
||||
enum gs_color_format color_format, void *data, uint32_t flags);
|
||||
EXPORT texture_t gs_create_cubetexture(uint32_t size,
|
||||
enum gs_color_format color_format, void *data[6],
|
||||
uint32_t flags);
|
||||
EXPORT texture_t gs_create_volumetexture(uint32_t width, uint32_t height,
|
||||
uint32_t depth, enum gs_color_format color_format, void *data,
|
||||
uint32_t flags);
|
||||
|
||||
EXPORT zstencil_t gs_create_zstencil(uint32_t width, uint32_t height,
|
||||
enum gs_zstencil_format format);
|
||||
|
||||
EXPORT stagesurf_t gs_create_stagesurface(uint32_t width, uint32_t height,
|
||||
enum gs_color_format color_format);
|
||||
|
||||
EXPORT samplerstate_t gs_create_samplerstate(struct gs_sampler_info *info);
|
||||
|
||||
EXPORT shader_t gs_create_vertexshader(const char *shader,
|
||||
const char *file, char **error_string);
|
||||
EXPORT shader_t gs_create_pixelshader(const char *shader,
|
||||
const char *file, char **error_string);
|
||||
|
||||
EXPORT vertbuffer_t gs_create_vertexbuffer(struct vb_data *data,
|
||||
uint32_t flags);
|
||||
EXPORT indexbuffer_t gs_create_indexbuffer(enum gs_index_type type,
|
||||
void *indices, size_t num, uint32_t flags);
|
||||
|
||||
EXPORT enum gs_texture_type gs_gettexturetype(texture_t texture);
|
||||
|
||||
EXPORT void gs_load_vertexbuffer(vertbuffer_t vertbuffer);
|
||||
EXPORT void gs_load_indexbuffer(indexbuffer_t indexbuffer);
|
||||
EXPORT void gs_load_texture(texture_t tex, int unit);
|
||||
EXPORT void gs_load_samplerstate(samplerstate_t samplerstate, int unit);
|
||||
EXPORT void gs_load_vertexshader(shader_t vertshader);
|
||||
EXPORT void gs_load_pixelshader(shader_t pixelshader);
|
||||
|
||||
EXPORT void gs_load_defaultsamplerstate(bool b_3d, int unit);
|
||||
|
||||
EXPORT shader_t gs_getvertexshader(void);
|
||||
EXPORT shader_t gs_getpixelshader(void);
|
||||
|
||||
EXPORT texture_t gs_getrendertarget(void);
|
||||
EXPORT zstencil_t gs_getzstenciltarget(void);
|
||||
|
||||
EXPORT void gs_setrendertarget(texture_t tex, zstencil_t zstencil);
|
||||
EXPORT void gs_setcuberendertarget(texture_t cubetex, int side,
|
||||
zstencil_t zstencil);
|
||||
|
||||
EXPORT void gs_copy_texture(texture_t dst, texture_t src);
|
||||
EXPORT void gs_stage_texture(stagesurf_t dst, texture_t src);
|
||||
|
||||
EXPORT void gs_beginscene(void);
|
||||
EXPORT void gs_draw(enum gs_draw_mode draw_mode, uint32_t start_vert,
|
||||
uint32_t num_verts);
|
||||
EXPORT void gs_endscene(void);
|
||||
|
||||
#define GS_CLEAR_COLOR (1<<0)
|
||||
#define GS_CLEAR_DEPTH (1<<1)
|
||||
#define GS_CLEAR_STENCIL (1<<2)
|
||||
|
||||
EXPORT void gs_load_swapchain(swapchain_t swapchain);
|
||||
EXPORT void gs_clear(uint32_t clear_flags, struct vec4 *color,
|
||||
float depth, uint8_t stencil);
|
||||
EXPORT void gs_present(void);
|
||||
|
||||
EXPORT void gs_setcullmode(enum gs_cull_mode mode);
|
||||
EXPORT enum gs_cull_mode gs_getcullmode(void);
|
||||
|
||||
EXPORT void gs_enable_blending(bool enable);
|
||||
EXPORT void gs_enable_depthtest(bool enable);
|
||||
EXPORT void gs_enable_stenciltest(bool enable);
|
||||
EXPORT void gs_enable_stencilwrite(bool enable);
|
||||
EXPORT void gs_enable_color(bool red, bool blue, bool green, bool alpha);
|
||||
|
||||
EXPORT void gs_blendfunction(enum gs_blend_type src, enum gs_blend_type dest);
|
||||
EXPORT void gs_depthfunction(enum gs_depth_test test);
|
||||
|
||||
EXPORT void gs_stencilfunction(enum gs_stencil_side side,
|
||||
enum gs_depth_test test);
|
||||
EXPORT void gs_stencilop(enum gs_stencil_side side, enum gs_stencil_op fail,
|
||||
enum gs_stencil_op zfail, enum gs_stencil_op zpass);
|
||||
|
||||
EXPORT void gs_setclip(struct plane *p);
|
||||
|
||||
EXPORT void gs_enable_fullscreen(bool enable);
|
||||
EXPORT int gs_fullscreen_enabled(void);
|
||||
EXPORT void gs_setdisplaymode(const struct gs_display_mode *mode);
|
||||
EXPORT void gs_getdisplaymode(struct gs_display_mode *mode);
|
||||
EXPORT void gs_setcolorramp(float gamma, float brightness, float contrast);
|
||||
|
||||
EXPORT void gs_setviewport(int x, int y, int width, int height);
|
||||
EXPORT void gs_getviewport(struct gs_rect *rect);
|
||||
EXPORT void gs_setscissorrect(struct gs_rect *rect);
|
||||
|
||||
EXPORT void gs_ortho(float left, float right, float top, float bottom,
|
||||
float znear, float zfar);
|
||||
EXPORT void gs_frustum(float left, float right, float top, float bottom,
|
||||
float znear, float zfar);
|
||||
EXPORT void gs_perspective(float fovy, float aspect, float znear,
|
||||
float zfar);
|
||||
|
||||
EXPORT void gs_projection_push(void);
|
||||
EXPORT void gs_projection_pop(void);
|
||||
|
||||
EXPORT void swapchain_destroy(swapchain_t swapchain);
|
||||
|
||||
EXPORT void texture_destroy(texture_t tex);
|
||||
EXPORT uint32_t texture_getwidth(texture_t tex);
|
||||
EXPORT uint32_t texture_getheight(texture_t tex);
|
||||
EXPORT enum gs_color_format texture_getcolorformat(texture_t tex);
|
||||
EXPORT bool texture_map(texture_t tex, void **ptr, uint32_t *byte_width);
|
||||
EXPORT void texture_unmap(texture_t tex);
|
||||
|
||||
EXPORT void cubetexture_destroy(texture_t cubetex);
|
||||
EXPORT uint32_t cubetexture_getsize(texture_t cubetex);
|
||||
EXPORT enum gs_color_format cubetexture_getcolorformat(texture_t cubetex);
|
||||
|
||||
EXPORT void volumetexture_destroy(texture_t voltex);
|
||||
EXPORT uint32_t volumetexture_getwidth(texture_t voltex);
|
||||
EXPORT uint32_t volumetexture_getheight(texture_t voltex);
|
||||
EXPORT uint32_t volumetexture_getdepth(texture_t voltex);
|
||||
EXPORT enum gs_color_format volumetexture_getcolorformat(texture_t voltex);
|
||||
|
||||
EXPORT void stagesurface_destroy(stagesurf_t stagesurf);
|
||||
EXPORT uint32_t stagesurface_getwidth(stagesurf_t stagesurf);
|
||||
EXPORT uint32_t stagesurface_getheight(stagesurf_t stagesurf);
|
||||
EXPORT enum gs_color_format stagesurface_getcolorformat(stagesurf_t stagesurf);
|
||||
EXPORT bool stagesurface_map(stagesurf_t stagesurf, const void **data,
|
||||
uint32_t *byte_width);
|
||||
EXPORT void stagesurface_unmap(stagesurf_t stagesurf);
|
||||
|
||||
EXPORT void zstencil_destroy(zstencil_t zstencil);
|
||||
|
||||
EXPORT void samplerstate_destroy(samplerstate_t samplerstate);
|
||||
|
||||
EXPORT void vertexbuffer_destroy(vertbuffer_t vertbuffer);
|
||||
EXPORT void vertexbuffer_flush(vertbuffer_t vertbuffer, bool rebuild);
|
||||
EXPORT struct vb_data *vertexbuffer_getdata(vertbuffer_t vertbuffer);
|
||||
|
||||
EXPORT void indexbuffer_destroy(indexbuffer_t indexbuffer);
|
||||
EXPORT void indexbuffer_flush(indexbuffer_t indexbuffer);
|
||||
EXPORT void *indexbuffer_getdata(indexbuffer_t indexbuffer);
|
||||
EXPORT size_t indexbuffer_numindices(indexbuffer_t indexbuffer);
|
||||
EXPORT enum gs_index_type indexbuffer_gettype(indexbuffer_t indexbuffer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,155 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef INPUT_H
|
||||
#define INPUT_H
|
||||
|
||||
/* TODO: incomplete/may not be necessary */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define KBC_ESCAPE 0x0
|
||||
#define KBC_1 0x1
|
||||
#define KBC_2 0x2
|
||||
#define KBC_3 0x3
|
||||
#define KBC_4 0x4
|
||||
#define KBC_5 0x5
|
||||
#define KBC_6 0x6
|
||||
#define KBC_7 0x7
|
||||
#define KBC_8 0x8
|
||||
#define KBC_9 0x9
|
||||
#define KBC_0 0xA
|
||||
#define KBC_MINUS 0xB
|
||||
#define KBC_EQUALS 0xC
|
||||
#define KBC_BACK 0xD
|
||||
#define KBC_TAB 0xE
|
||||
#define KBC_Q 0xF
|
||||
#define KBC_W 0x10
|
||||
#define KBC_E 0x11
|
||||
#define KBC_R 0x12
|
||||
#define KBC_T 0x13
|
||||
#define KBC_Y 0x14
|
||||
#define KBC_U 0x15
|
||||
#define KBC_I 0x16
|
||||
#define KBC_O 0x17
|
||||
#define KBC_P 0x18
|
||||
#define KBC_LBRACKET 0x19
|
||||
#define KBC_RBRACKET 0x1A
|
||||
#define KBC_RETURN 0x1B
|
||||
#define KBC_LCONTROL 0x1C
|
||||
#define KBC_A 0x1D
|
||||
#define KBC_S 0x1E
|
||||
#define KBC_D 0x1F
|
||||
#define KBC_F 0x20
|
||||
#define KBC_G 0x21
|
||||
#define KBC_H 0x22
|
||||
#define KBC_J 0x23
|
||||
#define KBC_K 0x24
|
||||
#define KBC_L 0x25
|
||||
#define KBC_SEMICOLON 0x26
|
||||
#define KBC_APOSTROPHE 0x27
|
||||
#define KBC_TILDE 0x28
|
||||
#define KBC_LSHIFT 0x29
|
||||
#define KBC_BACKSLASH 0x2A
|
||||
#define KBC_Z 0x2B
|
||||
#define KBC_X 0x2C
|
||||
#define KBC_C 0x2D
|
||||
#define KBC_V 0x2E
|
||||
#define KBC_B 0x2F
|
||||
#define KBC_N 0x30
|
||||
#define KBC_M 0x31
|
||||
#define KBC_COMMA 0x32
|
||||
#define KBC_PERIOD 0x33
|
||||
#define KBC_SLASH 0x34
|
||||
#define KBC_RSHIFT 0x35
|
||||
#define KBC_MULTIPLY 0x36
|
||||
#define KBC_LALT 0x37
|
||||
#define KBC_SPACE 0x38
|
||||
#define KBC_CAPSLOCK 0x39
|
||||
#define KBC_F1 0x3A
|
||||
#define KBC_F2 0x3B
|
||||
#define KBC_F3 0x3C
|
||||
#define KBC_F4 0x3D
|
||||
#define KBC_F5 0x3E
|
||||
#define KBC_F6 0x3F
|
||||
#define KBC_F7 0x40
|
||||
#define KBC_F8 0x41
|
||||
#define KBC_F9 0x42
|
||||
#define KBC_F10 0x43
|
||||
#define KBC_NUMLOCK 0x44
|
||||
#define KBC_SCROLLLOCK 0x45
|
||||
#define KBC_NUMPAD7 0x46
|
||||
#define KBC_NUMPAD8 0x47
|
||||
#define KBC_NUMPAD9 0x48
|
||||
#define KBC_SUBTRACT 0x49
|
||||
#define KBC_NUMPAD4 0x4A
|
||||
#define KBC_NUMPAD5 0x4B
|
||||
#define KBC_NUMPAD6 0x4C
|
||||
#define KBC_ADD 0x4D
|
||||
#define KBC_NUMPAD1 0x4E
|
||||
#define KBC_NUMPAD2 0x4F
|
||||
#define KBC_NUMPAD3 0x50
|
||||
#define KBC_NUMPAD0 0x51
|
||||
#define KBC_DECIMAL 0x52
|
||||
#define KBC_F11 0x53
|
||||
#define KBC_F12 0x54
|
||||
#define KBC_NUMPADENTER 0x55
|
||||
#define KBC_RCONTROL 0x56
|
||||
#define KBC_DIVIDE 0x57
|
||||
#define KBC_SYSRQ 0x58
|
||||
#define KBC_RALT 0x59
|
||||
#define KBC_PAUSE 0x5A
|
||||
#define KBC_HOME 0x5B
|
||||
#define KBC_UP 0x5C
|
||||
#define KBC_PAGEDOWN 0x5D
|
||||
#define KBC_LEFT 0x5E
|
||||
#define KBC_RIGHT 0x5F
|
||||
#define KBC_END 0x60
|
||||
#define KBC_DOWN 0x61
|
||||
#define KBC_PAGEUP 0x62
|
||||
#define KBC_INSERT 0x63
|
||||
#define KBC_DELETE 0x64
|
||||
|
||||
#define MOUSE_LEFTBUTTON 0x65
|
||||
#define MOUSE_MIDDLEBUTTON 0x66
|
||||
#define MOUSE_RIGHTBUTTON 0x67
|
||||
#define MOUSE_WHEEL 0x68
|
||||
#define MOUSE_MOVE 0x69
|
||||
|
||||
#define KBC_CONTROL 0xFFFFFFFE
|
||||
#define KBC_ALT 0xFFFFFFFD
|
||||
#define KBC_SHIFT 0xFFFFFFFC
|
||||
|
||||
#define STATE_LBUTTONDOWN (1<<0)
|
||||
#define STATE_RBUTTONDOWN (1<<1)
|
||||
#define STATE_MBUTTONDOWN (1<<2)
|
||||
#define STATE_X4BUTTONDOWN (1<<3)
|
||||
#define STATE_X5BUTTONDOWN (1<<4)
|
||||
|
||||
/* wrapped opaque data types */
|
||||
struct input_subsystem;
|
||||
typedef struct input_subsystem* input_t;
|
||||
|
||||
EXPORT int input_getbuttonstate(input_t input, uint32_t button);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,48 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef MATH_DEFS
|
||||
#define MATH_DEFS
|
||||
|
||||
#include "../util/c99defs.h"
|
||||
#include <math.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.1415926535897932384626433832795f
|
||||
#endif
|
||||
|
||||
#define RAD(val) ((val)*0.0174532925199432957692369076848f)
|
||||
#define DEG(val) ((val)*57.295779513082320876798154814105f)
|
||||
#define LARGE_EPSILON 1e-2f
|
||||
#define EPSILON 1e-4f
|
||||
#define TINY_EPSILON 1e-5f
|
||||
#define M_INFINITE 3.4e38f
|
||||
|
||||
static inline bool close_float(float f1, float f2, float precision)
|
||||
{
|
||||
return fabsf(f1-f2) <= precision;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,132 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "vec2.h"
|
||||
#include "vec3.h"
|
||||
#include "math-extra.h"
|
||||
|
||||
void polar_to_cart(struct vec3 *dst, const struct vec3 *v)
|
||||
{
|
||||
struct vec3 cart;
|
||||
float sinx = cosf(v->x);
|
||||
float sinx_z = v->z * sinx;
|
||||
|
||||
cart.x = sinx_z * sinf(v->y);
|
||||
cart.z = sinx_z * cosf(v->y);
|
||||
cart.y = v->z * sinf(v->x);
|
||||
|
||||
vec3_copy(dst, &cart);
|
||||
}
|
||||
|
||||
void cart_to_polar(struct vec3 *dst, const struct vec3 *v)
|
||||
{
|
||||
struct vec3 polar;
|
||||
polar.z = vec3_len(v);
|
||||
|
||||
if (close_float(polar.z, 0.0f, EPSILON)) {
|
||||
vec3_zero(&polar);
|
||||
} else {
|
||||
polar.x = asinf(v->y / polar.z);
|
||||
polar.y = atan2f(v->x, v->z);
|
||||
}
|
||||
|
||||
vec3_copy(dst, &polar);
|
||||
}
|
||||
|
||||
void norm_to_polar(struct vec2 *dst, const struct vec3 *norm)
|
||||
{
|
||||
dst->x = atan2f(norm->x, norm->z);
|
||||
dst->y = asinf(norm->y);
|
||||
}
|
||||
|
||||
void polar_to_norm(struct vec3 *dst, const struct vec2 *polar)
|
||||
{
|
||||
float sinx = sinf(polar->x);
|
||||
|
||||
dst->x = sinx * cosf(polar->y);
|
||||
dst->y = sinx * sinf(polar->y);
|
||||
dst->z = cosf(polar->x);
|
||||
}
|
||||
|
||||
float calc_torquef(float val1, float val2, float torque, float min_adjust,
|
||||
float t)
|
||||
{
|
||||
float out = val1;
|
||||
float dist;
|
||||
bool over;
|
||||
|
||||
if (val1 == val2)
|
||||
return val1;
|
||||
|
||||
dist = (val2-val1)*torque;
|
||||
over = dist > 0.0f;
|
||||
|
||||
if (over) {
|
||||
if (dist < min_adjust) /* prevents from going too slow */
|
||||
dist = min_adjust;
|
||||
out += dist*t; /* add torque */
|
||||
if (out > val2) /* clamp if overshoot */
|
||||
out = val2;
|
||||
} else {
|
||||
if (dist > -min_adjust)
|
||||
dist = -min_adjust;
|
||||
out += dist*t;
|
||||
if (out < val2)
|
||||
out = val2;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void calc_torque(struct vec3 *dst, const struct vec3 *v1,
|
||||
const struct vec3 *v2, float torque, float min_adjust,
|
||||
float t)
|
||||
{
|
||||
struct vec3 line, dir;
|
||||
float orig_dist, torque_dist, adjust_dist;
|
||||
|
||||
if (vec3_close(v1, v2, EPSILON)) {
|
||||
vec3_copy(dst, v1);
|
||||
return;
|
||||
}
|
||||
|
||||
vec3_sub(&line, v2, v1);
|
||||
orig_dist = vec3_len(&line);
|
||||
vec3_mulf(&dir, &line, 1.0f/orig_dist);
|
||||
|
||||
torque_dist = orig_dist*torque; /* use distance to determine speed */
|
||||
adjust_dist = torque_dist*t;
|
||||
|
||||
if (torque_dist < min_adjust) /* prevent from going too slow */
|
||||
torque_dist = min_adjust;
|
||||
|
||||
if (adjust_dist <= (orig_dist-LARGE_EPSILON)) {
|
||||
vec3_mulf(dst, &dir, adjust_dist);
|
||||
vec3_add(dst, dst, v1); /* add torque */
|
||||
} else {
|
||||
vec3_copy(dst, v2); /* clamp if overshoot */
|
||||
}
|
||||
}
|
||||
|
||||
float rand_float(int positive_only)
|
||||
{
|
||||
if (positive_only)
|
||||
return (float)((double)rand()/(double)RAND_MAX);
|
||||
else
|
||||
return (float)(((double)rand()/(double)RAND_MAX*2.0)-1.0);
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef MATH_EXTRA_H
|
||||
#define MATH_EXTRA_H
|
||||
|
||||
#include "../util/c99defs.h"
|
||||
|
||||
/*
|
||||
* A few general math functions that I couldn't really decide where to put.
|
||||
*
|
||||
* Polar/Cart conversion, torque functions (for smooth movement), percentage,
|
||||
* random floats.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct vec2;
|
||||
struct vec3;
|
||||
|
||||
EXPORT void polar_to_cart(struct vec3 *dst, const struct vec3 *v);
|
||||
EXPORT void cart_to_polar(struct vec3 *dst, const struct vec3 *v);
|
||||
|
||||
EXPORT void norm_to_polar(struct vec2 *dst, const struct vec3 *norm);
|
||||
EXPORT void polar_to_norm(struct vec3 *dst, const struct vec2 *polar);
|
||||
|
||||
EXPORT float calc_torquef(float val1, float val2, float torque,
|
||||
float min_adjust, float t);
|
||||
|
||||
EXPORT void calc_torque(struct vec3 *dst, const struct vec3 *v1,
|
||||
const struct vec3 *v2, float torque, float min_adjust,
|
||||
float t);
|
||||
|
||||
static inline float get_percentage(float start, float end, float mid)
|
||||
{
|
||||
return (mid-start) / (end-start);
|
||||
}
|
||||
|
||||
static inline float get_percentagei(int start, int end, int mid)
|
||||
{
|
||||
return (float)(mid-start) / (float)(end-start);
|
||||
}
|
||||
|
||||
EXPORT float rand_float(int positive_only);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,145 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "matrix3.h"
|
||||
#include "matrix4.h"
|
||||
#include "plane.h"
|
||||
#include "quat.h"
|
||||
|
||||
|
||||
void matrix3_from_quat(struct matrix3 *dst, const struct quat *q)
|
||||
{
|
||||
float norm = quat_dot(q, q);
|
||||
float s = (norm > 0.0f) ? (2.0f/norm) : 0.0f;
|
||||
|
||||
float xx = q->x * q->x * s;
|
||||
float yy = q->y * q->y * s;
|
||||
float zz = q->z * q->z * s;
|
||||
float xy = q->x * q->y * s;
|
||||
float xz = q->x * q->z * s;
|
||||
float yz = q->y * q->z * s;
|
||||
float wx = q->w * q->x * s;
|
||||
float wy = q->w * q->y * s;
|
||||
float wz = q->w * q->z * s;
|
||||
|
||||
dst->x.x = 1.0f - (yy + zz);
|
||||
dst->x.y = xy + wz;
|
||||
dst->x.z = xz - wy;
|
||||
dst->x.w = 0.0f;
|
||||
|
||||
dst->y.x = xy - wz;
|
||||
dst->y.y = 1.0f - (xx + zz);
|
||||
dst->y.z = yz + wx;
|
||||
dst->y.w = 0.0f;
|
||||
|
||||
dst->z.x = xz + wy;
|
||||
dst->z.y = yz - wx;
|
||||
dst->z.z = 1.0f - (xx + yy);
|
||||
dst->z.w = 0.0f;
|
||||
|
||||
vec3_zero(&dst->t);
|
||||
}
|
||||
|
||||
void matrix3_from_axisang(struct matrix3 *dst, const struct axisang *aa)
|
||||
{
|
||||
struct quat q;
|
||||
quat_from_axisang(&q, aa);
|
||||
matrix3_from_quat(dst, &q);
|
||||
}
|
||||
|
||||
void matrix3_from_matrix4(struct matrix3 *dst, const struct matrix4 *m)
|
||||
{
|
||||
dst->x.m = m->x.m;
|
||||
dst->y.m = m->y.m;
|
||||
dst->z.m = m->z.m;
|
||||
dst->t.m = m->t.m;
|
||||
dst->x.w = 0.0f;
|
||||
dst->y.w = 0.0f;
|
||||
dst->z.w = 0.0f;
|
||||
dst->t.w = 0.0f;
|
||||
}
|
||||
|
||||
void matrix3_mul(struct matrix3 *dst, const struct matrix3 *m1,
|
||||
const struct matrix3 *m2)
|
||||
{
|
||||
vec3_rotate(&dst->x, &m1->x, m2);
|
||||
vec3_rotate(&dst->y, &m1->y, m2);
|
||||
vec3_rotate(&dst->z, &m1->z, m2);
|
||||
vec3_transform(&dst->t, &m1->t, m2);
|
||||
}
|
||||
|
||||
void matrix3_rotate(struct matrix3 *dst, const struct matrix3 *m,
|
||||
const struct quat *q)
|
||||
{
|
||||
struct matrix3 temp;
|
||||
matrix3_from_quat(&temp, q);
|
||||
matrix3_mul(dst, m, &temp);
|
||||
}
|
||||
|
||||
void matrix3_rotate_aa(struct matrix3 *dst, const struct matrix3 *m,
|
||||
const struct axisang *aa)
|
||||
{
|
||||
struct matrix3 temp;
|
||||
matrix3_from_axisang(&temp, aa);
|
||||
matrix3_mul(dst, m, &temp);
|
||||
}
|
||||
|
||||
void matrix3_scale(struct matrix3 *dst, const struct matrix3 *m,
|
||||
const struct vec3 *v)
|
||||
{
|
||||
vec3_mul(&dst->x, &m->x, v);
|
||||
vec3_mul(&dst->y, &m->y, v);
|
||||
vec3_mul(&dst->z, &m->z, v);
|
||||
vec3_mul(&dst->t, &m->t, v);
|
||||
}
|
||||
|
||||
void matrix3_transpose(struct matrix3 *dst, const struct matrix3 *m)
|
||||
{
|
||||
__m128 tmp1, tmp2;
|
||||
vec3_transform(&dst->t, &m->t, m);
|
||||
vec3_neg(&dst->t, &dst->t);
|
||||
|
||||
tmp1 = _mm_movelh_ps(m->x.m, m->y.m);
|
||||
tmp2 = _mm_movehl_ps(m->y.m, m->x.m);
|
||||
dst->x.m = _mm_shuffle_ps(tmp1, m->z.m, _MM_SHUFFLE(3, 0, 2, 0));
|
||||
dst->y.m = _mm_shuffle_ps(tmp1, m->z.m, _MM_SHUFFLE(3, 1, 3, 1));
|
||||
dst->z.m = _mm_shuffle_ps(tmp2, m->z.m, _MM_SHUFFLE(3, 2, 2, 0));
|
||||
}
|
||||
|
||||
void matrix3_inv(struct matrix3 *dst, const struct matrix3 *m)
|
||||
{
|
||||
matrix4_inv((struct matrix4*)dst, (struct matrix4*)m);
|
||||
}
|
||||
|
||||
void matrix3_mirror(struct matrix3 *dst, const struct matrix3 *m,
|
||||
const struct plane *p)
|
||||
{
|
||||
vec3_mirrorv(&dst->x, &m->x, &p->dir);
|
||||
vec3_mirrorv(&dst->y, &m->y, &p->dir);
|
||||
vec3_mirrorv(&dst->z, &m->z, &p->dir);
|
||||
vec3_mirror(&dst->t, &m->t, p);
|
||||
}
|
||||
|
||||
void matrix3_mirrorv(struct matrix3 *dst, const struct matrix3 *m,
|
||||
const struct vec3 *v)
|
||||
{
|
||||
vec3_mirrorv(&dst->x, &m->x, v);
|
||||
vec3_mirrorv(&dst->y, &m->y, v);
|
||||
vec3_mirrorv(&dst->z, &m->z, v);
|
||||
vec3_mirrorv(&dst->t, &m->t, v);
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef MATRIX_H
|
||||
#define MATRIX_H
|
||||
|
||||
#include "vec3.h"
|
||||
|
||||
/* 3x4 Matrix */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct axisang;
|
||||
struct matrix4;
|
||||
|
||||
struct matrix3 {
|
||||
struct vec3 x;
|
||||
struct vec3 y;
|
||||
struct vec3 z;
|
||||
struct vec3 t;
|
||||
};
|
||||
|
||||
static inline void matrix3_copy(struct matrix3 *dst, const struct matrix3 *m)
|
||||
{
|
||||
vec3_copy(&dst->x, &m->x);
|
||||
vec3_copy(&dst->y, &m->y);
|
||||
vec3_copy(&dst->z, &m->z);
|
||||
vec3_copy(&dst->t, &m->t);
|
||||
}
|
||||
|
||||
static inline void matrix3_identity(struct matrix3 *dst)
|
||||
{
|
||||
vec3_zero(&dst->x);
|
||||
vec3_zero(&dst->y);
|
||||
vec3_zero(&dst->z);
|
||||
vec3_zero(&dst->t);
|
||||
dst->x.x = dst->y.y = dst->z.z = 1.0f;
|
||||
}
|
||||
|
||||
EXPORT void matrix3_from_quat(struct matrix3 *dst, const struct quat *q);
|
||||
EXPORT void matrix3_from_axisang(struct matrix3 *dst,
|
||||
const struct axisang *aa);
|
||||
EXPORT void matrix3_from_matrix4(struct matrix3 *dst, const struct matrix4 *m);
|
||||
|
||||
EXPORT void matrix3_mul(struct matrix3 *dst, const struct matrix3 *m1,
|
||||
const struct matrix3 *m2);
|
||||
static inline void matrix3_translate(struct matrix3 *dst,
|
||||
const struct matrix3 *m, const struct vec3 *v)
|
||||
{
|
||||
vec3_sub(&dst->t, &m->t, v);
|
||||
}
|
||||
|
||||
EXPORT void matrix3_rotate(struct matrix3 *dst, const struct matrix3 *m,
|
||||
const struct quat *q);
|
||||
EXPORT void matrix3_rotate_aa(struct matrix3 *dst, const struct matrix3 *m,
|
||||
const struct axisang *aa);
|
||||
EXPORT void matrix3_scale(struct matrix3 *dst, const struct matrix3 *m,
|
||||
const struct vec3 *v);
|
||||
EXPORT void matrix3_transpose(struct matrix3 *dst, const struct matrix3 *m);
|
||||
EXPORT void matrix3_inv(struct matrix3 *dst, const struct matrix3 *m);
|
||||
|
||||
EXPORT void matrix3_mirror(struct matrix3 *dst, const struct matrix3 *m,
|
||||
const struct plane *p);
|
||||
EXPORT void matrix3_mirrorv(struct matrix3 *dst, const struct matrix3 *m,
|
||||
const struct vec3 *v);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,209 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "math-defs.h"
|
||||
#include "matrix4.h"
|
||||
#include "matrix3.h"
|
||||
|
||||
void matrix4_from_matrix3(struct matrix4 *dst, const struct matrix3 *m)
|
||||
{
|
||||
dst->x.m = m->x.m;
|
||||
dst->y.m = m->y.m;
|
||||
dst->z.m = m->z.m;
|
||||
dst->t.m = m->t.m;
|
||||
dst->t.w = 1.0f;
|
||||
}
|
||||
|
||||
void matrix4_mul(struct matrix4 *dst, const struct matrix4 *m1,
|
||||
const struct matrix4 *m2)
|
||||
{
|
||||
const struct vec4 *m1v = (const struct vec4*)m1;
|
||||
const float *m2f = (const float*)m2;
|
||||
struct vec4 out[4];
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (j=0; j<4; j++) {
|
||||
struct vec4 temp;
|
||||
vec4_set(&temp, m2f[j], m2f[j+4], m2f[j+8], m2f[j+12]);
|
||||
out[i].ptr[j] = vec4_dot(&m1v[i], &temp);
|
||||
}
|
||||
}
|
||||
|
||||
matrix4_copy(dst, (struct matrix4*)out);
|
||||
}
|
||||
|
||||
static inline void get_3x3_submatrix(float *dst, const struct matrix4 *m,
|
||||
int i, int j)
|
||||
{
|
||||
const float *mf = (const float *)m;
|
||||
int ti, tj, idst, jdst;
|
||||
|
||||
for (ti = 0; ti < 4; ti++) {
|
||||
if (ti < i)
|
||||
idst = ti;
|
||||
else if (ti > i)
|
||||
idst = ti-1;
|
||||
else
|
||||
continue;
|
||||
|
||||
for (tj = 0; tj < 4; tj++) {
|
||||
if (tj < j)
|
||||
jdst = tj;
|
||||
else if (tj > j)
|
||||
jdst = tj-1;
|
||||
else
|
||||
continue;
|
||||
|
||||
dst[(idst*3) + jdst] = mf[(ti*4) + tj];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline float get_3x3_determinant(const float *m)
|
||||
{
|
||||
return (m[0] * ((m[4]*m[8]) - (m[7]*m[5]))) -
|
||||
(m[1] * ((m[3]*m[8]) - (m[6]*m[5]))) +
|
||||
(m[2] * ((m[3]*m[7]) - (m[6]*m[4])));
|
||||
}
|
||||
|
||||
float matrix4_determinant(const struct matrix4 *m)
|
||||
{
|
||||
const float *mf = (const float *)m;
|
||||
float det, result = 0.0f, i = 1.0f;
|
||||
float m3x3[9];
|
||||
int n;
|
||||
|
||||
for (n = 0; n < 4; n++, i *= -1.0f) {
|
||||
get_3x3_submatrix(m3x3, m, 0, n);
|
||||
|
||||
det = get_3x3_determinant(m3x3);
|
||||
result += mf[n] * det * i;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool matrix4_inv(struct matrix4 *dst, const struct matrix4 *m)
|
||||
{
|
||||
struct vec4 *dstv = (struct vec4 *)dst;
|
||||
float det = matrix4_determinant(m);
|
||||
float m3x3[9];
|
||||
int i, j, sign;
|
||||
|
||||
if (fabs(det) < 0.0005f)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
sign = 1 - ((i+j) % 2) * 2;
|
||||
get_3x3_submatrix(m3x3, m, i, j);
|
||||
dstv[j].ptr[i] = get_3x3_determinant(m3x3) *
|
||||
(float)sign / det;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void matrix4_transpose(struct matrix4 *dst, const struct matrix4 *m)
|
||||
{
|
||||
struct matrix4 temp;
|
||||
|
||||
/* TODO: Use SSE */
|
||||
temp.x.x = m->x.x;
|
||||
temp.x.y = m->y.x;
|
||||
temp.x.z = m->z.x;
|
||||
temp.x.w = m->t.x;
|
||||
temp.y.x = m->x.y;
|
||||
temp.y.y = m->y.y;
|
||||
temp.y.z = m->z.y;
|
||||
temp.y.w = m->t.y;
|
||||
temp.z.x = m->x.z;
|
||||
temp.z.y = m->y.z;
|
||||
temp.z.z = m->z.z;
|
||||
temp.z.w = m->t.z;
|
||||
temp.t.x = m->x.w;
|
||||
temp.t.y = m->y.w;
|
||||
temp.t.z = m->z.w;
|
||||
temp.t.w = m->t.w;
|
||||
|
||||
matrix4_copy(dst, &temp);
|
||||
}
|
||||
|
||||
void matrix4_ortho(struct matrix4 *dst, float left, float right,
|
||||
float top, float bottom, float near, float far)
|
||||
{
|
||||
float rml = right-left;
|
||||
float bmt = bottom-top;
|
||||
float fmn = far-near;
|
||||
|
||||
vec4_zero(&dst->x);
|
||||
vec4_zero(&dst->y);
|
||||
vec4_zero(&dst->z);
|
||||
vec4_zero(&dst->t);
|
||||
|
||||
dst->x.x = 2.0f / rml;
|
||||
dst->t.x = (left+right) / -rml;
|
||||
|
||||
dst->y.y = 2.0f / -bmt;
|
||||
dst->t.y = (bottom+top) / bmt;
|
||||
|
||||
dst->z.z = 1.0f / fmn;
|
||||
dst->t.z = near / -fmn;
|
||||
|
||||
dst->t.w = 1.0f;
|
||||
}
|
||||
|
||||
void matrix4_frustum(struct matrix4 *dst, float left, float right,
|
||||
float top, float bottom, float near, float far)
|
||||
{
|
||||
float rml = right-left;
|
||||
float bmt = bottom-top;
|
||||
float fmn = far-near;
|
||||
float nearx2 = 2.0f*near;
|
||||
|
||||
vec4_zero(&dst->x);
|
||||
vec4_zero(&dst->y);
|
||||
vec4_zero(&dst->z);
|
||||
vec4_zero(&dst->t);
|
||||
|
||||
dst->x.x = nearx2 / rml;
|
||||
dst->z.x = (left+right) / -rml;
|
||||
|
||||
dst->y.y = nearx2 / -bmt;
|
||||
dst->z.y = (bottom+top) / bmt;
|
||||
|
||||
dst->z.z = far / fmn;
|
||||
dst->t.z = (near*far) / -fmn;
|
||||
|
||||
dst->z.w = 1.0f;
|
||||
}
|
||||
|
||||
void matrix4_perspective(struct matrix4 *dst, float angle,
|
||||
float aspect, float near, float far)
|
||||
{
|
||||
float xmin, xmax, ymin, ymax;
|
||||
|
||||
ymax = near * tanf(RAD(angle)*0.5f);
|
||||
ymin = -ymax;
|
||||
|
||||
xmin = ymin * aspect;
|
||||
xmax = ymax * aspect;
|
||||
|
||||
matrix4_frustum(dst, xmin, xmax, ymin, ymax, near, far);
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef MATRIX4_H
|
||||
#define MATRIX4_H
|
||||
|
||||
#include "vec4.h"
|
||||
|
||||
/* 4x4 Matrix */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct matrix3;
|
||||
|
||||
struct matrix4 {
|
||||
struct vec4 x, y, z, t;
|
||||
};
|
||||
|
||||
static inline void matrix4_copy(struct matrix4 *dst, const struct matrix4 *m)
|
||||
{
|
||||
dst->x.m = m->x.m;
|
||||
dst->y.m = m->y.m;
|
||||
dst->z.m = m->z.m;
|
||||
dst->t.m = m->t.m;
|
||||
}
|
||||
|
||||
static inline void matrix4_identity(struct matrix4 *dst)
|
||||
{
|
||||
vec4_zero(&dst->x);
|
||||
vec4_zero(&dst->y);
|
||||
vec4_zero(&dst->z);
|
||||
vec4_zero(&dst->t);
|
||||
dst->x.x = 1.0f;
|
||||
dst->y.y = 1.0f;
|
||||
dst->z.z = 1.0f;
|
||||
dst->t.w = 1.0f;
|
||||
}
|
||||
|
||||
EXPORT void matrix4_from_matrix3(struct matrix4 *dst, const struct matrix3 *m);
|
||||
|
||||
EXPORT void matrix4_mul(struct matrix4 *dst, const struct matrix4 *m1,
|
||||
const struct matrix4 *m2);
|
||||
|
||||
EXPORT float matrix4_determinant(const struct matrix4 *m);
|
||||
|
||||
EXPORT bool matrix4_inv(struct matrix4 *dst, const struct matrix4 *m);
|
||||
EXPORT void matrix4_transpose(struct matrix4 *dst, const struct matrix4 *m);
|
||||
|
||||
EXPORT void matrix4_ortho(struct matrix4 *dst, float left, float right,
|
||||
float top, float bottom, float near, float far);
|
||||
EXPORT void matrix4_frustum(struct matrix4 *dst, float left, float right,
|
||||
float top, float bottom, float near, float far);
|
||||
EXPORT void matrix4_perspective(struct matrix4 *dst, float angle,
|
||||
float aspect, float near, float far);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,148 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "../util/c99defs.h"
|
||||
#include "matrix3.h"
|
||||
#include "plane.h"
|
||||
|
||||
void plane_from_tri(struct plane *dst,
|
||||
const struct vec3 *v1,
|
||||
const struct vec3 *v2,
|
||||
const struct vec3 *v3)
|
||||
{
|
||||
struct vec3 temp;
|
||||
|
||||
vec3_sub(&temp, v2, v1);
|
||||
vec3_sub(&dst->dir, v3, v1);
|
||||
vec3_cross(&dst->dir, &temp, &dst->dir);
|
||||
vec3_norm(&dst->dir, &dst->dir);
|
||||
dst->dist = vec3_dot(v1, &dst->dir);
|
||||
}
|
||||
|
||||
void plane_transform(struct plane *dst, const struct plane *p,
|
||||
const struct matrix3 *m)
|
||||
{
|
||||
struct vec3 temp;
|
||||
|
||||
vec3_transform(&dst->dir, &p->dir, m);
|
||||
vec3_norm(&dst->dir, &dst->dir);
|
||||
|
||||
vec3_transform(&temp, &m->t, m);
|
||||
dst->dist = p->dist - vec3_dot(&dst->dir, &temp);
|
||||
}
|
||||
|
||||
bool plane_intersection_ray(const struct plane *p, const struct vec3 *orig,
|
||||
const struct vec3 *dir, float *t)
|
||||
{
|
||||
float c = vec3_dot(&p->dir, dir);
|
||||
|
||||
if (fabsf(c) < EPSILON) {
|
||||
*t = 0.0f;
|
||||
return false;
|
||||
} else {
|
||||
*t = (p->dist - vec3_dot(&p->dir, orig)) / c;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool plane_intersection_line(const struct plane *p, const struct vec3 *v1,
|
||||
const struct vec3 *v2, float *t)
|
||||
{
|
||||
float p1_dist, p2_dist, p1_abs_dist, dist2;
|
||||
bool p1_over, p2_over;
|
||||
|
||||
p1_dist = vec3_plane_dist(v1, p);
|
||||
p2_dist = vec3_plane_dist(v2, p);
|
||||
|
||||
if (close_float(p1_dist, 0.0f, EPSILON)) {
|
||||
if (close_float(p2_dist, 0.0f, EPSILON))
|
||||
return false;
|
||||
|
||||
*t = 0.0f;
|
||||
return true;
|
||||
} else if (close_float(p2_dist, 0.0f, EPSILON)) {
|
||||
*t = 1.0f;
|
||||
return true;
|
||||
}
|
||||
|
||||
p1_over = (p1_dist > 0.0f);
|
||||
p2_over = (p2_dist > 0.0f);
|
||||
|
||||
if (p1_over == p2_over)
|
||||
return false;
|
||||
|
||||
p1_abs_dist = fabsf(p1_dist);
|
||||
dist2 = p1_abs_dist + fabsf(p2_dist);
|
||||
if (dist2 < EPSILON)
|
||||
return false;
|
||||
|
||||
*t = p1_abs_dist / dist2;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool plane_tri_inside(const struct plane *p,
|
||||
const struct vec3 *v1,
|
||||
const struct vec3 *v2,
|
||||
const struct vec3 *v3,
|
||||
float precision)
|
||||
{
|
||||
/* bit 1: part or all is behind the plane */
|
||||
/* bit 2: part or all is in front of the plane */
|
||||
int sides = 0;
|
||||
float d1 = vec3_plane_dist(v1, p);
|
||||
float d2 = vec3_plane_dist(v2, p);
|
||||
float d3 = vec3_plane_dist(v3, p);
|
||||
|
||||
if (d1 >= precision)
|
||||
sides = 2;
|
||||
else if (d1 <= -precision)
|
||||
sides = 1;
|
||||
|
||||
if (d2 >= precision)
|
||||
sides |= 2;
|
||||
else if (d2 <= -precision)
|
||||
sides |= 1;
|
||||
|
||||
if (d3 >= precision)
|
||||
sides |= 2;
|
||||
else if (d3 <= -precision)
|
||||
sides |= 1;
|
||||
|
||||
return sides;
|
||||
}
|
||||
|
||||
bool plane_line_inside(const struct plane *p, const struct vec3 *v1,
|
||||
const struct vec3 *v2, float precision)
|
||||
{
|
||||
/* bit 1: part or all is behind the plane */
|
||||
/* bit 2: part or all is in front of the plane */
|
||||
int sides = 0;
|
||||
float d1 = vec3_plane_dist(v1, p);
|
||||
float d2 = vec3_plane_dist(v2, p);
|
||||
|
||||
if (d1 >= precision)
|
||||
sides = 2;
|
||||
else if (d1 <= -precision)
|
||||
sides = 1;
|
||||
|
||||
if (d2 >= precision)
|
||||
sides |= 2;
|
||||
else if (d2 <= -precision)
|
||||
sides |= 1;
|
||||
|
||||
return sides;
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef PLANE_H
|
||||
#define PLANE_H
|
||||
|
||||
#include "math-defs.h"
|
||||
#include "vec3.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct matrix3;
|
||||
|
||||
struct plane {
|
||||
struct vec3 dir;
|
||||
float dist;
|
||||
};
|
||||
|
||||
static inline void plane_copy(struct plane *dst, const struct plane *p)
|
||||
{
|
||||
vec3_copy(&dst->dir, &p->dir);
|
||||
dst->dist = p->dist;
|
||||
}
|
||||
|
||||
static inline void plane_set(struct plane *dst, const struct vec3 *dir,
|
||||
float dist)
|
||||
{
|
||||
vec3_copy(&dst->dir, dir);
|
||||
dst->dist = dist;
|
||||
}
|
||||
|
||||
static inline void plane_setf(struct plane *dst, float a, float b, float c,
|
||||
float d)
|
||||
{
|
||||
vec3_set(&dst->dir, a, b, c);
|
||||
dst->dist = d;
|
||||
}
|
||||
|
||||
EXPORT void plane_from_tri(struct plane *dst,
|
||||
const struct vec3 *v1,
|
||||
const struct vec3 *v2,
|
||||
const struct vec3 *v3);
|
||||
|
||||
EXPORT void plane_transform(struct plane *dst, const struct plane *p,
|
||||
const struct matrix3 *m);
|
||||
|
||||
EXPORT bool plane_intersection_ray(const struct plane *p,
|
||||
const struct vec3 *orig, const struct vec3 *dir, float *t);
|
||||
EXPORT bool plane_intersection_line(const struct plane *p,
|
||||
const struct vec3 *v1, const struct vec3 *v2, float *t);
|
||||
|
||||
EXPORT bool plane_tri_inside(const struct plane *p,
|
||||
const struct vec3 *v1,
|
||||
const struct vec3 *v2,
|
||||
const struct vec3 *v3,
|
||||
float precision);
|
||||
|
||||
EXPORT bool plane_line_inside(const struct plane *p, const struct vec3 *v1,
|
||||
const struct vec3 *v2, float precision);
|
||||
|
||||
static inline bool plane_close(const struct plane *p1, const struct plane *p2,
|
||||
float precision)
|
||||
{
|
||||
return vec3_close(&p1->dir, &p2->dir, precision) &&
|
||||
close_float(p1->dist, p2->dist, precision);
|
||||
}
|
||||
|
||||
static inline bool plane_coplanar(const struct plane *p1,
|
||||
const struct plane *p2, float precision)
|
||||
{
|
||||
float cos_angle = vec3_dot(&p1->dir, &p2->dir);
|
||||
|
||||
if (close_float(cos_angle, 1.0f, precision))
|
||||
return close_float(p1->dist, p2->dist, precision);
|
||||
else if (close_float(cos_angle, -1.0f, precision))
|
||||
return close_float(-p1->dist, p2->dist, precision);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,216 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "quat.h"
|
||||
#include "vec3.h"
|
||||
#include "matrix3.h"
|
||||
#include "axisang.h"
|
||||
|
||||
static inline void quat_vec3(struct vec3 *v, const struct quat *q)
|
||||
{
|
||||
v->m = q->m;
|
||||
v->w = 0.0f;
|
||||
}
|
||||
|
||||
void quat_mul(struct quat *dst, const struct quat *q1, const struct quat *q2)
|
||||
{
|
||||
struct vec3 q1axis, q2axis;
|
||||
struct vec3 temp1, temp2;
|
||||
|
||||
quat_vec3(&q1axis, q1);
|
||||
quat_vec3(&q2axis, q2);
|
||||
|
||||
vec3_mulf(&temp1, &q2axis, q1->w);
|
||||
vec3_mulf(&temp2, &q1axis, q2->w);
|
||||
vec3_add(&temp1, &temp1, &temp2);
|
||||
vec3_cross(&temp2, &q1axis, &q2axis);
|
||||
vec3_add((struct vec3 *)dst, &temp1, &temp2);
|
||||
|
||||
dst->w = (q1->w * q2->w) - vec3_dot(&q1axis, &q2axis);
|
||||
}
|
||||
|
||||
void quat_from_axisang(struct quat *dst, const struct axisang *aa)
|
||||
{
|
||||
float halfa = aa->w * 0.5f;
|
||||
float sine = sinf(halfa);
|
||||
|
||||
dst->x = aa->x * sine;
|
||||
dst->y = aa->y * sine;
|
||||
dst->z = aa->z * sine;
|
||||
dst->w = cosf(halfa);
|
||||
}
|
||||
|
||||
struct f4x4 {
|
||||
float ptr[4][4];
|
||||
};
|
||||
|
||||
void quat_from_matrix(struct quat *dst, const struct matrix3 *m)
|
||||
{
|
||||
float tr = (m->x.x + m->y.y + m->z.z);
|
||||
float inv_half;
|
||||
float four_d;
|
||||
int i,j,k;
|
||||
|
||||
if (tr > 0.0f) {
|
||||
four_d = sqrtf(tr+1.0f);
|
||||
dst->w = four_d*0.5f;
|
||||
|
||||
inv_half = 0.5f/four_d;
|
||||
dst->x = (m->y.z - m->z.y)*inv_half;
|
||||
dst->y = (m->z.x - m->x.z)*inv_half;
|
||||
dst->z = (m->x.y - m->y.x)*inv_half;
|
||||
} else {
|
||||
struct f4x4 *val = (struct f4x4*)m;
|
||||
|
||||
i = (m->x.x > m->y.y) ? 0 : 1;
|
||||
|
||||
if (m->z.z > val->ptr[i][i])
|
||||
i = 2;
|
||||
|
||||
j = (i+1)%3;
|
||||
k = (i+2)%3;
|
||||
|
||||
/* ---------------------------------- */
|
||||
|
||||
four_d = sqrtf((val->ptr[i][i] - val->ptr[j][j] -
|
||||
val->ptr[k][k]) + 1.0f);
|
||||
|
||||
dst->ptr[i] = four_d*0.5f;
|
||||
|
||||
inv_half = 0.5f/four_d;
|
||||
dst->ptr[j] = (val->ptr[i][j] + val->ptr[j][i])*inv_half;
|
||||
dst->ptr[k] = (val->ptr[i][k] + val->ptr[k][i])*inv_half;
|
||||
dst->w = (val->ptr[j][k] - val->ptr[k][j])*inv_half;
|
||||
}
|
||||
}
|
||||
|
||||
void quat_get_dir(struct vec3 *dst, const struct quat *q)
|
||||
{
|
||||
struct matrix3 m;
|
||||
matrix3_from_quat(&m, q);
|
||||
vec3_copy(dst, &m.z);
|
||||
}
|
||||
|
||||
void quat_set_look_dir(struct quat *dst, const struct vec3 *dir)
|
||||
{
|
||||
struct vec3 new_dir;
|
||||
struct quat xz_rot, yz_rot;
|
||||
bool xz_valid;
|
||||
bool yz_valid;
|
||||
struct axisang aa;
|
||||
|
||||
vec3_norm(&new_dir, dir);
|
||||
vec3_neg(&new_dir, &new_dir);
|
||||
|
||||
quat_identity(&xz_rot);
|
||||
quat_identity(&yz_rot);
|
||||
|
||||
xz_valid = close_float(new_dir.x, 0.0f, EPSILON) ||
|
||||
close_float(new_dir.z, 0.0f, EPSILON);
|
||||
yz_valid = close_float(new_dir.y, 0.0f, EPSILON);
|
||||
|
||||
if (xz_valid) {
|
||||
axisang_set(&aa, 0.0f, 1.0f, 0.0f,
|
||||
atan2f(new_dir.x, new_dir.z));
|
||||
|
||||
quat_from_axisang(&xz_rot, &aa);
|
||||
}
|
||||
if (yz_valid) {
|
||||
axisang_set(&aa, -1.0f, 0.0f, 0.0f, asinf(new_dir.y));
|
||||
quat_from_axisang(&yz_rot, &aa);
|
||||
}
|
||||
|
||||
if (!xz_valid)
|
||||
quat_copy(dst, &yz_rot);
|
||||
else if (!yz_valid)
|
||||
quat_copy(dst, &xz_rot);
|
||||
else
|
||||
quat_mul(dst, &xz_rot, &yz_rot);
|
||||
}
|
||||
|
||||
void quat_log(struct quat *dst, const struct quat *q)
|
||||
{
|
||||
float angle = acosf(q->w);
|
||||
float sine = sinf(angle);
|
||||
float w = q->w;
|
||||
|
||||
quat_copy(dst, q);
|
||||
dst->w = 0.0f;
|
||||
|
||||
if ((fabsf(w) < 1.0f) && (fabsf(sine) >= EPSILON)) {
|
||||
sine = angle/sine;
|
||||
quat_mulf(dst, dst, sine);
|
||||
}
|
||||
}
|
||||
|
||||
void quat_exp(struct quat *dst, const struct quat *q)
|
||||
{
|
||||
float length = sqrtf(q->x*q->x + q->y*q->y + q->z*q->z);
|
||||
float sine = sinf(length);
|
||||
|
||||
quat_copy(dst, q);
|
||||
sine = (length > EPSILON) ? (sine/length) : 1.0f;
|
||||
quat_mulf(dst, dst, sine);
|
||||
dst->w = cosf(length);
|
||||
}
|
||||
|
||||
void quat_interpolate(struct quat *dst, const struct quat *q1,
|
||||
const struct quat *q2, float t)
|
||||
{
|
||||
float dot = quat_dot(q1, q2);
|
||||
float anglef = acosf(dot);
|
||||
float sine, sinei, sinet, sineti;
|
||||
struct quat temp;
|
||||
|
||||
if (anglef >= EPSILON) {
|
||||
sine = sinf(anglef);
|
||||
sinei = 1/sine;
|
||||
sinet = sinf(anglef*t)*sinei;
|
||||
sineti = sinf(anglef*(1.0f-t))*sinei;
|
||||
|
||||
quat_mulf(&temp, q1, sineti);
|
||||
quat_mulf(dst, q2, sinet);
|
||||
quat_add(dst, &temp, dst);
|
||||
} else {
|
||||
quat_sub(&temp, q2, q1);
|
||||
quat_mulf(&temp, &temp, t);
|
||||
quat_add(dst, &temp, q1);
|
||||
}
|
||||
}
|
||||
|
||||
void quat_get_tangent(struct quat *dst, const struct quat *prev,
|
||||
const struct quat *q, const struct quat *next)
|
||||
{
|
||||
struct quat temp;
|
||||
|
||||
quat_sub(&temp, q, prev);
|
||||
quat_add(&temp, &temp, next);
|
||||
quat_sub(&temp, &temp, q);
|
||||
quat_mulf(dst, &temp, 0.5f);
|
||||
}
|
||||
|
||||
void quat_interpolate_cubic(struct quat *dst,
|
||||
const struct quat *q1, const struct quat *q2,
|
||||
const struct quat *m1, const struct quat *m2,
|
||||
float t)
|
||||
{
|
||||
struct quat temp1, temp2;
|
||||
|
||||
quat_interpolate(&temp1, q1, q2, t);
|
||||
quat_interpolate(&temp2, m1, m2, t);
|
||||
quat_interpolate(dst, &temp1, &temp2, 2.0f*(1.0f-t)*t);
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef QUAT_H
|
||||
#define QUAT_H
|
||||
|
||||
#include "../util/c99defs.h"
|
||||
#include "math-defs.h"
|
||||
#include "vec3.h"
|
||||
#include <xmmintrin.h>
|
||||
|
||||
/*
|
||||
* Quaternion math
|
||||
*
|
||||
* Generally used to represent rotational data more than anything. Allows
|
||||
* for efficient and correct rotational interpolation without suffering from
|
||||
* things like gimbal lock.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct matrix3;
|
||||
struct axisang;
|
||||
|
||||
struct quat {
|
||||
union {
|
||||
struct {float x, y, z, w;};
|
||||
float ptr[4];
|
||||
__m128 m;
|
||||
};
|
||||
};
|
||||
|
||||
static inline void quat_identity(struct quat *q)
|
||||
{
|
||||
q->m = _mm_setzero_ps();
|
||||
q->w = 1.0f;
|
||||
}
|
||||
|
||||
static inline void quat_set(struct quat *dst, float x, float y, float z,
|
||||
float w)
|
||||
{
|
||||
dst->m = _mm_set_ps(x, y, z, w);
|
||||
}
|
||||
|
||||
static inline void quat_copy(struct quat *dst, const struct quat *q)
|
||||
{
|
||||
dst->m = q->m;
|
||||
}
|
||||
|
||||
static inline void quat_add(struct quat *dst, const struct quat *q1,
|
||||
const struct quat *q2)
|
||||
{
|
||||
dst->m = _mm_add_ps(q1->m, q2->m);
|
||||
}
|
||||
|
||||
static inline void quat_sub(struct quat *dst, const struct quat *q1,
|
||||
const struct quat *q2)
|
||||
{
|
||||
dst->m = _mm_sub_ps(q1->m, q2->m);
|
||||
}
|
||||
|
||||
EXPORT void quat_mul(struct quat *dst, const struct quat *q1,
|
||||
const struct quat *q2);
|
||||
|
||||
static inline void quat_addf(struct quat *dst, const struct quat *q,
|
||||
float f)
|
||||
{
|
||||
dst->m = _mm_add_ps(q->m, _mm_set1_ps(f));
|
||||
}
|
||||
|
||||
static inline void quat_subf(struct quat *dst, const struct quat *q,
|
||||
float f)
|
||||
{
|
||||
dst->m = _mm_sub_ps(q->m, _mm_set1_ps(f));
|
||||
}
|
||||
|
||||
static inline void quat_mulf(struct quat *dst, const struct quat *q,
|
||||
float f)
|
||||
{
|
||||
dst->m = _mm_mul_ps(q->m, _mm_set1_ps(f));
|
||||
}
|
||||
|
||||
static inline void quat_divf(struct quat *dst, const struct quat *q,
|
||||
float f)
|
||||
{
|
||||
dst->m = _mm_div_ps(q->m, _mm_set1_ps(f));
|
||||
}
|
||||
|
||||
static inline float quat_dot(const struct quat *q1, const struct quat *q2)
|
||||
{
|
||||
struct vec3 add;
|
||||
__m128 mul = _mm_mul_ps(q1->m, q2->m);
|
||||
add.m = _mm_add_ps(_mm_movehl_ps(mul, mul), mul);
|
||||
add.m = _mm_add_ps(_mm_shuffle_ps(add.m, add.m, 0x55), add.m);
|
||||
return add.x;
|
||||
}
|
||||
|
||||
static inline void quat_inv(struct quat *dst, const struct quat *q)
|
||||
{
|
||||
dst->x = -q->x;
|
||||
dst->y = -q->y;
|
||||
dst->z = -q->z;
|
||||
}
|
||||
|
||||
static inline void quat_neg(struct quat *dst, const struct quat *q)
|
||||
{
|
||||
dst->x = -q->x;
|
||||
dst->y = -q->y;
|
||||
dst->z = -q->z;
|
||||
dst->w = -q->w;
|
||||
}
|
||||
|
||||
static inline float quat_len(const struct quat *q)
|
||||
{
|
||||
float dot_val = quat_dot(q, q);
|
||||
return (dot_val > 0.0f) ? sqrtf(dot_val) : 0.0f;
|
||||
}
|
||||
|
||||
static inline float quat_dist(const struct quat *q1, const struct quat *q2)
|
||||
{
|
||||
struct quat temp;
|
||||
float dot_val;
|
||||
|
||||
quat_sub(&temp, q1, q2);
|
||||
dot_val = quat_dot(&temp, &temp);
|
||||
return (dot_val > 0.0f) ? sqrtf(dot_val) : 0.0f;
|
||||
}
|
||||
|
||||
static inline void quat_norm(struct quat *dst, const struct quat *q)
|
||||
{
|
||||
float dot_val = quat_dot(q, q);
|
||||
dst->m = (dot_val > 0.0f) ?
|
||||
_mm_mul_ps(q->m, _mm_set1_ps(1.0f/sqrtf(dot_val))) :
|
||||
_mm_setzero_ps();
|
||||
}
|
||||
|
||||
static inline bool quat_close(const struct quat *q1, const struct quat *q2,
|
||||
float epsilon)
|
||||
{
|
||||
struct quat test;
|
||||
quat_sub(&test, q1, q2);
|
||||
return test.x < epsilon &&
|
||||
test.y < epsilon &&
|
||||
test.z < epsilon &&
|
||||
test.w < epsilon;
|
||||
}
|
||||
|
||||
EXPORT void quat_from_axisang(struct quat *dst, const struct axisang *aa);
|
||||
EXPORT void quat_from_matrix3(struct quat *dst, const struct matrix3 *m);
|
||||
|
||||
EXPORT void quat_get_dir(struct vec3 *dst, const struct quat *q);
|
||||
EXPORT void quat_set_look_dir(struct quat *dst, const struct vec3 *dir);
|
||||
|
||||
EXPORT void quat_log(struct quat *dst, const struct quat *q);
|
||||
EXPORT void quat_exp(struct quat *dst, const struct quat *q);
|
||||
|
||||
EXPORT void quat_interpolate(struct quat *dst, const struct quat *q1,
|
||||
const struct quat *q2, float t);
|
||||
EXPORT void quat_get_tangent(struct quat *dst, const struct quat *prev,
|
||||
const struct quat *q, const struct quat *next);
|
||||
EXPORT void quat_interpolate_cubic(struct quat *dst, const struct quat *q1,
|
||||
const struct quat *q2, const struct quat *m1,
|
||||
const struct quat *m2, float t);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,677 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "shader-parser.h"
|
||||
|
||||
enum shader_param_type get_shader_param_type(const char *type)
|
||||
{
|
||||
if (strcmp(type, "float") == 0)
|
||||
return SHADER_PARAM_FLOAT;
|
||||
else if (strcmp(type, "float2") == 0)
|
||||
return SHADER_PARAM_VEC2;
|
||||
else if (strcmp(type, "float3") == 0)
|
||||
return SHADER_PARAM_VEC3;
|
||||
else if (strcmp(type, "float4") == 0)
|
||||
return SHADER_PARAM_VEC4;
|
||||
else if (astrcmp_n(type, "texture", 7) == 0)
|
||||
return SHADER_PARAM_TEXTURE;
|
||||
else if (strcmp(type, "float3x3") == 0)
|
||||
return SHADER_PARAM_MATRIX3X3;
|
||||
else if (strcmp(type, "float4x4") == 0)
|
||||
return SHADER_PARAM_MATRIX4X4;
|
||||
else if (strcmp(type, "bool") == 0)
|
||||
return SHADER_PARAM_BOOL;
|
||||
else if (strcmp(type, "int") == 0)
|
||||
return SHADER_PARAM_INT;
|
||||
else if (strcmp(type, "string") == 0)
|
||||
return SHADER_PARAM_STRING;
|
||||
|
||||
return SHADER_PARAM_UNKNOWN;
|
||||
}
|
||||
|
||||
enum gs_sample_filter get_sample_filter(const char *filter)
|
||||
{
|
||||
if (astrcmpi(filter, "Anisotropy") == 0)
|
||||
return GS_FILTER_ANISOTROPIC;
|
||||
|
||||
else if (astrcmpi(filter, "Point") == 0 ||
|
||||
strcmp(filter, "MIN_MAG_MIP_POINT") == 0)
|
||||
return GS_FILTER_POINT;
|
||||
|
||||
else if (astrcmpi(filter, "Linear") == 0 ||
|
||||
strcmp(filter, "MIN_MAG_MIP_LINEAR") == 0)
|
||||
return GS_FILTER_LINEAR;
|
||||
|
||||
else if (strcmp(filter, "MIN_MAG_POINT_MIP_LINEAR") == 0)
|
||||
return GS_FILTER_MIN_MAG_POINT_MIP_LINEAR;
|
||||
|
||||
else if (strcmp(filter, "MIN_POINT_MAG_LINEAR_MIP_POINT") == 0)
|
||||
return GS_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
|
||||
|
||||
else if (strcmp(filter, "MIN_POINT_MAG_MIP_LINEAR") == 0)
|
||||
return GS_FILTER_MIN_POINT_MAG_MIP_LINEAR;
|
||||
|
||||
else if (strcmp(filter, "MIN_LINEAR_MAG_MIP_POINT") == 0)
|
||||
return GS_FILTER_MIN_LINEAR_MAG_MIP_POINT;
|
||||
|
||||
else if (strcmp(filter, "MIN_LINEAR_MAG_POINT_MIP_LINEAR") == 0)
|
||||
return GS_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
|
||||
|
||||
else if (strcmp(filter, "MIN_MAG_LINEAR_MIP_POINT") == 0)
|
||||
return GS_FILTER_MIN_MAG_LINEAR_MIP_POINT;
|
||||
|
||||
return GS_FILTER_LINEAR;
|
||||
}
|
||||
|
||||
extern enum gs_address_mode get_address_mode(const char *mode)
|
||||
{
|
||||
if (astrcmpi(mode, "Wrap") == 0 || astrcmpi(mode, "Repeat") == 0)
|
||||
return GS_ADDRESS_WRAP;
|
||||
else if (astrcmpi(mode, "Clamp") == 0 || astrcmpi(mode, "None") == 0)
|
||||
return GS_ADDRESS_CLAMP;
|
||||
else if (astrcmpi(mode, "Mirror") == 0)
|
||||
return GS_ADDRESS_MIRROR;
|
||||
else if (astrcmpi(mode, "Border") == 0)
|
||||
return GS_ADDRESS_BORDER;
|
||||
else if (astrcmpi(mode, "MirrorOnce") == 0)
|
||||
return GS_ADDRESS_MIRRORONCE;
|
||||
|
||||
return GS_ADDRESS_CLAMP;
|
||||
}
|
||||
|
||||
void shader_sampler_convert(struct shader_sampler *ss,
|
||||
struct gs_sampler_info *info)
|
||||
{
|
||||
size_t i;
|
||||
memset(info, 0, sizeof(struct gs_sampler_info));
|
||||
|
||||
for (i = 0; i < ss->states.num; i++) {
|
||||
const char *state = ss->states.array[i];
|
||||
const char *value = ss->values.array[i];
|
||||
|
||||
if (astrcmpi(state, "Filter") == 0)
|
||||
info->filter = get_sample_filter(value);
|
||||
else if (astrcmpi(state, "AddressU") == 0)
|
||||
info->address_u = get_address_mode(value);
|
||||
else if (astrcmpi(state, "AddressV") == 0)
|
||||
info->address_v = get_address_mode(value);
|
||||
else if (astrcmpi(state, "AddressW") == 0)
|
||||
info->address_w = get_address_mode(value);
|
||||
else if (astrcmpi(state, "MaxAnisotropy") == 0)
|
||||
info->max_anisotropy = strtol(value, NULL, 10);
|
||||
/*else if (astrcmpi(state, "BorderColor") == 0)
|
||||
// TODO */
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static int sp_parse_sampler_state_item(struct shader_parser *sp,
|
||||
struct shader_sampler *ss)
|
||||
{
|
||||
int ret;
|
||||
char *state = NULL, *value = NULL;
|
||||
|
||||
ret = next_name(&sp->cfp, &state, "state name", ";");
|
||||
if (ret != PARSE_SUCCESS) goto fail;
|
||||
|
||||
ret = next_token_should_be(&sp->cfp, "=", ";", NULL);
|
||||
if (ret != PARSE_SUCCESS) goto fail;
|
||||
|
||||
ret = next_name(&sp->cfp, &value, "value name", ";");
|
||||
if (ret != PARSE_SUCCESS) goto fail;
|
||||
|
||||
ret = next_token_should_be(&sp->cfp, ";", ";", NULL);
|
||||
if (ret != PARSE_SUCCESS) goto fail;
|
||||
|
||||
da_push_back(ss->states, &state);
|
||||
da_push_back(ss->values, &value);
|
||||
return ret;
|
||||
|
||||
fail:
|
||||
bfree(state);
|
||||
bfree(value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sp_parse_sampler_state(struct shader_parser *sp)
|
||||
{
|
||||
struct shader_sampler ss;
|
||||
struct cf_token peek;
|
||||
shader_sampler_init(&ss);
|
||||
|
||||
if (next_name(&sp->cfp, &ss.name, "name", ";") != PARSE_SUCCESS)
|
||||
goto error;
|
||||
if (next_token_should_be(&sp->cfp, "{", ";", NULL) != PARSE_SUCCESS)
|
||||
goto error;
|
||||
|
||||
if (!peek_valid_token(&sp->cfp, &peek))
|
||||
goto error;
|
||||
|
||||
while (strref_cmp(&peek.str, "}") != 0) {
|
||||
int ret = sp_parse_sampler_state_item(sp, &ss);
|
||||
if (ret == PARSE_EOF)
|
||||
goto error;
|
||||
|
||||
if (!peek_valid_token(&sp->cfp, &peek))
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (next_token_should_be(&sp->cfp, "}", ";", NULL) != PARSE_SUCCESS)
|
||||
goto error;
|
||||
if (next_token_should_be(&sp->cfp, ";", NULL, NULL) != PARSE_SUCCESS)
|
||||
goto error;
|
||||
|
||||
da_push_back(sp->samplers, &ss);
|
||||
return;
|
||||
|
||||
error:
|
||||
shader_sampler_free(&ss);
|
||||
}
|
||||
|
||||
static inline int sp_parse_struct_var(struct shader_parser *sp,
|
||||
struct shader_var *var)
|
||||
{
|
||||
int errcode;
|
||||
|
||||
/* -------------------------------------- */
|
||||
/* variable type */
|
||||
|
||||
if (!next_valid_token(&sp->cfp)) return PARSE_EOF;
|
||||
|
||||
if (token_is(&sp->cfp, ";")) return PARSE_CONTINUE;
|
||||
if (token_is(&sp->cfp, "}")) return PARSE_BREAK;
|
||||
|
||||
errcode = token_is_type(&sp->cfp, CFTOKEN_NAME, "type name", ";");
|
||||
if (errcode != PARSE_SUCCESS)
|
||||
return errcode;
|
||||
|
||||
copy_token(&sp->cfp, &var->type);
|
||||
|
||||
/* -------------------------------------- */
|
||||
/* variable name */
|
||||
|
||||
if (!next_valid_token(&sp->cfp)) return PARSE_EOF;
|
||||
|
||||
if (token_is(&sp->cfp, ";")) return PARSE_UNEXPECTED_CONTINUE;
|
||||
if (token_is(&sp->cfp, "}")) return PARSE_UNEXPECTED_BREAK;
|
||||
|
||||
errcode = token_is_type(&sp->cfp, CFTOKEN_NAME, "variable name", ";");
|
||||
if (errcode != PARSE_SUCCESS)
|
||||
return errcode;
|
||||
|
||||
copy_token(&sp->cfp, &var->name);
|
||||
|
||||
/* -------------------------------------- */
|
||||
/* variable mapping if any (POSITION, TEXCOORD, etc) */
|
||||
|
||||
if (!next_valid_token(&sp->cfp)) return PARSE_EOF;
|
||||
|
||||
if (token_is(&sp->cfp, ":")) {
|
||||
if (!next_valid_token(&sp->cfp)) return PARSE_EOF;
|
||||
|
||||
if (token_is(&sp->cfp, ";")) return PARSE_UNEXPECTED_CONTINUE;
|
||||
if (token_is(&sp->cfp, "}")) return PARSE_UNEXPECTED_BREAK;
|
||||
|
||||
errcode = token_is_type(&sp->cfp, CFTOKEN_NAME,
|
||||
"mapping name", ";");
|
||||
if (errcode != PARSE_SUCCESS)
|
||||
return errcode;
|
||||
|
||||
copy_token(&sp->cfp, &var->mapping);
|
||||
|
||||
if (!next_valid_token(&sp->cfp)) return PARSE_EOF;
|
||||
}
|
||||
|
||||
/* -------------------------------------- */
|
||||
|
||||
if (!token_is(&sp->cfp, ";")) {
|
||||
if (!go_to_valid_token(&sp->cfp, ";", "}"))
|
||||
return PARSE_EOF;
|
||||
return PARSE_CONTINUE;
|
||||
}
|
||||
|
||||
return PARSE_SUCCESS;
|
||||
}
|
||||
|
||||
static void sp_parse_struct(struct shader_parser *sp)
|
||||
{
|
||||
struct shader_struct ss;
|
||||
shader_struct_init(&ss);
|
||||
|
||||
if (next_name(&sp->cfp, &ss.name, "name", ";") != PARSE_SUCCESS)
|
||||
goto error;
|
||||
if (next_token_should_be(&sp->cfp, "{", ";", NULL) != PARSE_SUCCESS)
|
||||
goto error;
|
||||
|
||||
/* get structure variables */
|
||||
while (true) {
|
||||
bool do_break = false;
|
||||
struct shader_var var;
|
||||
|
||||
shader_var_init(&var);
|
||||
|
||||
switch (sp_parse_struct_var(sp, &var)) {
|
||||
|
||||
case PARSE_UNEXPECTED_CONTINUE:
|
||||
cf_adderror_syntax_error(&sp->cfp);
|
||||
case PARSE_CONTINUE:
|
||||
shader_var_free(&var);
|
||||
continue;
|
||||
|
||||
case PARSE_UNEXPECTED_BREAK:
|
||||
cf_adderror_syntax_error(&sp->cfp);
|
||||
case PARSE_BREAK:
|
||||
shader_var_free(&var);
|
||||
do_break = true;
|
||||
break;
|
||||
|
||||
case PARSE_EOF:
|
||||
shader_var_free(&var);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (do_break)
|
||||
break;
|
||||
|
||||
da_push_back(ss.vars, &var);
|
||||
}
|
||||
|
||||
if (next_token_should_be(&sp->cfp, ";", NULL, NULL) != PARSE_SUCCESS)
|
||||
goto error;
|
||||
|
||||
da_push_back(sp->structs, &ss);
|
||||
return;
|
||||
|
||||
error:
|
||||
shader_struct_free(&ss);
|
||||
}
|
||||
|
||||
static inline int sp_check_for_keyword(struct shader_parser *sp,
|
||||
const char *keyword, bool *val)
|
||||
{
|
||||
bool new_val;
|
||||
new_val = token_is(&sp->cfp, keyword);
|
||||
if (new_val) {
|
||||
if (!next_valid_token(&sp->cfp))
|
||||
return PARSE_EOF;
|
||||
|
||||
if (new_val && *val)
|
||||
cf_adderror(&sp->cfp, "'$1' keyword already specified",
|
||||
LEVEL_WARNING, keyword, NULL, NULL);
|
||||
*val = new_val;
|
||||
|
||||
return PARSE_CONTINUE;
|
||||
}
|
||||
|
||||
return PARSE_SUCCESS;
|
||||
}
|
||||
|
||||
static inline int sp_parse_func_param(struct shader_parser *sp,
|
||||
struct shader_func *func, struct shader_var *var)
|
||||
{
|
||||
int errcode;
|
||||
bool is_uniform;
|
||||
|
||||
if (!next_valid_token(&sp->cfp))
|
||||
return PARSE_EOF;
|
||||
|
||||
errcode = sp_check_for_keyword(sp, "uniform", &is_uniform);
|
||||
if (errcode == PARSE_EOF)
|
||||
return PARSE_EOF;
|
||||
|
||||
var->var_type = is_uniform ? SHADER_VAR_UNIFORM : SHADER_VAR_NONE;
|
||||
|
||||
errcode = get_name(&sp->cfp, &var->type, "type", ")");
|
||||
if (errcode != PARSE_SUCCESS)
|
||||
return errcode;
|
||||
|
||||
errcode = next_name(&sp->cfp, &var->name, "name", ")");
|
||||
if (errcode != PARSE_SUCCESS)
|
||||
return errcode;
|
||||
|
||||
if (!next_valid_token(&sp->cfp))
|
||||
return PARSE_EOF;
|
||||
|
||||
if (token_is(&sp->cfp, ":")) {
|
||||
errcode = next_name(&sp->cfp, &var->mapping,
|
||||
"mapping specifier", ")");
|
||||
if (errcode != PARSE_SUCCESS)
|
||||
return errcode;
|
||||
|
||||
if (!next_valid_token(&sp->cfp))
|
||||
return PARSE_EOF;
|
||||
}
|
||||
|
||||
return PARSE_SUCCESS;
|
||||
}
|
||||
|
||||
static bool sp_parse_func_params(struct shader_parser *sp,
|
||||
struct shader_func *func)
|
||||
{
|
||||
struct cf_token peek;
|
||||
int errcode;
|
||||
|
||||
cf_token_clear(&peek);
|
||||
|
||||
if (!peek_valid_token(&sp->cfp, &peek))
|
||||
return false;
|
||||
|
||||
if (*peek.str.array == ')') {
|
||||
next_token(&sp->cfp);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
do {
|
||||
struct shader_var var;
|
||||
shader_var_init(&var);
|
||||
|
||||
if (!token_is(&sp->cfp, "(") && !token_is(&sp->cfp, ","))
|
||||
cf_adderror_syntax_error(&sp->cfp);
|
||||
|
||||
errcode = sp_parse_func_param(sp, func, &var);
|
||||
if (errcode != PARSE_SUCCESS) {
|
||||
shader_var_free(&var);
|
||||
|
||||
if (errcode == PARSE_CONTINUE)
|
||||
goto exit;
|
||||
else if (errcode == PARSE_EOF)
|
||||
return false;
|
||||
}
|
||||
|
||||
da_push_back(func->params, &var);
|
||||
} while (!token_is(&sp->cfp, ")"));
|
||||
|
||||
exit:
|
||||
return true;
|
||||
}
|
||||
|
||||
static void sp_parse_function(struct shader_parser *sp,
|
||||
char *type, char *name)
|
||||
{
|
||||
struct shader_func func;
|
||||
|
||||
shader_func_init(&func, type, name);
|
||||
if (!sp_parse_func_params(sp, &func))
|
||||
goto error;
|
||||
|
||||
if (!next_valid_token(&sp->cfp))
|
||||
goto error;
|
||||
|
||||
/* if function is mapped to something, for example COLOR */
|
||||
if (token_is(&sp->cfp, ":")) {
|
||||
if (!next_valid_token(&sp->cfp))
|
||||
goto error;
|
||||
if (!next_valid_token(&sp->cfp))
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!token_is(&sp->cfp, "{")) {
|
||||
cf_adderror_expecting(&sp->cfp, "{");
|
||||
goto error;
|
||||
}
|
||||
|
||||
func.start = sp->cfp.cur_token;
|
||||
if (!pass_pair(&sp->cfp, '{', '}'))
|
||||
goto error;
|
||||
|
||||
/* it is established that the current token is '}' if we reach this */
|
||||
next_token(&sp->cfp);
|
||||
|
||||
func.end = sp->cfp.cur_token;
|
||||
da_push_back(sp->funcs, &func);
|
||||
return;
|
||||
|
||||
error:
|
||||
shader_func_free(&func);
|
||||
}
|
||||
|
||||
/* parses "array[count]" */
|
||||
static bool sp_parse_param_array(struct shader_parser *sp,
|
||||
struct shader_var *param)
|
||||
{
|
||||
if (!next_valid_token(&sp->cfp))
|
||||
return false;
|
||||
|
||||
if (sp->cfp.cur_token->type != CFTOKEN_NUM ||
|
||||
!valid_int_str(sp->cfp.cur_token->str.array,
|
||||
sp->cfp.cur_token->str.len))
|
||||
return false;
|
||||
|
||||
param->array_count = strtol(sp->cfp.cur_token->str.array, NULL, 10);
|
||||
|
||||
if (next_token_should_be(&sp->cfp, "]", ";", NULL) == PARSE_EOF)
|
||||
return false;
|
||||
|
||||
if (!next_valid_token(&sp->cfp))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline int sp_parse_param_assign_intfloat(struct shader_parser *sp,
|
||||
struct shader_var *param, bool is_float)
|
||||
{
|
||||
int errcode;
|
||||
|
||||
if (!next_valid_token(&sp->cfp))
|
||||
return PARSE_EOF;
|
||||
|
||||
errcode = token_is_type(&sp->cfp, CFTOKEN_NUM, "numeric value", ";");
|
||||
if (errcode != PARSE_SUCCESS)
|
||||
return errcode;
|
||||
|
||||
if (is_float) {
|
||||
float f = (float)strtod(sp->cfp.cur_token->str.array, NULL);
|
||||
da_push_back_array(param->default_val, &f, sizeof(float));
|
||||
} else {
|
||||
long l = strtol(sp->cfp.cur_token->str.array, NULL, 10);
|
||||
da_push_back_array(param->default_val, &l, sizeof(long));
|
||||
}
|
||||
|
||||
return PARSE_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* parses assignment for float1, float2, float3, float4, and any combination
|
||||
* for float3x3, float4x4, etc
|
||||
*/
|
||||
static inline int sp_parse_param_assign_float_array(struct shader_parser *sp,
|
||||
struct shader_var *param)
|
||||
{
|
||||
const char *float_type = param->type+5;
|
||||
int float_count = 0, errcode, i;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
if (float_type[0] < '1' || float_type[0] > '4')
|
||||
cf_adderror(&sp->cfp, "Invalid row count", LEVEL_ERROR,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
float_count = float_type[0]-'0';
|
||||
|
||||
if (float_type[1] == 'x') {
|
||||
if (float_type[2] < '1' || float_type[2] > '4')
|
||||
cf_adderror(&sp->cfp, "Invalid column count",
|
||||
LEVEL_ERROR, NULL, NULL, NULL);
|
||||
|
||||
float_count *= float_type[2]-'0';
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
errcode = next_token_should_be(&sp->cfp, "{", ";", NULL);
|
||||
if (errcode != PARSE_SUCCESS) return errcode;
|
||||
|
||||
for (i = 0; i < float_count; i++) {
|
||||
char *next = ((i+1) < float_count) ? "," : "}";
|
||||
|
||||
errcode = sp_parse_param_assign_intfloat(sp, param, true);
|
||||
if (errcode != PARSE_SUCCESS) return errcode;
|
||||
|
||||
errcode = next_token_should_be(&sp->cfp, next, ";", NULL);
|
||||
if (errcode != PARSE_SUCCESS) return errcode;
|
||||
}
|
||||
|
||||
return PARSE_SUCCESS;
|
||||
}
|
||||
|
||||
static int sp_parse_param_assignment_val(struct shader_parser *sp,
|
||||
struct shader_var *param)
|
||||
{
|
||||
if (strcmp(param->type, "int") == 0)
|
||||
return sp_parse_param_assign_intfloat(sp, param, false);
|
||||
else if (strcmp(param->type, "float") == 0)
|
||||
return sp_parse_param_assign_intfloat(sp, param, true);
|
||||
else if (astrcmp_n(param->type, "float", 5) == 0)
|
||||
return sp_parse_param_assign_float_array(sp, param);
|
||||
|
||||
cf_adderror(&sp->cfp, "Invalid type '$1' used for assignment",
|
||||
LEVEL_ERROR, param->type, NULL, NULL);
|
||||
|
||||
return PARSE_CONTINUE;
|
||||
}
|
||||
|
||||
static inline bool sp_parse_param_assignment(struct shader_parser *sp,
|
||||
struct shader_var *param)
|
||||
{
|
||||
if (sp_parse_param_assignment_val(sp, param) != PARSE_SUCCESS)
|
||||
return false;
|
||||
|
||||
if (!next_valid_token(&sp->cfp))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void sp_parse_param(struct shader_parser *sp,
|
||||
char *type, char *name, bool is_const, bool is_uniform)
|
||||
{
|
||||
struct shader_var param;
|
||||
shader_var_init_param(¶m, type, name, is_uniform, is_const);
|
||||
|
||||
if (token_is(&sp->cfp, ";"))
|
||||
goto complete;
|
||||
if (token_is(&sp->cfp, "[") && !sp_parse_param_array(sp, ¶m))
|
||||
goto error;
|
||||
if (token_is(&sp->cfp, "=") && !sp_parse_param_assignment(sp, ¶m))
|
||||
goto error;
|
||||
if (!token_is(&sp->cfp, ";"))
|
||||
goto error;
|
||||
|
||||
complete:
|
||||
da_push_back(sp->params, ¶m);
|
||||
return;
|
||||
|
||||
error:
|
||||
shader_var_free(¶m);
|
||||
}
|
||||
|
||||
static bool sp_get_var_specifiers(struct shader_parser *sp,
|
||||
bool *is_const, bool *is_uniform)
|
||||
{
|
||||
while(true) {
|
||||
int errcode;
|
||||
errcode = sp_check_for_keyword(sp, "const", is_const);
|
||||
if (errcode == PARSE_EOF)
|
||||
return false;
|
||||
else if (errcode == PARSE_CONTINUE)
|
||||
continue;
|
||||
|
||||
errcode = sp_check_for_keyword(sp, "uniform", is_uniform);
|
||||
if (errcode == PARSE_EOF)
|
||||
return false;
|
||||
else if (errcode == PARSE_CONTINUE)
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void report_invalid_func_keyword(struct shader_parser *sp,
|
||||
const char *name, bool val)
|
||||
{
|
||||
if (val)
|
||||
cf_adderror(&sp->cfp, "'$1' keyword cannot be used with a "
|
||||
"function", LEVEL_ERROR,
|
||||
name, NULL, NULL);
|
||||
}
|
||||
|
||||
static void sp_parse_other(struct shader_parser *sp)
|
||||
{
|
||||
bool is_const = false, is_uniform = false;
|
||||
char *type = NULL, *name = NULL;
|
||||
|
||||
if (!sp_get_var_specifiers(sp, &is_const, &is_uniform))
|
||||
goto error;
|
||||
|
||||
if (get_name(&sp->cfp, &type, "type", ";") != PARSE_SUCCESS)
|
||||
goto error;
|
||||
if (next_name(&sp->cfp, &name, "name", ";") != PARSE_SUCCESS)
|
||||
goto error;
|
||||
|
||||
if (!next_valid_token(&sp->cfp))
|
||||
goto error;
|
||||
|
||||
if (token_is(&sp->cfp, "(")) {
|
||||
report_invalid_func_keyword(sp, "const", is_const);
|
||||
report_invalid_func_keyword(sp, "uniform", is_uniform);
|
||||
|
||||
sp_parse_function(sp, type, name);
|
||||
return;
|
||||
} else {
|
||||
sp_parse_param(sp, type, name, is_const, is_uniform);
|
||||
return;
|
||||
}
|
||||
|
||||
error:
|
||||
bfree(type);
|
||||
bfree(name);
|
||||
}
|
||||
|
||||
bool shader_parse(struct shader_parser *sp, const char *shader,
|
||||
const char *file)
|
||||
{
|
||||
if (!cf_parser_parse(&sp->cfp, shader, file))
|
||||
return false;
|
||||
|
||||
while (sp->cfp.cur_token && sp->cfp.cur_token->type != CFTOKEN_NONE) {
|
||||
if (token_is(&sp->cfp, ";") ||
|
||||
is_whitespace(*sp->cfp.cur_token->str.array)) {
|
||||
sp->cfp.cur_token++;
|
||||
|
||||
} else if (token_is(&sp->cfp, "struct")) {
|
||||
sp_parse_struct(sp);
|
||||
|
||||
} else if (token_is(&sp->cfp, "sampler_state")) {
|
||||
sp_parse_sampler_state(sp);
|
||||
|
||||
} else if (token_is(&sp->cfp, "{")) {
|
||||
cf_adderror(&sp->cfp, "Unexpected code segment",
|
||||
LEVEL_ERROR, NULL, NULL, NULL);
|
||||
pass_pair(&sp->cfp, '{', '}');
|
||||
|
||||
} else {
|
||||
/* parameters and functions */
|
||||
sp_parse_other(sp);
|
||||
}
|
||||
}
|
||||
|
||||
return !error_data_has_errors(&sp->cfp.error_list);
|
||||
}
|
|
@ -0,0 +1,246 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef SHADER_PARSER_H
|
||||
#define SHADER_PARSER_H
|
||||
|
||||
#include "../util/cf-parser.h"
|
||||
#include "graphics.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
EXPORT enum shader_param_type get_shader_param_type(const char *type);
|
||||
EXPORT enum gs_sample_filter get_sample_filter(const char *filter);
|
||||
EXPORT enum gs_address_mode get_address_mode(const char *address_mode);
|
||||
|
||||
/*
|
||||
* Shader Parser
|
||||
*
|
||||
* Parses a shader and extracts data such as shader constants, samplers,
|
||||
* and vertex input information. Also allows the reformatting of shaders for
|
||||
* different libraries. This is usually used only by graphics libraries,
|
||||
*/
|
||||
|
||||
enum shader_var_type {
|
||||
SHADER_VAR_NONE,
|
||||
SHADER_VAR_UNIFORM,
|
||||
SHADER_VAR_CONST
|
||||
};
|
||||
|
||||
struct shader_var {
|
||||
char *type;
|
||||
char *name;
|
||||
char *mapping;
|
||||
enum shader_var_type var_type;
|
||||
int array_count;
|
||||
|
||||
DARRAY(uint8_t) default_val;
|
||||
};
|
||||
|
||||
static inline void shader_var_init(struct shader_var *sv)
|
||||
{
|
||||
memset(sv, 0, sizeof(struct shader_var));
|
||||
}
|
||||
|
||||
static inline void shader_var_init_param(struct shader_var *sv,
|
||||
char *type, char *name, bool is_uniform,
|
||||
bool is_const)
|
||||
{
|
||||
if (is_uniform)
|
||||
sv->var_type = SHADER_VAR_UNIFORM;
|
||||
else if (is_const)
|
||||
sv->var_type = SHADER_VAR_CONST;
|
||||
else
|
||||
sv->var_type = SHADER_VAR_NONE;
|
||||
|
||||
sv->type = type;
|
||||
sv->name = name;
|
||||
sv->mapping = NULL;
|
||||
sv->array_count = 0;
|
||||
da_init(sv->default_val);
|
||||
}
|
||||
|
||||
static inline void shader_var_free(struct shader_var *sv)
|
||||
{
|
||||
bfree(sv->type);
|
||||
bfree(sv->name);
|
||||
bfree(sv->mapping);
|
||||
da_free(sv->default_val);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
struct shader_sampler {
|
||||
char *name;
|
||||
DARRAY(char*) states;
|
||||
DARRAY(char*) values;
|
||||
};
|
||||
|
||||
static inline void shader_sampler_init(struct shader_sampler *ss)
|
||||
{
|
||||
memset(ss, 0, sizeof(struct shader_sampler));
|
||||
}
|
||||
|
||||
static inline void shader_sampler_free(struct shader_sampler *ss)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < ss->states.num; i++)
|
||||
bfree(ss->states.array[i]);
|
||||
for (i = 0; i < ss->values.num; i++)
|
||||
bfree(ss->values.array[i]);
|
||||
|
||||
bfree(ss->name);
|
||||
da_free(ss->states);
|
||||
da_free(ss->values);
|
||||
}
|
||||
|
||||
EXPORT void shader_sampler_convert(struct shader_sampler *ss,
|
||||
struct gs_sampler_info *info);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
struct shader_struct {
|
||||
char *name;
|
||||
DARRAY(struct shader_var) vars;
|
||||
};
|
||||
|
||||
static inline void shader_struct_init(struct shader_struct *ss)
|
||||
{
|
||||
memset(ss, 0, sizeof(struct shader_struct));
|
||||
}
|
||||
|
||||
static inline void shader_struct_free(struct shader_struct *ss)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < ss->vars.num; i++)
|
||||
shader_var_free(ss->vars.array+i);
|
||||
|
||||
bfree(ss->name);
|
||||
da_free(ss->vars);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
struct shader_func {
|
||||
char *name;
|
||||
char *return_type;
|
||||
DARRAY(struct shader_var) params;
|
||||
|
||||
const struct cf_token *start, *end;
|
||||
};
|
||||
|
||||
static inline void shader_func_init(struct shader_func *sf,
|
||||
char *return_type, char *name)
|
||||
{
|
||||
da_init(sf->params);
|
||||
|
||||
sf->return_type = return_type;
|
||||
sf->name = name;
|
||||
sf->start = NULL;
|
||||
sf->end = NULL;
|
||||
}
|
||||
|
||||
static inline void shader_func_free(struct shader_func *sf)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < sf->params.num; i++)
|
||||
shader_var_free(sf->params.array+i);
|
||||
|
||||
bfree(sf->name);
|
||||
bfree(sf->return_type);
|
||||
da_free(sf->params);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
struct shader_parser {
|
||||
struct cf_parser cfp;
|
||||
|
||||
DARRAY(struct shader_var) params;
|
||||
DARRAY(struct shader_struct) structs;
|
||||
DARRAY(struct shader_sampler) samplers;
|
||||
DARRAY(struct shader_func) funcs;
|
||||
};
|
||||
|
||||
static inline void shader_parser_init(struct shader_parser *sp)
|
||||
{
|
||||
cf_parser_init(&sp->cfp);
|
||||
|
||||
da_init(sp->params);
|
||||
da_init(sp->structs);
|
||||
da_init(sp->samplers);
|
||||
da_init(sp->funcs);
|
||||
}
|
||||
|
||||
static inline void shader_parser_free(struct shader_parser *sp)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < sp->params.num; i++)
|
||||
shader_var_free(sp->params.array+i);
|
||||
for (i = 0; i < sp->structs.num; i++)
|
||||
shader_struct_free(sp->structs.array+i);
|
||||
for (i = 0; i < sp->samplers.num; i++)
|
||||
shader_sampler_free(sp->samplers.array+i);
|
||||
for (i = 0; i < sp->funcs.num; i++)
|
||||
shader_func_free(sp->funcs.array+i);
|
||||
|
||||
cf_parser_free(&sp->cfp);
|
||||
da_free(sp->params);
|
||||
da_free(sp->structs);
|
||||
da_free(sp->samplers);
|
||||
da_free(sp->funcs);
|
||||
}
|
||||
|
||||
EXPORT bool shader_parse(struct shader_parser *sp, const char *shader,
|
||||
const char *file);
|
||||
|
||||
static inline struct shader_func *shader_parser_getfunc(
|
||||
struct shader_parser *sp, const char *func_name)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < sp->funcs.num; i++) {
|
||||
struct shader_func *func = sp->funcs.array+i;
|
||||
if (strcmp(func->name, func_name) == 0)
|
||||
return func;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct shader_struct *shader_parser_getstruct(
|
||||
struct shader_parser *sp, const char *struct_name)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < sp->structs.num; i++) {
|
||||
struct shader_struct *st = sp->structs.array+i;
|
||||
if (strcmp(st->name, struct_name) == 0)
|
||||
return st;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,139 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* This is a set of helper functions to more easily render to textures
|
||||
* without having to duplicate too much code.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "graphics.h"
|
||||
|
||||
struct gs_texture_render {
|
||||
texture_t target, prev_target;
|
||||
zstencil_t zs, prev_zs;
|
||||
|
||||
int cx, cy;
|
||||
|
||||
enum gs_color_format format;
|
||||
enum gs_zstencil_format zsformat;
|
||||
|
||||
bool rendered;
|
||||
};
|
||||
|
||||
texrender_t texrender_create(enum gs_color_format format,
|
||||
enum gs_zstencil_format zsformat)
|
||||
{
|
||||
struct gs_texture_render *texrender;
|
||||
texrender = bmalloc(sizeof(struct gs_texture_render));
|
||||
memset(texrender, 0, sizeof(struct gs_texture_render));
|
||||
|
||||
texrender->format = format;
|
||||
texrender->zsformat = zsformat;
|
||||
|
||||
return texrender;
|
||||
}
|
||||
|
||||
void texrender_destroy(texrender_t texrender)
|
||||
{
|
||||
if (texrender) {
|
||||
texture_destroy(texrender->target);
|
||||
zstencil_destroy(texrender->zs);
|
||||
bfree(texrender);
|
||||
}
|
||||
}
|
||||
|
||||
static bool texrender_resetbuffer(texrender_t texrender, int cx, int cy)
|
||||
{
|
||||
texture_destroy(texrender->target);
|
||||
zstencil_destroy(texrender->zs);
|
||||
|
||||
texrender->target = NULL;
|
||||
texrender->zs = NULL;
|
||||
texrender->cx = cx;
|
||||
texrender->cy = cy;
|
||||
|
||||
texrender->target = gs_create_texture(cx, cy, texrender->format,
|
||||
NULL, GS_RENDERTARGET);
|
||||
if (!texrender->target)
|
||||
return false;
|
||||
|
||||
if (texrender->zsformat != GS_ZS_NONE) {
|
||||
texrender->zs = gs_create_zstencil(cx, cy, texrender->zsformat);
|
||||
if (!texrender->zs) {
|
||||
texture_destroy(texrender->target);
|
||||
texrender->target = NULL;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool texrender_begin(texrender_t texrender, int cx, int cy)
|
||||
{
|
||||
if (texrender->rendered)
|
||||
return false;
|
||||
|
||||
if (cx == -1)
|
||||
cx = gs_getwidth();
|
||||
if (cy == -1)
|
||||
cy = gs_getheight();
|
||||
|
||||
assert(cx && cy);
|
||||
if (!cx || !cy)
|
||||
return false;
|
||||
|
||||
if (texrender->cx != cx || texrender->cy != cy)
|
||||
if (!texrender_resetbuffer(texrender, cx, cy))
|
||||
return false;
|
||||
|
||||
gs_viewport_push();
|
||||
gs_projection_push();
|
||||
gs_matrix_push();
|
||||
gs_matrix_identity();
|
||||
|
||||
texrender->prev_target = gs_getrendertarget();
|
||||
texrender->prev_zs = gs_getzstenciltarget();
|
||||
gs_setrendertarget(texrender->target, texrender->zs);
|
||||
|
||||
gs_setviewport(0, 0, texrender->cx, texrender->cy);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void texrender_end(texrender_t texrender)
|
||||
{
|
||||
gs_setrendertarget(texrender->prev_target, texrender->prev_zs);
|
||||
|
||||
gs_matrix_pop();
|
||||
gs_projection_pop();
|
||||
gs_viewport_pop();
|
||||
|
||||
texrender->rendered = true;
|
||||
}
|
||||
|
||||
void texrender_reset(texrender_t texrender)
|
||||
{
|
||||
texrender->rendered = false;
|
||||
}
|
||||
|
||||
texture_t texrender_gettexture(texrender_t texrender)
|
||||
{
|
||||
return texrender->target;
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include <math.h>
|
||||
#include "math-extra.h"
|
||||
#include "math-defs.h"
|
||||
#include "vec2.h"
|
||||
|
||||
void vec2_abs(struct vec2 *dst, const struct vec2 *v)
|
||||
{
|
||||
vec2_set(dst, fabsf(v->x), fabsf(v->y));
|
||||
}
|
||||
|
||||
void vec2_floor(struct vec2 *dst, const struct vec2 *v)
|
||||
{
|
||||
vec2_set(dst, floorf(v->x), floorf(v->y));
|
||||
}
|
||||
|
||||
void vec2_ceil(struct vec2 *dst, const struct vec2 *v)
|
||||
{
|
||||
vec2_set(dst, ceilf(v->x), ceilf(v->y));
|
||||
}
|
||||
|
||||
int vec2_close(const struct vec2 *v1, const struct vec2 *v2, float epsilon)
|
||||
{
|
||||
return close_float(v1->x, v2->x, epsilon) &&
|
||||
close_float(v1->y, v2->y, epsilon);
|
||||
}
|
||||
|
||||
void vec2_norm(struct vec2 *dst, const struct vec2 *v)
|
||||
{
|
||||
float len = vec2_len(v);
|
||||
|
||||
if (len > 0.0f) {
|
||||
len = 1.0f / len;
|
||||
vec2_mulf(dst, v, len);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef VECT2_H
|
||||
#define VECT2_H
|
||||
|
||||
#include "../util/c99defs.h"
|
||||
#include <math.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct vec2 {
|
||||
union {
|
||||
struct {
|
||||
float x, y;
|
||||
};
|
||||
float ptr[2];
|
||||
};
|
||||
};
|
||||
|
||||
static inline void vec2_zero(struct vec2 *dst)
|
||||
{
|
||||
dst->x = 0.0f;
|
||||
dst->y = 0.0f;
|
||||
}
|
||||
|
||||
static inline void vec2_set(struct vec2 *dst, float x, float y)
|
||||
{
|
||||
dst->x = x;
|
||||
dst->y = y;
|
||||
}
|
||||
|
||||
static inline void vec2_copy(struct vec2 *dst, const struct vec2 *v)
|
||||
{
|
||||
dst->x = v->x;
|
||||
dst->y = v->y;
|
||||
}
|
||||
|
||||
static inline void vec2_add(struct vec2 *dst, const struct vec2 *v1,
|
||||
const struct vec2 *v2)
|
||||
{
|
||||
vec2_set(dst, v1->x+v2->x, v1->y+v2->y);
|
||||
}
|
||||
|
||||
static inline void vec2_sub(struct vec2 *dst, const struct vec2 *v1,
|
||||
const struct vec2 *v2)
|
||||
{
|
||||
vec2_set(dst, v1->x-v2->x, v1->y-v2->y);
|
||||
}
|
||||
|
||||
static inline void vec2_mul(struct vec2 *dst, const struct vec2 *v1,
|
||||
const struct vec2 *v2)
|
||||
{
|
||||
vec2_set(dst, v1->x*v2->x, v1->y*v2->y);
|
||||
}
|
||||
|
||||
static inline void vec2_div(struct vec2 *dst, const struct vec2 *v1,
|
||||
const struct vec2 *v2)
|
||||
{
|
||||
vec2_set(dst, v1->x/v2->x, v1->y/v2->y);
|
||||
}
|
||||
|
||||
static inline void vec2_addf(struct vec2 *dst, const struct vec2 *v,
|
||||
float f)
|
||||
{
|
||||
vec2_set(dst, v->x+f, v->y+f);
|
||||
}
|
||||
|
||||
static inline void vec2_subf(struct vec2 *dst, const struct vec2 *v,
|
||||
float f)
|
||||
{
|
||||
vec2_set(dst, v->x-f, v->y-f);
|
||||
}
|
||||
|
||||
static inline void vec2_mulf(struct vec2 *dst, const struct vec2 *v,
|
||||
float f)
|
||||
{
|
||||
vec2_set(dst, v->x*f, v->y*f);
|
||||
}
|
||||
|
||||
static inline void vec2_divf(struct vec2 *dst, const struct vec2 *v,
|
||||
float f)
|
||||
{
|
||||
vec2_set(dst, v->x/f, v->y/f);
|
||||
}
|
||||
|
||||
static inline void vec2_neg(struct vec2 *dst, const struct vec2 *v)
|
||||
{
|
||||
vec2_set(dst, -v->x, -v->y);
|
||||
}
|
||||
|
||||
static inline float vec2_dot(const struct vec2 *v1, const struct vec2 *v2)
|
||||
{
|
||||
return (v1->x+v2->x) * (v1->y+v2->y);
|
||||
}
|
||||
|
||||
static inline float vec2_len(const struct vec2 *v)
|
||||
{
|
||||
return sqrtf(v->x*v->x + v->y*v->y);
|
||||
}
|
||||
|
||||
static inline float vec2_dist(const struct vec2 *v1, const struct vec2 *v2)
|
||||
{
|
||||
struct vec2 temp;
|
||||
vec2_sub(&temp, v1, v2);
|
||||
return vec2_len(&temp);
|
||||
}
|
||||
|
||||
static inline void vec2_minf(struct vec2 *dst, const struct vec2 *v,
|
||||
float val)
|
||||
{
|
||||
if (v->x < val)
|
||||
dst->x = val;
|
||||
if (v->y < val)
|
||||
dst->y = val;
|
||||
}
|
||||
|
||||
static inline void vec2_min(struct vec2 *dst, const struct vec2 *v,
|
||||
const struct vec2 *min_v)
|
||||
{
|
||||
if (v->x < min_v->x)
|
||||
dst->x = min_v->x;
|
||||
if (v->y < min_v->y)
|
||||
dst->y = min_v->y;
|
||||
}
|
||||
|
||||
static inline void vec2_maxf(struct vec2 *dst, const struct vec2 *v,
|
||||
float val)
|
||||
{
|
||||
if (v->x > val)
|
||||
dst->x = val;
|
||||
if (v->y > val)
|
||||
dst->y = val;
|
||||
}
|
||||
|
||||
static inline void vec2_max(struct vec2 *dst, const struct vec2 *v,
|
||||
const struct vec2 *max_v)
|
||||
{
|
||||
if (v->x > max_v->x)
|
||||
dst->x = max_v->x;
|
||||
if (v->y > max_v->y)
|
||||
dst->y = max_v->y;
|
||||
}
|
||||
|
||||
EXPORT void vec2_abs(struct vec2 *dst, const struct vec2 *v);
|
||||
EXPORT void vec2_floor(struct vec2 *dst, const struct vec2 *v);
|
||||
EXPORT void vec2_ceil(struct vec2 *dst, const struct vec2 *v);
|
||||
EXPORT int vec2_close(const struct vec2 *v1, const struct vec2 *v2,
|
||||
float epsilon);
|
||||
EXPORT void vec2_norm(struct vec2 *dst, const struct vec2 *v);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,73 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "vec3.h"
|
||||
#include "quat.h"
|
||||
#include "axisang.h"
|
||||
#include "plane.h"
|
||||
#include "matrix3.h"
|
||||
#include "math-extra.h"
|
||||
|
||||
float vec3_plane_dist(const struct vec3 *v, const struct plane *p)
|
||||
{
|
||||
return vec3_dot(v, &p->dir) - p->dist;
|
||||
}
|
||||
|
||||
void vec3_rotate(struct vec3 *dst, const struct vec3 *v,
|
||||
const struct matrix3 *m)
|
||||
{
|
||||
struct vec3 temp;
|
||||
vec3_copy(&temp, v);
|
||||
|
||||
dst->x = vec3_dot(&temp, &m->x);
|
||||
dst->y = vec3_dot(&temp, &m->y);
|
||||
dst->z = vec3_dot(&temp, &m->z);
|
||||
}
|
||||
|
||||
void vec3_transform(struct vec3 *dst, const struct vec3 *v,
|
||||
const struct matrix3 *m)
|
||||
{
|
||||
struct vec3 temp;
|
||||
vec3_sub(&temp, v, &m->t);
|
||||
|
||||
dst->x = vec3_dot(&temp, &m->x);
|
||||
dst->y = vec3_dot(&temp, &m->y);
|
||||
dst->z = vec3_dot(&temp, &m->z);
|
||||
}
|
||||
|
||||
void vec3_mirror(struct vec3 *dst, const struct vec3 *v, const struct plane *p)
|
||||
{
|
||||
struct vec3 temp;
|
||||
vec3_mulf(&temp, &p->dir, vec3_plane_dist(v, p) * 2.0f);
|
||||
vec3_sub(dst, v, &temp);
|
||||
}
|
||||
|
||||
void vec3_mirrorv(struct vec3 *dst, const struct vec3 *v,
|
||||
const struct vec3 *vec)
|
||||
{
|
||||
struct vec3 temp;
|
||||
vec3_mulf(&temp, vec, vec3_dot(v, vec) * 2.0f);
|
||||
vec3_sub(dst, v, &temp);
|
||||
}
|
||||
|
||||
void vec3_rand(struct vec3 *dst, int positive_only)
|
||||
{
|
||||
dst->x = rand_float(positive_only);
|
||||
dst->y = rand_float(positive_only);
|
||||
dst->z = rand_float(positive_only);
|
||||
dst->w = 0.0f;
|
||||
}
|
|
@ -0,0 +1,236 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef VECT_H
|
||||
#define VECT_H
|
||||
|
||||
#include "math-defs.h"
|
||||
#include <xmmintrin.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct plane;
|
||||
struct matrix3;
|
||||
struct quat;
|
||||
|
||||
struct vec3 {
|
||||
union {
|
||||
struct {
|
||||
float x, y, z, w;
|
||||
};
|
||||
float ptr[4];
|
||||
__m128 m;
|
||||
};
|
||||
};
|
||||
|
||||
static inline void vec3_zero(struct vec3 *v)
|
||||
{
|
||||
v->m = _mm_setzero_ps();
|
||||
}
|
||||
|
||||
static inline void vec3_set(struct vec3 *dst, float x, float y, float z)
|
||||
{
|
||||
dst->m = _mm_set_ps(0.0f, z, y, x);
|
||||
}
|
||||
|
||||
static inline void vec3_copy(struct vec3 *dst, const struct vec3 *v)
|
||||
{
|
||||
dst->m = v->m;
|
||||
}
|
||||
|
||||
static inline void vec3_add(struct vec3 *dst, const struct vec3 *v1,
|
||||
const struct vec3 *v2)
|
||||
{
|
||||
dst->m = _mm_add_ps(v1->m, v2->m);
|
||||
dst->w = 0.0f;
|
||||
}
|
||||
|
||||
static inline void vec3_sub(struct vec3 *dst, const struct vec3 *v1,
|
||||
const struct vec3 *v2)
|
||||
{
|
||||
dst->m = _mm_sub_ps(v1->m, v2->m);
|
||||
dst->w = 0.0f;
|
||||
}
|
||||
|
||||
static inline void vec3_mul(struct vec3 *dst, const struct vec3 *v1,
|
||||
const struct vec3 *v2)
|
||||
{
|
||||
dst->m = _mm_mul_ps(v1->m, v2->m);
|
||||
}
|
||||
|
||||
static inline void vec3_div(struct vec3 *dst, const struct vec3 *v1,
|
||||
const struct vec3 *v2)
|
||||
{
|
||||
dst->m = _mm_div_ps(v1->m, v2->m);
|
||||
dst->w = 0.0f;
|
||||
}
|
||||
|
||||
static inline void vec3_addf(struct vec3 *dst, const struct vec3 *v,
|
||||
float f)
|
||||
{
|
||||
dst->m = _mm_add_ps(v->m, _mm_set1_ps(f));
|
||||
dst->w = 0.0f;
|
||||
}
|
||||
|
||||
static inline void vec3_subf(struct vec3 *dst, const struct vec3 *v,
|
||||
float f)
|
||||
{
|
||||
dst->m = _mm_sub_ps(v->m, _mm_set1_ps(f));
|
||||
dst->w = 0.0f;
|
||||
}
|
||||
|
||||
static inline void vec3_mulf(struct vec3 *dst, const struct vec3 *v,
|
||||
float f)
|
||||
{
|
||||
dst->m = _mm_mul_ps(v->m, _mm_set1_ps(f));
|
||||
}
|
||||
|
||||
static inline void vec3_divf(struct vec3 *dst, const struct vec3 *v,
|
||||
float f)
|
||||
{
|
||||
dst->m = _mm_div_ps(v->m, _mm_set1_ps(f));
|
||||
dst->w = 0.0f;
|
||||
}
|
||||
|
||||
static inline float vec3_dot(const struct vec3 *v1, const struct vec3 *v2)
|
||||
{
|
||||
struct vec3 add;
|
||||
__m128 mul = _mm_mul_ps(v1->m, v2->m);
|
||||
add.m = _mm_add_ps(_mm_movehl_ps(mul, mul), mul);
|
||||
add.m = _mm_add_ps(_mm_shuffle_ps(add.m, add.m, 0x55), add.m);
|
||||
return add.x;
|
||||
}
|
||||
|
||||
static inline void vec3_cross(struct vec3 *dst, const struct vec3 *v1,
|
||||
const struct vec3 *v2)
|
||||
{
|
||||
__m128 s1v1 = _mm_shuffle_ps(v1->m, v1->m, _MM_SHUFFLE(3, 0, 2, 1));
|
||||
__m128 s1v2 = _mm_shuffle_ps(v2->m, v2->m, _MM_SHUFFLE(3, 1, 0, 2));
|
||||
__m128 s2v1 = _mm_shuffle_ps(v1->m, v1->m, _MM_SHUFFLE(3, 1, 0, 2));
|
||||
__m128 s2v2 = _mm_shuffle_ps(v2->m, v2->m, _MM_SHUFFLE(3, 0, 2, 1));
|
||||
dst->m = _mm_sub_ps(_mm_mul_ps(s1v1, s1v2), _mm_mul_ps(s2v1, s2v2));
|
||||
}
|
||||
|
||||
static inline void vec3_neg(struct vec3 *dst, const struct vec3 *v)
|
||||
{
|
||||
dst->x = -dst->x;
|
||||
dst->y = -dst->y;
|
||||
dst->z = -dst->z;
|
||||
}
|
||||
|
||||
static inline float vec3_len(const struct vec3 *v)
|
||||
{
|
||||
float dot_val = vec3_dot(v, v);
|
||||
return (dot_val > 0.0f) ? sqrtf(dot_val) : 0.0f;
|
||||
}
|
||||
|
||||
static inline float vec3_dist(const struct vec3 *v1, const struct vec3 *v2)
|
||||
{
|
||||
struct vec3 temp;
|
||||
float dot_val;
|
||||
|
||||
vec3_sub(&temp, v1, v2);
|
||||
dot_val = vec3_dot(&temp, &temp);
|
||||
return (dot_val > 0.0f) ? sqrtf(dot_val) : 0.0f;
|
||||
}
|
||||
|
||||
static inline void vec3_norm(struct vec3 *dst, const struct vec3 *v)
|
||||
{
|
||||
float dot_val = vec3_dot(v, v);
|
||||
dst->m = (dot_val > 0.0f) ?
|
||||
_mm_mul_ps(v->m, _mm_set1_ps(1.0f/sqrtf(dot_val))) :
|
||||
_mm_setzero_ps();
|
||||
}
|
||||
|
||||
static inline bool vec3_close(const struct vec3 *v1, const struct vec3 *v2,
|
||||
float epsilon)
|
||||
{
|
||||
struct vec3 test;
|
||||
vec3_sub(&test, v1, v2);
|
||||
return test.x < epsilon && test.y < epsilon && test.z < epsilon;
|
||||
}
|
||||
|
||||
static inline void vec3_min(struct vec3 *dst, const struct vec3 *v1,
|
||||
const struct vec3 *v2)
|
||||
{
|
||||
dst->m = _mm_min_ps(v1->m, v2->m);
|
||||
dst->w = 0.0f;
|
||||
}
|
||||
|
||||
static inline void vec3_minf(struct vec3 *dst, const struct vec3 *v,
|
||||
float f)
|
||||
{
|
||||
dst->m = _mm_min_ps(v->m, _mm_set1_ps(f));
|
||||
dst->w = 0.0f;
|
||||
}
|
||||
|
||||
static inline void vec3_max(struct vec3 *dst, const struct vec3 *v1,
|
||||
const struct vec3 *v2)
|
||||
{
|
||||
dst->m = _mm_max_ps(v1->m, v2->m);
|
||||
dst->w = 0.0f;
|
||||
}
|
||||
|
||||
static inline void vec3_maxf(struct vec3 *dst, const struct vec3 *v,
|
||||
float f)
|
||||
{
|
||||
dst->m = _mm_max_ps(v->m, _mm_set1_ps(f));
|
||||
dst->w = 0.0f;
|
||||
}
|
||||
|
||||
static inline void vec3_abs(struct vec3 *dst, const struct vec3 *v)
|
||||
{
|
||||
dst->x = fabsf(v->x);
|
||||
dst->y = fabsf(v->y);
|
||||
dst->z = fabsf(v->z);
|
||||
}
|
||||
|
||||
static inline void vec3_floor(struct vec3 *dst, const struct vec3 *v)
|
||||
{
|
||||
dst->x = floorf(v->x);
|
||||
dst->y = floorf(v->y);
|
||||
dst->z = floorf(v->z);
|
||||
}
|
||||
|
||||
static inline void vec3_ceil(struct vec3 *dst, const struct vec3 *v)
|
||||
{
|
||||
dst->x = ceilf(v->x);
|
||||
dst->y = ceilf(v->y);
|
||||
dst->z = ceilf(v->z);
|
||||
}
|
||||
|
||||
EXPORT float vec3_plane_dist(const struct vec3 *v, const struct plane *p);
|
||||
|
||||
EXPORT void vec3_rotate(struct vec3 *dst, const struct vec3 *v,
|
||||
const struct matrix3 *m);
|
||||
EXPORT void vec3_transform(struct vec3 *dst, const struct vec3 *v,
|
||||
const struct matrix3 *m);
|
||||
|
||||
EXPORT void vec3_mirror(struct vec3 *dst, const struct vec3 *v,
|
||||
const struct plane *p);
|
||||
EXPORT void vec3_mirrorv(struct vec3 *dst, const struct vec3 *v,
|
||||
const struct vec3 *vec);
|
||||
|
||||
EXPORT void vec3_rand(struct vec3 *dst, int positive_only);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,32 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "vec4.h"
|
||||
#include "matrix4.h"
|
||||
|
||||
void vec4_transform(struct vec4 *dst, const struct vec4 *v,
|
||||
const struct matrix4 *m)
|
||||
{
|
||||
struct vec4 temp;
|
||||
|
||||
temp.x = vec4_dot(&m->x, v);
|
||||
temp.y = vec4_dot(&m->y, v);
|
||||
temp.z = vec4_dot(&m->z, v);
|
||||
temp.w = vec4_dot(&m->t, v);
|
||||
|
||||
vec4_copy(dst, &temp);
|
||||
}
|
|
@ -0,0 +1,253 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef VECT4_H
|
||||
#define VECT4_H
|
||||
|
||||
#include "math-defs.h"
|
||||
#include <xmmintrin.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct matrix4;
|
||||
|
||||
struct vec4 {
|
||||
union {
|
||||
struct {
|
||||
float x, y, z, w;
|
||||
};
|
||||
float ptr[4];
|
||||
__m128 m;
|
||||
};
|
||||
};
|
||||
|
||||
static inline void vec4_zero(struct vec4 *v)
|
||||
{
|
||||
v->m = _mm_setzero_ps();
|
||||
}
|
||||
|
||||
static inline void vec4_set(struct vec4 *dst, float x, float y, float z,
|
||||
float w)
|
||||
{
|
||||
dst->m = _mm_set_ps(w, z, y, x);
|
||||
}
|
||||
|
||||
static inline void vec4_copy(struct vec4 *dst, const struct vec4 *v)
|
||||
{
|
||||
dst->m = v->m;
|
||||
}
|
||||
|
||||
static inline void vec4_add(struct vec4 *dst, const struct vec4 *v1,
|
||||
const struct vec4 *v2)
|
||||
{
|
||||
dst->m = _mm_add_ps(v1->m, v2->m);
|
||||
}
|
||||
|
||||
static inline void vec4_sub(struct vec4 *dst, const struct vec4 *v1,
|
||||
const struct vec4 *v2)
|
||||
{
|
||||
dst->m = _mm_sub_ps(v1->m, v2->m);
|
||||
}
|
||||
|
||||
static inline void vec4_mul(struct vec4 *dst, const struct vec4 *v1,
|
||||
const struct vec4 *v2)
|
||||
{
|
||||
dst->m = _mm_mul_ps(v1->m, v2->m);
|
||||
}
|
||||
|
||||
static inline void vec4_div(struct vec4 *dst, const struct vec4 *v1,
|
||||
const struct vec4 *v2)
|
||||
{
|
||||
dst->m = _mm_div_ps(v1->m, v2->m);
|
||||
}
|
||||
|
||||
static inline void vec4_addf(struct vec4 *dst, const struct vec4 *v,
|
||||
float f)
|
||||
{
|
||||
dst->m = _mm_add_ps(v->m, _mm_set1_ps(f));
|
||||
}
|
||||
|
||||
static inline void vec4_subf(struct vec4 *dst, const struct vec4 *v,
|
||||
float f)
|
||||
{
|
||||
dst->m = _mm_sub_ps(v->m, _mm_set1_ps(f));
|
||||
}
|
||||
|
||||
static inline void vec4_mulf(struct vec4 *dst, const struct vec4 *v,
|
||||
float f)
|
||||
{
|
||||
dst->m = _mm_mul_ps(v->m, _mm_set1_ps(f));
|
||||
}
|
||||
|
||||
static inline void vec4_divf(struct vec4 *dst, const struct vec4 *v,
|
||||
float f)
|
||||
{
|
||||
dst->m = _mm_div_ps(v->m, _mm_set1_ps(f));
|
||||
}
|
||||
|
||||
static inline float vec4_dot(const struct vec4 *v1, const struct vec4 *v2)
|
||||
{
|
||||
struct vec4 add;
|
||||
__m128 mul = _mm_mul_ps(v1->m, v2->m);
|
||||
add.m = _mm_add_ps(_mm_movehl_ps(mul, mul), mul);
|
||||
add.m = _mm_add_ps(_mm_shuffle_ps(add.m, add.m, 0x55), add.m);
|
||||
return add.x;
|
||||
}
|
||||
|
||||
static inline void vec4_neg(struct vec4 *dst, const struct vec4 *v)
|
||||
{
|
||||
dst->x = -dst->x;
|
||||
dst->y = -dst->y;
|
||||
dst->z = -dst->z;
|
||||
dst->w = -dst->w;
|
||||
}
|
||||
|
||||
static inline float vec4_len(const struct vec4 *v)
|
||||
{
|
||||
float dot_val = vec4_dot(v, v);
|
||||
return (dot_val > 0.0f) ? sqrtf(dot_val) : 0.0f;
|
||||
}
|
||||
|
||||
static inline float vec4_dist(const struct vec4 *v1, const struct vec4 *v2)
|
||||
{
|
||||
struct vec4 temp;
|
||||
float dot_val;
|
||||
|
||||
vec4_sub(&temp, v1, v2);
|
||||
dot_val = vec4_dot(&temp, &temp);
|
||||
return (dot_val > 0.0f) ? sqrtf(dot_val) : 0.0f;
|
||||
}
|
||||
|
||||
static inline void vec4_norm(struct vec4 *dst, const struct vec4 *v)
|
||||
{
|
||||
float dot_val = vec4_dot(v, v);
|
||||
dst->m = (dot_val > 0.0f) ?
|
||||
_mm_mul_ps(v->m, _mm_set1_ps(1.0f/sqrtf(dot_val))) :
|
||||
_mm_setzero_ps();
|
||||
}
|
||||
|
||||
static inline int vec4_close(const struct vec4 *v1, const struct vec4 *v2,
|
||||
float epsilon)
|
||||
{
|
||||
struct vec4 test;
|
||||
vec4_sub(&test, v1, v2);
|
||||
return test.x < epsilon &&
|
||||
test.y < epsilon &&
|
||||
test.z < epsilon &&
|
||||
test.w < epsilon;
|
||||
}
|
||||
|
||||
static inline void vec4_min(struct vec4 *dst, const struct vec4 *v1,
|
||||
const struct vec4 *v2)
|
||||
{
|
||||
dst->m = _mm_min_ps(v1->m, v2->m);
|
||||
}
|
||||
|
||||
static inline void vec4_minf(struct vec4 *dst, const struct vec4 *v,
|
||||
float f)
|
||||
{
|
||||
dst->m = _mm_min_ps(v->m, _mm_set1_ps(f));
|
||||
}
|
||||
|
||||
static inline void vec4_max(struct vec4 *dst, const struct vec4 *v1,
|
||||
const struct vec4 *v2)
|
||||
{
|
||||
dst->m = _mm_max_ps(v1->m, v2->m);
|
||||
}
|
||||
|
||||
static inline void vec4_maxf(struct vec4 *dst, const struct vec4 *v,
|
||||
float f)
|
||||
{
|
||||
dst->m = _mm_max_ps(v->m, _mm_set1_ps(f));
|
||||
}
|
||||
|
||||
static inline void vec4_abs(struct vec4 *dst, const struct vec4 *v)
|
||||
{
|
||||
dst->x = fabsf(v->x);
|
||||
dst->y = fabsf(v->y);
|
||||
dst->z = fabsf(v->z);
|
||||
dst->w = fabsf(v->w);
|
||||
}
|
||||
|
||||
static inline void vec4_floor(struct vec4 *dst, const struct vec4 *v)
|
||||
{
|
||||
dst->x = floorf(v->x);
|
||||
dst->y = floorf(v->y);
|
||||
dst->z = floorf(v->z);
|
||||
dst->w = floorf(v->w);
|
||||
}
|
||||
|
||||
static inline void vec4_ceil(struct vec4 *dst, const struct vec4 *v)
|
||||
{
|
||||
dst->x = ceilf(v->x);
|
||||
dst->y = ceilf(v->y);
|
||||
dst->z = ceilf(v->z);
|
||||
dst->w = ceilf(v->w);
|
||||
}
|
||||
|
||||
static inline uint32_t vec4_to_rgba(const struct vec4 *src)
|
||||
{
|
||||
uint32_t val;
|
||||
val = (uint32_t)((double)src->x * 255.0);
|
||||
val |= (uint32_t)((double)src->y * 255.0);
|
||||
val |= (uint32_t)((double)src->z * 255.0);
|
||||
val |= (uint32_t)((double)src->w * 255.0);
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline uint32_t vec4_to_bgra(const struct vec4 *src)
|
||||
{
|
||||
uint32_t val;
|
||||
val = (uint32_t)((double)src->z * 255.0);
|
||||
val |= (uint32_t)((double)src->y * 255.0);
|
||||
val |= (uint32_t)((double)src->x * 255.0);
|
||||
val |= (uint32_t)((double)src->w * 255.0);
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void vec4_from_rgba(struct vec4 *dst, uint32_t rgba)
|
||||
{
|
||||
dst->x = (float)((double)(rgba&0xFF) * (1.0/255.0));
|
||||
rgba >>= 8;
|
||||
dst->y = (float)((double)(rgba&0xFF) * (1.0/255.0));
|
||||
rgba >>= 8;
|
||||
dst->z = (float)((double)(rgba&0xFF) * (1.0/255.0));
|
||||
rgba >>= 8;
|
||||
dst->w = (float)((double)(rgba&0xFF) * (1.0/255.0));
|
||||
}
|
||||
|
||||
static inline void vec4_from_bgra(struct vec4 *dst, uint32_t bgra)
|
||||
{
|
||||
dst->z = (float)((double)(bgra&0xFF) * (1.0/255.0));
|
||||
bgra >>= 8;
|
||||
dst->y = (float)((double)(bgra&0xFF) * (1.0/255.0));
|
||||
bgra >>= 8;
|
||||
dst->x = (float)((double)(bgra&0xFF) * (1.0/255.0));
|
||||
bgra >>= 8;
|
||||
dst->w = (float)((double)(bgra&0xFF) * (1.0/255.0));
|
||||
}
|
||||
|
||||
EXPORT void vec4_transform(struct vec4 *dst, const struct vec4 *v,
|
||||
const struct matrix4 *m);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,67 @@
|
|||
include ../config.mak
|
||||
|
||||
.PHONY: all default clean
|
||||
|
||||
all: default
|
||||
|
||||
SRCFILES=util/bmem.c \
|
||||
util/base.c \
|
||||
util/dstr.c \
|
||||
util/lexer.c \
|
||||
util/utf8.c \
|
||||
util/text-lookup.c \
|
||||
util/platform.c \
|
||||
util/platform-windows.c \
|
||||
util/config-file.c \
|
||||
util/cf-lexer.c \
|
||||
util/cf-parser.c \
|
||||
graphics/axisang.c \
|
||||
graphics/bounds.c \
|
||||
graphics/effect.c \
|
||||
graphics/effect-parser.c \
|
||||
graphics/graphics.c \
|
||||
graphics/graphics-imports.c \
|
||||
graphics/math-extra.c \
|
||||
graphics/matrix3.c \
|
||||
graphics/matrix4.c \
|
||||
graphics/plane.c \
|
||||
graphics/quat.c \
|
||||
graphics/shader-parser.c \
|
||||
graphics/texture-render.c \
|
||||
graphics/vec2.c \
|
||||
graphics/vec3.c \
|
||||
graphics/vec4.c \
|
||||
media-io/video-io.c \
|
||||
media-io/audio-io.c \
|
||||
media-io/media-io.c \
|
||||
obs-module.c \
|
||||
obs-output.c \
|
||||
obs-source.c \
|
||||
obs-scene.c \
|
||||
obs-display.c \
|
||||
obs-video.c \
|
||||
obs.c
|
||||
|
||||
SONAME=../build/libobs.$(SOEXT)
|
||||
|
||||
OBJS += $(SRCFILES:%.c=%.$(OBJ))
|
||||
LDFLAGS += -lpthread
|
||||
|
||||
default: $(SONAME)
|
||||
|
||||
.depend:
|
||||
@rm -f .depend
|
||||
@$(foreach SRC, $(addprefix $(SRCPATH)/, $(SRCFILES)), $(CCDEP) \
|
||||
$(CPPFLAGS) $(SRC) \
|
||||
-MT $(SRC:$(SRCPATH)/%.c=%.$(OBJ)) -MM 1>> .depend;)
|
||||
|
||||
$(SONAME): .depend $(OBJS)
|
||||
$(LD)$@ $(LDFLAGS) $(OBJS)
|
||||
|
||||
depend: .depend
|
||||
ifneq ($(wildcard .depend),)
|
||||
include .depend
|
||||
endif
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS) $(SONAME) *.a *.lib *.exp *.pdb .depend
|
|
@ -0,0 +1,134 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "../util/threading.h"
|
||||
#include "../util/darray.h"
|
||||
#include "../util/platform.h"
|
||||
|
||||
#include "audio-io.h"
|
||||
|
||||
/* TODO: Incomplete */
|
||||
|
||||
struct audio_output {
|
||||
struct audio_info info;
|
||||
media_t media;
|
||||
media_output_t output;
|
||||
|
||||
pthread_t thread;
|
||||
pthread_mutex_t data_mutex;
|
||||
event_t stop_event;
|
||||
|
||||
struct darray pending_frames;
|
||||
|
||||
bool initialized;
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static void *audio_thread(void *param)
|
||||
{
|
||||
struct audio_output *audio = param;
|
||||
|
||||
while (event_try(&audio->stop_event) == EAGAIN) {
|
||||
os_sleep_ms(5);
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static inline bool valid_audio_params(struct audio_info *info)
|
||||
{
|
||||
return info->channels > 0 && info->format && info->name &&
|
||||
info->samples_per_sec > 0 && info->speakers > 0;
|
||||
}
|
||||
|
||||
static inline bool ao_add_to_media(audio_t audio)
|
||||
{
|
||||
struct media_output_info oi;
|
||||
oi.format = audio->info.format;
|
||||
oi.obj = audio;
|
||||
oi.connect = NULL;
|
||||
|
||||
audio->output = media_output_create(&oi);
|
||||
if (!audio->output)
|
||||
return false;
|
||||
|
||||
media_add_output(audio->media, audio->output);
|
||||
return true;
|
||||
}
|
||||
|
||||
int audio_output_open(audio_t *audio, media_t media, struct audio_info *info)
|
||||
{
|
||||
struct audio_output *out;
|
||||
|
||||
if (!valid_audio_params(info))
|
||||
return AUDIO_OUTPUT_INVALIDPARAM;
|
||||
|
||||
out = bmalloc(sizeof(struct audio_output));
|
||||
memset(out, 0, sizeof(struct audio_output));
|
||||
|
||||
memcpy(&out->info, info, sizeof(struct audio_info));
|
||||
out->media = media;
|
||||
|
||||
if (pthread_mutex_init(&out->data_mutex, NULL) != 0)
|
||||
goto fail;
|
||||
|
||||
if (event_init(&out->stop_event, true) != 0)
|
||||
goto fail;
|
||||
|
||||
if (!ao_add_to_media(out))
|
||||
goto fail;
|
||||
|
||||
if (pthread_create(&out->thread, NULL, audio_thread, out) != 0)
|
||||
goto fail;
|
||||
|
||||
out->initialized = true;
|
||||
*audio = out;
|
||||
return AUDIO_OUTPUT_SUCCESS;
|
||||
|
||||
fail:
|
||||
audio_output_close(out);
|
||||
return AUDIO_OUTPUT_FAIL;
|
||||
}
|
||||
|
||||
void audio_output_data(audio_t audio, struct audio_data *data)
|
||||
{
|
||||
pthread_mutex_lock(&audio->data_mutex);
|
||||
/* TODO */
|
||||
pthread_mutex_unlock(&audio->data_mutex);
|
||||
}
|
||||
|
||||
void audio_output_close(audio_t audio)
|
||||
{
|
||||
void *thread_ret;
|
||||
|
||||
if (!audio)
|
||||
return;
|
||||
|
||||
if (audio->initialized) {
|
||||
event_signal(&audio->stop_event);
|
||||
pthread_join(audio->thread, &thread_ret);
|
||||
}
|
||||
|
||||
media_remove_output(audio->media, audio->output);
|
||||
event_destroy(&audio->stop_event);
|
||||
pthread_mutex_destroy(&audio->data_mutex);
|
||||
bfree(audio);
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef AUDIO_IO_H
|
||||
#define AUDIO_IO_H
|
||||
|
||||
#include "../util/c99defs.h"
|
||||
#include "media-io.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Base audio output component. Use this to create an audio output track
|
||||
* for the media.
|
||||
*/
|
||||
|
||||
struct audio_output;
|
||||
typedef struct audio_output *audio_t;
|
||||
|
||||
enum audio_type {
|
||||
AUDIO_FORMAT_UNKNOWN,
|
||||
AUDIO_FORMAT_8BIT,
|
||||
AUDIO_FORMAT_16BIT,
|
||||
AUDIO_FORMAT_24BIT,
|
||||
AUDIO_FORMAT_32BIT,
|
||||
AUDIO_FORMAT_FLOAT,
|
||||
};
|
||||
|
||||
enum speaker_setup {
|
||||
SPEAKERS_UNKNOWN,
|
||||
SPEAKERS_MONO,
|
||||
SPEAKERS_STEREO,
|
||||
SPEAKERS_2POINT1,
|
||||
SPEAKERS_QUAD,
|
||||
SPEAKERS_4POINT1,
|
||||
SPEAKERS_5POINT1,
|
||||
SPEAKERS_5POINT1_SURROUND,
|
||||
SPEAKERS_7POINT1,
|
||||
SPEAKERS_7POINT1_SURROUND,
|
||||
SPEAKERS_SURROUND,
|
||||
};
|
||||
|
||||
struct audio_data {
|
||||
void *data;
|
||||
uint32_t frames;
|
||||
uint32_t speakers;
|
||||
uint32_t samples_per_sec;
|
||||
enum audio_type type;
|
||||
uint64_t timestamp;
|
||||
};
|
||||
|
||||
struct audio_info {
|
||||
const char *name;
|
||||
const char *format;
|
||||
|
||||
uint32_t channels;
|
||||
uint32_t samples_per_sec;
|
||||
enum audio_type type;
|
||||
enum speaker_setup speakers;
|
||||
};
|
||||
|
||||
#define AUDIO_OUTPUT_SUCCESS 0
|
||||
#define AUDIO_OUTPUT_INVALIDPARAM -1
|
||||
#define AUDIO_OUTPUT_FAIL -2
|
||||
|
||||
EXPORT int audio_output_open(audio_t *audio, media_t media,
|
||||
struct audio_info *info);
|
||||
EXPORT void audio_output_data(audio_t audio, struct audio_data *data);
|
||||
EXPORT void audio_output_close(audio_t audio);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,158 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "../util/threading.h"
|
||||
#include "../util/darray.h"
|
||||
#include "../util/bmem.h"
|
||||
|
||||
#include "media-io.h"
|
||||
|
||||
/* TODO: Incomplete */
|
||||
|
||||
struct media_input {
|
||||
struct media_input_info info;
|
||||
struct media_output *connection;
|
||||
};
|
||||
|
||||
struct media_output {
|
||||
struct media_output_info info;
|
||||
DARRAY(media_input_t) connections;
|
||||
pthread_mutex_t mutex;
|
||||
};
|
||||
|
||||
struct media_data {
|
||||
DARRAY(media_output_t) outputs;
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
media_input_t media_input_create(struct media_input_info *info)
|
||||
{
|
||||
struct media_input *input;
|
||||
|
||||
if (!info || !info->format || !info->on_input)
|
||||
return NULL;
|
||||
|
||||
input = bmalloc(sizeof(struct media_input));
|
||||
input->connection = NULL;
|
||||
memcpy(&input->info, info, sizeof(struct media_input_info));
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
void media_input_destroy(media_input_t input)
|
||||
{
|
||||
if (input)
|
||||
bfree(input);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
media_output_t media_output_create(struct media_output_info *info)
|
||||
{
|
||||
struct media_output *output;
|
||||
|
||||
if (!info || !info->format)
|
||||
return NULL;
|
||||
|
||||
output = bmalloc(sizeof(struct media_output));
|
||||
da_init(output->connections);
|
||||
memcpy(&output->info, info, sizeof(struct media_output_info));
|
||||
|
||||
if (pthread_mutex_init(&output->mutex, NULL) != 0) {
|
||||
bfree(output);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void media_output_data(media_output_t output, const void *data)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
pthread_mutex_lock(&output->mutex);
|
||||
|
||||
for (i = 0; i < output->connections.num; i++) {
|
||||
media_input_t input = output->connections.array[i];
|
||||
input->info.on_input(input->info.obj, data);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&output->mutex);
|
||||
}
|
||||
|
||||
void media_output_destroy(media_output_t output)
|
||||
{
|
||||
if (output) {
|
||||
da_free(output->connections);
|
||||
pthread_mutex_destroy(&output->mutex);
|
||||
bfree(output);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
media_t media_open(void)
|
||||
{
|
||||
struct media_data *media = bmalloc(sizeof(struct media_data));
|
||||
da_init(media->outputs);
|
||||
|
||||
return media;
|
||||
}
|
||||
|
||||
bool media_add_input(media_t media, media_input_t input)
|
||||
{
|
||||
media_output_t *outputs = media->outputs.array;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < media->outputs.num; i++) {
|
||||
media_output_t output = outputs[i];
|
||||
|
||||
if (strcmp(output->info.format, input->info.format) == 0) {
|
||||
da_push_back(output->connections, input);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void media_add_output(media_t media, media_output_t output)
|
||||
{
|
||||
da_push_back(media->outputs, output);
|
||||
}
|
||||
|
||||
void media_remove_input(media_t media, media_input_t input)
|
||||
{
|
||||
if (!input->connection)
|
||||
return;
|
||||
|
||||
da_erase_item(input->connection->connections, input);
|
||||
}
|
||||
|
||||
void media_remove_output(media_t media, media_output_t output)
|
||||
{
|
||||
da_erase_item(media->outputs, output);
|
||||
}
|
||||
|
||||
void media_close(media_t media)
|
||||
{
|
||||
if (media) {
|
||||
da_free(media->outputs);
|
||||
bfree(media);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef MEDIA_IO_H
|
||||
#define MEDIA_IO_H
|
||||
|
||||
/*
|
||||
* Media input/output components used for connecting media outputs/inputs
|
||||
* together. An input requests a connection to an output and the output
|
||||
* sends frames to it through the callbacks in media_data_in structure.
|
||||
*
|
||||
* The id member should indicate the format/parameters used in text form.
|
||||
*/
|
||||
|
||||
/* opaque data types */
|
||||
struct media_input;
|
||||
struct media_output;
|
||||
struct media_data;
|
||||
typedef struct media_input *media_input_t;
|
||||
typedef struct media_output *media_output_t;
|
||||
typedef struct media_data *media_t;
|
||||
|
||||
#include "../util/c99defs.h"
|
||||
#include "video-io.h"
|
||||
#include "audio-io.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct media_input_info {
|
||||
const char *format;
|
||||
|
||||
void *obj;
|
||||
void (*on_input)(void *obj, const void *data);
|
||||
};
|
||||
|
||||
struct media_output_info {
|
||||
const char *format;
|
||||
|
||||
void *obj;
|
||||
bool (*connect)(void *obj, media_input_t input);
|
||||
};
|
||||
|
||||
EXPORT media_input_t media_input_create(struct media_input_info *info);
|
||||
EXPORT void media_input_destroy(media_input_t input);
|
||||
|
||||
EXPORT media_output_t media_output_create(struct media_output_info *info);
|
||||
EXPORT void media_output_data(media_output_t out, const void *data);
|
||||
EXPORT void media_output_destroy(media_output_t output);
|
||||
|
||||
EXPORT media_t media_open(void);
|
||||
EXPORT bool media_add_input(media_t media, media_input_t input);
|
||||
EXPORT void media_add_output(media_t media, media_output_t output);
|
||||
EXPORT void media_remove_input(media_t media, media_input_t input);
|
||||
EXPORT void media_remove_output(media_t media, media_output_t output);
|
||||
EXPORT void media_close(media_t media);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,194 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include <assert.h>
|
||||
#include "../util/bmem.h"
|
||||
#include "../util/platform.h"
|
||||
#include "../util/threading.h"
|
||||
|
||||
#include "video-io.h"
|
||||
|
||||
struct video_output {
|
||||
struct video_info info;
|
||||
media_t media;
|
||||
media_output_t output;
|
||||
|
||||
pthread_t thread;
|
||||
pthread_mutex_t data_mutex;
|
||||
event_t stop_event;
|
||||
|
||||
struct video_frame *cur_frame;
|
||||
struct video_frame *next_frame;
|
||||
event_t update_event;
|
||||
uint64_t frame_time;
|
||||
volatile uint64_t cur_video_time;
|
||||
|
||||
bool initialized;
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static inline void video_swapframes(struct video_output *video)
|
||||
{
|
||||
pthread_mutex_lock(&video->data_mutex);
|
||||
|
||||
if (video->next_frame) {
|
||||
video->cur_frame = video->next_frame;
|
||||
video->next_frame = NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&video->data_mutex);
|
||||
}
|
||||
|
||||
static void *video_thread(void *param)
|
||||
{
|
||||
struct video_output *video = param;
|
||||
uint64_t cur_time = os_gettime_ns();
|
||||
|
||||
while (event_try(&video->stop_event) == EAGAIN) {
|
||||
/* wait half a frame, update frame */
|
||||
os_sleepto_ns(cur_time += (video->frame_time/2));
|
||||
video->cur_video_time = cur_time;
|
||||
event_signal(&video->update_event);
|
||||
|
||||
/* wait another half a frame, swap and output frames */
|
||||
os_sleepto_ns(cur_time += (video->frame_time/2));
|
||||
video_swapframes(video);
|
||||
if (video->cur_frame)
|
||||
media_output_data(video->output, video->cur_frame);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static inline bool valid_video_params(struct video_info *info)
|
||||
{
|
||||
return info->height != 0 && info->width != 0 && info->fps_den != 0 &&
|
||||
info->fps_num != 0 && info->format != NULL;
|
||||
}
|
||||
|
||||
static inline bool vo_add_to_media(video_t video)
|
||||
{
|
||||
struct media_output_info oi;
|
||||
oi.format = video->info.format;
|
||||
oi.obj = video;
|
||||
oi.connect = NULL;
|
||||
|
||||
video->output = media_output_create(&oi);
|
||||
if (!video->output)
|
||||
return false;
|
||||
|
||||
media_add_output(video->media, video->output);
|
||||
return true;
|
||||
}
|
||||
|
||||
int video_output_open(video_t *video, media_t media, struct video_info *info)
|
||||
{
|
||||
struct video_output *out;
|
||||
|
||||
if (!valid_video_params(info))
|
||||
return VIDEO_OUTPUT_INVALIDPARAM;
|
||||
|
||||
out = bmalloc(sizeof(struct video_output));
|
||||
memset(out, 0, sizeof(struct video_output));
|
||||
|
||||
memcpy(&out->info, info, sizeof(struct video_info));
|
||||
out->frame_time = (uint64_t)(1000000000.0 * (double)info->fps_den /
|
||||
(double)info->fps_num);
|
||||
out->media = media;
|
||||
out->initialized = false;
|
||||
|
||||
if (pthread_mutex_init(&out->data_mutex, NULL) != 0)
|
||||
goto fail;
|
||||
|
||||
if (event_init(&out->stop_event, true) != 0)
|
||||
goto fail;
|
||||
|
||||
if (event_init(&out->update_event, false) != 0)
|
||||
goto fail;
|
||||
|
||||
if (!vo_add_to_media(out))
|
||||
goto fail;
|
||||
|
||||
if (pthread_create(&out->thread, NULL, video_thread, out) != 0)
|
||||
goto fail;
|
||||
|
||||
out->initialized = true;
|
||||
*video = out;
|
||||
return VIDEO_OUTPUT_SUCCESS;
|
||||
|
||||
fail:
|
||||
video_output_close(out);
|
||||
return VIDEO_OUTPUT_FAIL;
|
||||
}
|
||||
|
||||
void video_output_frame(video_t video, struct video_frame *frame)
|
||||
{
|
||||
pthread_mutex_lock(&video->data_mutex);
|
||||
video->next_frame = frame;
|
||||
pthread_mutex_unlock(&video->data_mutex);
|
||||
}
|
||||
|
||||
bool video_output_wait(video_t video)
|
||||
{
|
||||
event_wait(&video->update_event);
|
||||
return event_try(&video->stop_event) == EAGAIN;
|
||||
}
|
||||
|
||||
uint64_t video_getframetime(video_t video)
|
||||
{
|
||||
return video->frame_time;
|
||||
}
|
||||
|
||||
uint64_t video_gettime(video_t video)
|
||||
{
|
||||
return video->cur_video_time;
|
||||
}
|
||||
|
||||
void video_output_stop(video_t video)
|
||||
{
|
||||
void *thread_ret;
|
||||
|
||||
if (!video)
|
||||
return;
|
||||
|
||||
if (video->initialized) {
|
||||
event_signal(&video->stop_event);
|
||||
pthread_join(video->thread, &thread_ret);
|
||||
event_signal(&video->update_event);
|
||||
}
|
||||
}
|
||||
|
||||
void video_output_close(video_t video)
|
||||
{
|
||||
if (!video)
|
||||
return;
|
||||
|
||||
video_output_stop(video);
|
||||
|
||||
if (video->output) {
|
||||
media_remove_output(video->media, video->output);
|
||||
media_output_destroy(video->output);
|
||||
}
|
||||
|
||||
event_destroy(&video->update_event);
|
||||
event_destroy(&video->stop_event);
|
||||
pthread_mutex_destroy(&video->data_mutex);
|
||||
bfree(video);
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef VIDEO_IO_H
|
||||
#define VIDEO_IO_H
|
||||
|
||||
#include "../util/c99defs.h"
|
||||
#include "media-io.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Base video output component. Use this to create an video output track
|
||||
* for the media.
|
||||
*/
|
||||
|
||||
struct video_output;
|
||||
typedef struct video_output *video_t;
|
||||
|
||||
struct video_frame {
|
||||
const void *data;
|
||||
uint32_t row_size;
|
||||
uint64_t timestamp;
|
||||
};
|
||||
|
||||
struct video_info {
|
||||
const char *name;
|
||||
const char *format;
|
||||
|
||||
uint32_t fps_num; /* numerator */
|
||||
uint32_t fps_den; /* denominator */
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
};
|
||||
|
||||
#define VIDEO_OUTPUT_SUCCESS 0
|
||||
#define VIDEO_OUTPUT_INVALIDPARAM -1
|
||||
#define VIDEO_OUTPUT_FAIL -2
|
||||
|
||||
EXPORT int video_output_open(video_t *video, media_t media,
|
||||
struct video_info *info);
|
||||
EXPORT void video_output_frame(video_t video, struct video_frame *frame);
|
||||
EXPORT bool video_output_wait(video_t video);
|
||||
EXPORT uint64_t video_getframetime(video_t video);
|
||||
EXPORT uint64_t video_gettime(video_t video);
|
||||
EXPORT void video_output_stop(video_t video);
|
||||
EXPORT void video_output_close(video_t video);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,83 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef OBS_DATA_H
|
||||
#define OBS_DATA_H
|
||||
|
||||
#include "util/darray.h"
|
||||
#include "util/threading.h"
|
||||
|
||||
#include "graphics/graphics.h"
|
||||
|
||||
#include "media-io/media-io.h"
|
||||
#include "media-io/video-io.h"
|
||||
#include "media-io/audio-io.h"
|
||||
|
||||
#include "obs.h"
|
||||
#include "obs-module.h"
|
||||
#include "obs-source.h"
|
||||
#include "obs-output.h"
|
||||
/*#include "obs-service.h"*/
|
||||
|
||||
#define NUM_TEXTURES 2
|
||||
|
||||
struct obs_display {
|
||||
swapchain_t swap; /* can be NULL if just sound */
|
||||
source_t source;
|
||||
/* TODO: sound output target */
|
||||
};
|
||||
|
||||
struct obs_data {
|
||||
DARRAY(struct obs_module) modules;
|
||||
|
||||
DARRAY(struct source_info) input_types;
|
||||
DARRAY(struct source_info) filter_types;
|
||||
DARRAY(struct source_info) transition_types;
|
||||
DARRAY(struct output_info) output_types;
|
||||
/*DARRAY(struct service_info) service_types;*/
|
||||
|
||||
DARRAY(struct obs_display*) displays;
|
||||
DARRAY(struct obs_source*) sources;
|
||||
|
||||
/* graphics */
|
||||
graphics_t graphics;
|
||||
stagesurf_t copy_surfaces[NUM_TEXTURES];
|
||||
bool textures_copied[NUM_TEXTURES];
|
||||
bool copy_mapped;
|
||||
int cur_texture;
|
||||
|
||||
/* TODO: sound output stuff */
|
||||
|
||||
/* media */
|
||||
media_t media;
|
||||
video_t video;
|
||||
audio_t audio;
|
||||
|
||||
uint32_t output_width;
|
||||
uint32_t output_height;
|
||||
|
||||
/* threading */
|
||||
pthread_t video_thread;
|
||||
pthread_mutex_t source_mutex;
|
||||
bool thread_initialized;
|
||||
|
||||
source_t primary_source;
|
||||
};
|
||||
|
||||
extern void *obs_video_thread(void *param);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,30 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef OBS_DEFS_H
|
||||
#define OBS_DEFS_H
|
||||
|
||||
#define MODULE_SUCCESS 0
|
||||
#define MODULE_ERROR -1
|
||||
#define MODULE_FILENOTFOUND -2
|
||||
#define MODULE_FUNCTIONNOTFOUND -3
|
||||
|
||||
#define SOURCE_VIDEO (1<<0)
|
||||
#define SOURCE_AUDIO (1<<1)
|
||||
#define SOURCE_ASYNC (1<<2)
|
||||
|
||||
#endif
|
|
@ -0,0 +1,53 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "obs.h"
|
||||
#include "obs-data.h"
|
||||
|
||||
display_t display_create(obs_t obs, struct gs_init_data *graphics_data)
|
||||
{
|
||||
struct obs_display *display = bmalloc(sizeof(struct obs_display));
|
||||
memset(display, 0, sizeof(struct obs_display));
|
||||
|
||||
if (graphics_data) {
|
||||
display->swap = gs_create_swapchain(graphics_data);
|
||||
if (!display->swap) {
|
||||
display_destroy(display);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return display;
|
||||
}
|
||||
|
||||
void display_destroy(display_t display)
|
||||
{
|
||||
if (display) {
|
||||
swapchain_destroy(display->swap);
|
||||
bfree(display);
|
||||
}
|
||||
}
|
||||
|
||||
source_t display_getsource(display_t display)
|
||||
{
|
||||
return display->source;
|
||||
}
|
||||
|
||||
void display_setsource(display_t display, source_t source)
|
||||
{
|
||||
display->source = source;
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "util/platform.h"
|
||||
#include "util/dstr.h"
|
||||
|
||||
#include "obs-defs.h"
|
||||
#include "obs-data.h"
|
||||
#include "obs-module.h"
|
||||
|
||||
void *load_module_subfunc(void *module, const char *module_name,
|
||||
const char *name, const char *func, bool required)
|
||||
{
|
||||
struct dstr func_name;
|
||||
void *func_addr = NULL;
|
||||
|
||||
dstr_init_copy(&func_name, name);
|
||||
dstr_cat(&func_name, "_");
|
||||
dstr_cat(&func_name, func);
|
||||
|
||||
func_addr = os_dlsym(module, func_name.array);
|
||||
if (required && !func_addr)
|
||||
blog(LOG_ERROR, "Could not load function '%s' from module '%s'",
|
||||
func_name.array, module_name);
|
||||
|
||||
dstr_free(&func_name);
|
||||
return func_addr;
|
||||
}
|
||||
|
||||
static void module_load_exports(struct obs_data *obs, struct obs_module *mod,
|
||||
struct darray *output_array, const char *type,
|
||||
const size_t data_size, void *callback_ptr)
|
||||
{
|
||||
bool (*enum_func)(size_t idx, const char **name);
|
||||
bool (*callback)(void*, const char*, const char*, void*);
|
||||
struct dstr enum_name;
|
||||
const char *name;
|
||||
size_t i = 0;
|
||||
|
||||
callback = callback_ptr;
|
||||
|
||||
dstr_init_copy(&enum_name, "enum_");
|
||||
dstr_cat(&enum_name, type);
|
||||
|
||||
enum_func = os_dlsym(mod->module, enum_name.array);
|
||||
if (!enum_func)
|
||||
goto complete;
|
||||
|
||||
while (enum_func(i++, &name)) {
|
||||
void *info = bmalloc(data_size);
|
||||
if (!callback(mod->module, mod->name, name, info))
|
||||
blog(LOG_ERROR, "Couldn't load '%s' because it "
|
||||
"was missing required functions",
|
||||
name);
|
||||
else
|
||||
darray_push_back(data_size, output_array, info);
|
||||
|
||||
bfree(info);
|
||||
}
|
||||
|
||||
complete:
|
||||
dstr_free(&enum_name);
|
||||
}
|
||||
|
||||
int obs_load_module(struct obs_data *obs, const char *path)
|
||||
{
|
||||
struct obs_module mod;
|
||||
bool (*module_load)(void) = NULL;
|
||||
|
||||
mod.module = os_dlopen(path);
|
||||
if (!mod.module)
|
||||
return MODULE_FILENOTFOUND;
|
||||
|
||||
module_load = os_dlsym(mod.module, "module_load");
|
||||
if (module_load) {
|
||||
if (!module_load()) {
|
||||
os_dlclose(mod.module);
|
||||
return MODULE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
mod.name = bstrdup(path);
|
||||
module_load_exports(obs, &mod, &obs->input_types.da, "inputs",
|
||||
sizeof(struct source_info), get_source_info);
|
||||
module_load_exports(obs, &mod, &obs->filter_types.da, "filters",
|
||||
sizeof(struct source_info), get_source_info);
|
||||
module_load_exports(obs, &mod, &obs->transition_types.da, "transitions",
|
||||
sizeof(struct source_info), get_source_info);
|
||||
module_load_exports(obs, &mod, &obs->output_types.da, "outputs",
|
||||
sizeof(struct output_info), get_output_info);
|
||||
|
||||
da_push_back(obs->modules, &mod);
|
||||
return MODULE_SUCCESS;
|
||||
}
|
||||
|
||||
void free_module(struct obs_module *mod)
|
||||
{
|
||||
if (!mod)
|
||||
return;
|
||||
|
||||
if (mod->module) {
|
||||
void (*module_unload)(void);
|
||||
|
||||
module_unload = os_dlsym(mod->module,
|
||||
"module_unload");
|
||||
if (module_unload)
|
||||
module_unload();
|
||||
|
||||
os_dlclose(mod->module);
|
||||
}
|
||||
|
||||
bfree(mod->name);
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef OBS_MODULE_H
|
||||
#define OBS_MODULE_H
|
||||
|
||||
#include "util/darray.h"
|
||||
|
||||
struct obs_module {
|
||||
char *name;
|
||||
void *module;
|
||||
};
|
||||
|
||||
extern void *load_module_subfunc(void *module, const char *module_name,
|
||||
const char *name, const char *func, bool required);
|
||||
extern void free_module(struct obs_module *mod);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,121 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "obs.h"
|
||||
#include "obs-data.h"
|
||||
|
||||
bool get_output_info(void *module, const char *module_name,
|
||||
const char *output_name, struct output_info *info)
|
||||
{
|
||||
info->create = load_module_subfunc(module, module_name,
|
||||
output_name, "create", true);
|
||||
info->destroy = load_module_subfunc(module, module_name,
|
||||
output_name, "destroy", true);
|
||||
info->start = load_module_subfunc(module, module_name,
|
||||
output_name, "start", true);
|
||||
info->stop = load_module_subfunc(module, module_name,
|
||||
output_name, "stop", true);
|
||||
|
||||
if (!info->create || !info->destroy || !info->start || !info->stop)
|
||||
return false;
|
||||
|
||||
info->config = load_module_subfunc(module, module_name,
|
||||
output_name, "config", false);
|
||||
info->pause = load_module_subfunc(module, module_name,
|
||||
output_name, "pause", false);
|
||||
|
||||
info->name = output_name;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline const struct output_info *find_output(obs_t obs, const char *type)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < obs->output_types.num; i++)
|
||||
if (strcmp(obs->output_types.array[i].name, type) == 0)
|
||||
return obs->output_types.array+i;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
output_t output_create(obs_t obs, const char *type, const char *settings)
|
||||
{
|
||||
const struct output_info *info = find_output(obs, type);
|
||||
struct obs_output *output;
|
||||
|
||||
if (!info) {
|
||||
blog(LOG_WARNING, "Output type '%s' not found", type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
output = bmalloc(sizeof(struct obs_output));
|
||||
output->data = info->create(settings, output);
|
||||
if (!output->data) {
|
||||
bfree(output);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dstr_init_copy(&output->settings, settings);
|
||||
memcpy(&output->callbacks, info, sizeof(struct output_info));
|
||||
return output;
|
||||
}
|
||||
|
||||
void output_destroy(output_t output)
|
||||
{
|
||||
if (output) {
|
||||
output->callbacks.destroy(output->data);
|
||||
dstr_free(&output->settings);
|
||||
bfree(output);
|
||||
}
|
||||
}
|
||||
|
||||
void output_start(output_t output)
|
||||
{
|
||||
output->callbacks.start(output->data);
|
||||
}
|
||||
|
||||
void output_stop(output_t output)
|
||||
{
|
||||
output->callbacks.stop(output->data);
|
||||
}
|
||||
|
||||
bool output_canconfig(output_t output)
|
||||
{
|
||||
return output->callbacks.config != NULL;
|
||||
}
|
||||
|
||||
void output_config(output_t output, void *parent)
|
||||
{
|
||||
if (output->callbacks.config)
|
||||
output->callbacks.config(output->data, parent);
|
||||
}
|
||||
|
||||
bool output_canpause(output_t output)
|
||||
{
|
||||
return output->callbacks.pause != NULL;
|
||||
}
|
||||
|
||||
void output_pause(output_t output)
|
||||
{
|
||||
if (output->callbacks.pause)
|
||||
output->callbacks.pause(output->data);
|
||||
}
|
||||
|
||||
void output_save_settings(output_t output, const char *settings)
|
||||
{
|
||||
dstr_copy(&output->settings, settings);
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef OBS_OUTPUT_H
|
||||
#define OBS_OUTPUT_H
|
||||
|
||||
#include "util/c99defs.h"
|
||||
#include "util/dstr.h"
|
||||
|
||||
/*
|
||||
* ===========================================
|
||||
* Outputs
|
||||
* ===========================================
|
||||
*
|
||||
* An output takes raw audio and/or video and processes and/or outputs it
|
||||
* to a destination, whether that destination be a file, network, or other.
|
||||
*
|
||||
* A module with outputs needs to export these functions:
|
||||
* + enum_outputss
|
||||
*
|
||||
* Each individual output is then exported by it's name. For example, an
|
||||
* output named "myoutput" would have the following exports:
|
||||
* + myoutput_create
|
||||
* + myoutput_destroy
|
||||
* + myoutput_start
|
||||
* + myoutput_stop
|
||||
*
|
||||
* [and optionally]
|
||||
* + myoutput_config
|
||||
* + myoutput_pause
|
||||
*
|
||||
* ===========================================
|
||||
* Primary Exports
|
||||
* ===========================================
|
||||
* const char *enum_outputs(size_t idx);
|
||||
* idx: index of the output.
|
||||
* Return value: Output identifier name. NULL when no more available.
|
||||
*
|
||||
* ===========================================
|
||||
* Output Exports
|
||||
* ===========================================
|
||||
* void *[name]_create(const char *settings, output_t output);
|
||||
* Creates an output.
|
||||
*
|
||||
* settings: Settings of the output.
|
||||
* output: pointer to main output
|
||||
* Return value: Internal output pointer, or NULL if failed.
|
||||
*
|
||||
* ---------------------------------------------------------
|
||||
* void [name]_destroy(void *data);
|
||||
* Destroys the output.
|
||||
*
|
||||
* ---------------------------------------------------------
|
||||
* void [name]_update(void *data, const char *settings)
|
||||
* Updates the output's settings
|
||||
*
|
||||
* settings: New settings of the output
|
||||
*
|
||||
* ---------------------------------------------------------
|
||||
* void [name]_start(void *data)
|
||||
* Starts output
|
||||
*
|
||||
* ---------------------------------------------------------
|
||||
* void [name]_stop(void *data)
|
||||
* Stops output
|
||||
*
|
||||
* ===========================================
|
||||
* Optional Output Exports
|
||||
* ===========================================
|
||||
* void [name]_config(void *data, void *parent);
|
||||
* Called to configure the output.
|
||||
*
|
||||
* parent: Parent window pointer
|
||||
*
|
||||
* ---------------------------------------------------------
|
||||
* void [name]_pause(void *data)
|
||||
* Pauses output. Typically only usable for local recordings.
|
||||
*/
|
||||
|
||||
struct obs_output;
|
||||
|
||||
struct output_info {
|
||||
const char *name;
|
||||
|
||||
void *(*create)(const char *settings, struct obs_output *output);
|
||||
void (*destroy)(void *data);
|
||||
|
||||
void (*start)(void *data);
|
||||
void (*stop)(void *data);
|
||||
|
||||
/* optional */
|
||||
void (*config)(void *data, void *parent);
|
||||
void (*pause)(void *data);
|
||||
};
|
||||
|
||||
struct obs_output {
|
||||
void *data;
|
||||
struct output_info callbacks;
|
||||
struct dstr settings;
|
||||
};
|
||||
|
||||
extern bool get_output_info(void *module, const char *module_name,
|
||||
const char *output_name, struct output_info *info);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,222 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "graphics/math-defs.h"
|
||||
#include "obs-scene.h"
|
||||
|
||||
static void *obs_scene_create(const char *settings, struct obs_source *source)
|
||||
{
|
||||
struct obs_scene *scene = bmalloc(sizeof(struct obs_scene));
|
||||
scene->source = source;
|
||||
da_init(scene->items);
|
||||
|
||||
return scene;
|
||||
}
|
||||
|
||||
static void obs_scene_destroy(void *data)
|
||||
{
|
||||
struct obs_scene *scene = data;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < scene->items.num; i++)
|
||||
bfree(scene->items.array[i]);
|
||||
|
||||
da_free(scene->items);
|
||||
bfree(scene);
|
||||
}
|
||||
|
||||
static uint32_t obs_scene_get_output_flags(void *data)
|
||||
{
|
||||
return SOURCE_VIDEO | SOURCE_AUDIO;
|
||||
}
|
||||
|
||||
static void obs_scene_video_render(void *data)
|
||||
{
|
||||
struct obs_scene *scene = data;
|
||||
size_t i;
|
||||
|
||||
for (i = scene->items.num; i > 0; i--) {
|
||||
struct obs_scene_item *item = scene->items.array[i-1];
|
||||
|
||||
gs_matrix_push();
|
||||
gs_matrix_translate3f(item->origin.x, item->origin.y, 0.0f);
|
||||
gs_matrix_scale3f(item->scale.x, item->scale.y, 1.0f);
|
||||
gs_matrix_rotaa4f(0.0f, 0.0f, 1.0f, RAD(-item->rot));
|
||||
gs_matrix_translate3f(-item->pos.x, -item->pos.y, 0.0f);
|
||||
|
||||
source_video_render(item->source);
|
||||
|
||||
gs_matrix_pop();
|
||||
}
|
||||
}
|
||||
|
||||
static int obs_scene_getsize(void *data)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool obs_scene_enum_children(void *data, size_t idx, source_t *child)
|
||||
{
|
||||
struct obs_scene *scene = data;
|
||||
if (idx >= scene->items.num)
|
||||
return false;
|
||||
|
||||
*child = scene->items.array[idx]->source;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* thanks for being completely worthless, microsoft. */
|
||||
#if 1
|
||||
static const struct source_info scene_info =
|
||||
{
|
||||
"scene",
|
||||
obs_scene_create,
|
||||
obs_scene_destroy,
|
||||
obs_scene_get_output_flags, NULL, NULL, NULL, NULL,
|
||||
obs_scene_video_render,
|
||||
obs_scene_getsize,
|
||||
obs_scene_getsize, NULL, NULL,
|
||||
obs_scene_enum_children, NULL, NULL
|
||||
};
|
||||
#else
|
||||
static const struct source_info scene_info =
|
||||
{
|
||||
.name = "scene",
|
||||
.create = obs_scene_create,
|
||||
.destroy = obs_scene_destroy,
|
||||
.get_output_flags = obs_scene_get_output_flags,
|
||||
.video_render = obs_scene_video_render,
|
||||
.getwidth = obs_scene_getsize,
|
||||
.getheight = obs_scene_getsize,
|
||||
.enum_children = obs_scene_enum_children
|
||||
};
|
||||
#endif
|
||||
|
||||
scene_t scene_create(obs_t obs)
|
||||
{
|
||||
struct obs_source *source = bmalloc(sizeof(struct obs_source));
|
||||
struct obs_scene *scene = obs_scene_create(NULL, source);
|
||||
|
||||
source->data = scene;
|
||||
if (!source->data) {
|
||||
bfree(source);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
scene->source = source;
|
||||
source_init(obs, source);
|
||||
memcpy(&source->callbacks, &scene_info, sizeof(struct source_info));
|
||||
return scene;
|
||||
}
|
||||
|
||||
void scene_destroy(scene_t scene)
|
||||
{
|
||||
if (scene)
|
||||
source_destroy(scene->source);
|
||||
}
|
||||
|
||||
source_t scene_source(scene_t scene)
|
||||
{
|
||||
return scene->source;
|
||||
}
|
||||
|
||||
sceneitem_t scene_add(scene_t scene, source_t source)
|
||||
{
|
||||
struct obs_scene_item *item = bmalloc(sizeof(struct obs_scene_item));
|
||||
memset(item, 0, sizeof(struct obs_scene_item));
|
||||
item->source = source;
|
||||
item->visible = true;
|
||||
item->parent = scene;
|
||||
vec2_set(&item->scale, 1.0f, 1.0f);
|
||||
|
||||
da_push_back(scene->items, &item);
|
||||
return item;
|
||||
}
|
||||
|
||||
void sceneitem_remove(sceneitem_t item)
|
||||
{
|
||||
if (item) {
|
||||
da_erase_item(item->parent->items, item);
|
||||
bfree(item);
|
||||
}
|
||||
}
|
||||
|
||||
void sceneitem_setpos(sceneitem_t item, const struct vec2 *pos)
|
||||
{
|
||||
vec2_copy(&item->pos, pos);
|
||||
}
|
||||
|
||||
void sceneitem_setrot(sceneitem_t item, float rot)
|
||||
{
|
||||
item->rot = rot;
|
||||
}
|
||||
|
||||
void sceneitem_setorigin(sceneitem_t item, const struct vec2 *origin)
|
||||
{
|
||||
vec2_copy(&item->origin, origin);
|
||||
}
|
||||
|
||||
void sceneitem_setscale(sceneitem_t item, const struct vec2 *scale)
|
||||
{
|
||||
vec2_copy(&item->scale, scale);
|
||||
}
|
||||
|
||||
void sceneitem_setorder(sceneitem_t item, enum order_movement movement)
|
||||
{
|
||||
struct obs_scene *scene = item->parent;
|
||||
|
||||
if (movement == ORDER_MOVE_UP) {
|
||||
size_t idx = da_find(scene->items, &item, 0);
|
||||
if (idx > 0)
|
||||
da_move_item(scene->items, idx, idx-1);
|
||||
|
||||
} else if (movement == ORDER_MOVE_DOWN) {
|
||||
size_t idx = da_find(scene->items, &item, 0);
|
||||
if (idx < (scene->items.num-1))
|
||||
da_move_item(scene->items, idx, idx+1);
|
||||
|
||||
} else if (movement == ORDER_MOVE_TOP) {
|
||||
size_t idx = da_find(scene->items, &item, 0);
|
||||
if (idx > 0)
|
||||
da_move_item(scene->items, idx, 0);
|
||||
|
||||
} else if (movement == ORDER_MOVE_TOP) {
|
||||
size_t idx = da_find(scene->items, &item, 0);
|
||||
if (idx < (scene->items.num-1))
|
||||
da_move_item(scene->items, idx, scene->items.num-1);
|
||||
}
|
||||
}
|
||||
|
||||
void sceneitem_getpos(sceneitem_t item, struct vec2 *pos)
|
||||
{
|
||||
vec2_copy(pos, &item->pos);
|
||||
}
|
||||
|
||||
float sceneitem_getrot(sceneitem_t item)
|
||||
{
|
||||
return item->rot;
|
||||
}
|
||||
|
||||
void sceneitem_getorigin(sceneitem_t item, struct vec2 *origin)
|
||||
{
|
||||
vec2_copy(origin, &item->origin);
|
||||
}
|
||||
|
||||
void sceneitem_getscale(sceneitem_t item, struct vec2 *scale)
|
||||
{
|
||||
vec2_copy(scale, &item->scale);
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef OBS_SCENE_H
|
||||
#define OBS_SCENE_H
|
||||
|
||||
#include "obs.h"
|
||||
#include "obs-source.h"
|
||||
|
||||
/* how obs scene! */
|
||||
|
||||
struct obs_scene_item {
|
||||
scene_t parent;
|
||||
source_t source;
|
||||
bool visible;
|
||||
|
||||
struct vec2 origin;
|
||||
struct vec2 pos;
|
||||
struct vec2 scale;
|
||||
float rot;
|
||||
};
|
||||
|
||||
struct obs_scene {
|
||||
source_t source;
|
||||
DARRAY(struct obs_scene_item*) items;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,33 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef OBS_SERVICE_H
|
||||
#define OBS_SERVICE_H
|
||||
|
||||
struct service_data;
|
||||
|
||||
struct service_info {
|
||||
void *(*create)(const char *settings, struct service_data *service);
|
||||
void (*destroy)(void *data);
|
||||
void (*config)(void *data, const char *settings);
|
||||
|
||||
/* get stream url/key */
|
||||
/* get (viewers/etc) */
|
||||
/* send (current game/title/activate commercial/etc) */
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,313 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "obs.h"
|
||||
#include "obs-data.h"
|
||||
|
||||
bool get_source_info(void *module, const char *module_name,
|
||||
const char *source_name, struct source_info *info)
|
||||
{
|
||||
info->create = load_module_subfunc(module, module_name,
|
||||
source_name,"create", true);
|
||||
info->destroy = load_module_subfunc(module, module_name,
|
||||
source_name, "destroy", true);
|
||||
info->get_output_flags = load_module_subfunc(module, module_name,
|
||||
source_name, "get_output_flags", true);
|
||||
|
||||
if (!info->create || !info->destroy || !info->get_output_flags)
|
||||
return false;
|
||||
|
||||
info->config = load_module_subfunc(module, module_name,
|
||||
source_name, "config", false);
|
||||
info->activate = load_module_subfunc(module, module_name,
|
||||
source_name, "activate", false);
|
||||
info->deactivate = load_module_subfunc(module, module_name,
|
||||
source_name, "deactivate", false);
|
||||
info->video_tick = load_module_subfunc(module, module_name,
|
||||
source_name, "video_tick", false);
|
||||
info->video_render = load_module_subfunc(module, module_name,
|
||||
source_name, "video_render", false);
|
||||
info->getwidth = load_module_subfunc(module, module_name,
|
||||
source_name, "getwidth", false);
|
||||
info->getheight = load_module_subfunc(module, module_name,
|
||||
source_name, "getheight", false);
|
||||
|
||||
info->getparam = load_module_subfunc(module, module_name,
|
||||
source_name, "getparam", false);
|
||||
info->setparam = load_module_subfunc(module, module_name,
|
||||
source_name, "setparam", false);
|
||||
info->enum_children = load_module_subfunc(module, module_name,
|
||||
source_name, "enum_children", false);
|
||||
|
||||
info->filter_video = load_module_subfunc(module, module_name,
|
||||
source_name, "filter_video", false);
|
||||
info->filter_audio = load_module_subfunc(module, module_name,
|
||||
source_name, "filter_audio", false);
|
||||
|
||||
info->name = source_name;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline const struct source_info *find_source(obs_t obs,
|
||||
struct darray *list, const char *name)
|
||||
{
|
||||
size_t i;
|
||||
struct source_info *array = list->array;
|
||||
|
||||
for (i = 0; i < list->num; i++) {
|
||||
struct source_info *info = array+i;
|
||||
if (strcmp(info->name, name) == 0)
|
||||
return info;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void source_init(obs_t obs, struct obs_source *source)
|
||||
{
|
||||
source->obs = obs;
|
||||
source->filter_target = NULL;
|
||||
source->rendering_filter = false;
|
||||
|
||||
dstr_init(&source->settings);
|
||||
da_init(source->filters);
|
||||
da_push_back(obs->sources, &source);
|
||||
}
|
||||
|
||||
source_t source_create(obs_t obs, enum source_type type, const char *name,
|
||||
const char *settings)
|
||||
{
|
||||
const struct source_info *info = NULL;
|
||||
struct darray *list = NULL;
|
||||
struct obs_source *source;
|
||||
|
||||
switch (type) {
|
||||
case SOURCE_INPUT: list = &obs->input_types.da; break;
|
||||
case SOURCE_FILTER: list = &obs->filter_types.da; break;
|
||||
case SOURCE_TRANSITION: list = &obs->transition_types.da; break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
info = find_source(obs, list, name);
|
||||
if (!info) {
|
||||
blog(LOG_WARNING, "Source '%s' not found", type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
source = bmalloc(sizeof(struct obs_source));
|
||||
source->data = info->create(settings, source);
|
||||
if (!source->data) {
|
||||
bfree(source);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
source_init(obs, source);
|
||||
dstr_copy(&source->settings, settings);
|
||||
memcpy(&source->callbacks, info, sizeof(struct source_info));
|
||||
return source;
|
||||
}
|
||||
|
||||
void source_destroy(source_t source)
|
||||
{
|
||||
if (source) {
|
||||
da_free(source->filters);
|
||||
da_erase_item(source->obs->sources, &source);
|
||||
|
||||
source->callbacks.destroy(source->data);
|
||||
dstr_free(&source->settings);
|
||||
bfree(source);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t source_get_output_flags(source_t source)
|
||||
{
|
||||
return source->callbacks.get_output_flags(source->data);
|
||||
}
|
||||
|
||||
bool source_hasconfig(source_t source)
|
||||
{
|
||||
return source->callbacks.config != NULL;
|
||||
}
|
||||
|
||||
void source_config(source_t source, void *parent)
|
||||
{
|
||||
if (source->callbacks.config)
|
||||
source->callbacks.config(source->data, parent);
|
||||
}
|
||||
|
||||
void source_activate(source_t source)
|
||||
{
|
||||
if (source->callbacks.activate)
|
||||
source->callbacks.activate(source->data);
|
||||
}
|
||||
|
||||
void source_deactivate(source_t source)
|
||||
{
|
||||
if (source->callbacks.deactivate)
|
||||
source->callbacks.deactivate(source->data);
|
||||
}
|
||||
|
||||
void source_video_tick(source_t source, float seconds)
|
||||
{
|
||||
if (source->callbacks.video_tick)
|
||||
source->callbacks.video_tick(source->data, seconds);
|
||||
}
|
||||
|
||||
void source_video_render(source_t source)
|
||||
{
|
||||
if (source->callbacks.video_render) {
|
||||
if (source->filters.num && !source->rendering_filter) {
|
||||
source->rendering_filter = true;
|
||||
source_video_render(source->filters.array[0]);
|
||||
source->rendering_filter = false;
|
||||
} else {
|
||||
source->callbacks.video_render(source->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int source_getwidth(source_t source)
|
||||
{
|
||||
if (source->callbacks.getwidth)
|
||||
return source->callbacks.getwidth(source->data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int source_getheight(source_t source)
|
||||
{
|
||||
if (source->callbacks.getheight)
|
||||
return source->callbacks.getheight(source->data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t source_getparam(source_t source, const char *param, void *buf,
|
||||
size_t buf_size)
|
||||
{
|
||||
if (source->callbacks.getparam)
|
||||
return source->callbacks.getparam(source->data, param, buf,
|
||||
buf_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void source_setparam(source_t source, const char *param, const void *data,
|
||||
size_t size)
|
||||
{
|
||||
if (source->callbacks.setparam)
|
||||
source->callbacks.setparam(source->data, param, data, size);
|
||||
}
|
||||
|
||||
bool source_enum_children(source_t source, size_t idx, source_t *child)
|
||||
{
|
||||
if (source->callbacks.enum_children)
|
||||
return source->callbacks.enum_children(source, idx, child);
|
||||
return false;
|
||||
}
|
||||
|
||||
source_t filter_gettarget(source_t filter)
|
||||
{
|
||||
return filter->filter_target;
|
||||
}
|
||||
|
||||
void source_filter_add(source_t source, source_t filter)
|
||||
{
|
||||
if (da_find(source->filters, &filter, 0) != -1) {
|
||||
blog(LOG_WARNING, "Tried to add a filter that was already "
|
||||
"present on the source");
|
||||
return;
|
||||
}
|
||||
|
||||
if (source->filters.num) {
|
||||
source_t *back = da_end(source->filters);
|
||||
(*back)->filter_target = filter;
|
||||
}
|
||||
|
||||
da_push_back(source->filters, &filter);
|
||||
filter->filter_target = source;
|
||||
}
|
||||
|
||||
void source_filter_remove(source_t source, source_t filter)
|
||||
{
|
||||
size_t idx = da_find(source->filters, &filter, 0);
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
if (idx > 0) {
|
||||
source_t prev = source->filters.array[idx-1];
|
||||
prev->filter_target = filter->filter_target;
|
||||
}
|
||||
|
||||
da_erase(source->filters, idx);
|
||||
filter->filter_target = NULL;
|
||||
}
|
||||
|
||||
void source_filter_setorder(source_t source, source_t filter,
|
||||
enum order_movement movement)
|
||||
{
|
||||
size_t idx = da_find(source->filters, &filter, 0);
|
||||
size_t i;
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
if (movement == ORDER_MOVE_UP) {
|
||||
if (idx == source->filters.num-1)
|
||||
return;
|
||||
da_move_item(source->filters, idx, idx+1);
|
||||
|
||||
} else if (movement == ORDER_MOVE_DOWN) {
|
||||
if (idx == 0)
|
||||
return;
|
||||
da_move_item(source->filters, idx, idx-1);
|
||||
|
||||
} else if (movement == ORDER_MOVE_TOP) {
|
||||
if (idx == source->filters.num-1)
|
||||
return;
|
||||
da_move_item(source->filters, idx, source->filters.num-1);
|
||||
|
||||
} else if (movement == ORDER_MOVE_BOTTOM) {
|
||||
if (idx == 0)
|
||||
return;
|
||||
da_move_item(source->filters, idx, 0);
|
||||
}
|
||||
|
||||
/* reorder filter targets */
|
||||
for (i = 0; i < source->filters.num; i++) {
|
||||
source_t next_filter = (i == source->filters.num-1) ?
|
||||
source : source->filters.array[idx+1];
|
||||
source->filters.array[i]->filter_target = next_filter;
|
||||
}
|
||||
}
|
||||
|
||||
const char *source_get_settings(source_t source)
|
||||
{
|
||||
return source->settings.array;
|
||||
}
|
||||
|
||||
void source_save_settings(source_t source, const char *settings)
|
||||
{
|
||||
dstr_copy(&source->settings, settings);
|
||||
}
|
||||
|
||||
void source_output_video(source_t source, struct video_frame *frame)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
void source_output_audio(source_t source, struct audio_data *audio)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
|
@ -0,0 +1,214 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef SOURCE_H
|
||||
#define SOURCE_H
|
||||
|
||||
#include "util/c99defs.h"
|
||||
#include "util/darray.h"
|
||||
#include "util/dstr.h"
|
||||
#include "media-io/media-io.h"
|
||||
|
||||
/*
|
||||
* ===========================================
|
||||
* Sources
|
||||
* ===========================================
|
||||
*
|
||||
* A source is literally a "source" of audio and/or video.
|
||||
*
|
||||
* A module with sources needs to export these functions:
|
||||
* + enum_[type]
|
||||
*
|
||||
* Each individual source is then exported by it's name. For example, a
|
||||
* source named "mysource" would have the following exports:
|
||||
* + mysource_create
|
||||
* + mysource_destroy
|
||||
* + mysource_getflags
|
||||
*
|
||||
* [and optionally]
|
||||
* + mysource_update
|
||||
* + mysource_config
|
||||
* + mysource_video_tick
|
||||
* + mysource_video_render
|
||||
* + mysource_getparam
|
||||
* + mysource_setparam
|
||||
*
|
||||
* ===========================================
|
||||
* Primary Exports
|
||||
* ===========================================
|
||||
* const bool enum_[type](size_t idx, const char **name);
|
||||
* idx: index of the source.
|
||||
* type: pointer to variable that receives the type of the source
|
||||
* Return value: false when no more available.
|
||||
*
|
||||
* ===========================================
|
||||
* Source Exports
|
||||
* ===========================================
|
||||
* void *[name]_create(const char *settings, source_t source);
|
||||
* Creates a source.
|
||||
*
|
||||
* settings: Settings of the source.
|
||||
* source: pointer to main source
|
||||
* Return value: Internal source pointer, or NULL if failed.
|
||||
*
|
||||
* ---------------------------------------------------------
|
||||
* void [name]_destroy(void *data);
|
||||
* Destroys the source.
|
||||
*
|
||||
* ---------------------------------------------------------
|
||||
* uint32_t [name]_getflags(void *data);
|
||||
* Returns a combination of one of the following values:
|
||||
* + SOURCE_VIDEO: source has video
|
||||
* + SOURCE_AUDIO: source has audio
|
||||
* + SOURCE_ASYNC: video is sent asynchronously via RAM
|
||||
*
|
||||
* ---------------------------------------------------------
|
||||
* int [name]_getwidth(void *data);
|
||||
* Returns the width of a source, or -1 for maximum width. If you render
|
||||
* video, this is required.
|
||||
*
|
||||
* ---------------------------------------------------------
|
||||
* int [name]_getheight(void *data);
|
||||
* Returns the height of a source, or -1 for maximum height. If you
|
||||
* render video, this is required.
|
||||
*
|
||||
* ===========================================
|
||||
* Optional Source Exports
|
||||
* ===========================================
|
||||
* void [name]_update(void *data, const char *settings)
|
||||
* Updates the source's settings
|
||||
*
|
||||
* settings: New settings of the source
|
||||
*
|
||||
* ---------------------------------------------------------
|
||||
* void [name]_config(void *data, void *parent);
|
||||
* Called to configure the source.
|
||||
*
|
||||
* parent: Parent window pointer
|
||||
*
|
||||
* ---------------------------------------------------------
|
||||
* void [name]_video_activate(void *data);
|
||||
* Called when the source is being displayed.
|
||||
*
|
||||
* ---------------------------------------------------------
|
||||
* void [name]_video_deactivate(void *data);
|
||||
* Called when the source is no longer being displayed.
|
||||
*
|
||||
* ---------------------------------------------------------
|
||||
* void [name]_video_tick(void *data, float seconds);
|
||||
* Called each video frame with the time taken between the last and
|
||||
* current frame, in seconds.
|
||||
*
|
||||
* ---------------------------------------------------------
|
||||
* void [name]_video_render(void *data);
|
||||
* Called to render the source.
|
||||
*
|
||||
* ---------------------------------------------------------
|
||||
* void [name]_getparam(void *data, const char *param, void *buf,
|
||||
* size_t buf_size);
|
||||
* Gets a source parameter value.
|
||||
*
|
||||
* param: Name of parameter.
|
||||
* Return value: Value of parameter.
|
||||
*
|
||||
* ---------------------------------------------------------
|
||||
* void [name]_setparam(void *data, const char *param, const void *buf,
|
||||
* size_t size);
|
||||
* Sets a source parameter value.
|
||||
*
|
||||
* param: Name of parameter.
|
||||
* val: Value of parameter to set.
|
||||
*
|
||||
* ---------------------------------------------------------
|
||||
* bool [name]_enum_children(void *data, size_t idx, source_t *child);
|
||||
* Enumerates child sources, if any.
|
||||
*
|
||||
* idx: Child source index.
|
||||
* child: Pointer to variable that receives child source.
|
||||
* Return value: true if sources remaining, otherwise false.
|
||||
*
|
||||
* ---------------------------------------------------------
|
||||
* void [name]_filter_video(void *data, struct video_frame *frame);
|
||||
* Filters audio data. Used with audio filters.
|
||||
*
|
||||
* frame: Video frame data.
|
||||
*
|
||||
* ---------------------------------------------------------
|
||||
* void [name]_filter_audio(void *data, struct audio_data *audio);
|
||||
* Filters video data. Used with async video data.
|
||||
*
|
||||
* audio: Audio data.
|
||||
*/
|
||||
|
||||
struct obs_source;
|
||||
|
||||
struct source_info {
|
||||
const char *name;
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
/* required implementations */
|
||||
|
||||
void *(*create)(const char *settings, struct obs_source *source);
|
||||
void (*destroy)(void *data);
|
||||
|
||||
uint32_t (*get_output_flags)(void *data);
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
/* optional implementations */
|
||||
|
||||
bool (*config)(void *data, void *parent);
|
||||
|
||||
void (*activate)(void *data);
|
||||
void (*deactivate)(void *data);
|
||||
|
||||
void (*video_tick)(void *data, float seconds);
|
||||
void (*video_render)(void *data);
|
||||
int (*getwidth)(void *data);
|
||||
int (*getheight)(void *data);
|
||||
|
||||
size_t (*getparam)(void *data, const char *param, void *data_out,
|
||||
size_t buf_size);
|
||||
void (*setparam)(void *data, const char *param, const void *data_in,
|
||||
size_t size);
|
||||
|
||||
bool (*enum_children)(void *data, size_t idx, source_t *child);
|
||||
|
||||
void (*filter_video)(void *data, struct video_frame *frame);
|
||||
void (*filter_audio)(void *data, struct audio_data *audio);
|
||||
};
|
||||
|
||||
struct obs_source {
|
||||
struct obs_data *obs;
|
||||
void *data;
|
||||
struct source_info callbacks;
|
||||
struct dstr settings;
|
||||
bool rendering_filter;
|
||||
|
||||
struct obs_source *filter_target;
|
||||
DARRAY(struct obs_source*) filters;
|
||||
};
|
||||
|
||||
extern bool get_source_info(void *module, const char *module_name,
|
||||
const char *source_name, struct source_info *info);
|
||||
|
||||
extern void source_init(obs_t obs, struct obs_source *source);
|
||||
|
||||
EXPORT void source_activate(source_t source);
|
||||
EXPORT void source_deactivate(source_t source);
|
||||
EXPORT void source_video_tick(source_t source, float seconds);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,126 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "obs.h"
|
||||
#include "obs-data.h"
|
||||
#include "graphics/vec4.h"
|
||||
|
||||
static void tick_sources(obs_t obs, uint64_t cur_time, uint64_t *last_time)
|
||||
{
|
||||
size_t i;
|
||||
uint64_t delta_time;
|
||||
float seconds;
|
||||
|
||||
if (!last_time)
|
||||
*last_time = cur_time - video_getframetime(obs->video);
|
||||
delta_time = cur_time - *last_time;
|
||||
seconds = (float)((double)delta_time / 1000000000.0);
|
||||
|
||||
for (i = 0; i < obs->sources.num; i++)
|
||||
source_video_tick(obs->sources.array[i], seconds);
|
||||
|
||||
*last_time = cur_time;
|
||||
}
|
||||
|
||||
static inline void render_displays(obs_t obs)
|
||||
{
|
||||
size_t i;
|
||||
struct vec4 clear_color;
|
||||
vec4_set(&clear_color, 0.3f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
//gs_enable_depthtest(false);
|
||||
|
||||
gs_ortho(0.0f, (float)obs->output_width,
|
||||
0.0f, (float)obs->output_height,
|
||||
-100.0f, 100.0f);
|
||||
|
||||
for (i = 0; i < obs->displays.num; i++) {
|
||||
display_t display = obs->displays.array[i];
|
||||
|
||||
gs_load_swapchain(display->swap);
|
||||
|
||||
gs_beginscene();
|
||||
gs_setviewport(0, 0, gs_getwidth(), gs_getheight());
|
||||
|
||||
if (display->source)
|
||||
source_video_render(display->source);
|
||||
|
||||
gs_endscene();
|
||||
gs_present();
|
||||
}
|
||||
|
||||
gs_load_swapchain(NULL);
|
||||
|
||||
gs_beginscene();
|
||||
gs_clear(GS_CLEAR_COLOR|GS_CLEAR_DEPTH|GS_CLEAR_STENCIL,
|
||||
&clear_color, 1.0f, 0);
|
||||
|
||||
gs_setviewport(0, 0, gs_getwidth(), gs_getheight());
|
||||
|
||||
if (obs->primary_source)
|
||||
source_video_render(obs->primary_source);
|
||||
|
||||
gs_endscene();
|
||||
gs_present();
|
||||
}
|
||||
|
||||
static bool swap_frame(obs_t obs, uint64_t timestamp)
|
||||
{
|
||||
stagesurf_t last_surface = obs->copy_surfaces[obs->cur_texture];
|
||||
stagesurf_t surface;
|
||||
struct video_frame frame;
|
||||
|
||||
if (obs->copy_mapped) {
|
||||
stagesurface_unmap(last_surface);
|
||||
obs->copy_mapped = false;
|
||||
}
|
||||
|
||||
obs->textures_copied[obs->cur_texture] = true;
|
||||
gs_stage_texture(last_surface, NULL);
|
||||
|
||||
if (++obs->cur_texture == NUM_TEXTURES)
|
||||
obs->cur_texture = 0;
|
||||
|
||||
if (obs->textures_copied[obs->cur_texture]) {
|
||||
surface = obs->copy_surfaces[obs->cur_texture];
|
||||
obs->copy_mapped = stagesurface_map(surface, &frame.data,
|
||||
&frame.row_size);
|
||||
|
||||
if (obs->copy_mapped) {
|
||||
frame.timestamp = timestamp;
|
||||
video_output_frame(obs->video, &frame);
|
||||
}
|
||||
}
|
||||
|
||||
return obs->copy_mapped;
|
||||
}
|
||||
|
||||
void *obs_video_thread(void *param)
|
||||
{
|
||||
struct obs_data *obs = param;
|
||||
uint64_t last_time = 0;
|
||||
|
||||
while (video_output_wait(obs->video)) {
|
||||
uint64_t cur_time = video_gettime(obs->video);
|
||||
|
||||
tick_sources(obs, cur_time, &last_time);
|
||||
render_displays(obs);
|
||||
swap_frame(obs, cur_time);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,242 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "obs.h"
|
||||
#include "obs-data.h"
|
||||
#include "obs-module.h"
|
||||
|
||||
static bool obs_init_graphics(struct obs_data *obs, const char *graphics_module,
|
||||
struct gs_init_data *graphics_data, struct video_info *vi)
|
||||
{
|
||||
int errorcode;
|
||||
size_t i;
|
||||
|
||||
errorcode = gs_create(&obs->graphics, graphics_module, graphics_data);
|
||||
if (errorcode != GS_SUCCESS) {
|
||||
if (errorcode == GS_ERROR_MODULENOTFOUND)
|
||||
blog(LOG_ERROR, "Could not find graphics module '%s'",
|
||||
graphics_module);
|
||||
return false;
|
||||
}
|
||||
|
||||
gs_setcontext(obs->graphics);
|
||||
|
||||
for (i = 0; i < NUM_TEXTURES; i++) {
|
||||
obs->copy_surfaces[i] = gs_create_stagesurface(vi->width,
|
||||
vi->height, graphics_data->format);
|
||||
if (!obs->copy_surfaces[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool obs_init_media(struct obs_data *obs,
|
||||
struct video_info *vi, struct audio_info *ai)
|
||||
{
|
||||
obs->media = media_open();
|
||||
if (!obs->media)
|
||||
return false;
|
||||
|
||||
if (!obs_reset_video(obs, vi))
|
||||
return false;
|
||||
if (!obs_reset_audio(obs, ai))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool obs_init_threading(struct obs_data *obs)
|
||||
{
|
||||
if (pthread_mutex_init(&obs->source_mutex, NULL) != 0)
|
||||
return false;
|
||||
if (pthread_create(&obs->video_thread, NULL, obs_video_thread,
|
||||
obs) != 0)
|
||||
return false;
|
||||
|
||||
obs->thread_initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static pthread_mutex_t pthread_init_val = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
obs_t obs_create(const char *graphics_module,
|
||||
struct gs_init_data *graphics_data,
|
||||
struct video_info *vi, struct audio_info *ai)
|
||||
{
|
||||
struct obs_data *obs = bmalloc(sizeof(struct obs_data));
|
||||
|
||||
memset(obs, 0, sizeof(struct obs_data));
|
||||
obs->source_mutex = pthread_init_val;
|
||||
|
||||
if (!obs_init_graphics(obs, graphics_module, graphics_data, vi))
|
||||
goto error;
|
||||
if (!obs_init_media(obs, vi, ai))
|
||||
goto error;
|
||||
if (!obs_init_threading(obs))
|
||||
goto error;
|
||||
|
||||
return obs;
|
||||
|
||||
error:
|
||||
obs_destroy(obs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void obs_free_graphics(obs_t obs)
|
||||
{
|
||||
size_t i;
|
||||
if (!obs->graphics)
|
||||
return;
|
||||
|
||||
if (obs->copy_mapped)
|
||||
stagesurface_unmap(obs->copy_surfaces[obs->cur_texture]);
|
||||
|
||||
for (i = 0; i < NUM_TEXTURES; i++)
|
||||
stagesurface_destroy(obs->copy_surfaces[i]);
|
||||
|
||||
gs_setcontext(NULL);
|
||||
gs_destroy(obs->graphics);
|
||||
}
|
||||
|
||||
static inline void obs_free_media(obs_t obs)
|
||||
{
|
||||
video_output_close(obs->video);
|
||||
audio_output_close(obs->audio);
|
||||
media_close(obs->media);
|
||||
}
|
||||
|
||||
static inline void obs_free_threading(obs_t obs)
|
||||
{
|
||||
void *thread_ret;
|
||||
video_output_stop(obs->video);
|
||||
if (obs->thread_initialized)
|
||||
pthread_join(obs->video_thread, &thread_ret);
|
||||
pthread_mutex_destroy(&obs->source_mutex);
|
||||
}
|
||||
|
||||
void obs_destroy(obs_t obs)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!obs)
|
||||
return;
|
||||
|
||||
for (i = 0; i < obs->displays.num; i++)
|
||||
display_destroy(obs->displays.array[i]);
|
||||
|
||||
da_free(obs->input_types);
|
||||
da_free(obs->filter_types);
|
||||
da_free(obs->transition_types);
|
||||
da_free(obs->output_types);
|
||||
/*da_free(obs->services);*/
|
||||
|
||||
da_free(obs->displays);
|
||||
da_free(obs->sources);
|
||||
|
||||
obs_free_threading(obs);
|
||||
obs_free_media(obs);
|
||||
obs_free_graphics(obs);
|
||||
|
||||
for (i = 0; i < obs->modules.num; i++)
|
||||
free_module(obs->modules.array+i);
|
||||
da_free(obs->modules);
|
||||
|
||||
bfree(obs);
|
||||
}
|
||||
|
||||
bool obs_reset_video(obs_t obs, struct video_info *vi)
|
||||
{
|
||||
int errorcode;
|
||||
|
||||
if (obs->video) {
|
||||
video_output_close(obs->video);
|
||||
obs->video = NULL;
|
||||
}
|
||||
|
||||
obs->output_width = vi->width;
|
||||
obs->output_height = vi->height;
|
||||
|
||||
errorcode = video_output_open(&obs->video, obs->media, vi);
|
||||
if (errorcode == VIDEO_OUTPUT_SUCCESS)
|
||||
return true;
|
||||
else if (errorcode == VIDEO_OUTPUT_INVALIDPARAM)
|
||||
blog(LOG_ERROR, "Invalid video parameters specified");
|
||||
else
|
||||
blog(LOG_ERROR, "Could not open video output");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool obs_reset_audio(obs_t obs, struct audio_info *ai)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool obs_enum_inputs(obs_t obs, size_t idx, const char **name)
|
||||
{
|
||||
if (idx >= obs->input_types.num)
|
||||
return false;
|
||||
*name = obs->input_types.array[idx].name;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool obs_enum_filters(obs_t obs, size_t idx, const char **name)
|
||||
{
|
||||
if (idx >= obs->filter_types.num)
|
||||
return false;
|
||||
*name = obs->filter_types.array[idx].name;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool obs_enum_transitions(obs_t obs, size_t idx, const char **name)
|
||||
{
|
||||
if (idx >= obs->transition_types.num)
|
||||
return false;
|
||||
*name = obs->transition_types.array[idx].name;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool obs_enum_outputs(obs_t obs, size_t idx, const char **name)
|
||||
{
|
||||
if (idx >= obs->output_types.num)
|
||||
return false;
|
||||
*name = obs->output_types.array[idx].name;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
graphics_t obs_graphics(obs_t obs)
|
||||
{
|
||||
return obs->graphics;
|
||||
}
|
||||
|
||||
media_t obs_media(obs_t obs)
|
||||
{
|
||||
return obs->media;
|
||||
}
|
||||
|
||||
source_t obs_get_primary_source(obs_t obs)
|
||||
{
|
||||
return obs->primary_source;
|
||||
}
|
||||
|
||||
void obs_set_primary_source(obs_t obs, source_t source)
|
||||
{
|
||||
obs->primary_source = source;
|
||||
}
|
|
@ -0,0 +1,304 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef LIBOBS_H
|
||||
#define LIBOBS_H
|
||||
|
||||
#include "util/c99defs.h"
|
||||
#include "graphics/graphics.h"
|
||||
#include "graphics/vec2.h"
|
||||
#include "media-io/media-io.h"
|
||||
|
||||
#include "obs-defs.h"
|
||||
|
||||
/*
|
||||
* Main libobs header used by applications.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum source_type {
|
||||
SOURCE_INPUT,
|
||||
SOURCE_FILTER,
|
||||
SOURCE_TRANSITION,
|
||||
SOURCE_SCENE
|
||||
};
|
||||
|
||||
enum order_movement {
|
||||
ORDER_MOVE_UP,
|
||||
ORDER_MOVE_DOWN,
|
||||
ORDER_MOVE_TOP,
|
||||
ORDER_MOVE_BOTTOM
|
||||
};
|
||||
|
||||
/* opaque types */
|
||||
struct obs_data;
|
||||
struct obs_display;
|
||||
struct obs_source;
|
||||
struct obs_scene;
|
||||
struct obs_scene_item;
|
||||
struct obs_output;
|
||||
|
||||
typedef struct obs_data *obs_t;
|
||||
typedef struct obs_display *display_t;
|
||||
typedef struct obs_source *source_t;
|
||||
typedef struct obs_scene *scene_t;
|
||||
typedef struct obs_scene_item *sceneitem_t;
|
||||
typedef struct obs_output *output_t;
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* OBS context */
|
||||
|
||||
/**
|
||||
* Creates the OBS context.
|
||||
*
|
||||
* Using the graphics module specified, creates an OBS context and sets the
|
||||
* primary video/audio output information.
|
||||
*/
|
||||
EXPORT obs_t obs_create(const char *graphics_module,
|
||||
struct gs_init_data *graphics_data,
|
||||
struct video_info *vi, struct audio_info *ai);
|
||||
EXPORT void obs_destroy(obs_t obs);
|
||||
|
||||
/**
|
||||
* Sets base video ouput base resolution/fps/format
|
||||
*
|
||||
* NOTE: Cannot reset base video if currently streaming/recording.
|
||||
*/
|
||||
EXPORT bool obs_reset_video(obs_t obs, struct video_info *vi);
|
||||
/**
|
||||
* Sets base audio output format/channels/samples/etc
|
||||
*
|
||||
* NOTE: Cannot reset base audio if currently streaming/recording.
|
||||
*/
|
||||
EXPORT bool obs_reset_audio(obs_t obs, struct audio_info *ai);
|
||||
|
||||
/**
|
||||
* Loads a plugin module
|
||||
*
|
||||
* A plugin module contains exports for inputs/fitlers/transitions/outputs.
|
||||
* See obs-source.h and obs-output.h for more information on the exports to
|
||||
* use.
|
||||
*/
|
||||
EXPORT int obs_load_module(obs_t obs, const char *path);
|
||||
|
||||
/**
|
||||
* Enumerates all available inputs.
|
||||
*
|
||||
* Inputs are general source inputs (such as capture sources, device sources,
|
||||
* etc).
|
||||
*/
|
||||
EXPORT bool obs_enum_inputs(obs_t obs, size_t idx, const char **name);
|
||||
/**
|
||||
* Enumerates all available filters.
|
||||
*
|
||||
* Filters are sources that are used to modify the video/audio output of
|
||||
* other sources.
|
||||
*/
|
||||
EXPORT bool obs_enum_filters(obs_t obs, size_t idx, const char **name);
|
||||
/**
|
||||
* Enumerates all available transitions.
|
||||
*
|
||||
* Transitions are sources used to transition between two or more other
|
||||
* sources.
|
||||
*/
|
||||
EXPORT bool obs_enum_transitions(obs_t obs, size_t idx,
|
||||
const char **name);
|
||||
/**
|
||||
* Enumerates all available ouputs.
|
||||
*
|
||||
* Outputs handle color space conversion, encoding, and output to file or
|
||||
* streams.
|
||||
*/
|
||||
EXPORT bool obs_enum_outputs(obs_t obs, size_t idx, const char **name);
|
||||
|
||||
/** Gets the graphics context for this OBS context */
|
||||
EXPORT graphics_t obs_graphics(obs_t obs);
|
||||
/** Get the media context for this OBS context (used for outputs) */
|
||||
EXPORT media_t obs_media(obs_t obs);
|
||||
|
||||
/**
|
||||
* Sets/gets the primary output source.
|
||||
*
|
||||
* The primary source is the source that's broadcasted/saved.
|
||||
*/
|
||||
EXPORT void obs_set_primary_source(obs_t obs, source_t source);
|
||||
EXPORT source_t obs_get_primary_source(obs_t obs);
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Display context */
|
||||
|
||||
/**
|
||||
* Creates an extra display context.
|
||||
*
|
||||
* An extra display can be used for things like separate previews,
|
||||
* viewing sources independently, and other things. Creates a new swap chain
|
||||
* linked to a specific window to display a source.
|
||||
*/
|
||||
EXPORT display_t display_create(obs_t obs, struct gs_init_data *graphics_data);
|
||||
EXPORT void display_destroy(display_t display);
|
||||
/** Sets the source to be used for a display context. */
|
||||
EXPORT void display_setsource(display_t display, source_t source);
|
||||
EXPORT source_t display_getsource(display_t display);
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Sources */
|
||||
|
||||
/**
|
||||
* Creates a source of the specified type with the specified settings.
|
||||
*
|
||||
* The "source" context is used for anything related to presenting
|
||||
* or modifying video/audio.
|
||||
*/
|
||||
EXPORT source_t source_create(obs_t obs, enum source_type type,
|
||||
const char *name, const char *settings);
|
||||
EXPORT void source_destroy(source_t source);
|
||||
/**
|
||||
* Retrieves flags that specify what type of data the source presents/modifies.
|
||||
*
|
||||
* SOURCE_VIDEO if it presents/modifies video_frame
|
||||
* SOURCE_ASYNC if the video is asynchronous.
|
||||
* SOURCE_AUDIO if it presents/modifies audio (always async)
|
||||
*/
|
||||
EXPORT uint32_t source_get_output_flags(source_t source);
|
||||
/** Specifies whether the source can be configured */
|
||||
EXPORT bool source_hasconfig(source_t source);
|
||||
/** Opens a configuration panel and attaches it to the parent window */
|
||||
EXPORT void source_config(source_t source, void *parent);
|
||||
/** Renders a video source. */
|
||||
EXPORT void source_video_render(source_t source);
|
||||
/** Gets the width of a source (if it has video) */
|
||||
EXPORT int source_getwidth(source_t source);
|
||||
/** Gets the height of a source (if it has video) */
|
||||
EXPORT int source_getheight(source_t source);
|
||||
/**
|
||||
* Gets a custom parameter from the source.
|
||||
*
|
||||
* Used for efficiently modifying source properties in real time.
|
||||
*/
|
||||
EXPORT size_t source_getparam(source_t source, const char *param, void *buf,
|
||||
size_t buf_size);
|
||||
/**
|
||||
* Sets a custom parameter for the source.
|
||||
*
|
||||
* Used for efficiently modifying source properties in real time.
|
||||
*/
|
||||
EXPORT void source_setparam(source_t source, const char *param,
|
||||
const void *data, size_t size);
|
||||
/**
|
||||
* Enumerates child sources this source has
|
||||
*/
|
||||
EXPORT bool source_enum_children(source_t source, size_t idx,
|
||||
source_t *child);
|
||||
|
||||
/** If the source is a filter, returns the target source of the filter */
|
||||
EXPORT source_t filter_gettarget(source_t filter);
|
||||
/** Adds a filter to the source (which is used whenever the source is used) */
|
||||
EXPORT void source_filter_add(source_t source, source_t filter);
|
||||
/** Removes a filter from the source */
|
||||
EXPORT void source_filter_remove(source_t source, source_t filter);
|
||||
/** Modifies the order of a specific filter */
|
||||
EXPORT void source_filter_setorder(source_t source, source_t filter,
|
||||
enum order_movement movement);
|
||||
|
||||
/** Gets the settings string for a source */
|
||||
EXPORT const char *source_get_settings(source_t source);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Functions used by sources */
|
||||
|
||||
/** Saves the settings string for a source */
|
||||
EXPORT void source_save_settings(source_t source, const char *settings);
|
||||
/** Outputs asynchronous video data */
|
||||
EXPORT void source_output_video(source_t source, struct video_frame *frame);
|
||||
/** Outputs audio data (always asynchronous) */
|
||||
EXPORT void source_output_audio(source_t source, struct audio_data *audio);
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Scenes */
|
||||
|
||||
/**
|
||||
* Creates a scene.
|
||||
*
|
||||
* A scene is a source which is a container of other sources with specific
|
||||
* display oriantations. Scenes can also be used like any other source.
|
||||
*/
|
||||
EXPORT scene_t scene_create(obs_t obs);
|
||||
EXPORT void scene_destroy(scene_t scene);
|
||||
/** Gets the scene's source context */
|
||||
EXPORT source_t scene_source(scene_t scene);
|
||||
|
||||
/** Adds/creates a new scene item for a source */
|
||||
EXPORT sceneitem_t scene_add(scene_t scene, source_t source);
|
||||
|
||||
/** Removes/destroys a scene item */
|
||||
EXPORT void sceneitem_destroy(sceneitem_t item);
|
||||
|
||||
/* Functions for gettings/setting specific oriantation of a scene item */
|
||||
EXPORT void sceneitem_setpos(sceneitem_t item, const struct vec2 *pos);
|
||||
EXPORT void sceneitem_setrot(sceneitem_t item, float rot);
|
||||
EXPORT void sceneitem_setorigin(sceneitem_t item, const struct vec2 *origin);
|
||||
EXPORT void sceneitem_setscale(sceneitem_t item, const struct vec2 *scale);
|
||||
EXPORT void sceneitem_setorder(sceneitem_t item, enum order_movement movement);
|
||||
|
||||
EXPORT void sceneitem_getpos(sceneitem_t item, struct vec2 *pos);
|
||||
EXPORT float sceneitem_getrot(sceneitem_t item);
|
||||
EXPORT void sceneitem_getorigin(sceneitem_t item, struct vec2 *center);
|
||||
EXPORT void sceneitem_getscale(sceneitem_t item, struct vec2 *scale);
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Outputs */
|
||||
|
||||
/**
|
||||
* Creates an output.
|
||||
*
|
||||
* Outputs allow outputting to file, outputting to network, outputting to
|
||||
* directshow, or other custom outputs.
|
||||
*/
|
||||
EXPORT output_t output_create(obs_t obs, const char *name,
|
||||
const char *settings);
|
||||
EXPORT void output_destroy(output_t output);
|
||||
/** Starts the output. */
|
||||
EXPORT void output_start(output_t output);
|
||||
/** Stops the output. */
|
||||
EXPORT void output_stop(output_t output);
|
||||
/** Specifies whether the output can be configured */
|
||||
EXPORT bool output_canconfig(output_t output);
|
||||
/** Opens a configuration panel with the specified parent window */
|
||||
EXPORT void output_config(output_t output, void *parent);
|
||||
/** Specifies whether the output can be paused */
|
||||
EXPORT bool output_canpause(output_t output);
|
||||
/** Pauses the output (if the functionality is allowed by the output */
|
||||
EXPORT void output_pause(output_t output);
|
||||
|
||||
/* Gets the current output settings string */
|
||||
EXPORT const char *output_get_settings(output_t output);
|
||||
|
||||
/* Saves the output settings string, typically used only by outputs */
|
||||
EXPORT void output_save_settings(output_t output, const char *settings);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,104 @@
|
|||
/******************************************************************************
|
||||
Copyright (c) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "c99defs.h"
|
||||
#include "base.h"
|
||||
|
||||
static enum log_type log_output_level = LOG_WARNING;
|
||||
static int crashing = 0;
|
||||
|
||||
static void def_log_handler(enum log_type type, const char *format,
|
||||
va_list args)
|
||||
{
|
||||
char out[4096];
|
||||
vsnprintf(out, sizeof(out), format, args);
|
||||
|
||||
if (type >= log_output_level) {
|
||||
switch (type) {
|
||||
case LOG_DEBUG:
|
||||
printf("debug: %s\n", out);
|
||||
break;
|
||||
|
||||
case LOG_INFO:
|
||||
printf("info: %s\n", out);
|
||||
break;
|
||||
|
||||
case LOG_WARNING:
|
||||
fprintf(stderr, "warning: %s\n", out);
|
||||
break;
|
||||
|
||||
case LOG_ERROR:
|
||||
fprintf(stderr, "error: %s\n", out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void def_crash_handler(const char *format, va_list args)
|
||||
{
|
||||
vfprintf(stderr, format, args);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void (*log_handler)(enum log_type, const char *, va_list) =
|
||||
def_log_handler;
|
||||
static void (*crash_handler)(const char *, va_list) = def_crash_handler;
|
||||
|
||||
void base_set_log_handler(
|
||||
void (*handler)(enum log_type, const char *, va_list))
|
||||
{
|
||||
log_handler = handler;
|
||||
}
|
||||
|
||||
void base_set_crash_handler(void (*handler)(const char *, va_list))
|
||||
{
|
||||
crash_handler = handler;
|
||||
}
|
||||
|
||||
void bcrash(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (crashing) {
|
||||
fputs("Crashed in the crash handler", stderr);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
crashing = 1;
|
||||
va_start(args, format);
|
||||
crash_handler(format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void blog(enum log_type type, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
log_handler(type, format, args);
|
||||
va_end(args);
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/******************************************************************************
|
||||
Copyright (c) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 BASE_H
|
||||
#define BASE_H
|
||||
|
||||
#include <wctype.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "c99defs.h"
|
||||
|
||||
/*
|
||||
* Just contains logging/crash related stuff
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum log_type {
|
||||
LOG_DEBUG,
|
||||
LOG_INFO,
|
||||
LOG_WARNING,
|
||||
LOG_ERROR
|
||||
};
|
||||
|
||||
EXPORT void base_set_log_handler(
|
||||
void (*handler)(enum log_type, const char *, va_list));
|
||||
EXPORT void base_set_crash_handler(void (*handler)(const char *, va_list));
|
||||
|
||||
EXPORT void blog(enum log_type type, const char *format, ...);
|
||||
EXPORT void bcrash(const char *format, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,131 @@
|
|||
/******************************************************************************
|
||||
Copyright (c) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 <malloc.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "base.h"
|
||||
#include "bmem.h"
|
||||
|
||||
static void *a_malloc(size_t size, size_t align)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return _aligned_malloc(size, align);
|
||||
#elif defined (__posix__)
|
||||
void *ptr;
|
||||
if (posix_memalign(&ptr, align, size) != 0)
|
||||
return NULL;
|
||||
|
||||
return ptr;
|
||||
#else
|
||||
#error unknown OS
|
||||
#endif
|
||||
}
|
||||
|
||||
static void a_free(void *ptr)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
_aligned_free(ptr);
|
||||
#elif defined (__posix__)
|
||||
free(ptr);
|
||||
#else
|
||||
#error unknown OS
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct base_allocator alloc = {malloc, realloc, free, a_malloc, a_free};
|
||||
static size_t num_allocs = 0;
|
||||
|
||||
void base_set_allocator(struct base_allocator *defs)
|
||||
{
|
||||
memcpy(&alloc, defs, sizeof(struct base_allocator));
|
||||
}
|
||||
|
||||
void *bmalloc(size_t size)
|
||||
{
|
||||
void *ptr = alloc.malloc(size);
|
||||
if (!ptr && !size)
|
||||
ptr = alloc.malloc(1);
|
||||
if (!ptr)
|
||||
bcrash("Out of memory while trying to allocate %lu bytes",
|
||||
(unsigned long)size);
|
||||
|
||||
num_allocs++;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *brealloc(void *ptr, size_t size)
|
||||
{
|
||||
if (!ptr)
|
||||
num_allocs++;
|
||||
|
||||
ptr = alloc.realloc(ptr, size);
|
||||
if (!ptr && !size)
|
||||
ptr = alloc.realloc(ptr, 1);
|
||||
if (!ptr)
|
||||
bcrash("Out of memory while trying to allocate %lu bytes",
|
||||
(unsigned long)size);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void bfree(void *ptr)
|
||||
{
|
||||
if (ptr)
|
||||
num_allocs--;
|
||||
alloc.free(ptr);
|
||||
}
|
||||
|
||||
void *baligned_malloc(size_t size, size_t align)
|
||||
{
|
||||
void *ptr = alloc.aligned_malloc(size, align);
|
||||
if (!ptr && !size)
|
||||
ptr = alloc.aligned_malloc(1, align);
|
||||
if (!ptr)
|
||||
bcrash("Out of memory while trying to allocate %lu bytes",
|
||||
(unsigned long)size);
|
||||
|
||||
num_allocs++;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void baligned_free(void *ptr)
|
||||
{
|
||||
if (ptr)
|
||||
num_allocs--;
|
||||
alloc.aligned_free(ptr);
|
||||
}
|
||||
|
||||
size_t bnum_allocs(void)
|
||||
{
|
||||
return num_allocs;
|
||||
}
|
||||
|
||||
void *bmemdup(const void *ptr, size_t size)
|
||||
{
|
||||
void *out = bmalloc(size);
|
||||
if (size)
|
||||
memcpy(out, ptr, size);
|
||||
|
||||
return out;
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
/******************************************************************************
|
||||
Copyright (c) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 BALLOC_H
|
||||
#define BALLOC_H
|
||||
|
||||
#include "c99defs.h"
|
||||
#include "base.h"
|
||||
#include <wchar.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct base_allocator {
|
||||
void *(*malloc)(size_t);
|
||||
void *(*realloc)(void *, size_t);
|
||||
void (*free)(void *);
|
||||
|
||||
void *(*aligned_malloc)(size_t, size_t);
|
||||
void (*aligned_free)(void *);
|
||||
};
|
||||
|
||||
EXPORT void base_set_allocator(struct base_allocator *defs);
|
||||
|
||||
EXPORT void *bmalloc(size_t size);
|
||||
EXPORT void *brealloc(void *ptr, size_t size);
|
||||
EXPORT void bfree(void *ptr);
|
||||
|
||||
EXPORT void *baligned_malloc(size_t size, size_t align);
|
||||
EXPORT void baligned_free(void *ptr);
|
||||
|
||||
EXPORT size_t bnum_allocs(void);
|
||||
|
||||
EXPORT void *bmemdup(const void *ptr, size_t size);
|
||||
|
||||
static inline char *bstrdup_n(const char *str, size_t n)
|
||||
{
|
||||
char *dup;
|
||||
if (!str || !*str)
|
||||
return NULL;
|
||||
|
||||
dup = (char*)bmemdup(str, n+1);
|
||||
dup[n] = 0;
|
||||
|
||||
return dup;
|
||||
}
|
||||
|
||||
static inline wchar_t *bwstrdup_n(const wchar_t *str, size_t n)
|
||||
{
|
||||
wchar_t *dup;
|
||||
if (!str || !*str)
|
||||
return NULL;
|
||||
|
||||
dup = (wchar_t*)bmemdup(str, (n+1) * sizeof(wchar_t));
|
||||
dup[n] = 0;
|
||||
|
||||
return dup;
|
||||
}
|
||||
|
||||
static inline char *bstrdup(const char *str)
|
||||
{
|
||||
if (!str)
|
||||
return NULL;
|
||||
|
||||
return bstrdup_n(str, strlen(str));
|
||||
}
|
||||
|
||||
static inline wchar_t *bwstrdup(const wchar_t *str)
|
||||
{
|
||||
if (!str)
|
||||
return NULL;
|
||||
|
||||
return bwstrdup_n(str, wcslen(str));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,75 @@
|
|||
/******************************************************************************
|
||||
Copyright (c) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 C99DEFS_H
|
||||
#define C99DEFS_H
|
||||
|
||||
/*
|
||||
* Contains hacks for getting some C99 stuff working in VC, things like
|
||||
* bool, inline, stdint
|
||||
*
|
||||
* TODO: Check for VC2013, because it actually supports this C99 stuff.
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define EXPORT extern __declspec(dllexport)
|
||||
#else
|
||||
#define EXPORT extern
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#pragma warning (disable : 4996)
|
||||
|
||||
#ifndef __cplusplus
|
||||
#define inline __inline
|
||||
#endif
|
||||
|
||||
#include "vc/stdint.h"
|
||||
#include "vc/stdbool.h"
|
||||
|
||||
#ifndef __off_t_defined
|
||||
#define __off_t_defined
|
||||
#if _FILE_OFFSET_BITS == 64
|
||||
typedef long long off_t;
|
||||
#else
|
||||
typedef long off_t;
|
||||
#endif
|
||||
typedef int64_t off64_t;
|
||||
#endif /* __off_t_defined */
|
||||
|
||||
#ifdef _WIN64
|
||||
typedef long long ssize_t;
|
||||
#else
|
||||
typedef long ssize_t;
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,216 @@
|
|||
/******************************************************************************
|
||||
Copyright (c) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 CF_LEXER_H
|
||||
#define CF_LEXER_H
|
||||
|
||||
#include "lexer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
EXPORT char *cf_literal_to_str(const char *literal, size_t count);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/*
|
||||
* A C-family lexer token is defined as:
|
||||
* 1.) A generic 'name' token. (abc123_def456)
|
||||
* 2.) A numeric sequence (usually starting with a number)
|
||||
* 3.) A sequence of generic whitespace defined as spaces and tabs
|
||||
* 4.) A newline
|
||||
* 5.) A string or character sequence (surrounded by single or double quotes)
|
||||
* 6.) A single character of a type not specified above
|
||||
*/
|
||||
enum cf_token_type {
|
||||
CFTOKEN_NONE,
|
||||
CFTOKEN_NAME,
|
||||
CFTOKEN_NUM,
|
||||
CFTOKEN_SPACETAB,
|
||||
CFTOKEN_NEWLINE,
|
||||
CFTOKEN_STRING,
|
||||
CFTOKEN_OTHER
|
||||
};
|
||||
|
||||
struct cf_token {
|
||||
const struct cf_lexer *lex;
|
||||
struct strref str;
|
||||
struct strref unmerged_str;
|
||||
enum cf_token_type type;
|
||||
};
|
||||
|
||||
static inline void cf_token_clear(struct cf_token *t)
|
||||
{
|
||||
memset(t, 0, sizeof(struct cf_token));
|
||||
}
|
||||
|
||||
static inline void cf_token_copy(struct cf_token *dst,
|
||||
const struct cf_token *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(struct cf_token));
|
||||
}
|
||||
|
||||
static inline void cf_token_add(struct cf_token *dst,
|
||||
const struct cf_token *add)
|
||||
{
|
||||
strref_add(&dst->str, &add->str);
|
||||
strref_add(&dst->unmerged_str, &add->unmerged_str);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/*
|
||||
* The c-family lexer is a base lexer for generating a list of string
|
||||
* reference tokens to be used with c-style languages.
|
||||
*
|
||||
* This base lexer is meant to be used as a stepping stone for an actual
|
||||
* language lexer/parser.
|
||||
*
|
||||
* It reformats the text in the two following ways:
|
||||
* 1.) Spliced lines (escaped newlines) are merged
|
||||
* 2.) All comments are converted to a single space
|
||||
*/
|
||||
|
||||
struct cf_lexer {
|
||||
char *file;
|
||||
struct lexer base_lexer;
|
||||
char *reformatted, *write_offset;
|
||||
DARRAY(struct cf_token) tokens;
|
||||
bool unexpected_eof; /* unexpected multi-line comment eof */
|
||||
};
|
||||
|
||||
EXPORT void cf_lexer_init(struct cf_lexer *lex);
|
||||
EXPORT void cf_lexer_free(struct cf_lexer *lex);
|
||||
|
||||
static inline struct cf_token *cf_lexer_gettokens(struct cf_lexer *lex)
|
||||
{
|
||||
return lex->tokens.array;
|
||||
}
|
||||
|
||||
EXPORT bool cf_lexer_lex(struct cf_lexer *lex, const char *str,
|
||||
const char *file);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* c-family preprocessor definition */
|
||||
|
||||
struct cf_def {
|
||||
struct cf_token name;
|
||||
DARRAY(struct cf_token) params;
|
||||
DARRAY(struct cf_token) tokens;
|
||||
bool macro;
|
||||
};
|
||||
|
||||
static inline void cf_def_init(struct cf_def *cfd)
|
||||
{
|
||||
cf_token_clear(&cfd->name);
|
||||
da_init(cfd->params);
|
||||
da_init(cfd->tokens);
|
||||
cfd->macro = false;
|
||||
}
|
||||
|
||||
static inline void cf_def_addparam(struct cf_def *cfd, struct cf_token *param)
|
||||
{
|
||||
da_push_back(cfd->params, param);
|
||||
}
|
||||
|
||||
static inline void cf_def_addtoken(struct cf_def *cfd, struct cf_token *token)
|
||||
{
|
||||
da_push_back(cfd->tokens, token);
|
||||
}
|
||||
|
||||
static inline struct cf_token *cf_def_getparam(const struct cf_def *cfd,
|
||||
size_t idx)
|
||||
{
|
||||
return cfd->params.array+idx;
|
||||
}
|
||||
|
||||
static inline void cf_def_free(struct cf_def *cfd)
|
||||
{
|
||||
cf_token_clear(&cfd->name);
|
||||
da_free(cfd->params);
|
||||
da_free(cfd->tokens);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/*
|
||||
* C-family preprocessor
|
||||
*
|
||||
* This preprocessor allows for standard c-style preprocessor directives
|
||||
* to be applied to source text, such as:
|
||||
*
|
||||
* + #include
|
||||
* + #define/#undef
|
||||
* + #ifdef/#ifndef/#if/#elif/#else/#endif
|
||||
*
|
||||
* Still left to implement (TODO):
|
||||
* + #if/#elif
|
||||
* + "defined" preprocessor keyword
|
||||
* + system includes
|
||||
* + variadic macros
|
||||
* + custom callbacks (for things like pragma)
|
||||
* + option to exclude features such as #import, variadic macros, and other
|
||||
* features for certain language implementations
|
||||
* + macro parameter string operator #
|
||||
* + macro parameter token concactenation operator ##
|
||||
* + predefined macros
|
||||
* + restricted macros
|
||||
*/
|
||||
|
||||
struct cf_preprocessor {
|
||||
struct cf_lexer *lex;
|
||||
struct error_data *ed;
|
||||
DARRAY(struct cf_def) defines;
|
||||
DARRAY(char*) sys_include_dirs;
|
||||
DARRAY(struct cf_lexer) dependencies;
|
||||
DARRAY(struct cf_token) tokens;
|
||||
bool ignore_state;
|
||||
};
|
||||
|
||||
EXPORT void cf_preprocessor_init(struct cf_preprocessor *pp);
|
||||
EXPORT void cf_preprocessor_free(struct cf_preprocessor *pp);
|
||||
|
||||
EXPORT bool cf_preprocess(struct cf_preprocessor *pp, struct cf_lexer *lex,
|
||||
struct error_data *ed);
|
||||
|
||||
static inline void cf_preprocessor_add_sys_include_dir(
|
||||
struct cf_preprocessor *pp, const char *include_dir)
|
||||
{
|
||||
if (include_dir)
|
||||
da_push_back(pp->sys_include_dirs, bstrdup(include_dir));
|
||||
}
|
||||
|
||||
EXPORT void cf_preprocessor_add_def(struct cf_preprocessor *pp,
|
||||
struct cf_def *def);
|
||||
EXPORT void cf_preprocessor_remove_def(struct cf_preprocessor *pp,
|
||||
const char *def_name);
|
||||
|
||||
static inline struct cf_token *cf_preprocessor_gettokens(
|
||||
struct cf_preprocessor *pp)
|
||||
{
|
||||
return pp->tokens.array;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,72 @@
|
|||
/******************************************************************************
|
||||
Copyright (c) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 "cf-parser.h"
|
||||
|
||||
void cf_adderror(struct cf_parser *p, const char *error, int level,
|
||||
const char *val1, const char *val2, const char *val3)
|
||||
{
|
||||
uint32_t row, col;
|
||||
lexer_getstroffset(&p->cur_token->lex->base_lexer,
|
||||
p->cur_token->unmerged_str.array,
|
||||
&row, &col);
|
||||
|
||||
if (!val1 && !val2 && !val3) {
|
||||
error_data_add(&p->error_list, p->cur_token->lex->file,
|
||||
row, col, error, level);
|
||||
} else {
|
||||
struct dstr formatted;
|
||||
dstr_init(&formatted);
|
||||
dstr_safe_printf(&formatted, error, val1, val2, val3, NULL);
|
||||
|
||||
error_data_add(&p->error_list, p->cur_token->lex->file,
|
||||
row, col, formatted.array, level);
|
||||
|
||||
dstr_free(&formatted);
|
||||
}
|
||||
}
|
||||
|
||||
bool pass_pair(struct cf_parser *p, char in, char out)
|
||||
{
|
||||
if (p->cur_token->type != CFTOKEN_OTHER ||
|
||||
*p->cur_token->str.array != in)
|
||||
return p->cur_token->type != CFTOKEN_NONE;
|
||||
|
||||
p->cur_token++;
|
||||
|
||||
while (p->cur_token->type != CFTOKEN_NONE) {
|
||||
if (*p->cur_token->str.array == in) {
|
||||
if (!pass_pair(p, in, out))
|
||||
break;
|
||||
continue;
|
||||
|
||||
} else if(*p->cur_token->str.array == out) {
|
||||
p->cur_token++;
|
||||
return true;
|
||||
}
|
||||
|
||||
p->cur_token++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
|
@ -0,0 +1,284 @@
|
|||
/******************************************************************************
|
||||
Copyright (c) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 CF_PARSER_H
|
||||
#define CF_PARSER_H
|
||||
|
||||
#include "cf-lexer.h"
|
||||
|
||||
/*
|
||||
* C-family parser
|
||||
*
|
||||
* Handles preprocessing/lexing/errors when parsing a file, and provides a
|
||||
* set of parsing functions to be able to go through all the resulting tokens
|
||||
* more easily.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define PARSE_SUCCESS 0
|
||||
#define PARSE_CONTINUE -1
|
||||
#define PARSE_BREAK -2
|
||||
#define PARSE_UNEXPECTED_CONTINUE -3
|
||||
#define PARSE_UNEXPECTED_BREAK -4
|
||||
#define PARSE_EOF -5
|
||||
|
||||
struct cf_parser {
|
||||
struct cf_lexer lex;
|
||||
struct cf_preprocessor pp;
|
||||
struct error_data error_list;
|
||||
|
||||
struct cf_token *cur_token;
|
||||
};
|
||||
|
||||
static inline void cf_parser_init(struct cf_parser *parser)
|
||||
{
|
||||
cf_lexer_init(&parser->lex);
|
||||
cf_preprocessor_init(&parser->pp);
|
||||
error_data_init(&parser->error_list);
|
||||
|
||||
parser->cur_token = NULL;
|
||||
}
|
||||
|
||||
static inline void cf_parser_free(struct cf_parser *parser)
|
||||
{
|
||||
cf_lexer_free(&parser->lex);
|
||||
cf_preprocessor_free(&parser->pp);
|
||||
error_data_free(&parser->error_list);
|
||||
|
||||
parser->cur_token = NULL;
|
||||
}
|
||||
|
||||
static inline bool cf_parser_parse(struct cf_parser *parser,
|
||||
const char *str, const char *file)
|
||||
{
|
||||
if (!cf_lexer_lex(&parser->lex, str, file))
|
||||
return false;
|
||||
|
||||
if (!cf_preprocess(&parser->pp, &parser->lex, &parser->error_list))
|
||||
return false;
|
||||
|
||||
parser->cur_token = cf_preprocessor_gettokens(&parser->pp);
|
||||
return true;
|
||||
}
|
||||
|
||||
EXPORT void cf_adderror(struct cf_parser *parser, const char *error,
|
||||
int level, const char *val1, const char *val2,
|
||||
const char *val3);
|
||||
|
||||
static inline void cf_adderror_expecting(struct cf_parser *p,
|
||||
const char *expected)
|
||||
{
|
||||
cf_adderror(p, "Expected $1", LEVEL_ERROR, expected, NULL, NULL);
|
||||
}
|
||||
|
||||
static inline void cf_adderror_unexpected_eof(struct cf_parser *p)
|
||||
{
|
||||
cf_adderror(p, "Unexpected end of file", LEVEL_ERROR,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static inline void cf_adderror_syntax_error(struct cf_parser *p)
|
||||
{
|
||||
cf_adderror(p, "Syntax error", LEVEL_ERROR,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static inline bool next_token(struct cf_parser *p)
|
||||
{
|
||||
if (p->cur_token->type != CFTOKEN_SPACETAB &&
|
||||
p->cur_token->type != CFTOKEN_NEWLINE &&
|
||||
p->cur_token->type != CFTOKEN_NONE)
|
||||
p->cur_token++;
|
||||
|
||||
while (p->cur_token->type == CFTOKEN_SPACETAB ||
|
||||
p->cur_token->type == CFTOKEN_NEWLINE)
|
||||
p->cur_token++;
|
||||
|
||||
return p->cur_token->type != CFTOKEN_NONE;
|
||||
}
|
||||
|
||||
static inline bool next_valid_token(struct cf_parser *p)
|
||||
{
|
||||
if (!next_token(p)) {
|
||||
cf_adderror_unexpected_eof(p);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
EXPORT bool pass_pair(struct cf_parser *p, char in, char out);
|
||||
|
||||
static inline bool go_to_token(struct cf_parser *p,
|
||||
const char *str1, const char *str2)
|
||||
{
|
||||
while (next_token(p)) {
|
||||
if (strref_cmp(&p->cur_token->str, str1) == 0) {
|
||||
return true;
|
||||
} else if (str2 && strref_cmp(&p->cur_token->str, str2) == 0) {
|
||||
return true;
|
||||
} else if (*p->cur_token->str.array == '{') {
|
||||
if (!pass_pair(p, '{', '}'))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool go_to_valid_token(struct cf_parser *p,
|
||||
const char *str1, const char *str2)
|
||||
{
|
||||
if (!go_to_token(p, str1, str2)) {
|
||||
cf_adderror_unexpected_eof(p);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool go_to_token_type(struct cf_parser *p,
|
||||
enum cf_token_type type)
|
||||
{
|
||||
while (p->cur_token->type != CFTOKEN_NONE &&
|
||||
p->cur_token->type != CFTOKEN_NEWLINE)
|
||||
p->cur_token++;
|
||||
|
||||
return p->cur_token->type != CFTOKEN_NONE;
|
||||
}
|
||||
|
||||
static inline int next_token_should_be(struct cf_parser *p,
|
||||
const char *str, const char *goto1, const char *goto2)
|
||||
{
|
||||
if (!next_token(p)) {
|
||||
cf_adderror_unexpected_eof(p);
|
||||
return PARSE_EOF;
|
||||
} else if (strref_cmp(&p->cur_token->str, str) == 0) {
|
||||
return PARSE_SUCCESS;
|
||||
}
|
||||
|
||||
if (goto1)
|
||||
go_to_token(p, goto1, goto2);
|
||||
|
||||
cf_adderror_expecting(p, str);
|
||||
return PARSE_CONTINUE;
|
||||
}
|
||||
|
||||
static inline bool peek_token(struct cf_parser *p, struct cf_token *peek)
|
||||
{
|
||||
struct cf_token *cur_token = p->cur_token;
|
||||
bool success = next_token(p);
|
||||
|
||||
*peek = *p->cur_token;
|
||||
p->cur_token = cur_token;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static inline bool peek_valid_token(struct cf_parser *p,
|
||||
struct cf_token *peek)
|
||||
{
|
||||
bool success = peek_token(p, peek);
|
||||
if (!success)
|
||||
cf_adderror_unexpected_eof(p);
|
||||
return success;
|
||||
}
|
||||
|
||||
static inline bool token_is(struct cf_parser *p, const char *val)
|
||||
{
|
||||
return strref_cmp(&p->cur_token->str, val) == 0;
|
||||
}
|
||||
|
||||
static inline int token_is_type(struct cf_parser *p,
|
||||
enum cf_token_type type, const char *type_expected,
|
||||
const char *goto_token)
|
||||
{
|
||||
if (p->cur_token->type != type) {
|
||||
cf_adderror_expecting(p, type_expected);
|
||||
if (goto_token) {
|
||||
if (!go_to_valid_token(p, goto_token, NULL))
|
||||
return PARSE_EOF;
|
||||
}
|
||||
return PARSE_CONTINUE;
|
||||
}
|
||||
|
||||
return PARSE_SUCCESS;
|
||||
}
|
||||
|
||||
static inline void copy_token(struct cf_parser *p, char **dst)
|
||||
{
|
||||
*dst = bstrdup_n(p->cur_token->str.array, p->cur_token->str.len);
|
||||
}
|
||||
|
||||
static inline int get_name(struct cf_parser *p, char **dst,
|
||||
const char *name, const char *goto_token)
|
||||
{
|
||||
int errcode;
|
||||
|
||||
errcode = token_is_type(p, CFTOKEN_NAME, name, goto_token);
|
||||
if (errcode != PARSE_SUCCESS)
|
||||
return errcode;
|
||||
|
||||
*dst = bstrdup_n(p->cur_token->str.array, p->cur_token->str.len);
|
||||
return PARSE_SUCCESS;
|
||||
}
|
||||
|
||||
static inline int next_name(struct cf_parser *p, char **dst,
|
||||
const char *name, const char *goto_token)
|
||||
{
|
||||
if (!next_valid_token(p))
|
||||
return PARSE_EOF;
|
||||
|
||||
return get_name(p, dst, name, goto_token);
|
||||
}
|
||||
|
||||
static inline int get_name_ref(struct cf_parser *p, struct strref *dst,
|
||||
const char *name, const char *goto_token)
|
||||
{
|
||||
int errcode;
|
||||
|
||||
errcode = token_is_type(p, CFTOKEN_NAME, name, goto_token);
|
||||
if (errcode != PARSE_SUCCESS)
|
||||
return errcode;
|
||||
|
||||
strref_copy(dst, &p->cur_token->str);
|
||||
return PARSE_SUCCESS;
|
||||
}
|
||||
|
||||
static inline int next_name_ref(struct cf_parser *p, struct strref *dst,
|
||||
const char *name, const char *goto_token)
|
||||
{
|
||||
if (!next_valid_token(p))
|
||||
return PARSE_EOF;
|
||||
|
||||
return get_name_ref(p, dst, name, goto_token);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,528 @@
|
|||
/******************************************************************************
|
||||
Copyright (c) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 <wchar.h>
|
||||
#include "config-file.h"
|
||||
#include "platform.h"
|
||||
#include "base.h"
|
||||
#include "bmem.h"
|
||||
#include "darray.h"
|
||||
#include "lexer.h"
|
||||
#include "dstr.h"
|
||||
|
||||
struct config_item {
|
||||
char *name;
|
||||
char *value;
|
||||
};
|
||||
|
||||
static inline void config_item_free(struct config_item *item)
|
||||
{
|
||||
bfree(item->name);
|
||||
bfree(item->value);
|
||||
}
|
||||
|
||||
struct config_section {
|
||||
char *name;
|
||||
struct darray items; /* struct config_item */
|
||||
};
|
||||
|
||||
static inline void config_section_free(struct config_section *section)
|
||||
{
|
||||
struct config_item *items = section->items.array;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < section->items.num; i++)
|
||||
config_item_free(items+i);
|
||||
|
||||
darray_free(§ion->items);
|
||||
bfree(section->name);
|
||||
}
|
||||
|
||||
struct config_data {
|
||||
char *file;
|
||||
struct darray sections; /* struct config_section */
|
||||
struct darray defaults; /* struct config_section */
|
||||
};
|
||||
|
||||
config_t config_create(const char *file)
|
||||
{
|
||||
struct config_data *config;
|
||||
FILE *f;
|
||||
|
||||
f = os_fopen(file, "wb");
|
||||
if (!f)
|
||||
return NULL;
|
||||
fclose(f);
|
||||
|
||||
config = bmalloc(sizeof(struct config_data));
|
||||
memset(config, 0, sizeof(struct config_data));
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
static inline void remove_ref_whitespace(struct strref *ref)
|
||||
{
|
||||
if (ref->array) {
|
||||
while (is_whitespace(*ref->array)) {
|
||||
ref->array++;
|
||||
ref->len--;
|
||||
}
|
||||
|
||||
while (ref->len && is_whitespace(ref->array[ref->len-1]))
|
||||
ref->len--;
|
||||
}
|
||||
}
|
||||
|
||||
static bool config_parse_string(struct lexer *lex, struct strref *ref,
|
||||
char end)
|
||||
{
|
||||
bool success = end != 0;
|
||||
struct base_token token;
|
||||
base_token_clear(&token);
|
||||
|
||||
while (lexer_getbasetoken(lex, &token, false)) {
|
||||
if (end) {
|
||||
if (*token.text.array == end) {
|
||||
success = true;
|
||||
break;
|
||||
} else if (is_newline(*token.text.array)) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (is_newline(*token.text.array)) {
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
strref_add(ref, &token.text);
|
||||
}
|
||||
|
||||
remove_ref_whitespace(ref);
|
||||
return success;
|
||||
}
|
||||
|
||||
static void config_add_item(struct darray *items, struct strref *name,
|
||||
struct strref *value)
|
||||
{
|
||||
struct config_item item;
|
||||
item.name = bstrdup_n(name->array, name->len);
|
||||
item.value = bstrdup_n(value->array, value->len);
|
||||
darray_push_back(sizeof(struct config_item), items, &item);
|
||||
}
|
||||
|
||||
static void config_parse_section(struct config_section *section,
|
||||
struct lexer *lex)
|
||||
{
|
||||
struct base_token token;
|
||||
|
||||
while (lexer_getbasetoken(lex, &token, false)) {
|
||||
struct strref name, value;
|
||||
|
||||
while (token.type == BASETOKEN_WHITESPACE) {
|
||||
if (!lexer_getbasetoken(lex, &token, false))
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.type == BASETOKEN_OTHER) {
|
||||
if (*token.text.array == '#') {
|
||||
do {
|
||||
if (!lexer_getbasetoken(lex, &token,
|
||||
false))
|
||||
return;
|
||||
} while (!is_newline(*token.text.array));
|
||||
|
||||
continue;
|
||||
} else if (*token.text.array == '[') {
|
||||
lex->offset--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
strref_copy(&name, &token.text);
|
||||
if (!config_parse_string(lex, &name, '='))
|
||||
continue;
|
||||
|
||||
strref_clear(&value);
|
||||
config_parse_string(lex, &value, 0);
|
||||
|
||||
config_add_item(§ion->items, &name, &value);
|
||||
}
|
||||
}
|
||||
|
||||
static int config_parse(struct darray *sections, const char *file)
|
||||
{
|
||||
char *file_data;
|
||||
struct lexer lex;
|
||||
struct base_token token;
|
||||
struct strref section_name;
|
||||
FILE *f;
|
||||
|
||||
f = os_fopen(file, "rb");
|
||||
if (!f)
|
||||
return CONFIG_FILENOTFOUND;
|
||||
|
||||
os_fread_utf8(f, &file_data);
|
||||
fclose(f);
|
||||
|
||||
if (!file_data)
|
||||
return CONFIG_SUCCESS;
|
||||
|
||||
lexer_init(&lex);
|
||||
lexer_start_move(&lex, file_data);
|
||||
|
||||
base_token_clear(&token);
|
||||
|
||||
while (lexer_getbasetoken(&lex, &token, false)) {
|
||||
struct config_section *section;
|
||||
|
||||
while (token.type == BASETOKEN_WHITESPACE) {
|
||||
if (!lexer_getbasetoken(&lex, &token, false))
|
||||
goto complete;
|
||||
}
|
||||
|
||||
if (*token.text.array != '[') {
|
||||
while (!is_newline(*token.text.array)) {
|
||||
if (!lexer_getbasetoken(&lex, &token, false))
|
||||
goto complete;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
strref_clear(§ion_name);
|
||||
config_parse_string(&lex, §ion_name, ']');
|
||||
if (!section_name.len)
|
||||
break;
|
||||
|
||||
section = darray_push_back_new(sizeof(struct config_section),
|
||||
sections);
|
||||
section->name = bstrdup_n(section_name.array,
|
||||
section_name.len);
|
||||
config_parse_section(section, &lex);
|
||||
}
|
||||
|
||||
complete:
|
||||
lexer_free(&lex);
|
||||
return CONFIG_SUCCESS;
|
||||
}
|
||||
|
||||
int config_open(config_t *config, const char *file, bool always_open)
|
||||
{
|
||||
int errorcode;
|
||||
|
||||
if (!config)
|
||||
return CONFIG_ERROR;
|
||||
|
||||
*config = bmalloc(sizeof(struct config_data));
|
||||
memset(*config, 0, sizeof(struct config_data));
|
||||
errorcode = config_parse(&(*config)->sections, file);
|
||||
|
||||
if (errorcode != CONFIG_SUCCESS) {
|
||||
config_close(*config);
|
||||
*config = NULL;
|
||||
}
|
||||
|
||||
return errorcode;
|
||||
}
|
||||
|
||||
int config_open_defaults(config_t config, const char *file)
|
||||
{
|
||||
if (!config)
|
||||
return CONFIG_ERROR;
|
||||
|
||||
return config_parse(&config->defaults, file);
|
||||
}
|
||||
|
||||
int config_save(config_t config)
|
||||
{
|
||||
FILE *f;
|
||||
struct dstr str;
|
||||
size_t i, j;
|
||||
|
||||
if (!config)
|
||||
return CONFIG_ERROR;
|
||||
|
||||
dstr_init(&str);
|
||||
|
||||
f = os_fopen(config->file, "wb");
|
||||
if (!f)
|
||||
return CONFIG_FILENOTFOUND;
|
||||
|
||||
for (i = 0; i < config->sections.num; i++) {
|
||||
struct config_section *section = darray_item(
|
||||
sizeof(struct config_section),
|
||||
&config->sections, i);
|
||||
|
||||
if (i) dstr_cat(&str, "\n");
|
||||
|
||||
dstr_cat(&str, "{");
|
||||
dstr_cat(&str, section->name);
|
||||
dstr_cat(&str, "]\n");
|
||||
|
||||
for (j = 0; j < section->items.num; j++) {
|
||||
struct config_item *item = darray_item(
|
||||
sizeof(struct config_item),
|
||||
§ion->items, i);
|
||||
|
||||
dstr_cat(&str, item->name);
|
||||
dstr_cat(&str, "=");
|
||||
dstr_cat(&str, item->value);
|
||||
dstr_cat(&str, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
fwrite("\xEF\xBB\xBF", 1, 3, f);
|
||||
#endif
|
||||
fwrite(str.array, 1, str.len, f);
|
||||
fclose(f);
|
||||
|
||||
dstr_free(&str);
|
||||
|
||||
return CONFIG_SUCCESS;
|
||||
}
|
||||
|
||||
void config_close(config_t config)
|
||||
{
|
||||
struct config_section *defaults, *sections;
|
||||
size_t i;
|
||||
|
||||
if (!config) return;
|
||||
|
||||
defaults = config->defaults.array;
|
||||
sections = config->sections.array;
|
||||
|
||||
for (i = 0; i < config->defaults.num; i++)
|
||||
config_section_free(defaults+i);
|
||||
for (i = 0; i < config->sections.num; i++)
|
||||
config_section_free(sections+i);
|
||||
|
||||
darray_free(&config->defaults);
|
||||
darray_free(&config->sections);
|
||||
bfree(config->file);
|
||||
bfree(config);
|
||||
}
|
||||
|
||||
static struct config_item *config_find_item(struct darray *sections,
|
||||
const char *section, const char *name)
|
||||
{
|
||||
size_t i, j;
|
||||
|
||||
for (i = 0; i < sections->num; i++) {
|
||||
struct config_section *sec = darray_item(
|
||||
sizeof(struct config_section), sections, i);
|
||||
|
||||
if (astrcmpi(sec->name, section) != 0) {
|
||||
for (j = 0; j < sec->items.num; j++) {
|
||||
struct config_item *item = darray_item(
|
||||
sizeof(struct config_item),
|
||||
&sec->items, i);
|
||||
|
||||
if (astrcmpi(item->name, name) == 0)
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void config_set_item(struct darray *sections, const char *section,
|
||||
const char *name, char *value)
|
||||
{
|
||||
struct config_section *sec = NULL;
|
||||
struct config_section *array = sections->array;
|
||||
struct config_item *item;
|
||||
size_t i, j;
|
||||
|
||||
for (i = 0; i < sections->num; i++) {
|
||||
struct config_section *cur_sec = array+i;
|
||||
struct config_item *items = cur_sec->items.array;
|
||||
|
||||
if (astrcmpi(cur_sec->name, section) == 0) {
|
||||
for (j = 0; j < cur_sec->items.num; j++) {
|
||||
item = items+i;
|
||||
|
||||
if (astrcmpi(item->name, name) == 0) {
|
||||
bfree(item->value);
|
||||
item->value = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
sec = cur_sec;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sec) {
|
||||
sec = darray_push_back_new(sizeof(struct config_section),
|
||||
sections);
|
||||
sec->name = bstrdup(section);
|
||||
}
|
||||
|
||||
item = darray_push_back_new(sizeof(struct config_item), &sec->items);
|
||||
item->name = bstrdup(name);
|
||||
item->value = value;
|
||||
}
|
||||
|
||||
void config_set_string(config_t config, const char *section,
|
||||
const char *name, const char *value)
|
||||
{
|
||||
if (!value)
|
||||
value = "";
|
||||
config_set_item(&config->sections, section, name, bstrdup(value));
|
||||
}
|
||||
|
||||
void config_set_int(config_t config, const char *section,
|
||||
const char *name, int64_t value)
|
||||
{
|
||||
struct dstr str;
|
||||
dstr_init(&str);
|
||||
dstr_printf(&str, "%dll", value);
|
||||
config_set_item(&config->sections, section, name, str.array);
|
||||
}
|
||||
|
||||
void config_set_uint(config_t config, const char *section,
|
||||
const char *name, uint64_t value)
|
||||
{
|
||||
struct dstr str;
|
||||
dstr_init(&str);
|
||||
dstr_printf(&str, "%ull", value);
|
||||
config_set_item(&config->sections, section, name, str.array);
|
||||
}
|
||||
|
||||
void config_set_bool(config_t config, const char *section,
|
||||
const char *name, bool value)
|
||||
{
|
||||
char *str = bstrdup(value ? "true" : "false");
|
||||
config_set_item(&config->sections, section, name, str);
|
||||
}
|
||||
|
||||
void config_set_double(config_t config, const char *section,
|
||||
const char *name, double value)
|
||||
{
|
||||
struct dstr str;
|
||||
dstr_init(&str);
|
||||
dstr_printf(&str, "%g", value);
|
||||
config_set_item(&config->sections, section, name, str.array);
|
||||
}
|
||||
|
||||
void config_set_default_string(config_t config, const char *section,
|
||||
const char *name, const char *value)
|
||||
{
|
||||
if (!value)
|
||||
value = "";
|
||||
config_set_item(&config->defaults, section, name, bstrdup(value));
|
||||
}
|
||||
|
||||
void config_set_default_int(config_t config, const char *section,
|
||||
const char *name, int64_t value)
|
||||
{
|
||||
struct dstr str;
|
||||
dstr_init(&str);
|
||||
dstr_printf(&str, "%dll", value);
|
||||
config_set_item(&config->defaults, section, name, str.array);
|
||||
}
|
||||
|
||||
void config_set_default_uint(config_t config, const char *section,
|
||||
const char *name, uint64_t value)
|
||||
{
|
||||
struct dstr str;
|
||||
dstr_init(&str);
|
||||
dstr_printf(&str, "%ull", value);
|
||||
config_set_item(&config->defaults, section, name, str.array);
|
||||
}
|
||||
|
||||
void config_set_default_bool(config_t config, const char *section,
|
||||
const char *name, bool value)
|
||||
{
|
||||
char *str = bstrdup(value ? "true" : "false");
|
||||
config_set_item(&config->defaults, section, name, str);
|
||||
}
|
||||
|
||||
void config_set_default_double(config_t config, const char *section,
|
||||
const char *name, double value)
|
||||
{
|
||||
struct dstr str;
|
||||
dstr_init(&str);
|
||||
dstr_printf(&str, "%g", value);
|
||||
config_set_item(&config->defaults, section, name, str.array);
|
||||
}
|
||||
|
||||
const char *config_get_string(config_t config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
struct config_item *item = config_find_item(&config->sections,
|
||||
section, name);
|
||||
if (!item)
|
||||
item = config_find_item(&config->defaults, section, name);
|
||||
if (!item)
|
||||
return NULL;
|
||||
|
||||
return item->value;
|
||||
}
|
||||
|
||||
int64_t config_get_int(config_t config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const char *value = config_get_string(config, section, name);
|
||||
if (value)
|
||||
return strtoll(value, NULL, 10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t config_get_uint(config_t config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const char *value = config_get_string(config, section, name);
|
||||
if (value)
|
||||
return strtoul(value, NULL, 10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool config_get_bool(config_t config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const char *value = config_get_string(config, section, name);
|
||||
if (value)
|
||||
return astrcmpi(value, "true") == 0 ||
|
||||
strtoul(value, NULL, 10);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
double config_get_double(config_t config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const char *value = config_get_string(config, section, name);
|
||||
if (value)
|
||||
return strtod(value, NULL);
|
||||
|
||||
return 0.0;
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/******************************************************************************
|
||||
Copyright (c) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 CONFIG_FILE_H
|
||||
#define CONFIG_FILE_H
|
||||
|
||||
#include "c99defs.h"
|
||||
|
||||
/*
|
||||
* Generic ini-style config file functions
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct config_data;
|
||||
typedef struct config_data *config_t;
|
||||
|
||||
#define CONFIG_SUCCESS 0
|
||||
#define CONFIG_FILENOTFOUND -1
|
||||
#define CONFIG_ERROR -2
|
||||
|
||||
EXPORT config_t config_create(const char *file);
|
||||
EXPORT int config_open(config_t *config, const char *file, bool always_open);
|
||||
EXPORT int config_open_defaults(config_t config, const char *file);
|
||||
EXPORT int config_save(config_t config);
|
||||
EXPORT void config_close(config_t config);
|
||||
|
||||
EXPORT void config_set_string(config_t config, const char *section,
|
||||
const char *name, const char *value);
|
||||
EXPORT void config_set_int(config_t config, const char *section,
|
||||
const char *name, int64_t value);
|
||||
EXPORT void config_set_uint(config_t config, const char *section,
|
||||
const char *name, uint64_t value);
|
||||
EXPORT void config_set_bool(config_t config, const char *section,
|
||||
const char *name, bool value);
|
||||
EXPORT void config_set_double(config_t config, const char *section,
|
||||
const char *name, double value);
|
||||
|
||||
EXPORT void config_set_default_string(config_t config, const char *section,
|
||||
const char *name, const char *value);
|
||||
EXPORT void config_set_default_int(config_t config, const char *section,
|
||||
const char *name, int64_t value);
|
||||
EXPORT void config_set_default_uint(config_t config, const char *section,
|
||||
const char *name, uint64_t value);
|
||||
EXPORT void config_set_default_bool(config_t config, const char *section,
|
||||
const char *name, bool value);
|
||||
EXPORT void config_set_default_double(config_t config, const char *section,
|
||||
const char *name, double value);
|
||||
|
||||
EXPORT const char *config_get_string(config_t config, const char *section,
|
||||
const char *name);
|
||||
EXPORT int64_t config_get_int(config_t config, const char *section,
|
||||
const char *name);
|
||||
EXPORT uint64_t config_get_uint(config_t config, const char *section,
|
||||
const char *name);
|
||||
EXPORT bool config_get_bool(config_t config, const char *section,
|
||||
const char *name);
|
||||
EXPORT double config_get_double(config_t config, const char *section,
|
||||
const char *name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,545 @@
|
|||
/******************************************************************************
|
||||
Copyright (c) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 DARRAY_H
|
||||
#define DARRAY_H
|
||||
|
||||
#include "c99defs.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "bmem.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Dynamic array.
|
||||
*
|
||||
* NOTE: Not type-safe when using directly.
|
||||
* Specifying size per call with inline maximizes compiler optimizations
|
||||
*
|
||||
* See DARRAY macro at the bottom of thhe file for slightly safer usage.
|
||||
*/
|
||||
|
||||
struct darray {
|
||||
void *array;
|
||||
size_t num;
|
||||
size_t capacity;
|
||||
};
|
||||
|
||||
static inline void darray_init(struct darray *dst)
|
||||
{
|
||||
dst->array = NULL;
|
||||
dst->num = 0;
|
||||
dst->capacity = 0;
|
||||
}
|
||||
|
||||
static inline void darray_free(struct darray *dst)
|
||||
{
|
||||
baligned_free(dst->array);
|
||||
dst->array = NULL;
|
||||
dst->num = 0;
|
||||
dst->capacity = 0;
|
||||
}
|
||||
|
||||
static inline size_t darray_alloc_size(const size_t element_size,
|
||||
const struct darray *da)
|
||||
{
|
||||
return element_size*da->num;
|
||||
}
|
||||
|
||||
static inline void *darray_item(const size_t element_size,
|
||||
const struct darray *da, size_t idx)
|
||||
{
|
||||
return (void*)(((uint8_t*)da->array) + element_size*idx);
|
||||
}
|
||||
|
||||
static inline void *darray_end(const size_t element_size,
|
||||
const struct darray *da)
|
||||
{
|
||||
if (!da->num)
|
||||
return NULL;
|
||||
|
||||
return darray_item(element_size, da, da->num-1);
|
||||
}
|
||||
|
||||
static inline void darray_reserve(const size_t element_size,
|
||||
struct darray *dst, const size_t capacity)
|
||||
{
|
||||
void *ptr;
|
||||
if (capacity == 0 || capacity <= dst->num)
|
||||
return;
|
||||
|
||||
ptr = baligned_malloc(element_size*capacity, 16);
|
||||
if (dst->num)
|
||||
memcpy(ptr, dst->array, element_size*dst->num);
|
||||
if (dst->array)
|
||||
baligned_free(dst->array);
|
||||
dst->array = ptr;
|
||||
dst->capacity = capacity;
|
||||
}
|
||||
|
||||
static inline void darray_ensure_capacity(const size_t element_size,
|
||||
struct darray *dst, const size_t new_size)
|
||||
{
|
||||
size_t new_cap;
|
||||
void *ptr;
|
||||
if (new_size <= dst->capacity)
|
||||
return;
|
||||
|
||||
new_cap = (!dst->capacity) ? new_size : dst->capacity*2;
|
||||
if (new_size > new_cap)
|
||||
new_cap = new_size;
|
||||
ptr = baligned_malloc(element_size*new_cap, 16);
|
||||
if (dst->capacity)
|
||||
memcpy(ptr, dst->array, element_size*dst->capacity);
|
||||
if (dst->array)
|
||||
baligned_free(dst->array);
|
||||
dst->array = ptr;
|
||||
dst->capacity = new_cap;
|
||||
}
|
||||
|
||||
static inline void darray_resize(const size_t element_size,
|
||||
struct darray *dst, const size_t size)
|
||||
{
|
||||
int b_clear;
|
||||
size_t old_num;
|
||||
|
||||
if (size == dst->num) {
|
||||
return;
|
||||
} else if (size == 0) {
|
||||
darray_free(dst);
|
||||
return;
|
||||
}
|
||||
|
||||
b_clear = size > dst->num;
|
||||
old_num = dst->num;
|
||||
|
||||
darray_ensure_capacity(element_size, dst, size);
|
||||
dst->num = size;
|
||||
|
||||
if (b_clear)
|
||||
memset(darray_item(element_size, dst, old_num), 0,
|
||||
element_size * (dst->num-old_num));
|
||||
}
|
||||
|
||||
static inline void darray_copy(const size_t element_size, struct darray *dst,
|
||||
const struct darray *da)
|
||||
{
|
||||
assert(element_size == element_size);
|
||||
|
||||
if (da->num == 0) {
|
||||
darray_free(dst);
|
||||
} else {
|
||||
darray_resize(element_size, dst, da->num);
|
||||
memcpy(dst->array, da->array, element_size*da->num);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void darray_copy_array(const size_t element_size,
|
||||
struct darray *dst, const void *array, const size_t num)
|
||||
{
|
||||
darray_resize(element_size, dst, num);
|
||||
memcpy(dst->array, array, element_size*dst->num);
|
||||
}
|
||||
|
||||
static inline void darray_move(struct darray *dst, struct darray *src)
|
||||
{
|
||||
darray_free(dst);
|
||||
memcpy(dst, src, sizeof(struct darray));
|
||||
src->array = NULL;
|
||||
src->num = 0;
|
||||
}
|
||||
|
||||
static inline size_t darray_find(const size_t element_size,
|
||||
const struct darray *da, const void *item, const size_t idx)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
assert(idx <= da->num);
|
||||
|
||||
for (i = idx; i < da->num; i++) {
|
||||
void *compare = darray_item(element_size, da, i);
|
||||
if (memcmp(compare, item, element_size) == 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline size_t darray_push_back(const size_t element_size,
|
||||
struct darray *dst, const void *item)
|
||||
{
|
||||
darray_ensure_capacity(element_size, dst, ++dst->num);
|
||||
memcpy(darray_end(element_size, dst), item, element_size);
|
||||
|
||||
return dst->num-1;
|
||||
}
|
||||
|
||||
static inline void *darray_push_back_new(const size_t element_size,
|
||||
struct darray *dst)
|
||||
{
|
||||
void *last;
|
||||
|
||||
darray_ensure_capacity(element_size, dst, ++dst->num);
|
||||
|
||||
last = darray_end(element_size, dst);
|
||||
memset(last, 0, element_size);
|
||||
return last;
|
||||
}
|
||||
|
||||
static inline size_t darray_push_back_array(const size_t element_size,
|
||||
struct darray *dst, const void *array, const size_t num)
|
||||
{
|
||||
size_t old_num = dst->num;
|
||||
|
||||
assert(array != NULL);
|
||||
assert(num != 0);
|
||||
|
||||
darray_resize(element_size, dst, dst->num+num);
|
||||
memcpy(darray_item(element_size, dst, old_num), array,
|
||||
element_size*num);
|
||||
|
||||
return old_num;
|
||||
}
|
||||
|
||||
static inline size_t darray_push_back_darray(const size_t element_size,
|
||||
struct darray *dst, const struct darray *da)
|
||||
{
|
||||
return darray_push_back_array(element_size, dst, da->array, da->num);
|
||||
}
|
||||
|
||||
static inline void darray_insert(const size_t element_size, struct darray *dst,
|
||||
const size_t idx, const void *item)
|
||||
{
|
||||
void *new_item;
|
||||
size_t move_count;
|
||||
|
||||
assert(idx <= dst->num);
|
||||
|
||||
if (idx == dst->num) {
|
||||
darray_push_back(element_size, dst, item);
|
||||
return;
|
||||
}
|
||||
|
||||
move_count = dst->num - idx;
|
||||
darray_ensure_capacity(element_size, dst, ++dst->num);
|
||||
|
||||
new_item = darray_item(element_size, dst, idx);
|
||||
|
||||
memmove(darray_item(element_size, dst, idx+1), new_item,
|
||||
move_count*element_size);
|
||||
memcpy(new_item, item, element_size);
|
||||
}
|
||||
|
||||
static inline void *darray_insert_new(const size_t element_size,
|
||||
struct darray *dst, const size_t idx)
|
||||
{
|
||||
void *item;
|
||||
size_t move_count;
|
||||
|
||||
assert(idx <= dst->num);
|
||||
if (idx == dst->num)
|
||||
return darray_push_back_new(element_size, dst);
|
||||
|
||||
item = darray_item(element_size, dst, idx);
|
||||
|
||||
move_count = dst->num - idx;
|
||||
darray_ensure_capacity(element_size, dst, ++dst->num);
|
||||
memmove(darray_item(element_size, dst, idx+1), item,
|
||||
move_count*element_size);
|
||||
|
||||
memset(item, 0, element_size);
|
||||
return item;
|
||||
}
|
||||
|
||||
static inline void darray_insert_array(const size_t element_size,
|
||||
struct darray *dst, const size_t idx,
|
||||
const void *array, const size_t num)
|
||||
{
|
||||
size_t old_num;
|
||||
|
||||
assert(array != NULL);
|
||||
assert(num != 0);
|
||||
assert(idx < dst->num);
|
||||
|
||||
old_num = dst->num;
|
||||
darray_resize(element_size, dst, dst->num+num);
|
||||
|
||||
memmove(darray_item(element_size, dst, idx+num),
|
||||
darray_item(element_size, dst, idx),
|
||||
element_size*(old_num-idx));
|
||||
memcpy(darray_item(element_size, dst, idx), array, element_size*num);
|
||||
}
|
||||
|
||||
static inline void darray_insert_darray(const size_t element_size,
|
||||
struct darray *dst, const size_t idx, const struct darray *da)
|
||||
{
|
||||
darray_insert_array(element_size, dst, idx, da->array, da->num);
|
||||
}
|
||||
|
||||
static inline void darray_erase(const size_t element_size, struct darray *dst,
|
||||
const size_t idx)
|
||||
{
|
||||
assert(idx < dst->num);
|
||||
|
||||
if (idx >= dst->num)
|
||||
return;
|
||||
|
||||
if (!--dst->num) {
|
||||
darray_free(dst);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(darray_item(element_size, dst, idx),
|
||||
darray_item(element_size, dst, idx+1),
|
||||
element_size*(dst->num-idx));
|
||||
}
|
||||
|
||||
static inline void darray_erase_item(const size_t element_size,
|
||||
struct darray *dst, const void *item)
|
||||
{
|
||||
size_t idx = darray_find(element_size, dst, item, 0);
|
||||
if (idx != (size_t)-1)
|
||||
darray_erase(element_size, dst, idx);
|
||||
}
|
||||
|
||||
static inline void darray_erase_range(const size_t element_size,
|
||||
struct darray *dst, const size_t start, const size_t end)
|
||||
{
|
||||
size_t count, move_count;
|
||||
|
||||
assert(start <= dst->num);
|
||||
assert(end <= dst->num);
|
||||
assert(end > start);
|
||||
|
||||
count = end-start;
|
||||
if (count == 1) {
|
||||
darray_erase(element_size, dst, start);
|
||||
return;
|
||||
} else if (count == dst->num) {
|
||||
darray_free(dst);
|
||||
return;
|
||||
}
|
||||
|
||||
move_count = dst->num - end;
|
||||
if (move_count)
|
||||
memmove(darray_item(element_size, dst, start),
|
||||
darray_item(element_size, dst, end),
|
||||
move_count);
|
||||
|
||||
dst->num -= count;
|
||||
}
|
||||
|
||||
static inline void darray_pop_back(const size_t element_size,
|
||||
struct darray *dst)
|
||||
{
|
||||
assert(dst->num != 0);
|
||||
|
||||
if (dst->num)
|
||||
darray_erase(element_size, dst, dst->num-1);
|
||||
}
|
||||
|
||||
static inline void darray_join(const size_t element_size, struct darray *dst,
|
||||
struct darray *da)
|
||||
{
|
||||
assert(element_size == element_size);
|
||||
|
||||
darray_push_back_darray(element_size, dst, da);
|
||||
darray_free(da);
|
||||
}
|
||||
|
||||
static inline void darray_split(const size_t element_size, struct darray *dst1,
|
||||
struct darray *dst2, const struct darray *da, const size_t idx)
|
||||
{
|
||||
struct darray temp;
|
||||
|
||||
assert(da->num >= idx);
|
||||
assert(dst1 != dst2);
|
||||
|
||||
darray_init(&temp);
|
||||
darray_copy(element_size, &temp, da);
|
||||
|
||||
darray_free(dst1);
|
||||
darray_free(dst2);
|
||||
|
||||
if (da->num) {
|
||||
if (idx)
|
||||
darray_copy_array(element_size, dst1, temp.array,
|
||||
temp.num);
|
||||
if (idx < temp.num-1)
|
||||
darray_copy_array(element_size, dst2,
|
||||
darray_item(element_size, &temp, idx),
|
||||
temp.num-idx);
|
||||
}
|
||||
|
||||
darray_free(&temp);
|
||||
}
|
||||
|
||||
static inline void darray_move_item(const size_t element_size,
|
||||
struct darray *dst, const size_t from, const size_t to)
|
||||
{
|
||||
void *temp, *p_from, *p_to;
|
||||
|
||||
if (from == to)
|
||||
return;
|
||||
|
||||
temp = bmalloc(element_size);
|
||||
p_from = darray_item(element_size, dst, from);
|
||||
p_to = darray_item(element_size, dst, to);
|
||||
|
||||
memcpy(temp, p_from, element_size);
|
||||
|
||||
if (to < from)
|
||||
memmove(darray_item(element_size, dst, to+1), p_to,
|
||||
element_size*(from-to));
|
||||
else
|
||||
memcpy(p_from, darray_item(element_size, dst, from+1),
|
||||
element_size*(to-from));
|
||||
|
||||
memcpy(p_to, temp, element_size);
|
||||
bfree(temp);
|
||||
}
|
||||
|
||||
static inline void darray_swap(const size_t element_size,
|
||||
struct darray *dst, const size_t a, const size_t b)
|
||||
{
|
||||
void *temp, *a_ptr, *b_ptr;
|
||||
|
||||
assert(a < dst->num);
|
||||
assert(b < dst->num);
|
||||
|
||||
if (a == b)
|
||||
return;
|
||||
|
||||
temp = bmalloc(element_size);
|
||||
a_ptr = darray_item(element_size, dst, a);
|
||||
b_ptr = darray_item(element_size, dst, b);
|
||||
|
||||
memcpy(temp, a_ptr, element_size);
|
||||
memcpy(a_ptr, b_ptr, element_size);
|
||||
memcpy(b_ptr, temp, element_size);
|
||||
|
||||
bfree(temp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Defines to make dynamic arrays more type-safe.
|
||||
* Note: Still not 100% type-safe but much better than using darray directly
|
||||
* Makes it a little easier to use as well.
|
||||
*
|
||||
* I did -not- want to use a gigantic macro to generate a crapload of
|
||||
* typsafe inline functions per type. It just feels like a mess to me.
|
||||
*/
|
||||
|
||||
#define DARRAY(type) \
|
||||
union { \
|
||||
struct darray da; \
|
||||
struct { \
|
||||
type *array; \
|
||||
size_t num; \
|
||||
size_t capacity; \
|
||||
}; \
|
||||
}
|
||||
|
||||
#define da_init(v) darray_init(&v.da)
|
||||
|
||||
#define da_free(v) darray_free(&v.da)
|
||||
|
||||
#define da_alloc_size(v) (sizeof(*v.array)*v.num)
|
||||
|
||||
#define da_end(v) darray_end(sizeof(*v.array), &v.da)
|
||||
|
||||
#define da_reserve(v, capacity) \
|
||||
darray_reserve(sizeof(*v.array), &v.da, capacity)
|
||||
|
||||
#define da_resize(v, size) darray_resize(sizeof(*v.array), &v.da, size)
|
||||
|
||||
#define da_copy(dst, src) \
|
||||
darray_copy(sizeof(*dst.array), &dst.da, &src.da)
|
||||
|
||||
#define da_copy_array(dst, src_array, n) \
|
||||
darray_copy_array(sizeof(*dst.array), &dst.da, src_array, n)
|
||||
|
||||
#define da_move(dst, src) darray_move(&dst.da, &src.da)
|
||||
|
||||
#define da_find(v, item, idx) \
|
||||
darray_find(sizeof(*v.array), &v.da, item, idx)
|
||||
|
||||
#define da_push_back(v, item) darray_push_back(sizeof(*v.array), &v.da, item)
|
||||
|
||||
#define da_push_back_new(v) darray_push_back_new(sizeof(*v.array), &v.da)
|
||||
|
||||
#define da_push_back_array(dst, src_array, n) \
|
||||
darray_push_back_array(sizeof(*dst.array), &dst.da, src_array, n)
|
||||
|
||||
#define da_push_back_da(dst, src) \
|
||||
darray_push_back_darray(sizeof(*dst.array), &dst.da, &src.da)
|
||||
|
||||
#define da_insert(v, idx, item) \
|
||||
darray_insert(sizeof(*v.array), &v.da, idx, item)
|
||||
|
||||
#define da_insert_new(v, idx) \
|
||||
darray_insert_new(sizeof(*v.array), &v.da, idx)
|
||||
|
||||
#define da_insert_array(dst, idx, src_array, n) \
|
||||
darray_insert_array(sizeof(*dst.array), &dst.da, idx, \
|
||||
src_array, n)
|
||||
|
||||
#define da_insert_da(dst, idx, src) \
|
||||
darray_insert_darray(sizeof(*dst.array), &dst.da, idx, \
|
||||
&src.da)
|
||||
|
||||
#define da_erase(dst, idx) \
|
||||
darray_erase(sizeof(*dst.array), &dst.da, idx)
|
||||
|
||||
#define da_erase_item(dst, item) \
|
||||
darray_erase_item(sizeof(*dst.array), &dst.da, item)
|
||||
|
||||
#define da_erase_range(dst, from, to) \
|
||||
darray_erase_range(sizeof(*dst.array), &dst.da, from, to)
|
||||
|
||||
#define da_pop_back(dst) \
|
||||
darray_pop_back(sizeof(*dst.array), &dst.da);
|
||||
|
||||
#define da_join(dst, src) \
|
||||
darray_join(sizeof(*dst.array), &dst.da, &src.da)
|
||||
|
||||
#define da_split(dst1, dst2, src, idx) \
|
||||
darray_split(sizeof(*src.array), &dst1.da, &dst2.da, \
|
||||
&src.da, idx)
|
||||
|
||||
#define da_move_item(v, from, to) \
|
||||
darray_move_item(sizeof(*v.array), &v.da, from, to)
|
||||
|
||||
#define da_swap_item(v, idx1, idx2) \
|
||||
darray_swap(sizeof(v.array), &v.da, idx1, idx2)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,611 @@
|
|||
/******************************************************************************
|
||||
Copyright (c) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <wchar.h>
|
||||
#include "c99defs.h"
|
||||
#include "dstr.h"
|
||||
#include "bmem.h"
|
||||
#include "utf8.h"
|
||||
#include "lexer.h"
|
||||
#include "platform.h"
|
||||
|
||||
static const char *astrblank = "";
|
||||
static const wchar_t *wstrblank = L"";
|
||||
|
||||
int astrcmpi(const char *str1, const char *str2)
|
||||
{
|
||||
if (!str1)
|
||||
str1 = astrblank;
|
||||
if (!str2)
|
||||
str2 = astrblank;
|
||||
|
||||
do {
|
||||
char ch1 = toupper(*str1);
|
||||
char ch2 = toupper(*str2);
|
||||
|
||||
if (ch1 < ch2)
|
||||
return -1;
|
||||
else if (ch1 > ch2)
|
||||
return 1;
|
||||
} while (*str1++ && *str2++);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wstrcmpi(const wchar_t *str1, const wchar_t *str2)
|
||||
{
|
||||
if (!str1)
|
||||
str1 = wstrblank;
|
||||
if (!str2)
|
||||
str2 = wstrblank;
|
||||
|
||||
do {
|
||||
wchar_t ch1 = towupper(*str1);
|
||||
wchar_t ch2 = towupper(*str2);
|
||||
|
||||
if (ch1 < ch2)
|
||||
return -1;
|
||||
else if (ch1 > ch2)
|
||||
return 1;
|
||||
} while (*str1++ && *str2++);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int astrcmp_n(const char *str1, const char *str2, size_t n)
|
||||
{
|
||||
if (!n)
|
||||
return 0;
|
||||
if (!str1)
|
||||
str1 = astrblank;
|
||||
if (!str2)
|
||||
str2 = astrblank;
|
||||
|
||||
do {
|
||||
char ch1 = *str1;
|
||||
char ch2 = *str2;
|
||||
|
||||
if (ch1 < ch2)
|
||||
return -1;
|
||||
else if (ch1 > ch2)
|
||||
return 1;
|
||||
} while (*str1++ && *str2++ && --n);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wstrcmp_n(const wchar_t *str1, const wchar_t *str2, size_t n)
|
||||
{
|
||||
if (!n)
|
||||
return 0;
|
||||
if (!str1)
|
||||
str1 = wstrblank;
|
||||
if (!str2)
|
||||
str2 = wstrblank;
|
||||
|
||||
do {
|
||||
wchar_t ch1 = *str1;
|
||||
wchar_t ch2 = *str2;
|
||||
|
||||
if (ch1 < ch2)
|
||||
return -1;
|
||||
else if (ch1 > ch2)
|
||||
return 1;
|
||||
} while (*str1++ && *str2++ && --n);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int astrcmpi_n(const char *str1, const char *str2, size_t n)
|
||||
{
|
||||
if (!n)
|
||||
return 0;
|
||||
if (!str1)
|
||||
str1 = astrblank;
|
||||
if (!str2)
|
||||
str2 = astrblank;
|
||||
|
||||
do {
|
||||
char ch1 = toupper(*str1);
|
||||
char ch2 = toupper(*str2);
|
||||
|
||||
if (ch1 < ch2)
|
||||
return -1;
|
||||
else if (ch1 > ch2)
|
||||
return 1;
|
||||
} while (*str1++ && *str2++ && --n);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wstrcmpi_n(const wchar_t *str1, const wchar_t *str2, size_t n)
|
||||
{
|
||||
if (!n)
|
||||
return 0;
|
||||
if (!str1)
|
||||
str1 = wstrblank;
|
||||
if (!str2)
|
||||
str2 = wstrblank;
|
||||
|
||||
do {
|
||||
wchar_t ch1 = towupper(*str1);
|
||||
wchar_t ch2 = towupper(*str2);
|
||||
|
||||
if (ch1 < ch2)
|
||||
return -1;
|
||||
else if (ch1 > ch2)
|
||||
return 1;
|
||||
} while (*str1++ && *str2++ && --n);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *strdepad(char *str)
|
||||
{
|
||||
char *temp;
|
||||
size_t len;
|
||||
|
||||
if (!str)
|
||||
return str;
|
||||
if (!*str)
|
||||
return str;
|
||||
|
||||
temp = str;
|
||||
|
||||
/* remove preceding spaces/tabs */
|
||||
while (*temp == ' ' || *temp == '\t')
|
||||
++temp;
|
||||
|
||||
len = strlen(str);
|
||||
if (temp != str)
|
||||
memmove(str, temp, len + 1);
|
||||
|
||||
if (len) {
|
||||
temp = str + (len-1);
|
||||
while (*temp == ' ' || *temp == '\t')
|
||||
*(temp--) = 0;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
wchar_t *wcsdepad(wchar_t *str)
|
||||
{
|
||||
wchar_t *temp;
|
||||
size_t len;
|
||||
|
||||
if (!str)
|
||||
return str;
|
||||
if (!*str)
|
||||
return str;
|
||||
|
||||
temp = str;
|
||||
|
||||
/* remove preceding spaces/tabs */
|
||||
while (*temp == ' ' || *temp == '\t')
|
||||
++temp;
|
||||
|
||||
len = wcslen(str);
|
||||
if (temp != str)
|
||||
memmove(str, temp, (len+1) * sizeof(wchar_t));
|
||||
|
||||
if (len) {
|
||||
temp = str + (len-1);
|
||||
while (*temp == ' ' || *temp == '\t')
|
||||
*(temp--) = 0;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
void dstr_init_strref(struct dstr *dst, const struct strref *src)
|
||||
{
|
||||
dstr_init(dst);
|
||||
dstr_copy_strref(dst, src);
|
||||
}
|
||||
|
||||
void dstr_copy(struct dstr *dst, const char *array)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
if (!array || !*array) {
|
||||
dstr_free(dst);
|
||||
return;
|
||||
}
|
||||
|
||||
len = strlen(array);
|
||||
dstr_ensure_capacity(dst, len + 1);
|
||||
memcpy(dst->array, array, len + 1);
|
||||
dst->len = len;
|
||||
}
|
||||
|
||||
void dstr_copy_strref(struct dstr *dst, const struct strref *src)
|
||||
{
|
||||
if (dst->array)
|
||||
dstr_free(dst);
|
||||
|
||||
dstr_ncopy(dst, src->array, src->len);
|
||||
}
|
||||
|
||||
static inline size_t size_min(size_t a, size_t b)
|
||||
{
|
||||
return (a < b) ? a : b;
|
||||
}
|
||||
|
||||
void dstr_ncopy(struct dstr *dst, const char *array, const size_t len)
|
||||
{
|
||||
if (dst->array)
|
||||
dstr_free(dst);
|
||||
|
||||
if (!len)
|
||||
return;
|
||||
|
||||
dst->array = bmemdup(array, len + 1);
|
||||
dst->len = len;
|
||||
|
||||
dst->array[len] = 0;
|
||||
}
|
||||
|
||||
void dstr_ncopy_dstr(struct dstr *dst, const struct dstr *str, const size_t len)
|
||||
{
|
||||
size_t newlen;
|
||||
|
||||
if (dst->array)
|
||||
dstr_free(dst);
|
||||
|
||||
if (!len)
|
||||
return;
|
||||
|
||||
newlen = size_min(len, str->len);
|
||||
dst->array = bmemdup(str->array, newlen + 1);
|
||||
dst->len = newlen;
|
||||
|
||||
dst->array[newlen] = 0;
|
||||
}
|
||||
|
||||
void dstr_cat_dstr(struct dstr *dst, const struct dstr *str)
|
||||
{
|
||||
size_t new_len;
|
||||
if (!str->len)
|
||||
return;
|
||||
|
||||
new_len = dst->len + str->len;
|
||||
|
||||
dstr_ensure_capacity(dst, new_len + 1);
|
||||
memcpy(dst->array+dst->len, str->array, str->len + 1);
|
||||
dst->len = new_len;
|
||||
}
|
||||
|
||||
void dstr_cat_strref(struct dstr *dst, const struct strref *str)
|
||||
{
|
||||
dstr_ncat(dst, str->array, str->len);
|
||||
}
|
||||
|
||||
void dstr_ncat(struct dstr *dst, const char *array, const size_t len)
|
||||
{
|
||||
size_t new_len;
|
||||
if (!array || !*array || !len)
|
||||
return;
|
||||
|
||||
new_len = dst->len + len;
|
||||
|
||||
dstr_ensure_capacity(dst, new_len + 1);
|
||||
memcpy(dst->array+dst->len, array, len);
|
||||
|
||||
dst->len = new_len;
|
||||
dst->array[new_len] = 0;
|
||||
}
|
||||
|
||||
void dstr_ncat_dstr(struct dstr *dst, const struct dstr *str, const size_t len)
|
||||
{
|
||||
size_t new_len, in_len;
|
||||
if (!str->array || !*str->array || !len)
|
||||
return;
|
||||
|
||||
in_len = size_min(len, str->len);
|
||||
new_len = dst->len + in_len;
|
||||
|
||||
dstr_ensure_capacity(dst, new_len + 1);
|
||||
memcpy(dst->array+dst->len, str->array, in_len);
|
||||
|
||||
dst->len = new_len;
|
||||
dst->array[new_len] = 0;
|
||||
}
|
||||
|
||||
void dstr_insert(struct dstr *dst, const size_t idx, const char *array)
|
||||
{
|
||||
size_t new_len, len;
|
||||
if (!array || !*array)
|
||||
return;
|
||||
if (idx == dst->len) {
|
||||
dstr_cat(dst, array);
|
||||
return;
|
||||
}
|
||||
|
||||
len = strlen(array);
|
||||
new_len = dst->len + len;
|
||||
|
||||
dstr_ensure_capacity(dst, new_len + 1);
|
||||
dst->len = new_len;
|
||||
|
||||
memmove(dst->array+idx+len, dst->array+idx, dst->len - idx + 1);
|
||||
memcpy(dst->array+idx, array, len);
|
||||
}
|
||||
|
||||
void dstr_insert_dstr(struct dstr *dst, const size_t idx,
|
||||
const struct dstr *str)
|
||||
{
|
||||
size_t new_len;
|
||||
if (!str->len)
|
||||
return;
|
||||
if (idx == dst->len) {
|
||||
dstr_cat_dstr(dst, str);
|
||||
return;
|
||||
}
|
||||
|
||||
new_len = dst->len + str->len;
|
||||
|
||||
dstr_ensure_capacity(dst, (new_len+1));
|
||||
dst->len = new_len;
|
||||
|
||||
memmove(dst->array+idx+str->len, dst->array+idx, dst->len - idx + 1);
|
||||
memcpy(dst->array+idx, str->array, str->len);
|
||||
}
|
||||
|
||||
void dstr_insert_ch(struct dstr *dst, const size_t idx, const char ch)
|
||||
{
|
||||
if (idx == dst->len) {
|
||||
dstr_cat_ch(dst, ch);
|
||||
return;
|
||||
}
|
||||
|
||||
dstr_ensure_capacity(dst, (++dst->len+1));
|
||||
memmove(dst->array+idx+1, dst->array+idx, dst->len - idx + 1);
|
||||
dst->array[idx] = ch;
|
||||
}
|
||||
|
||||
void dstr_remove(struct dstr *dst, const size_t idx, const size_t count)
|
||||
{
|
||||
size_t end;
|
||||
if (!count)
|
||||
return;
|
||||
if (count == dst->len) {
|
||||
dstr_free(dst);
|
||||
return;
|
||||
}
|
||||
|
||||
end = idx+count;
|
||||
if (end == dst->len)
|
||||
dst->array[idx] = 0;
|
||||
else
|
||||
memmove(dst->array+idx, dst->array+end, dst->len - end + 1);
|
||||
|
||||
dst->len -= count;
|
||||
}
|
||||
|
||||
void dstr_printf(struct dstr *dst, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
dstr_vprintf(dst, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void dstr_catf(struct dstr *dst, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
dstr_vcatf(dst, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void dstr_vprintf(struct dstr *dst, const char *format, va_list args)
|
||||
{
|
||||
dstr_ensure_capacity(dst, 4096);
|
||||
vsnprintf(dst->array, 4095, format, args);
|
||||
|
||||
if (!*dst->array) {
|
||||
dstr_free(dst);
|
||||
return;
|
||||
}
|
||||
|
||||
dst->len = strlen(dst->array);
|
||||
}
|
||||
|
||||
void dstr_vcatf(struct dstr *dst, const char *format, va_list args)
|
||||
{
|
||||
struct dstr temp;
|
||||
dstr_init(&temp);
|
||||
dstr_vprintf(&temp, format, args);
|
||||
dstr_cat_dstr(dst, &temp);
|
||||
dstr_free(&temp);
|
||||
}
|
||||
|
||||
void dstr_safe_printf(struct dstr *dst, const char *format,
|
||||
const char *val1, const char *val2, const char *val3,
|
||||
const char *val4)
|
||||
{
|
||||
dstr_copy(dst, format);
|
||||
if (val1)
|
||||
dstr_replace(dst, "$1", val1);
|
||||
if (val2)
|
||||
dstr_replace(dst, "$2", val2);
|
||||
if (val3)
|
||||
dstr_replace(dst, "$3", val3);
|
||||
if (val4)
|
||||
dstr_replace(dst, "$4", val4);
|
||||
}
|
||||
|
||||
void dstr_replace(struct dstr *str, const char *find,
|
||||
const char *replace)
|
||||
{
|
||||
size_t find_len, replace_len;
|
||||
char *temp;
|
||||
|
||||
if (!replace)
|
||||
replace = "";
|
||||
|
||||
find_len = strlen(find);
|
||||
replace_len = strlen(replace);
|
||||
temp = str->array;
|
||||
|
||||
if (replace_len < find_len) {
|
||||
int count = 0;
|
||||
|
||||
while ((temp = strstr(temp, find)) != NULL) {
|
||||
char *end = temp+find_len;
|
||||
size_t end_len = strlen(end);
|
||||
|
||||
if (end_len) {
|
||||
memmove(temp+replace_len, end, end_len + 1);
|
||||
if (replace_len)
|
||||
memcpy(temp, replace, replace_len);
|
||||
} else {
|
||||
strcpy(temp, replace);
|
||||
}
|
||||
|
||||
temp += replace_len;
|
||||
++count;
|
||||
}
|
||||
|
||||
if (count)
|
||||
str->len += (replace_len-find_len) * count;
|
||||
|
||||
} else if (replace_len > find_len) {
|
||||
int count = 0;
|
||||
|
||||
while ((temp = strstr(temp, find)) != NULL) {
|
||||
temp += find_len;
|
||||
++count;
|
||||
}
|
||||
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
str->len += (replace_len-find_len) * count;
|
||||
dstr_ensure_capacity(str, str->len + 1);
|
||||
temp = str->array;
|
||||
|
||||
while ((temp = strstr(temp, find)) != NULL) {
|
||||
char *end = temp+find_len;
|
||||
size_t end_len = strlen(end);
|
||||
|
||||
if (end_len) {
|
||||
memmove(temp+replace_len, end, end_len + 1);
|
||||
memcpy(temp, replace, replace_len);
|
||||
} else {
|
||||
strcpy(temp, replace);
|
||||
}
|
||||
|
||||
temp += replace_len;
|
||||
}
|
||||
|
||||
} else {
|
||||
while ((temp = strstr(temp, find)) != NULL) {
|
||||
memcpy(temp, replace, replace_len);
|
||||
temp += replace_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dstr_depad(struct dstr *str)
|
||||
{
|
||||
if (str->array) {
|
||||
str->array = strdepad(str->array);
|
||||
if (*str->array)
|
||||
str->len = strlen(str->array);
|
||||
else
|
||||
dstr_free(str);
|
||||
}
|
||||
}
|
||||
|
||||
void dstr_left(struct dstr *dst, const struct dstr *str, const size_t pos)
|
||||
{
|
||||
dstr_resize(dst, pos);
|
||||
if (dst != str)
|
||||
memcpy(dst->array, str->array, pos);
|
||||
}
|
||||
|
||||
void dstr_mid(struct dstr *dst, const struct dstr *str, const size_t start,
|
||||
const size_t count)
|
||||
{
|
||||
struct dstr temp;
|
||||
dstr_init(&temp);
|
||||
dstr_copy_dstr(&temp, str);
|
||||
dstr_ncopy(dst, temp.array+start, count);
|
||||
dstr_free(&temp);
|
||||
}
|
||||
|
||||
void dstr_right(struct dstr *dst, const struct dstr *str, const size_t pos)
|
||||
{
|
||||
struct dstr temp;
|
||||
dstr_init(&temp);
|
||||
dstr_ncopy(&temp, str->array+pos, str->len-pos);
|
||||
dstr_copy_dstr(dst, &temp);
|
||||
dstr_free(&temp);
|
||||
}
|
||||
|
||||
void dstr_from_mbs(struct dstr *dst, const char *mbstr)
|
||||
{
|
||||
dstr_free(dst);
|
||||
dst->len = os_mbs_to_utf8(mbstr, 0, &dst->array);
|
||||
}
|
||||
|
||||
char *dstr_to_mbs(const struct dstr *str)
|
||||
{
|
||||
char *dst;
|
||||
os_mbs_to_utf8(str->array, str->len, &dst);
|
||||
return dst;
|
||||
}
|
||||
|
||||
void dstr_from_wcs(struct dstr *dst, const wchar_t *wstr)
|
||||
{
|
||||
size_t len = wchar_to_utf8(wstr, 0, NULL, 0, 0);
|
||||
|
||||
if (len) {
|
||||
dstr_resize(dst, len);
|
||||
wchar_to_utf8(wstr, 0, dst->array, len+1, 0);
|
||||
} else {
|
||||
dstr_free(dst);
|
||||
}
|
||||
}
|
||||
|
||||
wchar_t *dstr_to_utf8(const struct dstr *str)
|
||||
{
|
||||
wchar_t *out = NULL;
|
||||
size_t len = utf8_to_wchar(str->array, str->len, NULL, 0, 0);
|
||||
|
||||
if (len) {
|
||||
out = bmalloc((len+1) * sizeof(wchar_t));
|
||||
utf8_to_wchar(str->array, str->len, out, len+1, 0);
|
||||
out[len] = 0;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
|
@ -0,0 +1,310 @@
|
|||
/******************************************************************************
|
||||
Copyright (c) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 DSTR_H
|
||||
#define DSTR_H
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include "c99defs.h"
|
||||
#include "bmem.h"
|
||||
|
||||
/*
|
||||
* Dynamic string
|
||||
*
|
||||
* Helper struct/functions for dynamically sizing string buffers.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct strref;
|
||||
|
||||
struct dstr {
|
||||
char *array;
|
||||
size_t len; /* number of characters, excluding null terminator */
|
||||
size_t capacity;
|
||||
};
|
||||
|
||||
EXPORT int astrcmpi(const char *str1, const char *str2);
|
||||
EXPORT int wstrcmpi(const wchar_t *str1, const wchar_t *str2);
|
||||
EXPORT int astrcmp_n(const char *str1, const char *str2, size_t n);
|
||||
EXPORT int wstrcmp_n(const wchar_t *str1, const wchar_t *str2, size_t n);
|
||||
EXPORT int astrcmpi_n(const char *str1, const char *str2, size_t n);
|
||||
EXPORT int wstrcmpi_n(const wchar_t *str1, const wchar_t *str2, size_t n);
|
||||
|
||||
EXPORT char *strdepad(char *str);
|
||||
EXPORT wchar_t *wcsdepad(wchar_t *str);
|
||||
|
||||
static inline void dstr_init(struct dstr *dst);
|
||||
static inline void dstr_init_move(struct dstr *dst, struct dstr *src);
|
||||
static inline void dstr_init_move_array(struct dstr *dst, char *str);
|
||||
static inline void dstr_init_copy(struct dstr *dst, const char *src);
|
||||
static inline void dstr_init_copy_dstr(struct dstr *dst,
|
||||
const struct dstr *src);
|
||||
EXPORT void dstr_init_strref(struct dstr *dst, const struct strref *src);
|
||||
|
||||
static inline void dstr_free(struct dstr *dst);
|
||||
static inline void dstr_array_free(struct dstr *array, const size_t count);
|
||||
|
||||
static inline void dstr_move(struct dstr *dst, struct dstr *src);
|
||||
static inline void dstr_move_array(struct dstr *dst, char *str);
|
||||
|
||||
EXPORT void dstr_copy(struct dstr *dst, const char *array);
|
||||
static inline void dstr_copy_dstr(struct dstr *dst, const struct dstr *src);
|
||||
EXPORT void dstr_copy_strref(struct dstr *dst, const struct strref *src);
|
||||
|
||||
EXPORT void dstr_ncopy(struct dstr *dst, const char *array,
|
||||
const size_t len);
|
||||
EXPORT void dstr_ncopy_dstr(struct dstr *dst, const struct dstr *src,
|
||||
const size_t len);
|
||||
|
||||
static inline void dstr_resize(struct dstr *dst, const size_t num);
|
||||
static inline void dstr_reserve(struct dstr *dst, const size_t num);
|
||||
|
||||
static inline bool dstr_isempty(const struct dstr *str);
|
||||
|
||||
static inline void dstr_cat(struct dstr *dst, const char *array);
|
||||
EXPORT void dstr_cat_dstr(struct dstr *dst, const struct dstr *str);
|
||||
EXPORT void dstr_cat_strref(struct dstr *dst, const struct strref *str);
|
||||
|
||||
static inline void dstr_cat_ch(struct dstr *dst, char ch);
|
||||
|
||||
EXPORT void dstr_ncat(struct dstr *dst, const char *array, const size_t len);
|
||||
EXPORT void dstr_ncat_dstr(struct dstr *dst, const struct dstr *str,
|
||||
const size_t len);
|
||||
|
||||
EXPORT void dstr_cat_strref(struct dstr *dst, const struct strref *str);
|
||||
|
||||
EXPORT void dstr_insert(struct dstr *dst, const size_t idx,
|
||||
const char *array);
|
||||
EXPORT void dstr_insert_dstr(struct dstr *dst, const size_t idx,
|
||||
const struct dstr *str);
|
||||
EXPORT void dstr_insert_ch(struct dstr *dst, const size_t idx,
|
||||
const char ch);
|
||||
|
||||
EXPORT void dstr_remove(struct dstr *dst, const size_t idx, const size_t count);
|
||||
|
||||
EXPORT void dstr_printf(struct dstr *dst, const char *format, ...);
|
||||
EXPORT void dstr_catf(struct dstr *dst, const char *format, ...);
|
||||
|
||||
EXPORT void dstr_vprintf(struct dstr *dst, const char *format, va_list args);
|
||||
EXPORT void dstr_vcatf(struct dstr *dst, const char *format, va_list args);
|
||||
|
||||
EXPORT void dstr_safe_printf(struct dstr *dst, const char *format,
|
||||
const char *val1, const char *val2, const char *val3,
|
||||
const char *val4);
|
||||
|
||||
static inline const char *dstr_find(const struct dstr *str,
|
||||
const char *find);
|
||||
|
||||
EXPORT void dstr_replace(struct dstr *str, const char *find,
|
||||
const char *replace);
|
||||
|
||||
static inline int dstr_cmp(const struct dstr *str1, const char *str2);
|
||||
static inline int dstr_cmpi(const struct dstr *str1, const char *str2);
|
||||
static inline int dstr_ncmp(const struct dstr *str1, const char *str2,
|
||||
const size_t n);
|
||||
static inline int dstr_ncmpi(const struct dstr *str1, const char *str2,
|
||||
const size_t n);
|
||||
|
||||
EXPORT void dstr_depad(struct dstr *dst);
|
||||
|
||||
EXPORT void dstr_left(struct dstr *dst, const struct dstr *str,
|
||||
const size_t pos);
|
||||
EXPORT void dstr_mid(struct dstr *dst, const struct dstr *str,
|
||||
const size_t start, const size_t count);
|
||||
EXPORT void dstr_right(struct dstr *dst, const struct dstr *str,
|
||||
const size_t pos);
|
||||
|
||||
EXPORT void dstr_from_mbs(struct dstr *dst, const char *mbstr);
|
||||
EXPORT char *dstr_to_mbs(const struct dstr *str);
|
||||
EXPORT void dstr_from_wcs(struct dstr *dst, const wchar_t *wstr);
|
||||
EXPORT wchar_t *dstr_to_wcs(const struct dstr *str);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static inline void dstr_init(struct dstr *dst)
|
||||
{
|
||||
dst->array = NULL;
|
||||
dst->len = 0;
|
||||
dst->capacity = 0;
|
||||
}
|
||||
|
||||
static inline void dstr_init_move_array(struct dstr *dst, char *str)
|
||||
{
|
||||
dst->array = str;
|
||||
dst->len = (!str) ? 0 : strlen(str);
|
||||
}
|
||||
|
||||
static inline void dstr_init_move(struct dstr *dst, struct dstr *src)
|
||||
{
|
||||
*dst = *src;
|
||||
dstr_init(src);
|
||||
}
|
||||
|
||||
static inline void dstr_init_copy(struct dstr *dst, const char *str)
|
||||
{
|
||||
dstr_init(dst);
|
||||
dstr_copy(dst, str);
|
||||
}
|
||||
|
||||
static inline void dstr_init_copy_dstr(struct dstr *dst, const struct dstr *src)
|
||||
{
|
||||
dstr_init(dst);
|
||||
dstr_copy_dstr(dst, src);
|
||||
}
|
||||
|
||||
static inline void dstr_free(struct dstr *dst)
|
||||
{
|
||||
bfree(dst->array);
|
||||
dst->array = NULL;
|
||||
dst->len = 0;
|
||||
dst->capacity = 0;
|
||||
}
|
||||
|
||||
static inline void dstr_array_free(struct dstr *array, const size_t count)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < count; i++)
|
||||
dstr_free(array+i);
|
||||
}
|
||||
|
||||
static inline void dstr_move_array(struct dstr *dst, char *str)
|
||||
{
|
||||
dstr_free(dst);
|
||||
dst->array = str;
|
||||
dst->len = (!str) ? 0 : strlen(str);
|
||||
}
|
||||
|
||||
static inline void dstr_move(struct dstr *dst, struct dstr *src)
|
||||
{
|
||||
dstr_free(dst);
|
||||
dstr_init_move(dst, src);
|
||||
}
|
||||
|
||||
static inline void dstr_ensure_capacity(struct dstr *dst, const size_t new_size)
|
||||
{
|
||||
size_t new_cap;
|
||||
if (new_size <= dst->capacity)
|
||||
return;
|
||||
|
||||
new_cap = (!dst->capacity) ? new_size : dst->capacity*2;
|
||||
if (new_size > new_cap)
|
||||
new_cap = new_size;
|
||||
dst->array = (char*)brealloc(dst->array, new_cap);
|
||||
dst->capacity = new_cap;
|
||||
}
|
||||
|
||||
static inline void dstr_copy_dstr(struct dstr *dst, const struct dstr *src)
|
||||
{
|
||||
if (dst->array)
|
||||
dstr_free(dst);
|
||||
|
||||
dstr_ensure_capacity(dst, src->len + 1);
|
||||
memcpy(dst->array, src->array, src->len + 1);
|
||||
dst->len = src->len;
|
||||
}
|
||||
|
||||
static inline void dstr_reserve(struct dstr *dst, const size_t capacity)
|
||||
{
|
||||
if (capacity == 0 || capacity <= dst->len)
|
||||
return;
|
||||
|
||||
dst->array = (char*)brealloc(dst->array, capacity);
|
||||
dst->capacity = capacity;
|
||||
}
|
||||
|
||||
static inline void dstr_resize(struct dstr *dst, const size_t num)
|
||||
{
|
||||
if (!num) {
|
||||
dstr_free(dst);
|
||||
return;
|
||||
}
|
||||
|
||||
dstr_ensure_capacity(dst, num + 1);
|
||||
dst->array[num] = 0;
|
||||
dst->len = num;
|
||||
}
|
||||
|
||||
static inline bool dstr_isempty(const struct dstr *str)
|
||||
{
|
||||
if (!str->array || !str->len)
|
||||
return true;
|
||||
if (!*str->array)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void dstr_cat(struct dstr *dst, const char *array)
|
||||
{
|
||||
size_t len;
|
||||
if (!array || !*array)
|
||||
return;
|
||||
|
||||
len = strlen(array);
|
||||
dstr_ncat(dst, array, len);
|
||||
}
|
||||
|
||||
static inline void dstr_cat_ch(struct dstr *dst, char ch)
|
||||
{
|
||||
dstr_ensure_capacity(dst, ++dst->len + 1);
|
||||
dst->array[dst->len-1] = ch;
|
||||
dst->array[dst->len] = 0;
|
||||
}
|
||||
|
||||
static inline const char *dstr_find(const struct dstr *str,
|
||||
const char *find)
|
||||
{
|
||||
return strstr(str->array, find);
|
||||
}
|
||||
|
||||
static inline int dstr_cmp(const struct dstr *str1, const char *str2)
|
||||
{
|
||||
return strcmp(str1->array, str2);
|
||||
}
|
||||
|
||||
static inline int dstr_cmpi(const struct dstr *str1, const char *str2)
|
||||
{
|
||||
return astrcmpi(str1->array, str2);
|
||||
}
|
||||
|
||||
static inline int dstr_ncmp(const struct dstr *str1, const char *str2,
|
||||
const size_t n)
|
||||
{
|
||||
return astrcmp_n(str1->array, str2, n);
|
||||
}
|
||||
|
||||
static inline int dstr_ncmpi(const struct dstr *str1, const char *str2,
|
||||
const size_t n)
|
||||
{
|
||||
return astrcmpi_n(str1->array, str2, n);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,321 @@
|
|||
/******************************************************************************
|
||||
Copyright (c) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 <ctype.h>
|
||||
#include "lexer.h"
|
||||
|
||||
static const char *astrblank = "";
|
||||
|
||||
static inline bool strref_is_empty(const struct strref *str)
|
||||
{
|
||||
return !str || !str->array || !str->len || !*str->array;
|
||||
}
|
||||
|
||||
int strref_cmp(const struct strref *str1, const char *str2)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
if (strref_is_empty(str1))
|
||||
return (!str2 || !*str2) ? 0 : -1;
|
||||
if (!str2)
|
||||
str2 = astrblank;
|
||||
|
||||
do {
|
||||
char ch1, ch2;
|
||||
|
||||
ch1 = (i < str1->len) ? str1->array[i] : 0;
|
||||
ch2 = *str2;
|
||||
|
||||
if (ch1 < ch2)
|
||||
return -1;
|
||||
else if (ch1 > ch2)
|
||||
return 1;
|
||||
} while (i++ < str1->len && *str2++);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int strref_cmpi(const struct strref *str1, const char *str2)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
if (strref_is_empty(str1))
|
||||
return (!str2 || !*str2) ? 0 : -1;
|
||||
if (!str2)
|
||||
str2 = astrblank;
|
||||
|
||||
do {
|
||||
char ch1, ch2;
|
||||
|
||||
ch1 = (i < str1->len) ? toupper(str1->array[i]) : 0;
|
||||
ch2 = toupper(*str2);
|
||||
|
||||
if (ch1 < ch2)
|
||||
return -1;
|
||||
else if (ch1 > ch2)
|
||||
return 1;
|
||||
} while (i++ < str1->len && *str2++);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int strref_cmp_strref(const struct strref *str1, const struct strref *str2)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
if (strref_is_empty(str1))
|
||||
return strref_is_empty(str2) ? 0 : -1;
|
||||
if (strref_is_empty(str2))
|
||||
return -1;
|
||||
|
||||
do {
|
||||
char ch1, ch2;
|
||||
|
||||
ch1 = (i < str1->len) ? str1->array[i] : 0;
|
||||
ch2 = (i < str2->len) ? str2->array[i] : 0;
|
||||
|
||||
if (ch1 < ch2)
|
||||
return -1;
|
||||
else if (ch1 > ch2)
|
||||
return 1;
|
||||
|
||||
i++;
|
||||
} while (i <= str1->len && i <= str2->len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int strref_cmpi_strref(const struct strref *str1, const struct strref *str2)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
if (strref_is_empty(str1))
|
||||
return strref_is_empty(str2) ? 0 : -1;
|
||||
if (strref_is_empty(str2))
|
||||
return -1;
|
||||
|
||||
do {
|
||||
char ch1, ch2;
|
||||
|
||||
ch1 = (i < str1->len) ? toupper(str1->array[i]) : 0;
|
||||
ch2 = (i < str2->len) ? toupper(str2->array[i]) : 0;
|
||||
|
||||
if (ch1 < ch2)
|
||||
return -1;
|
||||
else if (ch1 > ch2)
|
||||
return 1;
|
||||
|
||||
i++;
|
||||
} while (i <= str1->len && i <= str2->len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
bool valid_int_str(const char *str, size_t n)
|
||||
{
|
||||
bool found_num = false;
|
||||
|
||||
if (!str)
|
||||
return false;
|
||||
if (!*str)
|
||||
return false;
|
||||
|
||||
if (!n)
|
||||
n = strlen(str);
|
||||
if (*str == '-' || *str == '+')
|
||||
++str;
|
||||
|
||||
do {
|
||||
if (*str > '9' || *str < '0')
|
||||
return false;
|
||||
|
||||
found_num = true;
|
||||
} while(*++str && --n);
|
||||
|
||||
return found_num;
|
||||
}
|
||||
|
||||
bool valid_float_str(const char *str, size_t n)
|
||||
{
|
||||
bool found_num = false;
|
||||
bool found_exp = false;
|
||||
bool found_dec = false;
|
||||
|
||||
if (!str)
|
||||
return false;
|
||||
if (!*str)
|
||||
return false;
|
||||
|
||||
if (!n)
|
||||
n = strlen(str);
|
||||
if (*str == '-' || *str == '+')
|
||||
++str;
|
||||
|
||||
do {
|
||||
if (*str == '.') {
|
||||
if (found_dec || found_exp || !found_num)
|
||||
return false;
|
||||
|
||||
found_dec = true;
|
||||
|
||||
} else if (*str == 'e') {
|
||||
if (found_exp || !found_num)
|
||||
return false;
|
||||
|
||||
found_exp = true;
|
||||
found_num = false;
|
||||
|
||||
} else if (*str == '-' || *str == '+') {
|
||||
if (!found_exp || !found_num)
|
||||
return false;
|
||||
|
||||
} else if (*str > '9' || *str < '0') {
|
||||
return false;
|
||||
} else {
|
||||
found_num = true;
|
||||
}
|
||||
} while(*++str && --n);
|
||||
|
||||
return found_num;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void error_data_add(struct error_data *data, const char *file,
|
||||
uint32_t row, uint32_t column, const char *msg, int level)
|
||||
{
|
||||
struct error_item item;
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
item.file = file;
|
||||
item.row = row;
|
||||
item.column = column;
|
||||
item.level = level;
|
||||
item.error = bstrdup(msg);
|
||||
|
||||
da_push_back(data->errors, &item);
|
||||
}
|
||||
|
||||
char *error_data_buildstring(struct error_data *ed)
|
||||
{
|
||||
struct dstr str;
|
||||
struct error_item *items = ed->errors.array;
|
||||
size_t i;
|
||||
|
||||
dstr_init(&str);
|
||||
for (i = 0; i < ed->errors.num; i++) {
|
||||
struct error_item *item = items+i;
|
||||
dstr_catf(&str, "%s (%u, %u): %s\n", item->file, item->row,
|
||||
item->column, item->error);
|
||||
}
|
||||
|
||||
return str.array;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static inline enum base_token_type get_char_token_type(const char ch)
|
||||
{
|
||||
if (is_whitespace(ch))
|
||||
return BASETOKEN_WHITESPACE;
|
||||
else if (isdigit(ch))
|
||||
return BASETOKEN_DIGIT;
|
||||
else if (isalpha(ch))
|
||||
return BASETOKEN_ALPHA;
|
||||
|
||||
return BASETOKEN_OTHER;
|
||||
}
|
||||
|
||||
bool lexer_getbasetoken(struct lexer *lex, struct base_token *token,
|
||||
bool ignore_whitespace)
|
||||
{
|
||||
const char *offset = lex->offset;
|
||||
const char *token_start = NULL;
|
||||
enum base_token_type type = BASETOKEN_NONE;
|
||||
|
||||
if (!offset)
|
||||
return false;
|
||||
|
||||
while (*offset != 0) {
|
||||
char ch = *(offset++);
|
||||
enum base_token_type new_type = get_char_token_type(ch);
|
||||
|
||||
if (type == BASETOKEN_NONE) {
|
||||
if (new_type == BASETOKEN_WHITESPACE &&
|
||||
ignore_whitespace)
|
||||
continue;
|
||||
|
||||
token_start = offset-1;
|
||||
type = new_type;
|
||||
|
||||
if (type != BASETOKEN_DIGIT ||
|
||||
type != BASETOKEN_ALPHA) {
|
||||
if (is_newline(ch) &&
|
||||
is_newline_pair(ch, *offset)) {
|
||||
offset++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (type != new_type) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lex->offset = offset;
|
||||
|
||||
if (token_start && offset > token_start) {
|
||||
strref_set(&token->text, token_start, offset-token_start);
|
||||
token->type = type;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void lexer_getstroffset(const struct lexer *lex, const char *str,
|
||||
uint32_t *row, uint32_t *col)
|
||||
{
|
||||
uint32_t cur_col = 1, cur_row = 1;
|
||||
const char *text = lex->text;
|
||||
|
||||
if (!str)
|
||||
return;
|
||||
|
||||
while (text < str) {
|
||||
if (is_newline(*text)) {
|
||||
text += newline_size(text)-1;
|
||||
cur_col = 1;
|
||||
cur_row++;
|
||||
} else {
|
||||
cur_col++;
|
||||
}
|
||||
|
||||
text++;
|
||||
}
|
||||
|
||||
*row = cur_row;
|
||||
*col = cur_col;
|
||||
}
|
|
@ -0,0 +1,294 @@
|
|||
/******************************************************************************
|
||||
Copyright (c) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 LEXER_H
|
||||
#define LEXER_H
|
||||
|
||||
#include "c99defs.h"
|
||||
#include "dstr.h"
|
||||
#include "darray.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* string reference (string segment within an already existing array) */
|
||||
|
||||
struct strref {
|
||||
const char *array;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
static inline void strref_clear(struct strref *dst)
|
||||
{
|
||||
dst->array = NULL;
|
||||
dst->len = 0;
|
||||
}
|
||||
|
||||
static inline void strref_set(struct strref *dst, const char *array, size_t len)
|
||||
{
|
||||
dst->array = array;
|
||||
dst->len = len;
|
||||
}
|
||||
|
||||
static inline void strref_copy(struct strref *dst, const struct strref *src)
|
||||
{
|
||||
dst->array = src->array;
|
||||
dst->len = src->len;
|
||||
}
|
||||
|
||||
static inline void strref_add(struct strref *dst, const struct strref *t)
|
||||
{
|
||||
if (!dst->array)
|
||||
strref_copy(dst, t);
|
||||
else
|
||||
dst->len += t->len;
|
||||
}
|
||||
|
||||
static inline bool strref_isempty(const struct strref *str)
|
||||
{
|
||||
if (!str->array || !str->len)
|
||||
return true;
|
||||
if (!*str->array)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
EXPORT int strref_cmp(const struct strref *str1, const char *str2);
|
||||
EXPORT int strref_cmpi(const struct strref *str1, const char *str2);
|
||||
EXPORT int strref_cmp_strref(const struct strref *str1,
|
||||
const struct strref *str2);
|
||||
EXPORT int strref_cmpi_strref(const struct strref *str1,
|
||||
const struct strref *str2);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
EXPORT bool valid_int_str(const char *str, size_t n);
|
||||
EXPORT bool valid_float_str(const char *str, size_t n);
|
||||
|
||||
static inline bool valid_int_strref(const struct strref *str)
|
||||
{
|
||||
return valid_int_str(str->array, str->len);
|
||||
}
|
||||
|
||||
static inline bool valid_float_strref(const struct strref *str)
|
||||
{
|
||||
return valid_float_str(str->array, str->len);
|
||||
}
|
||||
|
||||
static inline bool is_whitespace(char ch)
|
||||
{
|
||||
return ch == ' ' || ch == '\r' || ch == '\t' || ch == '\n';
|
||||
}
|
||||
|
||||
static inline bool is_newline(char ch)
|
||||
{
|
||||
return ch == '\r' || ch == '\n';
|
||||
}
|
||||
|
||||
static inline bool is_space_or_tab(const char ch)
|
||||
{
|
||||
return ch == ' ' || ch == '\t';
|
||||
}
|
||||
|
||||
static inline bool is_newline_pair(char ch1, char ch2)
|
||||
{
|
||||
return (ch1 == '\r' && ch2 == '\n') ||
|
||||
(ch1 == '\n' && ch2 == '\r');
|
||||
}
|
||||
|
||||
static inline int newline_size(const char *array)
|
||||
{
|
||||
if (strncmp(array, "\r\n", 2) == 0 || strncmp(array, "\n\r", 2) == 0)
|
||||
return 2;
|
||||
else if (*array == '\r' || *array == '\n')
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* A "base" token is one of four things:
|
||||
* 1.) A sequence of alpha characters
|
||||
* 2.) A sequence of numeric characters
|
||||
* 3.) A single whitespace character if whitespace is not ignored
|
||||
* 4.) A single character that does not fall into the above 3 categories
|
||||
*/
|
||||
|
||||
enum base_token_type {
|
||||
BASETOKEN_NONE,
|
||||
BASETOKEN_ALPHA,
|
||||
BASETOKEN_DIGIT,
|
||||
BASETOKEN_WHITESPACE,
|
||||
BASETOKEN_OTHER,
|
||||
};
|
||||
|
||||
struct base_token {
|
||||
struct strref text;
|
||||
enum base_token_type type;
|
||||
bool passed_whitespace;
|
||||
};
|
||||
|
||||
static inline void base_token_clear(struct base_token *t)
|
||||
{
|
||||
memset(t, 0, sizeof(struct base_token));
|
||||
}
|
||||
|
||||
static inline void base_token_copy(struct base_token *dst,
|
||||
struct base_token *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(struct base_token));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#define LEVEL_ERROR 0
|
||||
#define LEVEL_WARNING 1
|
||||
|
||||
struct error_item {
|
||||
char *error;
|
||||
const char *file;
|
||||
uint32_t row, column;
|
||||
int level;
|
||||
};
|
||||
|
||||
static inline void error_item_init(struct error_item *ei)
|
||||
{
|
||||
memset(ei, 0, sizeof(struct error_item));
|
||||
}
|
||||
|
||||
static inline void error_item_free(struct error_item *ei)
|
||||
{
|
||||
bfree(ei->error);
|
||||
error_item_init(ei);
|
||||
}
|
||||
|
||||
static inline void error_item_array_free(struct error_item *array, size_t num)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < num; i++)
|
||||
error_item_free(array+i);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
struct error_data {
|
||||
DARRAY(struct error_item) errors;
|
||||
};
|
||||
|
||||
static inline void error_data_init(struct error_data *data)
|
||||
{
|
||||
da_init(data->errors);
|
||||
}
|
||||
|
||||
static inline void error_data_free(struct error_data *data)
|
||||
{
|
||||
error_item_array_free(data->errors.array, data->errors.num);
|
||||
da_free(data->errors);
|
||||
}
|
||||
|
||||
static inline const struct error_item *error_data_item(struct error_data *ed,
|
||||
size_t idx)
|
||||
{
|
||||
return ed->errors.array+idx;
|
||||
}
|
||||
|
||||
EXPORT char *error_data_buildstring(struct error_data *ed);
|
||||
|
||||
EXPORT void error_data_add(struct error_data *ed, const char *file,
|
||||
uint32_t row, uint32_t column, const char *msg, int level);
|
||||
|
||||
static inline size_t error_data_type_count(struct error_data *ed,
|
||||
int type)
|
||||
{
|
||||
size_t count = 0, i;
|
||||
for (i = 0; i < ed->errors.num; i++) {
|
||||
if (ed->errors.array[i].level == type)
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static inline bool error_data_has_errors(struct error_data *ed)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < ed->errors.num; i++)
|
||||
if (ed->errors.array[i].level == LEVEL_ERROR)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
struct lexer {
|
||||
char *text;
|
||||
const char *offset;
|
||||
};
|
||||
|
||||
static inline void lexer_init(struct lexer *lex)
|
||||
{
|
||||
memset(lex, 0, sizeof(struct lexer));
|
||||
}
|
||||
|
||||
static inline void lexer_free(struct lexer *lex)
|
||||
{
|
||||
bfree(lex->text);
|
||||
lexer_init(lex);
|
||||
}
|
||||
|
||||
static inline void lexer_start(struct lexer *lex, const char *text)
|
||||
{
|
||||
lexer_free(lex);
|
||||
lex->text = bstrdup(text);
|
||||
lex->offset = lex->text;
|
||||
}
|
||||
|
||||
static inline void lexer_start_move(struct lexer *lex, char *text)
|
||||
{
|
||||
lexer_free(lex);
|
||||
lex->text = text;
|
||||
lex->offset = lex->text;
|
||||
}
|
||||
|
||||
static inline void lexer_reset(struct lexer *lex)
|
||||
{
|
||||
lex->offset = lex->text;
|
||||
}
|
||||
|
||||
EXPORT bool lexer_getbasetoken(struct lexer *lex, struct base_token *t,
|
||||
bool ignore_whitespace);
|
||||
|
||||
EXPORT void lexer_getstroffset(const struct lexer *lex, const char *str,
|
||||
uint32_t *row, uint32_t *col);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,139 @@
|
|||
/******************************************************************************
|
||||
Copyright (c) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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.
|
||||
******************************************************************************/
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <windows.h>
|
||||
#include "base.h"
|
||||
#include "platform.h"
|
||||
#include "bmem.h"
|
||||
|
||||
static bool have_clockfreq = false;
|
||||
static LARGE_INTEGER clock_freq;
|
||||
static uint32_t winver = 0;
|
||||
|
||||
static inline uint64_t get_clockfreq(void)
|
||||
{
|
||||
if (!have_clockfreq)
|
||||
QueryPerformanceFrequency(&clock_freq);
|
||||
return clock_freq.QuadPart;
|
||||
}
|
||||
|
||||
static inline uint32_t get_winver(void)
|
||||
{
|
||||
if (!winver) {
|
||||
OSVERSIONINFO osvi;
|
||||
memset(&osvi, 0, sizeof(osvi));
|
||||
winver = (osvi.dwMajorVersion << 16) | (osvi.dwMinorVersion);
|
||||
}
|
||||
|
||||
return winver;
|
||||
}
|
||||
|
||||
void *os_dlopen(const char *path)
|
||||
{
|
||||
wchar_t *wpath;
|
||||
HMODULE h_library = NULL;
|
||||
|
||||
os_utf8_to_wcs(path, 0, &wpath);
|
||||
h_library = LoadLibraryW(wpath);
|
||||
bfree(wpath);
|
||||
|
||||
if (!h_library)
|
||||
blog(LOG_INFO, "LoadLibrary failed for '%s', error: %u",
|
||||
path, GetLastError());
|
||||
|
||||
return h_library;
|
||||
}
|
||||
|
||||
void *os_dlsym(void *module, const char *func)
|
||||
{
|
||||
return (void*)GetProcAddress(module, func);
|
||||
}
|
||||
|
||||
void os_dlclose(void *module)
|
||||
{
|
||||
FreeLibrary(module);
|
||||
}
|
||||
|
||||
void os_sleepto_ns(uint64_t time_target)
|
||||
{
|
||||
uint64_t t = os_gettime_ns();
|
||||
uint32_t milliseconds;
|
||||
|
||||
if (t >= time_target)
|
||||
return;
|
||||
|
||||
milliseconds = (uint32_t)((time_target - t)/1000000);
|
||||
if (milliseconds > 1)
|
||||
os_sleep_ms(milliseconds);
|
||||
|
||||
for (;;) {
|
||||
t = os_gettime_ns();
|
||||
if (t >= time_target)
|
||||
return;
|
||||
|
||||
#if 1
|
||||
Sleep(1);
|
||||
#else
|
||||
Sleep(0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void os_sleep_ms(uint32_t duration)
|
||||
{
|
||||
/* windows 8+ appears to have decreased sleep precision */
|
||||
if (get_winver() >= 0x0602 && duration > 0)
|
||||
duration--;
|
||||
|
||||
Sleep(duration);
|
||||
}
|
||||
|
||||
uint64_t os_gettime_ns(void)
|
||||
{
|
||||
LARGE_INTEGER current_time;
|
||||
double time_val;
|
||||
|
||||
QueryPerformanceCounter(¤t_time);
|
||||
time_val = (double)current_time.QuadPart;
|
||||
time_val *= 1000000000.0;
|
||||
time_val /= (double)get_clockfreq();
|
||||
|
||||
return (uint64_t)time_val;
|
||||
}
|
||||
|
||||
uint64_t os_gettime_ms(void)
|
||||
{
|
||||
LARGE_INTEGER current_time;
|
||||
uint64_t time_val;
|
||||
|
||||
QueryPerformanceCounter(¤t_time);
|
||||
time_val = current_time.QuadPart;
|
||||
time_val *= 1000;
|
||||
time_val /= get_clockfreq();
|
||||
|
||||
return time_val;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,305 @@
|
|||
/******************************************************************************
|
||||
Copyright (c) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include "c99defs.h"
|
||||
#include "platform.h"
|
||||
#include "bmem.h"
|
||||
#include "utf8.h"
|
||||
#include "dstr.h"
|
||||
|
||||
FILE *os_wfopen(const wchar_t *path, const char *mode)
|
||||
{
|
||||
FILE *file;
|
||||
#ifdef _MSC_VER
|
||||
wchar_t *wcs_mode;
|
||||
|
||||
os_utf8_to_wcs(mode, 0, &wcs_mode);
|
||||
file = _wfopen(path, wcs_mode);
|
||||
bfree(wcs_mode);
|
||||
#else
|
||||
char *mbs_path;
|
||||
|
||||
os_wcs_to_utf8(path, 0, &mbs_path);
|
||||
file = fopen(mbs_path, mode);
|
||||
bfree(mbs_path);
|
||||
#endif
|
||||
return file;
|
||||
}
|
||||
|
||||
FILE *os_fopen(const char *path, const char *mode)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
wchar_t *wpath = NULL;
|
||||
FILE *file = NULL;
|
||||
os_utf8_to_wcs(path, 0, &wpath);
|
||||
file = os_wfopen(wpath, mode);
|
||||
bfree(wpath);
|
||||
|
||||
return file;
|
||||
#else
|
||||
return fopen(path, mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
off_t os_fgetsize(FILE *file)
|
||||
{
|
||||
off_t cur_offset = ftello(file);
|
||||
off_t size;
|
||||
int errval = 0;
|
||||
|
||||
if (fseeko(file, 0, SEEK_END) == -1)
|
||||
return -1;
|
||||
|
||||
size = ftello(file);
|
||||
if (size == -1)
|
||||
errval = errno;
|
||||
|
||||
if (fseeko(file, cur_offset, SEEK_SET) != 0 && errval != 0)
|
||||
errno = errval;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t os_fread_mbs(FILE *file, char **pstr)
|
||||
{
|
||||
off_t size = 0;
|
||||
size_t len = 0;
|
||||
|
||||
fseeko(file, 0, SEEK_END);
|
||||
size = ftello(file);
|
||||
|
||||
if (size > 0) {
|
||||
char *mbstr = bmalloc(size+1);
|
||||
|
||||
fseeko(file, 0, SEEK_SET);
|
||||
fread(mbstr, 1, size, file);
|
||||
mbstr[size] = 0;
|
||||
len = os_mbs_to_utf8(mbstr, size, pstr);
|
||||
bfree(mbstr);
|
||||
} else {
|
||||
*pstr = NULL;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t os_fread_utf8(FILE *file, char **pstr)
|
||||
{
|
||||
off_t size = 0;
|
||||
size_t len = 0;
|
||||
|
||||
fseeko(file, 0, SEEK_END);
|
||||
size = ftello(file);
|
||||
|
||||
if (size > 0) {
|
||||
char bom[3];
|
||||
char *utf8str = bmalloc(size+1);
|
||||
off_t offset;
|
||||
|
||||
/* remove the ghastly BOM if present */
|
||||
fseeko(file, 0, SEEK_SET);
|
||||
fread(bom, 1, 3, file);
|
||||
offset = (astrcmp_n(bom, "\xEF\xBB\xBF", 3) == 0) ? 3 : 0;
|
||||
|
||||
fseeko(file, offset, SEEK_SET);
|
||||
fread(utf8str, 1, size, file);
|
||||
utf8str[size] = 0;
|
||||
|
||||
*pstr = utf8str;
|
||||
} else {
|
||||
*pstr = NULL;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
char *os_quick_read_mbs_file(const char *path)
|
||||
{
|
||||
FILE *f = os_fopen(path, "rb");
|
||||
char *file_string = NULL;
|
||||
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
os_fread_mbs(f, &file_string);
|
||||
fclose(f);
|
||||
|
||||
return file_string;
|
||||
}
|
||||
|
||||
char *os_quick_read_utf8_file(const char *path)
|
||||
{
|
||||
FILE *f = os_fopen(path, "rb");
|
||||
char *file_string = NULL;
|
||||
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
os_fread_utf8(f, &file_string);
|
||||
fclose(f);
|
||||
|
||||
return file_string;
|
||||
}
|
||||
|
||||
bool os_quick_write_mbs_file(const char *path, const char *str, size_t len)
|
||||
{
|
||||
FILE *f = os_fopen(path, "wb");
|
||||
char *mbs = NULL;
|
||||
size_t mbs_len = 0;
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
mbs_len = os_utf8_to_mbs(str, len, &mbs);
|
||||
if (mbs_len)
|
||||
fwrite(mbs, 1, mbs_len, f);
|
||||
bfree(mbs);
|
||||
fclose(f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool os_quick_write_utf8_file(const char *path, const char *str, size_t len,
|
||||
bool marker)
|
||||
{
|
||||
FILE *f = os_fopen(path, "wb");
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
if (marker)
|
||||
fwrite("\xEF\xBB\xBF", 1, 3, f);
|
||||
if (len)
|
||||
fwrite(str, 1, len, f);
|
||||
fclose(f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t os_mbs_to_wcs(const char *str, size_t len, wchar_t **pstr)
|
||||
{
|
||||
size_t out_len = mbstowcs(NULL, str, len);
|
||||
wchar_t *dst = NULL;
|
||||
|
||||
if (len) {
|
||||
dst = bmalloc((out_len+1) * sizeof(wchar_t));
|
||||
mbstowcs(dst, str, out_len+1);
|
||||
dst[out_len] = 0;
|
||||
}
|
||||
|
||||
*pstr = dst;
|
||||
return out_len;
|
||||
}
|
||||
|
||||
size_t os_utf8_to_wcs(const char *str, size_t len, wchar_t **pstr)
|
||||
{
|
||||
size_t in_len = len ? len : strlen(str);
|
||||
size_t out_len = utf8_to_wchar(str, in_len, NULL, 0, 0);
|
||||
wchar_t *dst = NULL;
|
||||
|
||||
if (out_len) {
|
||||
dst = bmalloc((out_len+1) * sizeof(wchar_t));
|
||||
utf8_to_wchar(str, in_len, dst, out_len+1, 0);
|
||||
dst[out_len] = 0;
|
||||
}
|
||||
|
||||
*pstr = dst;
|
||||
return out_len;
|
||||
}
|
||||
|
||||
size_t os_wcs_to_mbs(const wchar_t *str, size_t len, char **pstr)
|
||||
{
|
||||
size_t out_len = wcstombs(NULL, str, len);
|
||||
char *dst = NULL;
|
||||
|
||||
if (len) {
|
||||
dst = bmalloc(out_len+1);
|
||||
wcstombs(dst, str, out_len+1);
|
||||
dst[out_len] = 0;
|
||||
}
|
||||
|
||||
*pstr = dst;
|
||||
return out_len;
|
||||
}
|
||||
|
||||
size_t os_wcs_to_utf8(const wchar_t *str, size_t len, char **pstr)
|
||||
{
|
||||
size_t in_len = wcslen(str);
|
||||
size_t out_len = wchar_to_utf8(str, in_len, NULL, 0, 0);
|
||||
char *dst = NULL;
|
||||
|
||||
if (out_len) {
|
||||
dst = bmalloc(out_len+1);
|
||||
wchar_to_utf8(str, in_len, dst, out_len+1, 0);
|
||||
dst[out_len] = 0;
|
||||
}
|
||||
|
||||
*pstr = dst;
|
||||
return out_len;
|
||||
}
|
||||
|
||||
size_t os_utf8_to_mbs(const char *str, size_t len, char **pstr)
|
||||
{
|
||||
wchar_t *wstr = NULL;
|
||||
char *dst = NULL;
|
||||
size_t wlen = os_utf8_to_wcs(str, len, &wstr);
|
||||
size_t out_len = os_wcs_to_mbs(wstr, wlen, &dst);
|
||||
|
||||
bfree(wstr);
|
||||
*pstr = dst;
|
||||
|
||||
return out_len;
|
||||
}
|
||||
|
||||
size_t os_mbs_to_utf8(const char *str, size_t len, char **pstr)
|
||||
{
|
||||
wchar_t *wstr = NULL;
|
||||
char *dst = NULL;
|
||||
size_t wlen = os_mbs_to_wcs(str, len, &wstr);
|
||||
size_t out_len = os_wcs_to_utf8(wstr, wlen, &dst);
|
||||
|
||||
bfree(wstr);
|
||||
*pstr = dst;
|
||||
|
||||
return out_len;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
int fseeko(FILE *stream, off_t offset, int whence)
|
||||
{
|
||||
#if _FILE_OFFSET_BITS == 64
|
||||
return _fseeki64(stream, offset, whence);
|
||||
#else
|
||||
return fseek(stream, offset, whence);
|
||||
#endif /* _FILE_OFFSET_BITS == 64 */
|
||||
}
|
||||
|
||||
off_t ftello(FILE *stream)
|
||||
{
|
||||
#if _FILE_OFFSET_BITS == 64
|
||||
return _ftelli64(stream);
|
||||
#else
|
||||
return ftell(stream);
|
||||
#endif /* _FILE_OFFSET_BITS == 64 */
|
||||
}
|
||||
#endif /* _MSC_VER */
|
|
@ -0,0 +1,82 @@
|
|||
/******************************************************************************
|
||||
Copyright (c) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 PLATFORM_H
|
||||
#define PLATFORM_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
#include <sys/types.h>
|
||||
#include "c99defs.h"
|
||||
|
||||
/*
|
||||
* Platform-independent functions for Accessing files, encoding, DLLs,
|
||||
* sleep, timer, and timing.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
EXPORT FILE *os_wfopen(const wchar_t *path, const char *mode);
|
||||
EXPORT FILE *os_fopen(const char *path, const char *mode);
|
||||
EXPORT off_t os_fgetsize(FILE *file);
|
||||
|
||||
EXPORT size_t os_fread_mbs(FILE *file, char **pstr);
|
||||
EXPORT size_t os_fread_utf8(FILE *file, char **pstr);
|
||||
|
||||
/* functions purely for convenience */
|
||||
EXPORT char *os_quick_read_utf8_file(const char *path);
|
||||
EXPORT bool os_quick_write_utf8_file(const char *path, const char *str,
|
||||
size_t len, bool marker);
|
||||
|
||||
EXPORT size_t os_mbs_to_wcs(const char *str, size_t len, wchar_t **pstr);
|
||||
EXPORT size_t os_utf8_to_wcs(const char *str, size_t len, wchar_t **pstr);
|
||||
EXPORT size_t os_wcs_to_mbs(const wchar_t *str, size_t len, char **pstr);
|
||||
EXPORT size_t os_wcs_to_utf8(const wchar_t *str, size_t len, char **pstr);
|
||||
|
||||
EXPORT size_t os_utf8_to_mbs(const char *str, size_t len, char **pstr);
|
||||
EXPORT size_t os_mbs_to_utf8(const char *str, size_t len, char **pstr);
|
||||
|
||||
EXPORT void *os_dlopen(const char *path);
|
||||
EXPORT void *os_dlsym(void *module, const char *func);
|
||||
EXPORT void os_dlclose(void *module);
|
||||
|
||||
EXPORT void os_sleepto_ns(uint64_t time_target);
|
||||
EXPORT void os_sleep_ms(uint32_t duration);
|
||||
|
||||
EXPORT uint64_t os_gettime_ns(void);
|
||||
EXPORT uint64_t os_gettime_ms(void);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
EXPORT int fseeko(FILE *stream, off_t offset, int whence);
|
||||
EXPORT off_t ftello(FILE *stream);
|
||||
#endif
|
||||
|
||||
#define strtoll _strtoi64
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,128 @@
|
|||
/******************************************************************************
|
||||
Copyright (c) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 SERIALIZER_H
|
||||
#define SERIALIZER_H
|
||||
|
||||
/*
|
||||
* General programmable serialization functions. (A shared interface to
|
||||
* various reading/writing to/from different inputs/outputs)
|
||||
*
|
||||
* TODO: Not currently implemented
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum serialize_seek_type {
|
||||
SERIALIZE_SEEK_START,
|
||||
SERIALIZE_SEEK_CURRENT,
|
||||
SERIALIZE_SEEK_END
|
||||
};
|
||||
|
||||
struct serializer {
|
||||
void *param;
|
||||
size_t (*serialize)(struct serializer, void *, size_t);
|
||||
uint64_t (*seek)(struct serializer, int64_t, enum serialize_seek_type);
|
||||
uint64_t (*getpos)(struct serializer);
|
||||
};
|
||||
|
||||
static inline size_t serialize(struct serializer *s, void *data, size_t len)
|
||||
{
|
||||
if (s->serialize)
|
||||
return s->serialize(s, data, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline uint64_t serializer_seek(struct serializer *s, int64_t offset,
|
||||
enum serialize_seek_type seek_type)
|
||||
{
|
||||
if (s->seek)
|
||||
return s->seek(s, offset, seek_type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline uint64_t serializer_getpos(struct serializer *s)
|
||||
{
|
||||
if (s->getpos)
|
||||
return s->getpos(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void serializer_write_u8(struct serializer *s, uint8_t u8)
|
||||
{
|
||||
serialize(s, &u8, sizeof(uint8_t));
|
||||
}
|
||||
|
||||
static inline void serializer_write_i8(struct serializer *s, int8_t i8)
|
||||
{
|
||||
serialize(s, &i8, sizeof(int8_t));
|
||||
}
|
||||
|
||||
static inline void serializer_write_u16(struct serializer *s, uint16_t u16)
|
||||
{
|
||||
serialize(s, &u16, sizeof(uint16_t));
|
||||
}
|
||||
|
||||
static inline void serializer_write_i16(struct serializer *s, int16_t i16)
|
||||
{
|
||||
serialize(s, &i16, sizeof(int16_t));
|
||||
}
|
||||
|
||||
static inline void serializer_write_u32(struct serializer *s, uint32_t u32)
|
||||
{
|
||||
serialize(s, &u32, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
static inline void serializer_write_i32(struct serializer *s, int32_t i32)
|
||||
{
|
||||
serialize(s, &i32, sizeof(int32_t));
|
||||
}
|
||||
|
||||
static inline void serializer_write_u64(struct serializer *s, uint32_t u64)
|
||||
{
|
||||
serialize(s, &u64, sizeof(uint64_t));
|
||||
}
|
||||
|
||||
static inline void serializer_write_i64(struct serializer *s, int32_t i64)
|
||||
{
|
||||
serialize(s, &i64, sizeof(int64_t));
|
||||
}
|
||||
|
||||
static inline void serializer_write_float(struct serializer *s, float f)
|
||||
{
|
||||
serialize(s, &f, sizeof(float));
|
||||
}
|
||||
|
||||
static inline void serializer_write_double(struct serializer *s, double d)
|
||||
{
|
||||
serialize(s, &d, sizeof(double));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,371 @@
|
|||
/******************************************************************************
|
||||
Copyright (c) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
||||
|
||||
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 "dstr.h"
|
||||
#include "darray.h"
|
||||
#include "text-lookup.h"
|
||||
#include "lexer.h"
|
||||
#include "platform.h"
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
struct text_leaf {
|
||||
char *lookup, *value;
|
||||
};
|
||||
|
||||
static inline void text_leaf_free(struct text_leaf *leaf)
|
||||
{
|
||||
bfree(leaf->lookup);
|
||||
bfree(leaf->value);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
struct text_node {
|
||||
struct dstr str;
|
||||
struct darray subnodes; /* struct text_node * */
|
||||
struct text_leaf *leaf;
|
||||
};
|
||||
|
||||
static void text_node_destroy(struct text_node *node)
|
||||
{
|
||||
struct text_node **subnodes;
|
||||
size_t i;
|
||||
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
subnodes = node->subnodes.array;
|
||||
dstr_free(&node->str);
|
||||
for (i = 0; i < node->subnodes.num; i++)
|
||||
text_node_destroy(subnodes[i]);
|
||||
if (node->leaf)
|
||||
text_leaf_free(node->leaf);
|
||||
darray_free(&node->subnodes);
|
||||
bfree(node);
|
||||
}
|
||||
|
||||
static struct text_node *text_node_bychar(struct text_node *node, char ch)
|
||||
{
|
||||
size_t i;
|
||||
struct text_node **subnodes = node->subnodes.array;
|
||||
|
||||
for (i = 0; i < node->subnodes.num; i++) {
|
||||
struct text_node *child = subnodes[i];
|
||||
if (!dstr_isempty(&child->str) && child->str.array[0] == ch)
|
||||
return child;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct text_node *text_node_byname(struct text_node *node,
|
||||
const char *name)
|
||||
{
|
||||
size_t i;
|
||||
struct text_node **subnodes = node->subnodes.array;
|
||||
|
||||
for (i = 0; i < node->subnodes.num; i++) {
|
||||
struct text_node *child = subnodes[i];
|
||||
if (astrcmpi_n(child->str.array, name, child->str.len) == 0)
|
||||
return child;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void text_node_removesubnode(struct text_node *node,
|
||||
struct text_node *child, size_t idx)
|
||||
{
|
||||
darray_erase(sizeof(struct text_node*), &node->subnodes, idx);
|
||||
text_node_destroy(child);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
struct text_lookup {
|
||||
struct dstr language;
|
||||
struct text_node *top;
|
||||
};
|
||||
|
||||
static void lookup_createsubnode(const char *lookup_val,
|
||||
struct text_leaf *leaf, struct text_node *node)
|
||||
{
|
||||
struct text_node *new = bmalloc(sizeof(struct text_node));
|
||||
memset(new, 0, sizeof(struct text_node));
|
||||
|
||||
new->leaf = leaf;
|
||||
dstr_copy(&new->str, lookup_val);
|
||||
|
||||
darray_push_back(sizeof(struct text_node*), &new->subnodes, &new);
|
||||
}
|
||||
|
||||
static void lookup_splitnode(const char *lookup_val, size_t len,
|
||||
struct text_leaf *leaf, struct text_node *node)
|
||||
{
|
||||
struct text_node *split = bmalloc(sizeof(struct text_node));
|
||||
memset(split, 0, sizeof(struct text_node));
|
||||
|
||||
dstr_copy(&split->str, node->str.array+len);
|
||||
split->leaf = node->leaf;
|
||||
darray_move(&split->subnodes, &node->subnodes);
|
||||
|
||||
dstr_resize(&node->str, len);
|
||||
darray_push_back(sizeof(struct text_node), &node->subnodes, &split);
|
||||
|
||||
if (lookup_val[len] != 0) {
|
||||
node->leaf = NULL;
|
||||
lookup_createsubnode(lookup_val+len, leaf, node);
|
||||
} else {
|
||||
node->leaf = leaf;
|
||||
}
|
||||
}
|
||||
|
||||
static bool lookup_addstring(const char *lookup_val, struct text_leaf *leaf,
|
||||
struct text_node *node)
|
||||
{
|
||||
struct text_node *child;
|
||||
|
||||
if (!lookup_val || !*lookup_val)
|
||||
return false;
|
||||
|
||||
child = text_node_bychar(node, *lookup_val);
|
||||
if (child) {
|
||||
size_t len;
|
||||
|
||||
for (len = 0; len < child->str.len; len++) {
|
||||
char val1 = child->str.array[len],
|
||||
val2 = lookup_val[len];
|
||||
|
||||
if (val1 >= 'A' && val1 <= 'Z')
|
||||
val1 += 0x20;
|
||||
if (val2 >= 'A' && val2 <= 'Z')
|
||||
val2 += 0x20;
|
||||
|
||||
if (val1 != val2)
|
||||
break;
|
||||
}
|
||||
|
||||
if (len == child->str.len)
|
||||
return lookup_addstring(lookup_val+len, leaf, child);
|
||||
else
|
||||
lookup_splitnode(lookup_val, len, leaf, child);
|
||||
} else {
|
||||
lookup_createsubnode(lookup_val, leaf, child);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void lookup_getstringtoken(struct lexer *lex, struct strref *token)
|
||||
{
|
||||
const char *temp = lex->offset;
|
||||
bool was_backslash = false;
|
||||
|
||||
while (*temp != 0 && *temp != '\n') {
|
||||
if (!was_backslash) {
|
||||
if (*temp == '\\') {
|
||||
was_backslash = true;
|
||||
} else if (*temp == '"') {
|
||||
++temp;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
was_backslash = false;
|
||||
}
|
||||
|
||||
++temp;
|
||||
}
|
||||
|
||||
token->len += temp - lex->offset - 1; /* include starting " char */
|
||||
lex->offset = temp;
|
||||
}
|
||||
|
||||
static bool lookup_gettoken(struct lexer *lex, struct strref *str)
|
||||
{
|
||||
struct base_token temp;
|
||||
|
||||
base_token_clear(&temp);
|
||||
strref_clear(str);
|
||||
|
||||
while (lexer_getbasetoken(lex, &temp, false)) {
|
||||
char ch = *temp.text.array;
|
||||
|
||||
if (!str->array) {
|
||||
/* comments are designated with a #, and end at LF */
|
||||
if (ch == '#') {
|
||||
while(ch != '\n' && ch != 0)
|
||||
ch = *(++lex->offset);
|
||||
} else {
|
||||
strref_copy(str, &temp.text);
|
||||
}
|
||||
} else {
|
||||
if (temp.type == BASETOKEN_WHITESPACE) {
|
||||
lex->offset -= temp.text.len;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ch == '"') {
|
||||
lookup_getstringtoken(lex, str);
|
||||
break;
|
||||
} else if (ch == '#') {
|
||||
lex->offset--;
|
||||
break;
|
||||
}
|
||||
|
||||
str->len += temp.text.len;
|
||||
}
|
||||
}
|
||||
|
||||
return (str->len != 0);
|
||||
}
|
||||
|
||||
static inline bool lookup_goto_nextline(struct lexer *p)
|
||||
{
|
||||
struct strref val;
|
||||
bool success = true;
|
||||
|
||||
strref_clear(&val);
|
||||
|
||||
while (true) {
|
||||
if (!lookup_gettoken(p, &val)) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
if (*val.array == '\n')
|
||||
break;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static void lookup_addfiledata(struct text_lookup *lookup,
|
||||
const char *file_data)
|
||||
{
|
||||
struct lexer lex;
|
||||
struct strref name, value;
|
||||
|
||||
lexer_start(&lex, file_data);
|
||||
strref_clear(&name);
|
||||
strref_clear(&value);
|
||||
|
||||
while (lookup_gettoken(&lex, &name)) {
|
||||
struct text_leaf *leaf;
|
||||
bool got_eq = false;
|
||||
|
||||
if (*name.array == '\n')
|
||||
continue;
|
||||
getval:
|
||||
if (!lookup_gettoken(&lex, &value))
|
||||
break;
|
||||
if (*value.array == '\n')
|
||||
continue;
|
||||
else if (!got_eq && *value.array == '=') {
|
||||
got_eq = true;
|
||||
goto getval;
|
||||
}
|
||||
|
||||
leaf = bmalloc(sizeof(struct text_leaf));
|
||||
leaf->lookup = bstrdup_n(name.array, name.len);
|
||||
leaf->value = bstrdup_n(value.array, value.len);
|
||||
|
||||
lookup_addstring(leaf->lookup, leaf, lookup->top);
|
||||
|
||||
if (!lookup_goto_nextline(&lex))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool lookup_getstring(const char *lookup_val,
|
||||
const char **out, struct text_node *node)
|
||||
{
|
||||
struct text_node *child;
|
||||
char ch;
|
||||
|
||||
if (!node)
|
||||
return false;
|
||||
|
||||
child = text_node_byname(node, lookup_val);
|
||||
if (!child)
|
||||
return false;
|
||||
|
||||
lookup_val += child->str.len;
|
||||
ch = *lookup_val;
|
||||
if (ch)
|
||||
return lookup_getstring(lookup_val, out, child);
|
||||
|
||||
if (!child->leaf)
|
||||
return false;
|
||||
|
||||
*out = child->leaf->value;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
lookup_t text_lookup_create(const char *path)
|
||||
{
|
||||
struct text_lookup *lookup;
|
||||
struct dstr file_str;
|
||||
char *temp = NULL;
|
||||
FILE *file;
|
||||
|
||||
file = os_fopen(path, "rb");
|
||||
if (!file)
|
||||
return NULL;
|
||||
|
||||
os_fread_utf8(file, &temp);
|
||||
dstr_init_move_array(&file_str, temp);
|
||||
fclose(file);
|
||||
|
||||
if (!file_str.array)
|
||||
return NULL;
|
||||
|
||||
lookup = bmalloc(sizeof(struct text_lookup));
|
||||
memset(lookup, 0, sizeof(struct text_lookup));
|
||||
|
||||
lookup->top = bmalloc(sizeof(struct text_node));
|
||||
memset(lookup->top, 0, sizeof(struct text_node));
|
||||
|
||||
dstr_replace(&file_str, "\r", " ");
|
||||
lookup_addfiledata(lookup, file_str.array);
|
||||
dstr_free(&file_str);
|
||||
|
||||
return lookup;
|
||||
}
|
||||
|
||||
void text_lookup_destroy(lookup_t lookup)
|
||||
{
|
||||
if (lookup) {
|
||||
dstr_free(&lookup->language);
|
||||
text_node_destroy(lookup->top);
|
||||
|
||||
bfree(lookup);
|
||||
}
|
||||
}
|
||||
|
||||
bool text_lookup_getstr(lookup_t lookup, const char *lookup_val,
|
||||
const char **out)
|
||||
{
|
||||
return lookup_getstring(lookup_val, out, lookup->top);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue