Added Uq-Ruan Masters game - it compiles but does not work (renders too slowly? Another problem?)

This commit is contained in:
pelya
2010-08-21 18:57:13 +03:00
parent ffec83a679
commit 629f5b51f1
882 changed files with 230562 additions and 0 deletions

View File

@@ -0,0 +1,204 @@
We worship these two higher beings for making the original, legendary game:
Fred Ford
Paul Reiche III
The Ur-Quan Masters port:
-------------------------
Core team (in alphabetical order):
Serge van den Boom <svdb@stack.nl>
Mika Kolehmainen <mk@kapsi.fi>
Michael Chapman Martin <mcmartin@gmail.com>
Chris Nelson <chris@toysforbob.com>
Alex Volkov <codepro@usa.net>
Additional programming (in alphabetical order):
Geoffrey Hausheer <uqm-devel@phracturedblue.com>
Nicolas Simonds <uqm@submedia.net>
Music remixers (in alphabetical order):
Jouni Airaksinen <markvera@spacesynth.net>
Tore Aune Fjellstad
Espen Gätzschmann
Aaron J. Grier <agrier@poofygoof.com>
Dan Nicholson <dan@kosmic.org>
George Nowik <norgio@attbi.com>
Riku Nuottajärvi <riku.nuottajarvi@pp.inet.fi>
Erol Otus <erol@toysforbob.com>
Other contributions (in alphabetical order):
Jouni Airaksinen <markvera@spacesynth.net> (Startup Menu)
Karl Bartel <karlb@gmx.net>
Travis Chase <cftc@shaw.ca> (BeOS port)
Felix Lazarev <felix@freedo.org> (3DO internals)
Parker MacMillan
Sanjay Madhav <madhav@usc.edu> (code patches)
Robert McNamara <robert@americantenor.com> (MacOS X stuff)
Mike Melanson (ADPCM basis from FFmpeg used for DUK audio)
Mudrony Laszlo <mudronyl@dragon.klte.hu> (PC/DOS content unpacking)
Erol Otus <erol@toysforbob.com> (Splash screen)
Brian Rogers <burpmaster@truffula.net>
Horatiu Romosan <hory@post.ro> (v0.1 Win32 installer)
Zarla Sheenaza <astronia@aol.com> (0.6 Win32 installer graphics)
Joffrey Smith (setup graphics)
Peter van Valderen <p.vanvalderen@chello.nl>
Alex Volkov <codepro@usa.net> (additional slides)
Alexander Waseleski <Paxtez@hotmail.com> (code patches)
Yukki (v0.1 Win32 installer graphics)
Original game:
--------------
Programming & technology:
Fred Ford
Game design and fiction:
Paul Reiche III
3DO programming:
Ken Ford
Fred Ford
Brad Van Tighem
Producer (3DO version):
Mark Wallace
3DO production:
Paul Reiche III
Richard Antaki
Starring the voices of:
Richard Antaki ....... Thraddash
Alex Bennett ......... Starbase Commander
Rich Betz ............ Ariloulaleelay
............ Druuge
Roy Blumenfeld ....... Zoq-Fot-Pik
David Bryce .......... Kohr-Ah
.......... Ilwrath
.......... Shofixti
.......... Spathi
Lauren Forcella ...... Supox
Greg Johnson ......... Orz
......... Pkunk
......... Utwig
Bruce Leyland ........ Yehat
Erol Otus ............ Chmmr
Paul Reiche III ...... Mycon
...... Talking Pet
Brad Van Tighem ...... Slylandro Speaker
Madeleine Wild ....... Zoq-Fot-Pik
....... Syreen
....... VUX
Larry Zee ............ Umgah
............ Melnorme
............ Ur-Quan
840-AV ............... Slylandro Probe
Paul II, Paul III .... Victory Sequence
Arianna & Devin Reiche
Voice effects:
Jeff Forehan
Burke Treischmann
Mark Miller
Voice editing:
Richard Antaki
Paul Reiche III
Burke Treischmann
Steve Henefin
Jeremy Bredow
Erik Griss
Brad Van Tighem
Art and animation:
George Barr
Paul Reiche III
Erol Otus
Greg Johnson
Kyle Balda
Jeff Rianda
Taunya Shiffer
Leonard Robel
Greg Hammond
Armand Cabrera
Silicon Knights
Additional writing:
Greg Johnson
Mat Genser
Robert Leyland
Iain McCaig
Tomi Quintana
Erol Otus
Leonard Robel
John Estes
Music:
Burke Treischmann
Dan Nicholson
Riku Nuottajärvi
Eric Berge
Erol Otus
Marc Brown
Aaron Grier
Kevin Palivec
Tommy Dunbar
3D cinemagraphics:
Gene Bodio
Phil Le Marbre
TrueMotion(R) "S" Video Compression by The Duck Corporation
Product marketing manager (3DO version):
Jim Curry
3DO testers:
Susan Michele
Jeremy Bredow
Wes Gittens
Ty Johnson
Tate Schieferle
Carolina Esmurdoc
Rob Johnson
Kevin Kwan
Joe Ganis
Chang Fadel
Erik Griss
Eugene Law
Mark Ybarra
Steve Groll
Tim Jordan
Matt Young
PC/DOS testers:
Pam Levins
Tomi Quintana
Joel Dinolt
Robert Daly
Greg Hammond
B.J. Shea
Robert Leyland
Sean Vikoren
Mike Ebert
Tony Hsieh
ROL
Ed Gwynn
Akila Redmer
Russell Bornschlegel
Steve Graziano
Mark Voorsanger
Special thanks to:
Greg Johnson
John Ratcliffe
Paul's Foundation:
Laurie
Devin
and Arianna
Got us 86'ed out of a restaurant in Las Vegas:
Madeline Canepa (we love her anyway)

View File

@@ -0,0 +1,21 @@
AppSettingVersion=4
LibSdlVersion=1.2
AppName="Ur-Quan Masters"
AppFullName=com.sourceforge.sc2
ScreenOrientation=h
AppDataDownloadUrl="Main game data is 11 Mb|-http://prdownloads.sourceforge.net/sc2/uqm-0.6.0-content.uqm?download^3DO music (19 Mb)|-http://prdownloads.sourceforge.net/sc2/uqm-0.6.0-3domusic.uqm?download^UQM music remix pack 1 (50 Mb)|-http://prdownloads.sourceforge.net/sc2/uqm-remix-pack1.zip?download^UQM music remix pack 2 (60 Mb)|-http://prdownloads.sourceforge.net/sc2/uqm-remix-pack2.zip?download^UQM music remix pack 3 (40 Mb)|-http://prdownloads.sourceforge.net/sc2/uqm-remix-pack3.zip?download^Voice (115 Mb)|http://prdownloads.sourceforge.net/sc2/uqm-0.6.0-voice.uqm?download"
SdlVideoResize=y
NeedDepthBuffer=n
AppUsesMouse=n
AppNeedsArrowKeys=y
AppUsesJoystick=n
AppUsesMultitouch=n
RedefinedKeys="RETURN RCTRL KP_PLUS KP_MINUS ESCAPE F10"
AppTouchscreenKeyboardKeysAmount=2
MultiABI=n
AppVersionCode=1001
AppVersionName="1.0.01"
CompiledLibraries="sdl_image"
AppCflags='-O0 -DTHREADLIB_SDL=1 -DTIMELIB=SDL -DOVCODEC_TREMOR=1 -DNETPLAY=1 -DHAVE_REGEX=1 -DHAVE_GETOPT_LONG=1'
AppLdflags='-Lbin/ndk/local/armeabi -ltremor'
ReadmeText='^You may press "Home" now - the data will be downloaded in background'

View File

@@ -0,0 +1,5 @@
All known bugs and missing features are listed in our online bug database,
which can be found at
http://bugs.uqm.stack.nl/
New bugs that you may find can be reported at the same location.

View File

@@ -0,0 +1,944 @@
The Ur-Quan Masters
Copyright (C) 1992, 2002 Toys for Bob, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be entertaining,
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. A copy of the
General Public License is included at the end of this document.
The content -- voiceovers, dialogue, graphics, sounds, and music --
are copyright (C) 1992, 1993, 2002 Toys for Bob, Inc. or their
respective creators. The content may be used freely under the
terms of the Creative Commons Attribution-NonCommercial-ShareAlike
2.5 license (included below, and also available at
http://creativecommons.org/licenses/by-nc-sa/2.5/). The content
may also be copied freely as part of a distribution of The Ur-Quan
Masters.
The documentation -- excluding documentation that is part of the
code or otherwise clearly governed by the preceding licenses --
may be used freely under the terms of the Creative Commons
Attribution 2.0 license (included below, and also available at
http://creativecommons.org/licenses/by/2.0/).
----------------------------------------------------------------------------
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
----------------------------------------------------------------------------
CREATIVE COMMONS LICENSE
Attribution-NonCommercial-ShareAlike 2.5
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL
SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT
RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS"
BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION
PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE.
License
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE
COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY
COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS
AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE
TO BE BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS YOU THE
RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND
CONDITIONS.
1. Definitions
a. "Collective Work" means a work, such as a periodical issue,
anthology or encyclopedia, in which the Work in its entirety in
unmodified form, along with a number of other contributions,
constituting separate and independent works in themselves, are
assembled into a collective whole. A work that constitutes a
Collective Work will not be considered a Derivative Work (as
defined below) for the purposes of this License.
b. "Derivative Work" means a work based upon the Work or upon the
Work and other pre-existing works, such as a translation,
musical arrangement, dramatization, fictionalization, motion
picture version, sound recording, art reproduction, abridgment,
condensation, or any other form in which the Work may be recast,
transformed, or adapted, except that a work that constitutes a
Collective Work will not be considered a Derivative Work for the
purpose of this License. For the avoidance of doubt, where the
Work is a musical composition or sound recording, the
synchronization of the Work in timed-relation with a moving
image ("synching") will be considered a Derivative Work for the
purpose of this License.
c. "Licensor" means the individual or entity that offers the Work
under the terms of this License.
d. "Original Author" means the individual or entity who created the
Work.
e. "Work" means the copyrightable work of authorship offered under
the terms of this License.
f. "You" means an individual or entity exercising rights under this
License who has not previously violated the terms of this
License with respect to the Work, or who has received express
permission from the Licensor to exercise rights under this
License despite a previous violation.
g. "License Elements" means the following high-level license
attributes as selected by Licensor and indicated in the title of
this License: Attribution, Noncommercial, ShareAlike.
2. Fair Use Rights. Nothing in this license is intended to reduce,
limit, or restrict any rights arising from fair use, first sale or
other limitations on the exclusive rights of the copyright owner
under copyright law or other applicable laws.
3. License Grant. Subject to the terms and conditions of this License,
Licensor hereby grants You a worldwide, royalty-free,
non-exclusive, perpetual (for the duration of the applicable
copyright) license to exercise the rights in the Work as stated
below:
a. to reproduce the Work, to incorporate the Work into one or more
Collective Works, and to reproduce the Work as incorporated in
the Collective Works;
b. to create and reproduce Derivative Works;
c. to distribute copies or phonorecords of, display publicly,
perform publicly, and perform publicly by means of a digital
audio transmission the Work including as incorporated in
Collective Works;
d. to distribute copies or phonorecords of, display publicly,
perform publicly, and perform publicly by means of a digital
audio transmission Derivative Works;
The above rights may be exercised in all media and formats whether
now known or hereafter devised. The above rights include the right
to make such modifications as are technically necessary to exercise
the rights in other media and formats. All rights not expressly
granted by Licensor are hereby reserved, including but not limited
to the rights set forth in Sections 4(e) and 4(f).
4. Restrictions.
The license granted in Section 3 above is expressly made subject to and
limited by the following restrictions:
a. You may distribute, publicly display, publicly perform, or
publicly digitally perform the Work only under the terms of this
License, and You must include a copy of, or the Uniform Resource
Identifier for, this License with every copy or phonorecord of
the Work You distribute, publicly display, publicly perform, or
publicly digitally perform. You may not offer or impose any
terms on the Work that alter or restrict the terms of this
License or the recipients' exercise of the rights granted
hereunder. You may not sublicense the Work. You must keep intact
all notices that refer to this License and to the disclaimer of
warranties. You may not distribute, publicly display, publicly
perform, or publicly digitally perform the Work with any
technological measures that control access or use of the Work in
a manner inconsistent with the terms of this License
Agreement. The above applies to the Work as incorporated in a
Collective Work, but this does not require the Collective Work
apart from the Work itself to be made subject to the terms of
this License. If You create a Collective Work, upon notice from
any Licensor You must, to the extent practicable, remove from
the Collective Work any credit as required by clause 4(d), as
requested. If You create a Derivative Work, upon notice from any
Licensor You must, to the extent practicable, remove from the
Derivative Work any credit as required by clause 4(d), as
requested.
b. You may distribute, publicly display, publicly perform, or
publicly digitally perform a Derivative Work only under the
terms of this License, a later version of this License with the
same License Elements as this License, or a Creative Commons
iCommons license that contains the same License Elements as this
License (e.g. Attribution-NonCommercial-ShareAlike 2.5
Japan). You must include a copy of, or the Uniform Resource
Identifier for, this License or other license specified in the
previous sentence with every copy or phonorecord of each
Derivative Work You distribute, publicly display, publicly
perform, or publicly digitally perform. You may not offer or
impose any terms on the Derivative Works that alter or restrict
the terms of this License or the recipients' exercise of the
rights granted hereunder, and You must keep intact all notices
that refer to this License and to the disclaimer of
warranties. You may not distribute, publicly display, publicly
perform, or publicly digitally perform the Derivative Work with
any technological measures that control access or use of the
Work in a manner inconsistent with the terms of this License
Agreement. The above applies to the Derivative Work as
incorporated in a Collective Work, but this does not require the
Collective Work apart from the Derivative Work itself to be made
subject to the terms of this License.
c. You may not exercise any of the rights granted to You in Section
3 above in any manner that is primarily intended for or directed
toward commercial advantage or private monetary
compensation. The exchange of the Work for other copyrighted
works by means of digital file-sharing or otherwise shall not be
considered to be intended for or directed toward commercial
advantage or private monetary compensation, provided there is no
payment of any monetary compensation in connection with the
exchange of copyrighted works.
d. If you distribute, publicly display, publicly perform, or
publicly digitally perform the Work or any Derivative Works or
Collective Works, You must keep intact all copyright notices for
the Work and provide, reasonable to the medium or means You are
utilizing: (i) the name of the Original Author (or pseudonym, if
applicable) if supplied, and/or (ii) if the Original Author
and/or Licensor designate another party or parties (e.g. a
sponsor institute, publishing entity, journal) for attribution
in Licensor's copyright notice, terms of service or by other
reasonable means, the name of such party or parties; the title
of the Work if supplied; to the extent reasonably practicable,
the Uniform Resource Identifier, if any, that Licensor specifies
to be associated with the Work, unless such URI does not refer
to the copyright notice or licensing information for the Work;
and in the case of a Derivative Work, a credit identifying the
use of the Work in the Derivative Work (e.g., "French
translation of the Work by Original Author," or "Screenplay
based on original Work by Original Author"). Such credit may be
implemented in any reasonable manner; provided, however, that in
the case of a Derivative Work or Collective Work, at a minimum
such credit will appear where any other comparable authorship
credit appears and in a manner at least as prominent as such
other comparable authorship credit.
e. For the avoidance of doubt, where the Work is a musical composition:
i. Performance Royalties Under Blanket Licenses. Licensor
reserves the exclusive right to collect, whether
individually or via a performance rights society
(e.g. ASCAP, BMI, SESAC), royalties for the public
performance or public digital performance (e.g. webcast)
of the Work if that performance is primarily intended for
or directed toward commercial advantage or private
monetary compensation.
ii. Mechanical Rights and Statutory Royalties. Licensor
reserves the exclusive right to collect, whether
individually or via a music rights agency or designated
agent (e.g. Harry Fox Agency), royalties for any
phonorecord You create from the Work ("cover version")
and distribute, subject to the compulsory license created
by 17 USC Section 115 of the US Copyright Act (or the
equivalent in other jurisdictions), if Your distribution
of such cover version is primarily intended for or
directed toward commercial advantage or private monetary
compensation.
f. Webcasting Rights and Statutory Royalties. For the avoidance of
doubt, where the Work is a sound recording, Licensor reserves
the exclusive right to collect, whether individually or via a
performance-rights society (e.g. SoundExchange), royalties for
the public digital performance (e.g. webcast) of the Work,
subject to the compulsory license created by 17 USC Section 114
of the US Copyright Act (or the equivalent in other
jurisdictions), if Your public digital performance is primarily
intended for or directed toward commercial advantage or private
monetary compensation.
5. Representations, Warranties and Disclaimer
UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING,
LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR
WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED,
STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF
TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE,
NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY,
OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT
DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED
WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
6. Limitation on Liability.
EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL
LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL,
INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT
OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
7. Termination
a. This License and the rights granted hereunder will terminate
automatically upon any breach by You of the terms of this
License. Individuals or entities who have received Derivative
Works or Collective Works from You under this License, however,
will not have their licenses terminated provided such
individuals or entities remain in full compliance with those
licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any
termination of this License.
b. Subject to the above terms and conditions, the license granted
here is perpetual (for the duration of the applicable copyright
in the Work). Notwithstanding the above, Licensor reserves the
right to release the Work under different license terms or to
stop distributing the Work at any time; provided, however that
any such election will not serve to withdraw this License (or
any other license that has been, or is required to be, granted
under the terms of this License), and this License will continue
in full force and effect unless terminated as stated above.
8. Miscellaneous
a. Each time You distribute or publicly digitally perform the Work
or a Collective Work, the Licensor offers to the recipient a
license to the Work on the same terms and conditions as the
license granted to You under this License.
b. Each time You distribute or publicly digitally perform a
Derivative Work, Licensor offers to the recipient a license to
the original Work on the same terms and conditions as the
license granted to You under this License.
c. If any provision of this License is invalid or unenforceable
under applicable law, it shall not affect the validity or
enforceability of the remainder of the terms of this License,
and without further action by the parties to this agreement,
such provision shall be reformed to the minimum extent necessary
to make such provision valid and enforceable.
d. No term or provision of this License shall be deemed waived and
no breach consented to unless such waiver or consent shall be in
writing and signed by the party to be charged with such waiver
or consent.
e. This License constitutes the entire agreement between the
parties with respect to the Work licensed here. There are no
understandings, agreements or representations with respect to
the Work not specified here. Licensor shall not be bound by any
additional provisions that may appear in any communication from
You. This License may not be modified without the mutual written
agreement of the Licensor and You.
Creative Commons is not a party to this License, and makes no warranty
whatsoever in connection with the Work. Creative Commons will not be
liable to You or any party on any legal theory for any damages
whatsoever, including without limitation any general, special,
incidental or consequential damages arising in connection to this
license. Notwithstanding the foregoing two (2) sentences, if Creative
Commons has expressly identified itself as the Licensor hereunder, it
shall have all rights and obligations of Licensor.
Except for the limited purpose of indicating to the public that the
Work is licensed under the CCPL, neither party will use the trademark
"Creative Commons" or any related trademark or logo of Creative
Commons without the prior written consent of Creative Commons. Any
permitted use will be in compliance with Creative Commons'
then-current trademark usage guidelines, as may be published on its
website or otherwise made available upon request from time to time.
Creative Commons may be contacted at http://creativecommons.org/.
----------------------------------------------------------------------
CREATIVE COMMONS LICENSE ATTRIBUTION-2.0
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR
DAMAGES RESULTING FROM ITS USE.
License
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS
CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS
PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE
WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS
PROHIBITED.
BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND
AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS
YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF
SUCH TERMS AND CONDITIONS.
1. Definitions
a. "Collective Work" means a work, such as a periodical issue,
anthology or encyclopedia, in which the Work in its entirety in
unmodified form, along with a number of other contributions,
constituting separate and independent works in themselves, are
assembled into a collective whole. A work that constitutes a
Collective Work will not be considered a Derivative Work (as
defined below) for the purposes of this License.
b. "Derivative Work" means a work based upon the Work or upon the
Work and other pre-existing works, such as a translation,
musical arrangement, dramatization, fictionalization, motion
picture version, sound recording, art reproduction, abridgment,
condensation, or any other form in which the Work may be recast,
transformed, or adapted, except that a work that constitutes a
Collective Work will not be considered a Derivative Work for the
purpose of this License. For the avoidance of doubt, where the
Work is a musical composition or sound recording, the
synchronization of the Work in timed-relation with a moving
image ("synching") will be considered a Derivative Work for the
purpose of this License.
c. "Licensor" means the individual or entity that offers the Work
under the terms of this License.
d. "Original Author" means the individual or entity who created the
Work.
e. "Work" means the copyrightable work of authorship offered under
the terms of this License.
f. "You" means an individual or entity exercising rights under this
License who has not previously violated the terms of this
License with respect to the Work, or who has received express
permission from the Licensor to exercise rights under this
License despite a previous violation.
2. Fair Use Rights. Nothing in this license is intended to reduce,
limit, or restrict any rights arising from fair use, first sale or
other limitations on the exclusive rights of the copyright owner
under copyright law or other applicable laws.
3. License Grant. Subject to the terms and conditions of this License,
Licensor hereby grants You a worldwide, royalty-free,
non-exclusive, perpetual (for the duration of the applicable
copyright) license to exercise the rights in the Work as stated
below:
a. to reproduce the Work, to incorporate the Work into one or more
Collective Works, and to reproduce the Work as incorporated in
the Collective Works;
b. to create and reproduce Derivative Works;
c. to distribute copies or phonorecords of, display publicly,
perform publicly, and perform publicly by means of a digital
audio transmission the Work including as incorporated in
Collective Works;
d. to distribute copies or phonorecords of, display publicly,
perform publicly, and perform publicly by means of a digital
audio transmission Derivative Works.
e. For the avoidance of doubt, where the work is a musical
composition:
i. Performance Royalties Under Blanket Licenses. Licensor
waives the exclusive right to collect, whether
individually or via a performance rights society
(e.g. ASCAP, BMI, SESAC), royalties for the public
performance or public digital performance (e.g. webcast)
of the Work.
ii. Mechanical Rights and Statutory Royalties. Licensor
waives the exclusive right to collect, whether
individually or via a music rights agency or designated
agent (e.g. Harry Fox Agency), royalties for any
phonorecord You create from the Work ("cover version")
and distribute, subject to the compulsory license created
by 17 USC Section 115 of the US Copyright Act (or the
equivalent in other jurisdictions).
f. Webcasting Rights and Statutory Royalties. For the avoidance of
doubt, where the Work is a sound recording, Licensor waives the
exclusive right to collect, whether individually or via a
performance-rights society (e.g. SoundExchange), royalties for
the public digital performance (e.g. webcast) of the Work,
subject to the compulsory license created by 17 USC Section 114
of the US Copyright Act (or the equivalent in other
jurisdictions).
The above rights may be exercised in all media and formats whether
now known or hereafter devised. The above rights include the right
to make such modifications as are technically necessary to exercise
the rights in other media and formats. All rights not expressly
granted by Licensor are hereby reserved.
4. Restrictions. The license granted in Section 3 above is expressly
made subject to and limited by the following restrictions:
a. You may distribute, publicly display, publicly perform, or
publicly digitally perform the Work only under the terms of this
License, and You must include a copy of, or the Uniform Resource
Identifier for, this License with every copy or phonorecord of
the Work You distribute, publicly display, publicly perform, or
publicly digitally perform. You may not offer or impose any
terms on the Work that alter or restrict the terms of this
License or the recipients' exercise of the rights granted
hereunder. You may not sublicense the Work. You must keep intact
all notices that refer to this License and to the disclaimer of
warranties. You may not distribute, publicly display, publicly
perform, or publicly digitally perform the Work with any
technological measures that control access or use of the Work in
a manner inconsistent with the terms of this License
Agreement. The above applies to the Work as incorporated in a
Collective Work, but this does not require the Collective Work
apart from the Work itself to be made subject to the terms of
this License. If You create a Collective Work, upon notice from
any Licensor You must, to the extent practicable, remove from
the Collective Work any reference to such Licensor or the
Original Author, as requested. If You create a Derivative Work,
upon notice from any Licensor You must, to the extent
practicable, remove from the Derivative Work any reference to
such Licensor or the Original Author, as requested.
b. If you distribute, publicly display, publicly perform, or
publicly digitally perform the Work or any Derivative Works or
Collective Works, You must keep intact all copyright notices for
the Work and give the Original Author credit reasonable to the
medium or means You are utilizing by conveying the name (or
pseudonym if applicable) of the Original Author if supplied; the
title of the Work if supplied; to the extent reasonably
practicable, the Uniform Resource Identifier, if any, that
Licensor specifies to be associated with the Work, unless such
URI does not refer to the copyright notice or licensing
information for the Work; and in the case of a Derivative Work,
a credit identifying the use of the Work in the Derivative Work
(e.g., "French translation of the Work by Original Author," or
"Screenplay based on original Work by Original Author"). Such
credit may be implemented in any reasonable manner; provided,
however, that in the case of a Derivative Work or Collective
Work, at a minimum such credit will appear where any other
comparable authorship credit appears and in a manner at least as
prominent as such other comparable authorship credit.
5. Representations, Warranties and Disclaimer. UNLESS OTHERWISE
MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK
AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND
CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE,
INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY,
FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF
LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF
ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW
THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY
TO YOU.
6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY
APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY
LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE
OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE
WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
7. Termination
a. This License and the rights granted hereunder will terminate
automatically upon any breach by You of the terms of this
License. Individuals or entities who have received Derivative
Works or Collective Works from You under this License, however,
will not have their licenses terminated provided such
individuals or entities remain in full compliance with those
licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any
termination of this License.
b. Subject to the above terms and conditions, the license granted
here is perpetual (for the duration of the applicable copyright
in the Work). Notwithstanding the above, Licensor reserves the
right to release the Work under different license terms or to
stop distributing the Work at any time; provided, however that
any such election will not serve to withdraw this License (or
any other license that has been, or is required to be, granted
under the terms of this License), and this License will continue
in full force and effect unless terminated as stated above.
8. Miscellaneous
a. Each time You distribute or publicly digitally perform the Work
or a Collective Work, the Licensor offers to the recipient a
license to the Work on the same terms and conditions as the
license granted to You under this License.
b. Each time You distribute or publicly digitally perform a
Derivative Work, Licensor offers to the recipient a license to
the original Work on the same terms and conditions as the
license granted to You under this License.
c. If any provision of this License is invalid or unenforceable
under applicable law, it shall not affect the validity or
enforceability of the remainder of the terms of this License,
and without further action by the parties to this agreement,
such provision shall be reformed to the minimum extent necessary
to make such provision valid and enforceable.
d. No term or provision of this License shall be deemed waived and
no breach consented to unless such waiver or consent shall be in
writing and signed by the party to be charged with such waiver
or consent.
e. This License constitutes the entire agreement between the
parties with respect to the Work licensed here. There are no
understandings, agreements or representations with respect to
the Work not specified here. Licensor shall not be bound by any
additional provisions that may appear in any communication from
You. This License may not be modified without the mutual written
agreement of the Licensor and You.
Creative Commons is not a party to this License, and makes no warranty
whatsoever in connection with the Work. Creative Commons will not be
liable to You or any party on any legal theory for any damages
whatsoever, including without limitation any general, special,
incidental or consequential damages arising in connection to this
license. Notwithstanding the foregoing two (2) sentences, if Creative
Commons has expressly identified itself as the Licensor hereunder, it
shall have all rights and obligations of Licensor.
Except for the limited purpose of indicating to the public that the
Work is licensed under the CCPL, neither party will use the trademark
"Creative Commons" or any related trademark or logo of Creative
Commons without the prior written consent of Creative Commons. Any
permitted use will be in compliance with Creative Commons'
then-current trademark usage guidelines, as may be published on its
website or otherwise made available upon request from time to time.
Creative Commons may be contacted at http://creativecommons.org/.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,135 @@
These are some guidelines for people who want to contribute to the code.
Don't be surprised if your contributions get tossed in the bit-bucket if you
do not follow them. We don't want to be unfriendly, but our time is limited.
These guidelines are there so that you won't waste both our and your time.
Before making changes:
- Read this entire document
- See if the the Bugzilla bug database at
http://bugs.uqm.stack.nl/ contains any comments on what you're planning
to do.
- Make sure you're using the most recent Subversion version
- Discuss in advance what you're planning to do, with the core team.
The best place to do this is on #sc2 on irc.freenode.net.
This prevents you from wasting your time when
- someone else is already working on your issue
- we've got a very clear idea of how we want it to be
- the code you're planning to change will be completely rewritten
in the near future.
- Don't bother on adding "great ideas" you have for the game;
Our current goal is a straight port. The code is GPL, so feel free
to start your own modified version, but don't bother sending them
in for the official version.
Making changes:
- Follow the coding style of the existing source. You don't have to like it,
we don't even always do, but we've accepted this as our standard. The main
reason is that this is very close to the original style.
Trying to start a discussion about the standard is pointless and is
definately NOT appreciated.
- Use 1 tab per indentation level
- Use no more than 76 chars on a line, when using a tabsize of 4.
- Use 2 extra indentation levels for the continuation of a broken line,
like this:
if (blablablabla || foobar ||
zut || linefiller ||
morezut)
printf ("Yeah!\n");
- Don't use tabs for anything but indenting. If you would, and someone
has a different tab size, or something in the line changes, other stuff
on the line may or may not move, depending on where on the line it is.
If you for instance want to align a list of declarations, use spaces,
like this:
{
<TAB>long l,
<TAB> m;
<TAB>int i;
}
(Though in this particular case, I personally would repeat the 'long',
or place l and m on the same line)
- Put { on a seperate line, both for the start of a function and
for the start of a block.
- one space around binary operators, and after commas.
- one space between the function name and following '(', both in
declaration and call (unusual as it is).
- one space after 'if', 'while', 'do', 'for' and 'switch'.
- even for short selections or repetitions, don't have the statement
to execute on the same line as the guard. So:
if (a)
a--;
- Use unix-style line-endings, that is '\n' only. If the editor you're
using doesn't support this, please pass your code through a conversion
program before submitting.
- Don't hurry into changing code. All code is there for a reason. Be sure
you understand that reason before changing it. Don't just go recode a part
because you think that would be easier than trying to understand the
original. If you don't have the skills or patience to do so, this is not
the place for you.
- Only use portable functions. The code is intended to work on Windows,
Linux, FreeBSD, BeOS and MacOS X.
Try to avoid unnecessary system-dependant code, but use #ifdefs if you
really have to.
- No shortcuts. Don't assume anything about user input (like the length),
and check the return values of functions that may fail.
- Your code shouldn't cause any compile-time or runtime-warnings. We know
the current source is far from warning-free, but those should be removed
eventually and we don't want to make it worse.
- Don't add comment lines saying things like "This line added by <me>".
These comments only foul the code and don't add anything for people
reading it. You'll still be credited in the Changelog, and for large
contributions (or many small ones) in the authors list. We have
Subversion for when we need to find out when what changes were made.
Making the patches:
- One issue per patch.
We need to keep track of what's being changed, and multiple changes
in one patch will make that more difficult.
Also, we might want to accept one patch, and reject the other.
- Use unified diffs.
That way, there's a bigger chance the patch can be automatically applied
successfully against modified files.
- Make the patches against the current Subversion tree.
Test the patches:
- If possible, test your changes both on Windows and a *nix platform, or
send them to someone to test them for you.
Getting the patches committed:
- Either attach the patches to the appropriate bug report in the Bugzilla
bug database or send them to one of the committers, in plain-text format.
This can be done by email, DCC from within the #sc2 channel, or by
mentioning an URL where we can get the patch.
The committers are listed below (in alphabetical order), with their
particular field of expertise with the source. Though all of us
should have enough experience to deal with most issues not explicitely
mentioned.
Serge van den Boom (svdb at stack.nl), Meep-Eep at #sc2
- Resource system
- 3DO historical code
- *nix build system
- Netplay
- General issues (particularly on *nix)
Mika Kolehmainen (mk at kapsi.fi), Gwl at #sc2
- Graphics
- Sound
- General issues
Michael Martin (mcmartin at stanford.edu), McMartin at #sc2
- Threading
- Alien communications code
- Graphics
- Input system
- In-game configuration
- General issues
Alex Volkov (codepro at usa.net), fOSSiL at #sc2
- Graphics
- Sound (particularly MixSDL)
- General issues
- Only submit code that can be used under the GPL. By submitting code you
hold the copyright to, you agree that it can be used under the term of
the GPL. If you use code by someone else, make sure that it can be used
under the GPL and let us know, so that adequate credit can be given.
Initial version of this file by Serge van den Boom, 2002-12-05.

View File

@@ -0,0 +1,21 @@
You're looking at the readme for 'The Ur-Quan Masters', a volunteer
project that intends to bring the classic game 'Star Control II' to
modern systems.
The program code that comprises 'The Ur-Quan Masters' was derived from code
written by Toys for Bob, Inc. for the 3DO version of 'Star Control II', with
their permission and encouragement.
If you've got this file from the source tree, you can find everything
you need to get started in INSTALL (INSTALL.mingw for MinGW) and
doc/users/unixinstall.
The home page of the project is located at http://sc2.sourceforge.net/
You can find links to downloads, our bug database, and our forum there.
Have fun!
Star Control II is a registered trademark of Accolade, Inc.
All other trademarks and tradenames belong to their respective owners.

View File

@@ -0,0 +1,370 @@
This file tries to organize and describe the changes between releases.
Changes are broadly classified into the following categories:
- New Features: These are either elements of the original games that
were first implemented in this release, or actually new capabilities
that are visible to the user.
- Bugfixes: The removal of visible Bad Things from the code.
- Internal Changes: The removal of invisible Bad Things from the code,
or changes in the way the program itself is structured. These are
unlikely to be of interest to you unless you plan on coding
extensions.
Version 0.6
-------------
NEW FEATURES
- Netplay! You can now engage in Super Melee over the Internet.
- Key configuration is now entirely in-game.
- UQM now compiles and runs on 64-bit systems.
BUGFIXES
- The Quit button (F10) now works properly when used during the
introduction sequence.
- Various small fixes to text and conversation logic.
INTERNAL CHANGES
- The setup menu now reads all its text from the content, easing
translation.
- The MOD player for PC-style music can now be linked against an
external version of libmikmod.
- Various code cleanups and memory optimizations.
Version 0.5
-------------
NEW FEATURES
- The Starmap is searchable! Type / then the beginning of the
constellation name, and you can tab through all possible
completions.
- New 'hq' scaler, based on Maxim Stepin's "HQ2X" scaler. See
www.hiend3d.com/hq2x.html for more details.
- Scalers can use MMX/SSE/3DNow! instructions for significant speed
improvements. The "Processor pack" is necessary for compilation of
same on VC6.
- Imported DOS versions of many graphics; these have richer palettes
and so generally look better
- There's a proper credit roll at the end of the game now.
- Superior Planet handling: topographical maps scaled far more
precisely; optional 3DO-style throbbing slave shield; planets are
finally rotating spheres instead of spotlit cylinders or rectangles.
The old PC-style "Entering Planetary Orbit..." screen is back.
- Setup Menu far more complete and easy to use, and selections made in
the Setup Menu will actually persist when you restart the program
- Added support for the Tremor Ogg Vorbis decoder (avoids floating point
math)
- Home, End and BackSpace keys work as you'd expect in text input.
- Most of the game works with Unicode properly now, and so, with proper
font characters installed, will work with non-Latin alphabets. (On
Windows, Unicode input requires a very recent version of SDL.)
- Text may be input with the joystick again, as on the 3DO. The
available characters are stored in content/lbm/joyalpha.txt.
- The intro now plays only when a new game is started.
- Color depth is now determined entirely automatically.
BUGFIXES
- Only SELECT and CANCEL trigger the fade-to-black at the end of a
Super Melee, solving the issue of invisible "Really Quit?" menus for
Super Melee. The "quit during fades" problem in general is still
extant.
- Many dialog, and comm animation, and general graphical fixes
- Keypress status is not reset when entering battle mode, so (for
instance) Melnorme ships can continue to charge a shot across
battles.
- The Melnorme would occasionally strip off Plot Points as part of a
fuel deal. No longer.
- Bugs in the original code prevented certain ships from properly
spawning in "uncontrolled" space. The "wilds" are now a bit wilder,
as apparently originally intended.
- Venus's atmospheric density was incorrectly corrected in the 3DO
version. It's been correctly corrected now.
- Scheduled plot events work properly, even when the game suddenly
skips ahead in time.
- Fixed version checking in unix build scripts. SDL 1.2.10 is now
recognised as newer than 1.2.9.
- Spliced communications can be safely skipped past now.
- Fixed fast escape weirdness (bug #619)
- Threading system no longer assumes that there is no thread 0; this
permits compilation on AmigaOS.
- Relative paths and fallback paths work properly now.
- Scalers now use surface pitch instead of image width - this is
reported to solve many strange display problems in non-OpenGL mode
on Macs
- Ending sequences may now be safely paused.
INTERNAL CHANGES
- Added the rest of devel/ and users/ documentation into MSVC .dsp
files.
- Control scheme upgraded. Old versions of keys.cfg will no longer
work.
- PNG transparency info (tRNS chunk) is now set properly, based on
info in the .ani files.
- Paletted images should render much faster now, and collisions
between mods are less likely.
- New font engine: fonts are loaded and treated as alpha-channel-only
images, with font effects handled as backing images.
- Melee works properly with alpha-channel graphics new, even when
mipmapped.
- Lander report drawing handled more sensibly now
- Binary resource indexes have been replaced with textual ones.
- All spritework is done internally in 32BPP.
- Removed MikMod i/o hacks.
- The temp files for representing star and group data are now kept in
memory instead.
- Separate config_win.h file for build.sh builds on Windows
- Lowered some animation rates to reasonable levels, lowering CPU
usage.
- Changed comm subtitle caching scheme. Should kill the "blue comm
screen" problem forever.
- Refactored setup menu code to use generic widgets.
- Cleaner build output. Set '$MAKE_VERBOSE' to 1 for old output.
- Improved dependency tracking for unix build system. "./build.sh uqm
depend" is now only needed for checking for new source files.
Version 0.4
-------------
NEW FEATURES
- Savegame slot defaults to the last one used during this play
- PC intro and ending sequence are now present
- 3DO intro and ending movies are supported for those who have these
movies from the 3DO CD of Star Control II
- Improved slave shield graphics
- Added a new -l option to produce logfiles
- Added a new 'triscan' scaler derived from scale2x
- Made the fact that self-destructing ships grant resources more obvious
- Added a "config dir" option for holding saves and melee information
- Cocoa hooks
- Setup menu now permits configuration of some options. They do not
yet persist past program quit, though.
- Added a "--version" option
- Melee images are now based on the (richer) DOS content
- 3-step melee zooming as per the PC version is now implemented
- It is now possible to complete the game without ever allying with the
Starbase (if one is insane; this is known on the forum as "Beating The
Game Differently" - but bugs and plot elements preventing this have been
fixed or evaded under this circumstance).
BUGFIXES
- Fixes to the Quit Confirmation dialog
- Collisions/encounters with "invisible" fleeing ships gone
- Other ships insystem remain in proper locations after planet landing
- Fixed some keyboard "focus" problems where flight controls were
being cleared at inappropriate times, or interfering with menus
- Graphics fixes
- Subtitle timings work in the absence of oggs
- Conversation summaries with Melnorme no longer crash
- --contentdir argument may now have spaces
- $HOME isn't required for Unix systems anymore
- Fuel estimates fixed (original bug)
- Fuel usage on planet landing now correcly reported on all versions
- MOD music will play on big-endian machines under high-quality now
- Space marines die in a self-destructing Scout
- ZFP speech is properly vertically aligned now
- Various odd behaviors when loading in HyperSpace now fixed
- Quitting from the Roster screen no longer crashes
- Many dialog fixes
- The "Blue Comm Screen" problem no longer occurs
- Combat Energy computation in Outfit Flagship screen corrected
- A game crash that manifested when pausing after 85 minutes has been
corrected
- Main menu version number drawn more consistently
- Transparency bugfixes - 3DO ending credits, planets in battle
- Content packs may also be named ".uqm" - these are really still
zip files, but you can't expand them by accident.
- One may now configure a joystick without crashing the game if the
joystick is not present
- Music volume normalized throughout the game
INTERNAL CHANGES
- Thread system completely reworked to provide more detailed thread
information, and to prevent resource leaks
- Sound code is now virtualized and separate from game logic
- Fine-grained control of menu sounds
- Input system fully unified - all parts of the game use the same
basic structure now
- Build scripts made more robust
- Window-drawing code was lifted out of confirm.c and made more general
- Lots of debugging functions
- Unicode support for game dialogs and fonts
- Lots of code cleanups
- Documentation of more internals
Version 0.3
-------------
NEW FEATURES
- PC-style shipyard graphics, complete with animated power lines
- Selling ships in the shipyards has slightly different controls
that make it harder to sell ships accidentally
- Main menu displays version number
- Added a '-g' option to control gamma correction
- Planet spin has been improved
- Trilinear (mipmap-based) scaling in melee
- PC-style conversation summaries have been implemented
- Ship location display in status bar matches original more closely
- Game flags (such as AWARE_OF_SAMATRA) that were ignored by half the
game (even in the original) now are more universally available
- Oscilloscope and Mini-Map have borders now
- Commander Hayes won't let you rescue him until he's explained his
predicament
- Confirmation dialogs are now menu-based
- Positional sound effects are available for OpenAL
- Delete key works on Super-Melee team editing
- Exit key from the Main Menu will quit the game
- Quit option available in GAME menu
- New Main Menu graphics: Setup (not yet implemented) and Quit are
options at the Main Menu now
- Cubic resampling in high quality audio mode
- PC-style alien outtakes when game is completed
- 2 more ship slots in melee, as the PC Star Control 2 had.
- All the standard melee teams from the Star Control 2 PC version.
- Support for 50 savegames, instead of just 10
- 'CREW'/'BATT' instead of icons in melee when using PC menus
BUGFIXES
- Text entry doesn't freeze up lander reports anymore
- VUX warps in at proper range
- Distance-based ship effects (Syreen, Slylandro, Kohr-Ah) were screen
size dependent
- Line clipping fixed
- Various communication animation glitches solved
- Various melee crashes solved
- Various race conditions eliminated
- Scaling of graphics is handled by the rendering thread now, solving
issues where the background and object scales would drift out of
sync
- Subtitle text is clipped more carefully
- Objects can no longer be scaled to total invisibility
- Various dialogue fixes
- Crossfade glitches eliminated
- Pause and Exit keys function properly everywhere
- Visit Count overflow with Yehat and Chmmr patched
- Wav loader and color transforms are now endian safe
- Menu glitches when leaving the "GAME" menu are gone
- Druuge transactions no longer baselessly increase crew cost
- Lander speed has been retimed to match 3DO
- Audio resampling works now correctly (less cracklings)
- MixSDL buffer underrun handling fixed
- Some memory leaks have been eliminated
- Fixes and speed improvements on bilinear, biadapt, biadv scalers
- Various minor graphics glitch fixes
- Crew death on planet is now counted properly in all cases
- Mouse cursor is now hidden in fullscreen mode
- Guardian in Blazer mode being drained by DOGI will no longer
result in a non-blazer Guardian with Blazer effects.
INTERNAL CHANGES
- Legacy graphics code stripped down tremendously, a lot of "poor
man's object orientation" has fallen away too. Many uses of
function pointers with only one possible value replaced with simple
direct calls.
- Crossfades require you to explicitly cache the screen before drawing
the transition target
- User Input code has been completely rewritten
- File I/O code has been completely rewritten
- Subtitle drawing is now cached as its own sprite; communication
screens are much less graphics intensive now
- DRAWABLE_DESC uses separately allocated arrays for its frames
Version 0.2
-------------
NEW FEATURES
- Planet info "coarse scan" information available and properly rendered,
either in 3DO way (symbols) or PC (text)
- 3D spinning planet in orbit window is present, with antialiasing and
phong lighting and an animated approach
- Pixel-perfect collision detection; Spathi/Mycon are thus playable, and
the game is now beatable
- Build system enhanced and generalized to handle OpenBSD and FreeBSD cleanly.
- Oscilloscope display works in communication now
- Color-shading in planet scans
- Earth with its slave shield now functions properly
- Outfit Starship and Shipyard graphics re-extracted
- Save data and temp files are put in a separate directory now
- Star sizes and colors are properly differentiated.
- Planet surface is smoothed, blurred, and randomized slightly when it's
magnified
- SIS Status window fully implemented (including gradiated fonts from PC
version)
- Dialogue "slider" shows how far along the speech is; rewind/forward works
- 'ESC' alone lets you emergency-warp-escape
- Optional PC version menus
- Preliminary support for MacOS X (needs more work)
BUGFIXES
- Melee screens cleaned up, SuperMelee menus work.
- Subtitles now render for all alien races
- Major editing of subtitles to match more closely the speeches
- Speech and subtitles are now synchronized properly
- Autopilot indicator doesn't take over the top of the screen anymore.
- Entering star systems on autopilot doesn't crash the system.
- Planet scan is properly erased when cancelling/landing
- Initial display of planet surface on landing is at correct position
- Spheres of influence now move correctly on the starmap
- Melnorme correctly compute the required additional credits
- Team names switching when selecting the next ship to fight in melee fixed
- Commas left dots behind on planetary reports; this is fixed
- Screen resets properly after loading/saving
- Dialog choices wrap properly
- Precursor ship crew count now placed correctly in melee
- 'Cued' color transforms in conversations occur at the right time now
- SIS correctly predicts its own fuel usage now
- Melnorme no longer give away fuel
- Flagship modules are properly aligned
- The PC soundtrack now loops correctly
- Lander upgrades were drawn incorrectly
- Autopilot now works in QuasiSpace without fuel
- Captain portraits in melee are updated properly now
- If you have over 1000 units of a resource, those numbers are properly
cleared
INTERNAL CHANGES
- SDL_mixer has been abandoned in favor of either OpenAL or the new
"MixSDL" library built on the basic SDL_audio routines
- Color transforms in communications are merged into the core animation
thread now, improving speed and stability
- Much more flexible handling of commandline options
- All allocated memory is allocated through 'safe' routines that abort if
the allocation fails.
- Thread library now includes condition variables
- Threads can tell the rendering thread to sleep until everything they've
requested is done
- The rendering thread has been recoded to use no heap space and to have a
far smaller memory footprint.
- Added a special #define, DCQ_OF_DOOM, which simulates severe overload
stresses.
- SAI and related scalers removed due to GPL incompatibilities; similar
algorithms reimplemented under GPL.
- Files for the intro and ending sequence have been successfully extracted
- Rendering thread routines are somewhat more modular than before
- Created a new set of graphics primitives that's much easier to use
- Only parts of the screen that actually changed are updated
- Input code rewritten entirely
- Various functions have their names changed to avoid conflicts with
core library routines on OS X
Version 0.1
-------------
Initial release.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -0,0 +1,20 @@
uqm_SUBDIRS="libs res uqm"
if [ "$uqm_HAVE_GETOPT_LONG" = 0 ]; then
uqm_SUBDIRS="$uqm_SUBDIRS getopt"
fi
case "$HOST_SYSTEM" in
Darwin)
uqm_SUBDIRS="$uqm_SUBDIRS darwin"
;;
esac
if [ "$uqm_HAVE_REGEX" = 0 ]; then
uqm_SUBDIRS="$uqm_SUBDIRS regex"
fi
uqm_CFILES="options.c port.c uqm.c"
test_CFILES=test.c

View File

@@ -0,0 +1,21 @@
/* This file contains some compile-time configuration options.
*/
#ifdef _MSC_VER
/* In this case, build.sh is not run to generate a config file, so
* we use a default file config_vc6.h instead.
* If you want anything else than the defaults, you'll have to edit
* that file manually. */
# include "config_vc6.h"
#elif defined(__SYMBIAN32__)
# include "symbian/config.h"
#elif defined (__MINGW32__) || defined (__CYGWIN__)
/* If we're compiling on MS Windows using build.sh, use
* config_win.h, generated from src/config_win.h.in. */
# include "config_win.h"
#else
/* If we're compiling in unix, use config_unix.h, generated from
* src/config_unix.h.in by build.sh. */
# include "config_unix.h"
#endif

View File

@@ -0,0 +1,67 @@
/* This file contains some compile-time configuration options for *nix
* systems.
* config_unix.h is generated from config_unix.h.in by build.sh
* When building on MS Windows using build.sh (MinGW, Cygwin),
* config_win.h is generated from src/config_win.h.in.
* When using MSVC on MS Windows, you'll have to edit src/msvc++/config.h
* manually if you want anything else than the defaults.
*/
#ifndef _CONFIG_UNIX_H
#define _CONFIG_UNIX_H
/* Directory where the UQM game data is located */
#define CONTENTDIR "."
/* Directory where game data will be stored */
#define USERDIR "."
/* Directory where config files will be stored */
#define CONFIGDIR USERDIR
/* Directory where supermelee teams will be stored */
#define MELEEDIR "${UQM_CONFIG_DIR}/teams/"
/* Directory where save games will be stored */
#define SAVEDIR "${UQM_CONFIG_DIR}/save/"
/* Defined if words are stored with the most significant byte first */
#ifdef __ARMEL__
#undef WORDS_BIGENDIAN
#endif
/* Defined if your system has readdir_r of its own */
#define HAVE_READDIR_R 1
/* Defined if your system has setenv of its own */
#ifndef HAVE_SETENV
#define HAVE_SETENV 1
#endif
/* Defined if your system has strupr of its own */
#undef HAVE_STRUPR
/* Defined if your system has strcasecmp of its own */
#define HAVE_STRCASECMP_UQM 1
// Not using "HAVE_STRCASECMP" as that conflicts with SDL.
/* Defined if your system has stricmp of its own */
#undef HAVE_STRICMP
/* Defined if your system has getopt_long */
#define HAVE_GETOPT_LONG 1
/* Defined if your system has iswgraph of its own*/
#define HAVE_ISWGRAPH 1
/* Defined if your system has wchar_t of its own */
#define HAVE_WCHAR_T 1
/* Defined if your system has wint_t of its own */
#define HAVE_WINT_T 1
/* Defined if your system has _Bool of its own */
#define HAVE__BOOL 1
#endif /* _CONFIG_UNIX_H */

View File

@@ -0,0 +1,63 @@
/* This file contains some compile-time configuration options for *nix
* systems.
* config_unix.h is generated from config_unix.h.in by build.sh
* When building on MS Windows using build.sh (MinGW, Cygwin),
* config_win.h is generated from src/config_win.h.in.
* When using MSVC on MS Windows, you'll have to edit src/msvc++/config.h
* manually if you want anything else than the defaults.
*/
#ifndef _CONFIG_UNIX_H
#define _CONFIG_UNIX_H
/* Directory where the UQM game data is located */
#define CONTENTDIR "@CONTENTDIR@"
/* Directory where game data will be stored */
#define USERDIR "~/.uqm/"
/* Directory where config files will be stored */
#define CONFIGDIR USERDIR
/* Directory where supermelee teams will be stored */
#define MELEEDIR "${UQM_CONFIG_DIR}/teams/"
/* Directory where save games will be stored */
#define SAVEDIR "${UQM_CONFIG_DIR}/save/"
/* Defined if words are stored with the most significant byte first */
@WORDS_BIGENDIAN@
/* Defined if your system has readdir_r of its own */
@HAVE_READDIR_R@
/* Defined if your system has setenv of its own */
@HAVE_SETENV@
/* Defined if your system has strupr of its own */
@HAVE_STRUPR@
/* Defined if your system has strcasecmp of its own */
@HAVE_STRCASECMP_UQM@
// Not using "HAVE_STRCASECMP" as that conflicts with SDL.
/* Defined if your system has stricmp of its own */
@HAVE_STRICMP@
/* Defined if your system has getopt_long */
@HAVE_GETOPT_LONG@
/* Defined if your system has iswgraph of its own*/
@HAVE_ISWGRAPH@
/* Defined if your system has wchar_t of its own */
@HAVE_WCHAR_T@
/* Defined if your system has wint_t of its own */
@HAVE_WINT_T@
/* Defined if your system has _Bool of its own */
@HAVE__BOOL@
#endif /* _CONFIG_UNIX_H */

View File

@@ -0,0 +1,61 @@
/* This file contains some compile-time configuration options for MS Windows
* systems when building using MSVC.
* Change the values below if you want anything other than the defaults.
* For *nix systems, config_unix.h is used, which is generated by build.sh
* from src/config_unix.h.in.
* When building on MS Windows using build.sh (MinGW, Cygwin),
* config_win.h is generated from src/config_win.h.in.
*/
#ifndef _CONFIG_H
#define _CONFIG_H
/* Directory where the UQM game data is located */
#define CONTENTDIR "../content/"
/* Directory where game data will be stored */
//#define USERDIR "../userdata/"
#define USERDIR "%APPDATA%/uqm/"
/* Directory where config files will be stored */
#define CONFIGDIR USERDIR
/* Directory where supermelee teams will be stored */
#define MELEEDIR "%UQM_CONFIG_DIR%/teams/"
/* Directory where save games will be stored */
#define SAVEDIR "%UQM_CONFIG_DIR%/save/"
/* Define if words are stored with the most significant byte first */
#undef WORDS_BIGENDIAN
/* Defined if your system has readdir_r of its own */
#undef HAVE_READDIR_R
/* Defined if your system has setenv of its own */
#undef HAVE_SETENV
/* Defined if your system has strupr of its own */
#define HAVE_STRUPR
/* Defined if your system has strcasecmp of its own */
#undef HAVE_STRCASECMP_UQM
// Not using "HAVE_STRCASECMP" as that conflicts with SDL.
/* Defined if your system has stricmp of its own */
#define HAVE_STRICMP
/* Defined if your system has getopt_long */
#undef HAVE_GETOPT_LONG
/* Defined if your system has iswgraph of its own*/
#define HAVE_ISWGRAPH
/* Defined if your system has wchar_t of its own */
#define HAVE_WCHAR_T
/* Defined if your system has wint_t of its own */
#define HAVE_WINT_T
#endif /* _CONFIG_H */

View File

@@ -0,0 +1,65 @@
/* This file contains some compile-time configuration options for MS Windows
* systems when building using build.sh (MinGW, Cygwin).
* config_win.h is generated from src/config_win.h.in by build.sh
* For building using MSVC, you'll have to edit src/msvc++/config.h manually
* if you want anything else than the defaults.
* For *nix systems, config_unix.h is used, which is generated by build.sh
* from src/config_unix.h.in.
*/
#ifndef _CONFIG_WIN_H
#define _CONFIG_WIN_H
/* Directory where the UQM game data is located */
#define CONTENTDIR "../content/"
/* Directory where game data will be stored */
//#define USERDIR "../userdata/"
#define USERDIR "%APPDATA%/uqm/"
/* Directory where config files will be stored */
#define CONFIGDIR USERDIR
/* Directory where supermelee teams will be stored */
#define MELEEDIR "%UQM_CONFIG_DIR%/teams/"
/* Directory where save games will be stored */
#define SAVEDIR "%UQM_CONFIG_DIR%/save/"
/* Defined if words are stored with the most significant byte first */
@WORDS_BIGENDIAN@
/* Defined if your system has readdir_r of its own */
@HAVE_READDIR_R@
/* Defined if your system has setenv of its own */
@HAVE_SETENV@
/* Defined if your system has strupr of its own */
@HAVE_STRUPR@
/* Defined if your system has strcasecmp of its own */
@HAVE_STRCASECMP_UQM@
// Not using "HAVE_STRCASECMP" as that conflicts with SDL.
/* Defined if your system has stricmp of its own */
@HAVE_STRICMP@
/* Defined if your system has getopt_long */
@HAVE_GETOPT_LONG@
/* Defined if your system has iswgraph of its own*/
@HAVE_ISWGRAPH@
/* Defined if your system has wchar_t of its own */
@HAVE_WCHAR_T@
/* Defined if your system has wint_t of its own */
@HAVE_WINT_T@
/* Defined if your system has _Bool of its own */
@HAVE__BOOL@
#endif /* _CONFIG_WIN_H */

View File

@@ -0,0 +1,127 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* Endian swapping, taken from SDL-1.2.5 sources and modified
* Original copyright (C) Sam Lantinga
*/
#ifndef _ENDIAN_UQM_H
#define _ENDIAN_UQM_H
#include "config.h"
#include "types.h"
#if defined (__APPLE__) && defined (__GNUC__)
// When using the MacOS gcc compiler to build universal binaries,
// each file will be compiled once for each platform.
// This means that checking endianness beforehand from build.sh will not do,
// but fortunately, gcc defines __BIG_ENDIAN__ or __LITTLE_ENDIAN__ on
// this platform.
# if defined(__BIG_ENDIAN__)
# undef WORDS_BIGENDIAN
# define WORDS_BIGENDIAN
# elif defined(__LITTLE_ENDIAN__)
# undef WORDS_BIGENDIAN
# else
// Neither __BIG_ENDIAN__ nor __LITTLE_ENDIAN__ is defined.
// Fallback to using the build.sh defined value.
# endif
#endif /* __APPLE__ */
#if defined(_MSC_VER) || defined(__BORLANDC__) || \
defined(__DMC__) || defined(__SC__) || \
defined(__WATCOMC__) || defined(__LCC__)
#ifndef __inline__
#define __inline__ __inline
#endif
#endif
/* The macros used to swap values */
/* Try to use superfast macros on systems that support them */
#ifdef linux
#include <endian.h>
#ifdef __arch__swab16
#define UQM_Swap16 __arch__swab16
#endif
#ifdef __arch__swab32
#define UQM_Swap32 __arch__swab32
#endif
#endif /* linux */
/* Use inline functions for compilers that support them, and static
functions for those that do not. Because these functions become
static for compilers that do not support inline functions, this
header should only be included in files that actually use them.
*/
#ifndef UQM_Swap16
static __inline__ uint16 UQM_Swap16(uint16 D)
{
return((D<<8)|(D>>8));
}
#endif
#ifndef UQM_Swap32
static __inline__ uint32 UQM_Swap32(uint32 D)
{
return((D<<24)|((D<<8)&0x00FF0000)|((D>>8)&0x0000FF00)|(D>>24));
}
#endif
#ifdef UQM_INT64
#ifndef UQM_Swap64
static __inline__ uint64 UQM_Swap64(uint64 val)
{
uint32 hi, lo;
/* Separate into high and low 32-bit values and swap them */
lo = (uint32)(val&0xFFFFFFFF);
val >>= 32;
hi = (uint32)(val&0xFFFFFFFF);
val = UQM_Swap32(lo);
val <<= 32;
val |= UQM_Swap32(hi);
return(val);
}
#endif
#else
#ifndef UQM_Swap64
/* This is mainly to keep compilers from complaining in SDL code.
If there is no real 64-bit datatype, then compilers will complain about
the fake 64-bit datatype that SDL provides when it compiles user code.
*/
#define UQM_Swap64(X) (X)
#endif
#endif /* UQM_INT64 */
/* Byteswap item from the specified endianness to the native endianness
* or vice versa.
*/
#ifndef WORDS_BIGENDIAN
#define UQM_SwapLE16(X) (X)
#define UQM_SwapLE32(X) (X)
#define UQM_SwapLE64(X) (X)
#define UQM_SwapBE16(X) UQM_Swap16(X)
#define UQM_SwapBE32(X) UQM_Swap32(X)
#define UQM_SwapBE64(X) UQM_Swap64(X)
#else
#define UQM_SwapLE16(X) UQM_Swap16(X)
#define UQM_SwapLE32(X) UQM_Swap32(X)
#define UQM_SwapLE64(X) UQM_Swap64(X)
#define UQM_SwapBE16(X) (X)
#define UQM_SwapBE32(X) (X)
#define UQM_SwapBE64(X) (X)
#endif
#endif /* _ENDIAN_H */

View File

@@ -0,0 +1,14 @@
uqm_SUBDIRS="callback decomp file graphics heap input list math memory
resource sound strings task threads time uio video log"
if [ -n "$uqm_USE_INTERNAL_MIKMOD" ]; then
uqm_SUBDIRS="$uqm_SUBDIRS mikmod"
fi
if [ -n "$uqm_NETPLAY" ]; then
uqm_SUBDIRS="$uqm_SUBDIRS network"
fi
#if [ "$DEBUG" = 1 ]; then
# uqm_SUBDIRS="$UQM_SUBDIRS debug"
#fi

View File

@@ -0,0 +1,2 @@
#include "callback/alarm.h"

View File

@@ -0,0 +1,2 @@
#include "callback/callback.h"

View File

@@ -0,0 +1,2 @@
uqm_CFILES="alarm.c callback.c"

View File

@@ -0,0 +1,134 @@
/*
* Copyright 2006 Serge van den Boom <svdb@stack.nl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "alarm.h"
#include "libs/heap.h"
#include <assert.h>
#include <stdlib.h>
Heap *alarmHeap;
static inline Alarm *
Alarm_alloc(void) {
return malloc(sizeof (Alarm));
}
static inline void
Alarm_free(Alarm *alarm) {
free(alarm);
}
static inline int
AlarmTime_compare(const AlarmTime t1, const AlarmTime t2) {
if (t1 < t2)
return -1;
if (t2 > t2)
return 1;
return 0;
}
static int
Alarm_compare(const Alarm *a1, const Alarm *a2) {
return AlarmTime_compare(a1->time, a2->time);
}
void
Alarm_init(void) {
assert(alarmHeap == NULL);
alarmHeap = Heap_new((HeapValue_Comparator) Alarm_compare,
4, 4, 0.8);
}
void
Alarm_uninit(void) {
assert(alarmHeap != NULL);
while (Heap_hasMore(alarmHeap)) {
Alarm *alarm = (Alarm *) Heap_pop(alarmHeap);
Alarm_free(alarm);
}
Heap_delete(alarmHeap);
alarmHeap = NULL;
}
static inline AlarmTime
AlarmTime_nowMS(void) {
return SDL_GetTicks();
}
Alarm *
Alarm_addRelativeMs(Uint32 ms, AlarmCallback callback,
AlarmCallbackArg arg) {
Alarm *alarm;
assert(alarmHeap != NULL);
alarm = Alarm_alloc();
alarm->time = AlarmTime_nowMS() + ms;
alarm->callback = callback;
alarm->arg = arg;
Heap_add(alarmHeap, (HeapValue *) alarm);
return alarm;
}
void
Alarm_remove(Alarm *alarm) {
assert(alarmHeap != NULL);
Heap_remove(alarmHeap, (HeapValue *) alarm);
Alarm_free(alarm);
}
// It is safe to call this function again from inside a callback function
// that it called. It should not be called from multiple threads at once.
void
Alarm_process(void) {
AlarmTime now;
assert(alarmHeap != NULL);
now = AlarmTime_nowMS();
while (Heap_hasMore(alarmHeap)) {
Alarm *alarm = (Alarm *) Heap_first(alarmHeap);
if (now < alarm->time)
break;
Heap_pop(alarmHeap);
alarm->callback(alarm->arg);
Alarm_free(alarm);
}
}
Uint32
Alarm_timeBeforeNextMs(void) {
Alarm *alarm;
if (!Heap_hasMore(alarmHeap))
return UINT32_MAX;
alarm = (Alarm *) Heap_first(alarmHeap);
return alarmTimeToMsUint32(alarm->time);
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2006 Serge van den Boom <svdb@stack.nl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _ALARM_H
#define _ALARM_H
#include "port.h"
#include "types.h"
#include SDL_INCLUDE(SDL.h)
typedef Uint32 AlarmTime;
static inline Uint32
alarmTimeToMsUint32(AlarmTime time) {
return (Uint32) time;
}
typedef struct Alarm Alarm;
typedef void *AlarmCallbackArg;
typedef void (*AlarmCallback)(AlarmCallbackArg arg);
struct Alarm {
size_t index;
// For the HeapValue 'base struct'.
AlarmTime time;
AlarmCallback callback;
AlarmCallbackArg arg;
};
void Alarm_init(void);
void Alarm_uninit(void);
Alarm *Alarm_addRelativeMs(Uint32 ms, AlarmCallback callback,
AlarmCallbackArg arg);
void Alarm_remove(Alarm *alarm);
void Alarm_process(void);
Uint32 Alarm_timeBeforeNextMs(void);
#endif /* _ALARM_H */

View File

@@ -0,0 +1,173 @@
/*
* Copyright 2006 Serge van den Boom <svdb@stack.nl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "port.h"
#include "types.h"
#include <assert.h>
#include <stdlib.h>
#include <sys/types.h>
typedef struct CallbackLink CallbackLink;
#define CALLBACK_INTERNAL
#include "callback.h"
struct CallbackLink {
CallbackLink *next;
CallbackFunction callback;
CallbackArg arg;
};
static CallbackLink *callbacks;
static CallbackLink **callbacksEnd;
static CallbackLink *const *callbacksProcessEnd;
static inline void
CallbackList_lock(void) {
// TODO
// Necessary for reentrant operation
}
static inline void
CallbackList_unlock(void) {
// TODO
// Necessary for reentrant operation
}
#if 0
static inline bool
CallbackList_isLocked(void) {
// TODO
}
#endif
void
Callback_init(void) {
callbacks = NULL;
callbacksEnd = &callbacks;
callbacksProcessEnd = &callbacks;
}
// Callbacks are guaranteed to be called in the order that they are queued.
CallbackID
Callback_add(CallbackFunction callback, CallbackArg arg) {
CallbackLink *link = malloc(sizeof (CallbackLink));
link->callback = callback;
link->arg = arg;
link->next = NULL;
CallbackList_lock();
*callbacksEnd = link;
callbacksEnd = &link->next;
CallbackList_unlock();
return (CallbackID) link;
}
static void
CallbackLink_delete(CallbackLink *link) {
free(link);
}
// Pre: CallbackList is locked.
static CallbackLink **
CallbackLink_find(CallbackLink *link) {
CallbackLink **ptr;
//assert(CallbackList_isLocked());
for (ptr = &callbacks; *ptr != NULL; ptr = &(*ptr)->next) {
if (*ptr == link)
return ptr;
}
return NULL;
}
bool
Callback_remove(CallbackID id) {
CallbackLink *link = (CallbackLink *) id;
CallbackLink **linkPtr;
CallbackList_lock();
linkPtr = CallbackLink_find(link);
if (linkPtr == NULL) {
CallbackList_unlock();
return false;
}
if (callbacksEnd == &(*linkPtr)->next)
callbacksEnd = linkPtr;
if (callbacksProcessEnd == &(*linkPtr)->next)
callbacksProcessEnd = linkPtr;
*linkPtr = (*linkPtr)->next;
CallbackList_unlock();
CallbackLink_delete(link);
return true;
}
static inline void
CallbackLink_doCallback(CallbackLink *link) {
(link->callback)(link->arg);
}
// Call all queued callbacks currently in the queue. Callbacks queued
// from inside the called functions will not be processed until the next
// call of Callback_process().
// It is allowed to remove callbacks from inside the called functions.
// NB: Callback_process() must never be called from more than one thread
// at the same time. It's the only sensible way to ensure that the
// callbacks are called in the order in which they were queued.
// It is however allowed to call Callback_process() from inside the
// callback function called by Callback_process() itself.
void
Callback_process(void) {
CallbackLink *link;
// We set 'callbacksProcessEnd' to callbacksEnd. Callbacks added
// from inside a callback function will be placed after
// callbacksProcessEnd, and will hence not be processed this
// call of Callback_process().
CallbackList_lock();
callbacksProcessEnd = callbacksEnd;
CallbackList_unlock();
for (;;) {
CallbackList_lock();
if (callbacksProcessEnd == &callbacks) {
CallbackList_unlock();
break;
}
assert(callbacks != NULL);
// If callbacks == NULL, then callbacksProcessEnd == &callbacks
link = callbacks;
callbacks = link->next;
if (callbacksEnd == &link->next)
callbacksEnd = &callbacks;
if (callbacksProcessEnd == &link->next)
callbacksProcessEnd = &callbacks;
CallbackList_unlock();
CallbackLink_doCallback(link);
CallbackLink_delete(link);
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2006 Serge van den Boom <svdb@stack.nl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _CALLBACK_H
#define _CALLBACK_H
#include "types.h"
#ifdef CALLBACK_INTERNAL
typedef CallbackLink *CallbackID;
#else
typedef void *CallbackID;
// Uniquely identifies a queued callback.
#endif
#define CallbackID_invalid ((CallbackID ) NULL)
typedef void *CallbackArg;
typedef void (*CallbackFunction)(CallbackArg arg);
void Callback_init(void);
CallbackID Callback_add(CallbackFunction callback, CallbackArg arg);
bool Callback_remove(CallbackID id);
void Callback_process(void);
#endif /* _CALLBACK_H */

View File

@@ -0,0 +1,24 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
* Nota bene: later versions of the GNU General Public License do not apply
* to this program.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef _CDPLIB_H
#define _CDPLIB_H
#include "cdp/cdp.h"
#endif /* _CDPLIB_H */

View File

@@ -0,0 +1,89 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _COMPILER_H
#define _COMPILER_H
#include "types.h"
typedef uint8 BYTE;
typedef uint8 UBYTE;
typedef sint8 SBYTE;
typedef uint16 UWORD;
typedef sint16 SWORD;
typedef uint32 DWORD;
typedef sint32 SDWORD;
typedef UWORD COUNT;
typedef SWORD SIZE;
typedef char UNICODE;
typedef enum
{
FALSE = 0,
TRUE
} BOOLEAN;
typedef void (*PVOIDFUNC) (void);
typedef BOOLEAN (*PBOOLFUNC) (void);
typedef BYTE (*PBYTEFUNC) (void);
typedef UWORD (*PUWORDFUNC) (void);
typedef SWORD (*PSWORDFUNC) (void);
typedef DWORD (*PDWORDFUNC) (void);
#define MAKE_BYTE(lo, hi) ((BYTE) (((BYTE) (hi) << (BYTE) 4) | (BYTE) (lo)))
#define LONIBBLE(x) ((BYTE) ((BYTE) (x) & (BYTE) 0x0F))
#define HINIBBLE(x) ((BYTE) ((BYTE) (x) >> (BYTE) 4))
#define MAKE_WORD(lo, hi) ((UWORD) ((BYTE) (hi) << 8) | (BYTE) (lo))
#define LOBYTE(x) ((BYTE) ((UWORD) (x)))
#define HIBYTE(x) ((BYTE) ((UWORD) (x) >> 8))
#define MAKE_DWORD(lo, hi) (((DWORD) (hi) << 16) | (UWORD) (lo))
#define LOWORD(x) ((UWORD) ((DWORD) (x)))
#define HIWORD(x) ((UWORD) ((DWORD) (x) >> 16))
// To be moved to port.h:
// _ALIGNED_ANY specifies an alignment suitable for any type
// _ALIGNED_ON specifies a caller-supplied alignment (should be a power of 2)
#if defined(__GNUC__)
# define _PACKED __attribute__((packed))
# define _ALIGNED_ANY __attribute__((aligned))
# define _ALIGNED_ON(bytes) __attribute__((aligned(bytes)))
#elif defined(_MSC_VER)
# define _ALIGNED_ANY
//# define _ALIGNED_ON(bytes) __declspec(align(bytes))
// __declspec(align(bytes)) expects a constant. 'sizeof (type)'
// will not do. This is something that needs some attention,
// once we find someone with a 64 bits Windows machine.
// Leaving it alone for now.
# define _PACKED
# define _ALIGNED_ON(bytes)
#elif defined(__ARMCC__)
# define _PACKED __attribute__((packed))
# define _ALIGNED_ANY __attribute__((aligned))
# define _ALIGNED_ON(bytes) __attribute__((aligned(bytes)))
#elif defined(__WINSCW__)
# define _PACKED
# define _ALIGNED_ANY
# define _ALIGNED_ON(bytes)
#endif
#endif /* _COMPILER_H */

View File

@@ -0,0 +1,48 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _DECLIB_H
#define _DECLIB_H
#include "libs/compiler.h"
typedef struct _LZHCODE_DESC* DECODE_REF;
enum
{
FILE_STREAM = 0,
MEMORY_STREAM
};
typedef BYTE STREAM_TYPE;
enum
{
STREAM_READ = 0,
STREAM_WRITE
};
typedef BYTE STREAM_MODE;
extern DECODE_REF copen (void *InStream, STREAM_TYPE SType,
STREAM_MODE SMode);
extern DWORD cclose (DECODE_REF DecodeRef);
extern void cfilelength (DECODE_REF DecodeRef, DWORD *pfilelen);
extern COUNT cread (void *pStr, COUNT size, COUNT count,
DECODE_REF DecodeRef);
extern COUNT cwrite (const void *pStr, COUNT size, COUNT count,
DECODE_REF DecodeRef);
#endif /* _DECLIB_H */

View File

@@ -0,0 +1 @@
uqm_CFILES="lzdecode.c lzencode.c update.c"

View File

@@ -0,0 +1,415 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* LZHUF.C English version 1.0
* Based on Japanese version 29-NOV-1988
* LZSS coded by Haruhiko OKUMURA
* Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
* Edited and translated to English by Kenji RIKITAKE
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "lzh.h"
#include "libs/reslib.h"
PLZHCODE_DESC _lpCurCodeDesc;
STREAM_TYPE _StreamType;
BYTE* _Stream;
UWORD _workbuf;
BYTE _workbuflen;
/* get one bit */
static SWORD
GetBit (void)
{
SWORD i;
while (_workbuflen <= 8)
{
if ((i = InChar ()) < 0)
i = 0;
_workbuf |= i << (8 - _workbuflen);
_workbuflen += 8;
}
i = (_workbuf & 0xFFFF) >> (16 - 1);
_workbuf = (_workbuf << 1) & 0xFFFF;
_workbuflen--;
return (i);
}
static UWORD
GetBits (BYTE num_bits)
{
SWORD i;
while (_workbuflen <= 8)
{
if ((i = InChar ()) < 0)
i = 0;
_workbuf |= i << (8 - _workbuflen);
_workbuflen += 8;
}
i = (_workbuf & 0xFFFF) >> (16 - num_bits);
_workbuf = (_workbuf << num_bits) & 0xFFFF;
_workbuflen -= num_bits;
return (i);
}
/* initialize freq tree */
void
StartHuff (void)
{
COUNT i, j;
for (i = 0; i < N_CHAR; i++)
{
_lpCurCodeDesc->freq[i] = 1;
_lpCurCodeDesc->son[i] = i + T;
_lpCurCodeDesc->prnt[i + T] = i;
}
i = 0; j = N_CHAR;
while (j <= R)
{
_lpCurCodeDesc->freq[j] = _lpCurCodeDesc->freq[i] + _lpCurCodeDesc->freq[i + 1];
_lpCurCodeDesc->son[j] = i;
_lpCurCodeDesc->prnt[i] = _lpCurCodeDesc->prnt[i + 1] = j;
i += 2; j++;
}
_lpCurCodeDesc->freq[T] = 0xffff;
_lpCurCodeDesc->prnt[R] = 0;
}
DECODE_REF
copen (void *InStream, STREAM_TYPE SType, STREAM_MODE SMode)
{
DWORD StreamLength;
_StreamType = SType;
_Stream = InStream;
if (SMode == STREAM_WRITE) /* writing */
{
OutChar (0); /* skip future StreamLength */
OutChar (0);
OutChar (0);
OutChar (0);
StreamLength = 0;
}
else /* reading */
{
BYTE lobyte, hibyte;
UWORD loword, hiword;
lobyte = (BYTE)InChar ();
hibyte = (BYTE)InChar ();
loword = MAKE_WORD (lobyte, hibyte);
lobyte = (BYTE)InChar ();
hibyte = (BYTE)InChar ();
hiword = MAKE_WORD (lobyte, hibyte);
StreamLength = MAKE_DWORD (loword, hiword);
}
if (StreamLength == 0xFFFFFFFF
|| (_lpCurCodeDesc = AllocCodeDesc ()) == NULL)
{
FreeCodeDesc (_lpCurCodeDesc);
_lpCurCodeDesc = NULL;
}
else
{
_lpCurCodeDesc->Stream = _Stream;
_lpCurCodeDesc->StreamType = _StreamType;
_lpCurCodeDesc->StreamMode = SMode;
_lpCurCodeDesc->StreamLength = StreamLength;
_lpCurCodeDesc->buf_index = N - F;
memset (&_lpCurCodeDesc->text_buf[0], ' ', N - F);
StartHuff ();
}
return ((DECODE_REF)_lpCurCodeDesc);
}
DWORD
cclose (PLZHCODE_DESC lpCodeDesc)
{
_lpCurCodeDesc = lpCodeDesc;
if (_lpCurCodeDesc)
{
DWORD StreamIndex;
if (_lpCurCodeDesc->CleanupFunc)
(*_lpCurCodeDesc->CleanupFunc) ();
StreamIndex = lpCodeDesc->StreamIndex;
FreeCodeDesc (lpCodeDesc);
_lpCurCodeDesc = NULL;
return (StreamIndex);
}
return (0);
}
void
cfilelength (PLZHCODE_DESC lpCodeDesc, DWORD *pfilelen)
{
if (lpCodeDesc == 0)
*pfilelen = 0;
else
*pfilelen = lpCodeDesc->StreamLength;
}
/* decoder table */
static const BYTE d_code[256] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D,
0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B,
0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F,
0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23,
0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B,
0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
};
static const BYTE d_len[256] =
{
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
};
/* decode upper 6 bits from given table */
#define DecodePosition(p) \
{ \
while (_workbuflen <= 8) \
{ \
*(p) = InChar (); \
_workbuf |= *(p) << (8 - _workbuflen); \
_workbuflen += 8; \
} \
*(p) = HIBYTE (_workbuf); \
_workbuf = (_workbuf << 8) & 0xFFFF; \
_workbuflen -= 8; \
\
/* input lower 6 bits directly */ \
j = d_len[*(p)]; \
*(p) = ((UWORD)d_code[*(p)] << 6) \
| (((*(p) << j) | GetBits (j)) & 0x3f); \
}
/* start searching tree from the root to leaves.
* choose node #(son[]) if input bit == 0
* else choose #(son[]+1) (input bit == 1)
*/
#define DecodeChar(c) \
{ \
for (*(c) = lpCodeDesc->son[R]; \
*(c) < T; \
*(c) = lpCodeDesc->son[*(c) + GetBit ()]) \
; \
_update (*(c)); \
*(c) -= T; \
}
COUNT
cread (void *buf, COUNT size, COUNT count, PLZHCODE_DESC lpCodeDesc)
{
COUNT r, j, i;
BYTE *lpStr;
if ((_lpCurCodeDesc = lpCodeDesc) == 0)
return (0);
size *= count;
if (lpCodeDesc->StreamIndex + size > lpCodeDesc->StreamLength)
{
size /= count;
count = (COUNT)((lpCodeDesc->StreamLength
- lpCodeDesc->StreamIndex) / size);
size *= count;
}
if (size == 0)
return (0);
lpStr = (BYTE*)buf;
_StreamType = lpCodeDesc->StreamType;
_Stream = lpCodeDesc->Stream;
_workbuf = lpCodeDesc->workbuf;
_workbuflen = lpCodeDesc->workbuflen;
lpCodeDesc->StreamIndex += size;
r = lpCodeDesc->buf_index;
j = lpCodeDesc->bytes_left;
if (j)
{
lpCodeDesc->bytes_left = 0;
i = lpCodeDesc->restart_index;
goto ReenterRun;
}
do
{
COUNT c;
DecodeChar (&c);
if (c < 256)
{
size--;
*lpStr++ = lpCodeDesc->text_buf[r++ & (N - 1)] = (BYTE)c;
}
else
{
COUNT copy_size;
//i is a COUNT;
DecodePosition(&i);
i = r - i - 1;
j = c - 255 + THRESHOLD;
ReenterRun:
if (j > size)
{
lpCodeDesc->bytes_left = j - size;
lpCodeDesc->restart_index = i + size;
j = size;
}
size -= j;
do
{
COUNT loc_size;
i &= (N - 1);
r &= (N - 1);
if ((i < r && i + j > r) || (i > r && i + j > r + N))
copy_size = (r - i) & (N - 1);
else if ((copy_size = j) > N)
copy_size = N;
loc_size = copy_size;
if (i + loc_size > N)
{
COUNT k;
k = N - i;
memcpy (lpStr, &lpCodeDesc->text_buf[i], k);
lpStr += k;
loc_size -= k;
i = 0;
}
memcpy (lpStr, &lpCodeDesc->text_buf[i], loc_size);
lpStr += loc_size;
i += loc_size;
lpStr -= copy_size;
loc_size = copy_size;
if (r + loc_size > N)
{
COUNT k;
k = N - r;
memcpy (&lpCodeDesc->text_buf[r], lpStr, k);
lpStr += k;
loc_size -= k;
r = 0;
}
memcpy (&lpCodeDesc->text_buf[r], lpStr, loc_size);
lpStr += loc_size;
r += loc_size;
} while (j -= copy_size);
}
} while (size);
lpCodeDesc->buf_index = r;
lpCodeDesc->Stream = _Stream;
lpCodeDesc->workbuf = _workbuf;
lpCodeDesc->workbuflen = _workbuflen;
return (count);
}

View File

@@ -0,0 +1,468 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* LZHUF.C English version 1.0
* Based on Japanese version 29-NOV-1988
* LZSS coded by Haruhiko OKUMURA
* Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
* Edited and translated to English by Kenji RIKITAKE
*/
#include <stdio.h>
#include "lzh.h"
#include "libs/reslib.h"
static UWORD match_position, match_length;
static SWORD *lson;
static SWORD *rson;
static SWORD *dad;
static SWORD *encode_arrays;
#define AllocEncodeArrays() \
HCalloc ( \
(((N + 1) + (N + 257) + (N + 1)) \
* sizeof (lson[0])))
#define FreeCodeArrays HFree
static BOOLEAN
InitTree (void)
{
if ((encode_arrays = AllocEncodeArrays ()) == NULL)
{
FreeCodeArrays (encode_arrays);
encode_arrays = NULL;
return (FALSE);
}
else
{
SWORD i;
lson = encode_arrays;
rson = lson + (N + 1);
dad = rson + (N + 257);
for (i = N + 1; i <= N + 256; i++)
rson[i] = NIL; /* root */
for (i = 0; i < N; i++)
dad[i] = NIL; /* node */
return (TRUE);
}
}
static void
InsertNode (SWORD r)
{
SWORD p, cmp;
BYTE *lpBuf;
cmp = 1;
lpBuf = _lpCurCodeDesc->text_buf;
p = N + 1 + lpBuf[r];
rson[r] = lson[r] = NIL;
match_length = 0;
for (;;)
{
UWORD i;
if (cmp >= 0)
{
if (rson[p] != NIL)
p = rson[p];
else
{
rson[p] = r;
dad[r] = p;
return;
}
}
else
{
if (lson[p] != NIL)
p = lson[p];
else
{
lson[p] = r;
dad[r] = p;
return;
}
}
i = F;
{
SWORD _r, _p;
_r = r;
_p = p;
while (--i && (cmp = lpBuf[++_r] - lpBuf[++_p]) == 0)
;
}
if ((i = F - i) > THRESHOLD)
{
if (i > match_length)
{
match_position = ((r - p) & (N - 1)) - 1;
if ((match_length = i) >= F)
break;
}
else if (i == match_length)
{
if ((i = ((r - p) & (N - 1)) - 1) < match_position)
{
match_position = i;
}
}
}
}
dad[r] = dad[p];
lson[r] = lson[p];
rson[r] = rson[p];
dad[lson[p]] = r;
dad[rson[p]] = r;
if (rson[dad[p]] == p)
rson[dad[p]] = r;
else
lson[dad[p]] = r;
dad[p] = NIL; /* remove p */
}
static void
DeleteNode (SWORD p)
{
SWORD q;
if (dad[p] == NIL)
return; /* unregistered */
if (rson[p] == NIL)
q = lson[p];
else if (lson[p] == NIL)
q = rson[p];
else
{
q = lson[p];
if (rson[q] != NIL)
{
do
{
q = rson[q];
} while (rson[q] != NIL);
rson[dad[q]] = lson[q];
dad[lson[q]] = dad[q];
lson[q] = lson[p];
dad[lson[p]] = q;
}
rson[q] = rson[p];
dad[rson[p]] = q;
}
dad[q] = dad[p];
if (rson[dad[p]] == p)
rson[dad[p]] = q;
else
lson[dad[p]] = q;
dad[p] = NIL;
}
static void
Putcode (SWORD l, UWORD c)
{
_workbuf |= c >> _workbuflen;
if ((_workbuflen += l) >= 8)
{
OutChar ((BYTE)(_workbuf >> 8));
++_lpCurCodeDesc->StreamIndex;
if ((_workbuflen -= 8) >= 8)
{
OutChar ((BYTE)(_workbuf));
++_lpCurCodeDesc->StreamIndex;
_workbuflen -= 8;
_workbuf = c << (l - _workbuflen);
}
else
{
_workbuf <<= 8;
}
_workbuf &= 0xFFFF;
}
}
static void
EncodeChar (UWORD c)
{
UWORD i;
SWORD j, k;
i = 0;
j = 0;
k = _lpCurCodeDesc->prnt[c + T];
/* search connections from leaf node to the root */
do
{
i >>= 1;
/*
if node's address is odd, output 1
else output 0
*/
if (k & 1)
i += 0x8000;
j++;
} while ((k = _lpCurCodeDesc->prnt[k]) != R);
Putcode (j, i);
_update (c + T);
}
static void
EncodePosition (UWORD c)
{
UWORD i;
/*
* Tables for encoding/decoding upper 6 bits of
* sliding dictionary pointer
*/
/* encoder table */
static const BYTE p_len[64] =
{
0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
};
static const BYTE p_code[64] =
{
0x00, 0x20, 0x30, 0x40, 0x50, 0x58, 0x60, 0x68,
0x70, 0x78, 0x80, 0x88, 0x90, 0x94, 0x98, 0x9C,
0xA0, 0xA4, 0xA8, 0xAC, 0xB0, 0xB4, 0xB8, 0xBC,
0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE,
0xD0, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA, 0xDC, 0xDE,
0xE0, 0xE2, 0xE4, 0xE6, 0xE8, 0xEA, 0xEC, 0xEE,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
};
/* output upper 6 bits with encoding */
i = c >> 6;
Putcode (p_len[i], (UWORD)p_code[i] << 8);
/* output lower 6 bits directly */
Putcode (6, (c & 0x3f) << 10);
}
static void
UninitTree (void)
{
if (_workbuflen)
{
OutChar ((BYTE)(_workbuf >> 8));
++_lpCurCodeDesc->StreamIndex;
}
FreeCodeArrays (encode_arrays);
encode_arrays = NULL;
lson = NULL;
rson = NULL;
dad = NULL;
}
static void
_encode_cleanup (void)
{
UWORD r, s, last_match_length, len;
_StreamType = _lpCurCodeDesc->StreamType;
_Stream = _lpCurCodeDesc->Stream;
_workbuf = _lpCurCodeDesc->workbuf;
_workbuflen = _lpCurCodeDesc->workbuflen;
r = _lpCurCodeDesc->buf_index;
s = _lpCurCodeDesc->restart_index;
last_match_length = _lpCurCodeDesc->bytes_left;
if (_lpCurCodeDesc->StreamLength >= F)
len = F;
else
{
UWORD i;
for (i = 1; i <= F; i++)
InsertNode (r - i);
InsertNode (r);
len = (UWORD)_lpCurCodeDesc->StreamLength;
}
while (1)
{
while (last_match_length--)
{
DeleteNode (s);
if (--len == 0)
{
BYTE lobyte, hibyte;
UWORD loword, hiword;
UninitTree ();
_lpCurCodeDesc->StreamIndex += 4;
/* rewind */
if (_lpCurCodeDesc->StreamType == FILE_STREAM)
SeekResFile ((uio_Stream *)_Stream,
-(int)_lpCurCodeDesc->StreamIndex, SEEK_CUR);
else /* _lpCurCodeDesc->StreamType == MEMORY_STREAM */
_Stream = (BYTE*)_Stream - _lpCurCodeDesc->StreamIndex;
loword = LOWORD (_lpCurCodeDesc->StreamLength);
lobyte = LOBYTE (loword);
hibyte = HIBYTE (loword);
OutChar (lobyte);
OutChar (hibyte);
hiword = HIWORD (_lpCurCodeDesc->StreamLength);
lobyte = LOBYTE (hiword);
hibyte = HIBYTE (hiword);
OutChar (lobyte);
OutChar (hibyte);
return;
}
s = (s + 1) & (N - 1);
r = (r + 1) & (N - 1);
InsertNode (r);
}
if (match_length > len)
match_length = len;
if (match_length <= THRESHOLD)
{
match_length = 1;
EncodeChar (_lpCurCodeDesc->text_buf[r]);
}
else
{
EncodeChar (255 - THRESHOLD + match_length);
EncodePosition (match_position);
}
last_match_length = match_length;
}
}
COUNT
cwrite (const void *buf, COUNT size, COUNT count, PLZHCODE_DESC lpCodeDesc)
{
UWORD r, s, last_match_length;
BYTE *lpBuf;
const BYTE *lpStr;
if ((_lpCurCodeDesc = lpCodeDesc) == 0
|| (size *= count) == 0)
return (0);
_StreamType = lpCodeDesc->StreamType;
_Stream = lpCodeDesc->Stream;
_workbuf = lpCodeDesc->workbuf;
_workbuflen = lpCodeDesc->workbuflen;
lpStr = (const BYTE *) buf;
lpBuf = lpCodeDesc->text_buf;
r = lpCodeDesc->buf_index;
s = lpCodeDesc->restart_index;
last_match_length = lpCodeDesc->bytes_left;
if (last_match_length)
{
lpCodeDesc->StreamLength += size;
goto EncodeRestart;
}
else if (lpCodeDesc->StreamLength < F)
{
UWORD i;
if ((i = (UWORD)lpCodeDesc->StreamLength) == 0)
{
if (!InitTree ())
return (0);
_lpCurCodeDesc->StreamIndex = 0;
lpCodeDesc->CleanupFunc = _encode_cleanup;
}
lpCodeDesc->StreamLength += size;
for (; i < F && size; ++i, --size)
lpBuf[r + i] = *lpStr++;
if (i < F)
goto EncodeExit;
for (i = 1; i <= F; i++)
InsertNode (r - i);
InsertNode (r);
if (size == 0)
goto EncodeExit;
}
else
lpCodeDesc->StreamLength += size;
do
{
if (match_length > F)
match_length = F;
if (match_length <= THRESHOLD)
{
match_length = 1;
EncodeChar (lpBuf[r]);
}
else
{
EncodeChar (255 - THRESHOLD + match_length);
EncodePosition (match_position);
}
last_match_length = match_length;
EncodeRestart:
while (last_match_length && size)
{
BYTE c;
--size;
--last_match_length;
DeleteNode (s);
c = *lpStr++;
lpBuf[s] = c;
if (s < F - 1)
lpBuf[s + N] = c;
s = (s + 1) & (N - 1);
r = (r + 1) & (N - 1);
InsertNode (r);
}
} while (last_match_length == 0);
EncodeExit:
lpCodeDesc->buf_index = r;
lpCodeDesc->restart_index = s;
lpCodeDesc->bytes_left = last_match_length;
lpCodeDesc->Stream = _Stream;
lpCodeDesc->workbuf = _workbuf;
lpCodeDesc->workbuflen = _workbuflen;
return (count);
}

View File

@@ -0,0 +1,91 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _LZH_H
#define _LZH_H
#include "libs/declib.h"
#include "libs/memlib.h"
/* LZSS Parameters */
#define N 4096 /* Size of string buffer */
#define F 16 /* Size of look-ahead buffer */
//#define F 60 /* Size of look-ahead buffer */
#define THRESHOLD 2
#define NIL N /* End of tree's node */
/* Huffman coding parameters */
#define N_CHAR (256 - THRESHOLD + F)
/* character code (= 0..N_CHAR-1) */
#define T (N_CHAR * 2 - 1) /* Size of table */
#define R (T - 1) /* root position */
#define MAX_FREQ 0x8000
/* update when cumulative frequency */
struct _LZHCODE_DESC
{
COUNT buf_index, restart_index, bytes_left;
BYTE text_buf[N + F - 1];
/* reconstruct freq tree */
COUNT freq[T + 1]; /* cumulative freq table */
/*
* pointing parent nodes.
* area [T..(T + N_CHAR - 1)] are pointers for leaves
*/
COUNT prnt[T + N_CHAR];
/* pointing children nodes (son[], son[] + 1)*/
COUNT son[T];
UWORD workbuf;
BYTE workbuflen;
STREAM_TYPE StreamType;
void *Stream;
DWORD StreamIndex, StreamLength;
STREAM_MODE StreamMode;
PVOIDFUNC CleanupFunc;
};
typedef struct _LZHCODE_DESC LZHCODE_DESC;
typedef LZHCODE_DESC *PLZHCODE_DESC;
#define InChar() (_StreamType == FILE_STREAM ? \
GetResFileChar ((uio_Stream *)_Stream) : \
(int)*_Stream++)
#define OutChar(c) (_StreamType == FILE_STREAM ? \
PutResFileChar ((c), (uio_Stream *)_Stream) : \
(*_Stream++ = (BYTE)(c)))
#define AllocCodeDesc() HCalloc (sizeof (LZHCODE_DESC))
#define FreeCodeDesc HFree
extern void _update (COUNT c);
extern void StartHuff (void);
extern PLZHCODE_DESC _lpCurCodeDesc;
extern STREAM_TYPE _StreamType;
extern BYTE* _Stream;
extern UWORD _workbuf;
extern BYTE _workbuflen;
#endif /* _LZH_H */

View File

@@ -0,0 +1,115 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <string.h>
#include "lzh.h"
static void
reconst (void)
{
COUNT i, j;
/* halven cumulative freq for leaf nodes */
j = 0;
for (i = 0; i < T; i++)
{
if (_lpCurCodeDesc->son[i] >= T)
{
_lpCurCodeDesc->freq[j] = (_lpCurCodeDesc->freq[i] + 1) >> 1;
_lpCurCodeDesc->son[j] = _lpCurCodeDesc->son[i];
j++;
}
}
/* make a tree : first, connect children nodes */
for (i = 0, j = N_CHAR; j < T; i += 2, j++)
{
SWORD k;
UWORD f, l;
k = i + 1;
f = _lpCurCodeDesc->freq[j] = _lpCurCodeDesc->freq[i] + _lpCurCodeDesc->freq[k];
for (k = j - 1; f < _lpCurCodeDesc->freq[k]; k--)
;
k++;
l = (j - k);
memmove (_lpCurCodeDesc->freq + k + 1, _lpCurCodeDesc->freq + k,
sizeof(_lpCurCodeDesc->freq[0]) * l);
_lpCurCodeDesc->freq[k] = f;
memmove (_lpCurCodeDesc->son + k + 1, _lpCurCodeDesc->son + k,
sizeof(_lpCurCodeDesc->son[0]) * l);
_lpCurCodeDesc->son[k] = i;
}
/* connect parent nodes */
for (i = 0; i < T; i++)
{
if ((j = _lpCurCodeDesc->son[i]) >= T)
_lpCurCodeDesc->prnt[j] = i;
else
_lpCurCodeDesc->prnt[j] = _lpCurCodeDesc->prnt[j + 1] = i;
}
}
/* update freq tree */
void
_update (COUNT c)
{
PLZHCODE_DESC lpCD;
if ((lpCD = _lpCurCodeDesc)->freq[R] == MAX_FREQ)
reconst ();
c = lpCD->prnt[c];
do
{
COUNT i, l;
i = ++lpCD->freq[c];
/* swap nodes to keep the tree freq-ordered */
if (i > lpCD->freq[l = c + 1])
{
COUNT j;
while (i > lpCD->freq[++l])
;
l--;
lpCD->freq[c] = lpCD->freq[l];
lpCD->freq[l] = i;
i = lpCD->son[c];
j = lpCD->son[l];
lpCD->son[l] = i;
lpCD->son[c] = j;
lpCD->prnt[i] = l;
if (i < T)
lpCD->prnt[i + 1] = l;
lpCD->prnt[j] = c;
if (j < T)
lpCD->prnt[j + 1] = c;
c = l;
}
} while ((c = lpCD->prnt[c]) != 0); /* do it until reaching the root */
}

View File

@@ -0,0 +1,87 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// Contains file handling code
#ifndef _FILE_H
#define _FILE_H
#include "port.h"
#include "libs/uio.h"
// for bool
#include "types.h"
#if 0
// from temp.h
void initTempDir (void);
void unInitTempDir (void);
char *tempFilePath (const char *filename);
extern uio_DirHandle *tempDir;
#endif
// from dirs.h
int mkdirhier (const char *path);
const char *getHomeDir (void);
int createDirectory (const char *dir, int mode);
int expandPath (char *dest, size_t len, const char *src, int what);
// values for 'what':
#define EP_HOME 1
// Expand '~' for home dirs.
#define EP_ABSOLUTE 2
// Make paths absolute
#define EP_ENVVARS 4
// Expand environment variables.
#define EP_DOTS 8
// Process ".." and "."
#define EP_SLASHES 16
// Consider backslashes as path component separators.
// They will be replaced by slashes. Windows UNC paths will always
// start with "\\server\share", with backslashes.
#define EP_SINGLESEP 32
// Replace multiple consecutive path separators by a single one.
#define EP_ALL (EP_HOME | EP_ENVVARS | EP_ABSOLUTE | EP_DOTS | EP_SLASHES \
EP_SINGLESEP)
// Everything
// Everything except Windows style backslashes on Unix Systems:
#ifdef WIN32
# define EP_ALL_SYSTEM (EP_HOME | EP_ENVVARS | EP_ABSOLUTE | EP_DOTS | \
EP_SLASHES | EP_SINGLESEP)
#else
# define EP_ALL_SYSTEM (EP_HOME | EP_ENVVARS | EP_ABSOLUTE | EP_DOTS | \
EP_SINGLESEP)
#endif
// from files.h
int copyFile (uio_DirHandle *srcDir, const char *srcName,
uio_DirHandle *dstDir, const char *newName);
bool fileExists (const char *name);
bool fileExists2(uio_DirHandle *dir, const char *fileName);
#ifdef HAVE_UNC_PATHS
size_t skipUNCServerShare(const char *inPath);
#endif /* HAVE_UNC_PATHS */
#ifdef HAVE_DRIVE_LETTERS
static inline int isDriveLetter(int c)
{
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
}
#endif /* HAVE_DRIVE_LETTERS */
#endif /* _FILE_H */

View File

@@ -0,0 +1 @@
uqm_CFILES="dirs.c files.c"

View File

@@ -0,0 +1,826 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// Contains code handling directories
#include <stdlib.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "port.h"
#include "config.h"
#include "filintrn.h"
#include "libs/compiler.h"
#include "libs/memlib.h"
#include "libs/misc.h"
#include "libs/log.h"
#ifdef HAVE_DRIVE_LETTERS
# include <ctype.h>
// For tolower()
#endif /* HAVE_DRIVE_LETTERS */
#ifdef WIN32
# include <direct.h>
// For _getdcwd()
#else
# include <pwd.h>
// For getpwuid()
#endif
/* Try to find a suitable value for %APPDATA% if it isn't defined on
* Windows.
*/
#define APPDATA_FALLBACK
static char *expandPathAbsolute (char *dest, size_t destLen, const char *src,
size_t *skipSrc, int what);
static char *strrchr2(const char *start, int c, const char *end);
int
createDirectory(const char *dir, int mode)
{
return MKDIR(dir, mode);
}
// make all components of the path if they don't exist already
// returns 0 on success, -1 on failure.
// on failure, some parts may still have been created.
int
mkdirhier (const char *path)
{
char *buf; // buffer
char *ptr; // end of the string in buf
const char *pathstart; // start of a component of path
const char *pathend; // first char past the end of a component of path
size_t len;
struct stat statbuf;
len = strlen (path);
buf = HMalloc (len + 2); // one extra for possibly added '/'
ptr = buf;
pathstart = path;
#ifdef HAVE_DRIVE_LETTERS
if (isDriveLetter(pathstart[0]) && pathstart[1] == ':')
{
// Driveletter + semicolon on Windows.
// Copy as is; don't try to create directories for it.
*(ptr++) = *(pathstart++);
*(ptr++) = *(pathstart++);
ptr[0] = '/';
ptr[1] = '\0';
if (stat (buf, &statbuf) == -1)
{
log_add (log_Error, "Can't stat \"%s\": %s", buf, strerror (errno));
goto err;
}
}
else
#endif /* HAVE_DRIVE_LETTERS */
#ifdef HAVE_UNC_PATHS
if (pathstart[0] == '\\' && pathstart[1] == '\\')
{
// Universal Naming Convention path. (\\server\share\...)
// Copy the server part as is; don't try to create directories for
// it, or stat it. Don't create a dir for the share either.
*(ptr++) = *(pathstart++);
*(ptr++) = *(pathstart++);
// Copy the server part
while (*pathstart != '\0' && *pathstart != '\\' && *pathstart != '/')
*(ptr++) = *(pathstart++);
if (*pathstart == '\0')
{
log_add (log_Error, "Incomplete UNC path \"%s\"", pathstart);
goto err;
}
// Copy the path seperator.
*(ptr++) = *(pathstart++);
// Copy the share part
while (*pathstart != '\0' && *pathstart != '\\' && *pathstart != '/')
*(ptr++) = *(pathstart++);
ptr[0] = '/';
ptr[1] = '\0';
if (stat (buf, &statbuf) == -1)
{
log_add (log_Error, "Can't stat \"%s\": %s", buf, strerror (errno));
goto err;
}
}
#else
{
// Making sure that there is an 'else' case if HAVE_DRIVE_LETTERS is
// defined.
}
#endif /* HAVE_UNC_PATHS */
if (*pathstart == '/')
*(ptr++) = *(pathstart++);
if (*pathstart == '\0') {
// path exists completely, nothing more to do
return 0;
}
// walk through the path as long as the components exist
while (1)
{
pathend = strchr (pathstart, '/');
if (pathend == NULL)
pathend = path + len;
memcpy(ptr, pathstart, pathend - pathstart);
ptr += pathend - pathstart;
*ptr = '\0';
if (stat (buf, &statbuf) == -1)
{
if (errno == ENOENT)
break;
#ifdef __SYMBIAN32__
// XXX: HACK: If we don't have access to a directory, we can
// still have access to the underlying entries. We don't
// actually know whether the entry is a directory, but I know of
// no way to find out. We just pretend that it is; if we were
// wrong, an error will occur when we try to do something with
// the directory. That /should/ not be a problem, as any such
// action should have its own error checking.
if (errno != EACCES)
#endif
{
log_add (log_Error, "Can't stat \"%s\": %s", buf,
strerror (errno));
goto err;
}
}
if (*pathend == '\0')
return 0;
*ptr = '/';
ptr++;
pathstart = pathend + 1;
while (*pathstart == '/')
pathstart++;
// pathstart is the next non-slash character
if (*pathstart == '\0')
return 0;
}
// create all components left
while (1)
{
if (createDirectory (buf, 0777) == -1)
{
log_add (log_Error, "Error: Can't create %s: %s", buf,
strerror (errno));
goto err;
}
if (*pathend == '\0')
break;
*ptr = '/';
ptr++;
pathstart = pathend + 1;
while (*pathstart == '/')
pathstart++;
// pathstart is the next non-slash character
if (*pathstart == '\0')
break;
pathend = strchr (pathstart, '/');
if (pathend == NULL)
pathend = path + len;
memcpy (ptr, pathstart, pathend - pathstart);
ptr += pathend - pathstart;
*ptr = '\0';
}
return 0;
err:
{
int savedErrno = errno;
HFree (buf);
errno = savedErrno;
}
return -1;
}
// Get the user's home dir
// returns a pointer to a static buffer from either getenv() or getpwuid().
const char *
getHomeDir (void)
{
#ifdef WIN32
return getenv ("HOME");
#else
const char *home;
struct passwd *pw;
home = getenv ("HOME");
if (home != NULL)
return home;
pw = getpwuid (getuid ());
if (pw == NULL)
return NULL;
// NB: pw points to a static buffer.
return pw->pw_dir;
#endif
}
// Performs various types of string expansions on a path.
// 'what' is an OR'd compination of the folowing flags, which
// specify what type of exmansions will be performed.
// EP_HOME - Expand '~' for home dirs.
// EP_ABSOLUTE - Make relative paths absolute
// EP_ENVVARS - Expand environment variables
// EP_DOTS - Process ".." and "."
// EP_SLASHES - Consider backslashes as path component separators.
// They will be replaced by slashes.
// EP_SINGLESEP - Replace multiple consecutive path seperators (which POSIX
// considers equivalent to a single one) by a single one.
// Additionally, there's EP_ALL, which indicates all of the above,
// and EP_ALL_SYSTEM, which does the same as EP_ALL, with the exception
// of EP_SLASHES, which will only be included if the operating system
// accepts backslashes as path terminators.
// Returns 0 on success.
// Returns -1 on failure, setting errno.
int
expandPath (char *dest, size_t len, const char *src, int what)
{
char *destptr, *destend;
char *buf = NULL;
char *bufptr, *bufend;
const char *srcend;
#define CHECKLEN(bufname, n) \
if (bufname##ptr + (n) >= bufname##end) \
{ \
errno = ENAMETOOLONG; \
goto err; \
} \
else \
(void) 0
destptr = dest;
destend = dest + len;
if (what & EP_ENVVARS)
{
buf = HMalloc (len);
bufptr = buf;
bufend = buf + len;
while (*src != '\0')
{
switch (*src)
{
#ifdef WIN32
case '%':
{
/* Environment variable substitution in Windows */
const char *end; // end of env var name in src
const char *envVar;
char *envName;
size_t envNameLen, envVarLen;
src++;
end = strchr (src, '%');
if (end == NULL)
{
errno = EINVAL;
goto err;
}
envNameLen = end - src;
envName = HMalloc (envNameLen + 1);
memcpy (envName, src, envNameLen + 1);
envName[envNameLen] = '\0';
envVar = getenv (envName);
HFree (envName);
if (envVar == NULL)
{
#ifdef APPDATA_FALLBACK
if (strncmp (src, "APPDATA", envNameLen) != 0)
{
// Substitute an empty string
src = end + 1;
break;
}
// fallback for when the APPDATA env var is not set
// Using SHGetFolderPath or SHGetSpecialFolderPath
// is problematic (not everywhere available).
log_add (log_Warning, "Warning: %%APPDATA%% is not set. "
"Falling back to \"%%USERPROFILE%%\\Application "
"Data\"");
envVar = getenv ("USERPROFILE");
if (envVar != NULL)
{
#define APPDATA_STRING "\\Application Data"
envVarLen = strlen (envVar);
CHECKLEN (buf,
envVarLen + sizeof (APPDATA_STRING) - 1);
strcpy (bufptr, envVar);
bufptr += envVarLen;
strcpy (bufptr, APPDATA_STRING);
bufptr += sizeof (APPDATA_STRING) - 1;
src = end + 1;
break;
}
// fallback to "./userdata"
#define APPDATA_FALLBACK_STRING ".\\userdata"
log_add (log_Warning,
"Warning: %%USERPROFILE%% is not set. "
"Falling back to \"%s\" for %%APPDATA%%",
APPDATA_FALLBACK_STRING);
CHECKLEN (buf, sizeof (APPDATA_FALLBACK_STRING) - 1);
strcpy (bufptr, APPDATA_FALLBACK_STRING);
bufptr += sizeof (APPDATA_FALLBACK_STRING) - 1;
src = end + 1;
break;
#else /* !defined (APPDATA_FALLBACK) */
// Substitute an empty string
src = end + 1;
break;
#endif /* APPDATA_FALLBACK */
}
envVarLen = strlen (envVar);
CHECKLEN (buf, envVarLen);
strcpy (bufptr, envVar);
bufptr += envVarLen;
src = end + 1;
break;
}
#endif
#ifndef WIN32
case '$':
{
const char *end;
char *envName;
size_t envNameLen;
const char *envVar;
size_t envVarLen;
src++;
if (*src == '{')
{
src++;
end = strchr(src, '}');
if (end == NULL)
{
errno = EINVAL;
goto err;
}
envNameLen = end - src;
end++; // Skip the '}'
}
else
{
end = src;
while ((*end >= 'A' && *end <= 'Z') ||
(*end >= 'a' && *end <= 'z') ||
(*end >= '0' && *end <= '9') ||
*end == '_')
end++;
envNameLen = end - src;
}
envName = HMalloc (envNameLen + 1);
memcpy (envName, src, envNameLen + 1);
envName[envNameLen] = '\0';
envVar = getenv (envName);
HFree (envName);
if (envVar != NULL)
{
envVarLen = strlen (envVar);
CHECKLEN (buf, envVarLen);
memcpy (bufptr, envVar, envVarLen);
bufptr += envVarLen;
}
src = end;
break;
}
#endif
default:
CHECKLEN(buf, 1);
*(bufptr++) = *(src++);
break;
} // switch
} // while
*bufptr = '\0';
src = buf;
srcend = bufptr;
} // if (what & EP_ENVVARS)
else
srcend = src + strlen (src);
if (what & EP_HOME)
{
if (src[0] == '~')
{
const char *home;
size_t homelen;
if (src[1] != '/')
{
errno = EINVAL;
goto err;
}
home = getHomeDir ();
if (home == NULL)
{
errno = ENOENT;
goto err;
}
homelen = strlen (home);
if (what & EP_ABSOLUTE) {
size_t skip;
destptr = expandPathAbsolute (dest, destend - dest,
home, &skip, what);
if (destptr == NULL)
{
// errno is set
goto err;
}
home += skip;
what &= ~EP_ABSOLUTE;
// The part after the '~' should not be seen
// as absolute.
}
CHECKLEN (dest, homelen);
memcpy (destptr, home, homelen);
destptr += homelen;
src++; /* skip the ~ */
}
}
if (what & EP_ABSOLUTE)
{
size_t skip;
destptr = expandPathAbsolute (destptr, destend - destptr, src,
&skip, what);
if (destptr == NULL)
{
// errno is set
goto err;
}
src += skip;
}
CHECKLEN (dest, srcend - src);
memcpy (destptr, src, srcend - src + 1);
// The +1 is for the '\0'. It is already taken into account by
// CHECKLEN.
if (what & EP_SLASHES)
{
/* Replacing backslashes in path by slashes. */
destptr = dest;
#ifdef HAVE_UNC_PATHS
{
// A UNC path should always start with two backslashes
// and have a backslash in between the server and share part.
size_t skip = skipUNCServerShare (destptr);
if (skip != 0)
{
char *slash = (char *) memchr (destptr + 2, '/', skip - 2);
if (slash)
*slash = '\\';
destptr += skip;
}
}
#endif /* HAVE_UNC_PATHS */
while (*destptr != '\0')
{
if (*destptr == '\\')
*destptr = '/';
destptr++;
}
}
if (what & EP_DOTS) {
// At this point backslashes are already replaced by slashes if they
// are specified to be path seperators.
// Note that the path can only get smaller, so no size checks
// need to be done.
char *pathStart;
// Start of the first path component, after any
// leading slashes or drive letters.
char *startPart;
char *endPart;
pathStart = dest;
#ifdef HAVE_DRIVE_LETTERS
if (isDriveLetter(pathStart[0]) && (pathStart[1] == ':'))
{
pathStart += 2;
}
else
#endif /* HAVE_DRIVE_LETTERS */
#ifdef HAVE_UNC_PATHS
{
// Test for a Universal Naming Convention path.
pathStart += skipUNCServerShare(pathStart);
}
#else
{
// Making sure that there is an 'else' case if HAVE_DRIVE_LETTERS is
// defined.
}
#endif /* HAVE_UNC_PATHS */
if (pathStart[0] == '/')
pathStart++;
startPart = pathStart;
destptr = pathStart;
for (;;)
{
endPart = strchr(startPart, '/');
if (endPart == NULL)
endPart = startPart + strlen(startPart);
if (endPart - startPart == 1 && startPart[0] == '.')
{
// Found "." as path component. Ignore this component.
}
else if (endPart - startPart == 2 &&
startPart[0] == '.' && startPart[1] == '.')
{
// Found ".." as path component. Remove the previous
// component, and ignore this one.
char *lastSlash;
lastSlash = strrchr2(pathStart, '/', destptr - 1);
if (lastSlash == NULL)
{
if (destptr == pathStart)
{
// We ran out of path components to back out of.
errno = EINVAL;
goto err;
}
destptr = pathStart;
}
else
{
destptr = lastSlash;
if (*endPart == '/')
destptr++;
}
}
else
{
// A normal path component; copy it.
// Using memmove as source and destination may overlap.
memmove(destptr, startPart, endPart - startPart);
destptr += (endPart - startPart);
if (*endPart == '/')
{
*destptr = '/';
destptr++;
}
}
if (*endPart == '\0')
break;
startPart = endPart + 1;
}
*destptr = '\0';
}
if (what & EP_SINGLESEP)
{
char *srcptr;
srcptr = dest;
destptr = dest;
while (*srcptr != '\0')
{
char ch = *srcptr;
*(destptr++) = *(srcptr++);
if (ch == '/')
{
while (*srcptr == '/')
srcptr++;
}
}
*destptr = '\0';
}
return 0;
err:
if (buf != NULL) {
int savedErrno = errno;
HFree (buf);
errno = savedErrno;
}
return -1;
}
#if defined(HAVE_DRIVE_LETTERS) && defined(HAVE_CWD_PER_DRIVE)
// This code is only needed if we have a current working directory
// per drive.
// letter is 0 based: 0 = A, 1 = B, ...
bool
driveLetterExists(int letter)
{
unsigned long drives;
drives = _getdrives ();
return ((drives >> letter) & 1) != 0;
}
#endif /* if defined(HAVE_DRIVE_LETTERS) && defined(HAVE_CWD_PER_DRIVE) */
// helper for expandPath, expanding an absolute path
// returns a pointer to the end of the filled in part of dest.
static char *
expandPathAbsolute (char *dest, size_t destLen, const char *src,
size_t *skipSrc, int what)
{
const char *orgSrc;
if (src[0] == '/' || ((what & EP_SLASHES) && src[0] == '\\'))
{
// Path is already absolute; nothing to do
*skipSrc = 0;
return dest;
}
orgSrc = src;
#ifdef HAVE_DRIVE_LETTERS
if (isDriveLetter(src[0]) && (src[1] == ':'))
{
int letter;
if (src[2] == '/' || src[2] == '\\')
{
// Path is already absolute (of the form "d:/"); nothing to do
*skipSrc = 0;
return dest;
}
// Path is of the form "d:path", without a (back)slash after the
// semicolon.
#ifdef REJECT_DRIVE_PATH_WITHOUT_SLASH
// We reject paths of the form "d:foo/bar".
errno = EINVAL;
return NULL;
#elif defined(HAVE_CWD_PER_DRIVE)
// Paths of the form "d:foo/bar" are treated as "foo/bar" relative
// to the working directory of d:.
letter = tolower(src[0]) - 'a';
// _getdcwd() should only be called on drives that exist.
// This is weird though, because it means a race condition
// in between the existance check and the call to _getdcwd()
// cannot be avoided, unless a drive still exists for Windows
// when the physical drive is removed.
if (!driveLetterExists (letter))
{
errno = ENOENT;
return NULL;
}
// Get the working directory for a specific drive.
if (_getdcwd (letter + 1, dest, destLen) == NULL)
{
// errno is set
return NULL;
}
src += 2;
#else /* if !defined(HAVE_CWD_PER_DRIVE) */
// We treat paths of the form "d:foo/bar" as "d:/foo/bar".
if (destLen < 3) {
errno = ERANGE;
return NULL;
}
dest[0] = src[0];
dest[1] = ':';
dest[2] = '/';
*skipSrc = 2;
dest += 3;
return dest;
#endif /* HAVE_CWD_PER_DRIVE */
}
else
#endif /* HAVE_DRIVE_LETTERS */
{
// Relative dir
if (getcwd (dest, destLen) == NULL)
{
// errno is set
return NULL;
}
}
{
size_t tempLen;
tempLen = strlen (dest);
if (tempLen == 0)
{
// getcwd() or _getdcwd() returned a 0-length string.
errno = ENOENT;
return NULL;
}
dest += tempLen;
destLen -= tempLen;
}
if (dest[-1] != '/'
#ifdef BACKSLASH_IS_PATH_SEPARATOR
&& dest[-1] != '\\'
#endif /* BACKSLASH_IS_PATH_SEPARATOR */
)
{
// Need to add a slash.
// There's always space, as we overwrite the '\0' that getcwd()
// always returns.
dest[0] = '/';
dest++;
destLen--;
}
*skipSrc = (size_t) (src - orgSrc);
return dest;
}
// As strrchr, but starts searching from the indicated end of the string.
static char *
strrchr2(const char *start, int c, const char *end) {
for (;;) {
end--;
if (end < start)
return (char *) NULL;
if (*end == c)
return (char *) unconst(end);
}
}
#ifdef HAVE_UNC_PATHS
// returns 0 if the path is not a valid UNC path.
// Does not skip trailing slashes.
size_t
skipUNCServerShare(const char *inPath) {
const char *path = inPath;
// Skip the initial two backslashes.
if (path[0] != '\\' || path[1] != '\\')
return (size_t) 0;
path += 2;
// Skip the server part.
while (*path != '\\' && *path != '/') {
if (*path == '\0')
return (size_t) 0;
path++;
}
// Skip the seperator.
path++;
// Skip the share part.
while (*path != '\0' && *path != '\\' && *path != '/')
path++;
return (size_t) (path - inPath);
}
#endif /* HAVE_UNC_PATHS */

View File

@@ -0,0 +1,165 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// Contains code handling files
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "port.h"
#include "libs/uio.h"
#include "config.h"
#include "types.h"
#include "filintrn.h"
#include "libs/memlib.h"
#include "libs/log.h"
static int copyError(uio_Handle *srcHandle, uio_Handle *dstHandle,
uio_DirHandle *unlinkHandle, const char *unlinkPath, uint8 *buf);
bool
fileExists (const char *name)
{
return access (name, F_OK) == 0;
}
bool
fileExists2(uio_DirHandle *dir, const char *fileName)
{
uio_Stream *stream;
stream = uio_fopen (dir, fileName, "rb");
if (stream == NULL)
return 0;
uio_fclose (stream);
return 1;
}
/*
* Copy a file with path srcName to a file with name newName.
* If the destination already exists, the operation fails.
* Links are followed.
* Special files (fifos, char devices, block devices, etc) will be
* read as long as there is data available and the destination will be
* a regular file with that data.
* The new file will have the same permissions as the old.
* If an error occurs during copying, an attempt will be made to
* remove the copy.
*/
int
copyFile (uio_DirHandle *srcDir, const char *srcName,
uio_DirHandle *dstDir, const char *newName)
{
uio_Handle *src, *dst;
struct stat sb;
#define BUFSIZE 65536
uint8 *buf, *bufPtr;
ssize_t numInBuf, numWritten;
src = uio_open (srcDir, srcName, O_RDONLY
#ifdef WIN32
| O_BINARY
#endif
, 0);
if (src == NULL)
return -1;
if (uio_fstat (src, &sb) == -1)
return copyError (src, NULL, NULL, NULL, NULL);
dst = uio_open (dstDir, newName, O_WRONLY | O_CREAT | O_EXCL
#ifdef WIN32
| O_BINARY
#endif
, sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO));
if (dst == NULL)
return copyError (src, NULL, NULL, NULL, NULL);
buf = HMalloc(BUFSIZE);
// This was originally a statically allocated buffer,
// but as this function might be run from a thread with
// a small Stack, this is better.
while (1)
{
numInBuf = uio_read (src, buf, BUFSIZE);
if (numInBuf == -1)
{
if (errno == EINTR)
continue;
return copyError (src, dst, dstDir, newName, buf);
}
if (numInBuf == 0)
break;
bufPtr = buf;
do
{
numWritten = uio_write (dst, bufPtr, numInBuf);
if (numWritten == -1)
{
if (errno == EINTR)
continue;
return copyError (src, dst, dstDir, newName, buf);
}
numInBuf -= numWritten;
bufPtr += numWritten;
} while (numInBuf > 0);
}
HFree (buf);
uio_close (src);
uio_close (dst);
errno = 0;
return 0;
}
/*
* Closes srcHandle if it's not -1.
* Closes dstHandle if it's not -1.
* Removes unlinkpath from the unlinkHandle dir if it's not NULL.
* Frees 'buf' if not NULL.
* Always returns -1.
* errno is what was before the call.
*/
static int
copyError(uio_Handle *srcHandle, uio_Handle *dstHandle,
uio_DirHandle *unlinkHandle, const char *unlinkPath, uint8 *buf)
{
int savedErrno;
savedErrno = errno;
log_add (log_Debug, "Error while copying: %s", strerror (errno));
if (srcHandle != NULL)
uio_close (srcHandle);
if (dstHandle != NULL)
uio_close (dstHandle);
if (unlinkPath != NULL)
uio_unlink (unlinkHandle, unlinkPath);
if (buf != NULL)
HFree(buf);
errno = savedErrno;
return -1;
}

View File

@@ -0,0 +1,24 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// Contains code handling temporary files and dirs
#ifndef _FILEINTRN_H
#include "../file.h"
#endif /* _FILEINTRN_H */

View File

@@ -0,0 +1,199 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// Contains code handling temporary files and dirs
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#ifdef WIN32
# include <io.h>
#endif
#include <string.h>
#include <time.h>
#include "filintrn.h"
#include "libs/timelib.h"
#include "port.h"
#include "libs/compiler.h"
#include "libs/log.h"
#include "libs/memlib.h"
static char *tempDirName;
uio_DirHandle *tempDir;
static void
removeTempDir (void)
{
rmdir (tempDirName);
}
// Try if the null-terminated path 'dir' to a directory is valid
// as temp path.
// On success, 'buf' will be filled with the path, with a trailing /,
// null-terminated, and 0 is returned.
// On failure, EINVAL, ENAMETOOLONG, or one of the errors access() can return
// is returned, and the contents of buf is unspecified.
static int
tryTempDir (char *buf, size_t buflen, const char *dir)
{
size_t len;
int haveSlash;
if (dir == NULL)
return EINVAL;
if (dir[0] == '\0')
return EINVAL;
len = strlen (dir);
haveSlash = (dir[len - 1] == '/'
#ifdef WIN32
|| dir[len - 1] == '\\'
#endif
);
if ((haveSlash ? len : len + 1) >= buflen)
return ENAMETOOLONG;
strcpy (buf, dir);
#if 0
//def WIN32
{
char *bufPtr;
for (bufPtr = buf; *bufPtr != '\0'; bufPtr++)
{
if (*bufPtr == '\\')
*bufPtr = '/';
}
}
#endif
if (!haveSlash)
{
buf[len] = '/';
len++;
buf[len] = '\0';
}
if (access (buf, R_OK | W_OK) == -1)
return errno;
return 0;
}
static void
getTempDir (char *buf, size_t buflen) {
char cwd[PATH_MAX];
if (tryTempDir (buf, buflen, getenv("TMP")) &&
tryTempDir (buf, buflen, getenv("TEMP")) &&
#if !defined(WIN32) || defined (__CYGWIN__)
tryTempDir (buf, buflen, "/tmp/") &&
tryTempDir (buf, buflen, "/var/tmp/") &&
#endif
tryTempDir (buf, buflen, getcwd (cwd, sizeof cwd)))
{
log_add (log_Fatal, "Fatal Error: Cannot find a suitable location "
"to store temporary files.");
exit (EXIT_FAILURE);
}
}
// Sets the global var 'tempDir'
static int
mountTempDir(const char *name) {
static uio_AutoMount *autoMount[] = { NULL };
uio_MountHandle *tempHandle;
extern uio_Repository *repository;
tempHandle = uio_mountDir (repository, "/tmp/",
uio_FSTYPE_STDIO, NULL, NULL, name, autoMount,
uio_MOUNT_TOP, NULL);
if (tempHandle == NULL) {
int saveErrno = errno;
log_add (log_Fatal, "Fatal error: Couldn't mount temp dir '%s': "
"%s", name, strerror (errno));
errno = saveErrno;
return -1;
}
tempDir = uio_openDir (repository, "/tmp", 0);
if (tempDir == NULL) {
int saveErrno = errno;
log_add (log_Fatal, "Fatal error: Could not open temp dir: %s",
strerror (errno));
errno = saveErrno;
return -1;
}
return 0;
}
#define NUM_TEMP_RETRIES 16
// Number of files to try to open before giving up.
void
initTempDir (void) {
size_t len;
DWORD num;
int i;
char *tempPtr;
// Pointer to the location in the tempDirName string where the
// path to the temp dir ends and the dir starts.
tempDirName = HMalloc (PATH_MAX);
getTempDir (tempDirName, PATH_MAX - 21);
// reserve 8 chars for dirname, 1 for slash, and 12 for filename
len = strlen(tempDirName);
num = ((DWORD) time (NULL));
// num = GetTimeCounter () % 0xffffffff;
tempPtr = tempDirName + len;
for (i = 0; i < NUM_TEMP_RETRIES; i++)
{
sprintf (tempPtr, "%08x", num + i);
if (createDirectory (tempDirName, 0700) == -1)
continue;
// Success, we've got a temp dir.
tempDirName = HRealloc (tempDirName, len + 9);
atexit (removeTempDir);
if (mountTempDir (tempDirName) == -1)
exit (EXIT_FAILURE);
return;
}
// Failure, could not make a temporary directory.
log_add (log_Fatal, "Fatal error: Cannot get a name for a temporary "
"directory.");
exit (EXIT_FAILURE);
}
void
unInitTempDir (void) {
uio_closeDir(tempDir);
// the removing of the dir is handled via atexit
}
// return the path to a file in the temp dir with the specified filename.
// returns a pointer to a static buffer.
char *
tempFilePath (const char *filename) {
static char file[PATH_MAX];
if (snprintf (file, PATH_MAX, "%s/%s", tempDirName, filename) == -1) {
log_add (log_Fatal, "Path to temp file too long.");
exit (EXIT_FAILURE);
}
return file;
}

View File

@@ -0,0 +1,457 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _GFXLIB_H
#define _GFXLIB_H
#include "port.h"
#include "libs/compiler.h"
typedef struct Color Color;
struct Color {
BYTE r;
BYTE g;
BYTE b;
BYTE a;
};
#include "libs/reslib.h"
typedef struct context_desc CONTEXT_DESC;
typedef struct frame_desc FRAME_DESC;
typedef struct font_desc FONT_DESC;
typedef struct drawable_desc DRAWABLE_DESC;
typedef CONTEXT_DESC *CONTEXT;
typedef FRAME_DESC *FRAME;
typedef FONT_DESC *FONT;
typedef DRAWABLE_DESC *DRAWABLE;
typedef UWORD TIME_VALUE;
#define TIME_SHIFT 8
#define MAX_TIME_VALUE ((1 << TIME_SHIFT) + 1)
typedef SWORD COORD;
static inline bool
sameColor(Color c1, Color c2)
{
return c1.r == c2.r &&
c1.g == c2.g &&
c1.b == c2.b &&
c1.a == c2.a;
}
// Transform a 5-bits color component to an 8-bits color component.
// Form 1, calculates '(r5 / 31.0) * 255.0, highest value is 0xff:
#define CC5TO8(c) (((c) << 3) | ((c) >> 2))
// Form 2, calculates '(r5 / 32.0) * 256.0, highest value is 0xf8:
//#define CC5TO8(c) ((c) << 3)
#define BUILD_COLOR(col, c256) col
// BUILD_COLOR used to combine a 15-bit RGB color tripple with a
// destination VGA palette index into a 32-bit value.
// Now, it is an empty wrapper which returns the first argument,
// which is of type Color, and ignores the second argument,
// the palette index.
//
// It is a remnant of 8bpp hardware paletted display (VGA).
// The palette index would be overwritten with the RGB value
// and the drawing op would use this index on screen.
// The palette indices 0-15, as used in DOS SC2, are unchanged
// from the standard VGA palette and are identical to 16-color EGA.
// Various frames, borders, menus, etc. frequently refer to these
// first 16 colors and normally do not change the RGB values from
// the standard ones (see colors.h; most likely unchanged from SC1)
// The palette index is meaningless in UQM for the most part.
// New code should just use index 0.
// Turn a 15 bits color into a 24-bits color.
// r, g, and b are each 5-bits color components.
static inline Color
colorFromRgb15 (BYTE r, BYTE g, BYTE b)
{
Color c;
c.r = CC5TO8 (r);
c.g = CC5TO8 (g);
c.b = CC5TO8 (b);
c.a = 0xff;
return c;
}
#define MAKE_RGB15(r, g, b) colorFromRgb15 ((r), (g), (b))
#ifdef NOTYET /* Need C'99 support */
#define MAKE_RGB15(r, g, b) (Color) { \
.r = CC5TO8 (r), \
.g = CC5TO8 (g), \
.b = CC5TO8 (b), \
.a = 0xff \
}
#endif
// Temporary, until we can use C'99 features. Then MAKE_RGB15 will be usable
// anywhere.
// This define is intended for global initialisations, where the
// expression must be constant.
#define MAKE_RGB15_INIT(r, g, b) { \
CC5TO8 (r), \
CC5TO8 (g), \
CC5TO8 (b), \
0xff \
}
static inline Color
buildColorRgba (BYTE r, BYTE g, BYTE b, BYTE a)
{
Color c;
c.r = r;
c.g = g;
c.b = b;
c.a = a;
return c;
}
#define BUILD_COLOR_RGBA(r, g, b, a) \
buildColorRgba ((r), (g), (b), (a))
typedef BYTE CREATE_FLAGS;
// WANT_MASK is deprecated (and non-functional). It used to generate a bitmap
// of changed pixels for a target DRAWABLE, so that DRAW_SUBTRACTIVE could
// paint background pixels over them, i.e. a revert draw. The backgrounds
// are fully erased now instead.
#define WANT_MASK (CREATE_FLAGS)(1 << 0)
#define WANT_PIXMAP (CREATE_FLAGS)(1 << 1)
// MAPPED_TO_DISPLAY is deprecated but still checked by LoadDisplayPixmap().
// Its former use was to indicate a pre-scaled graphic for the display.
#define MAPPED_TO_DISPLAY (CREATE_FLAGS)(1 << 2)
#define WANT_ALPHA (CREATE_FLAGS)(1 << 3)
typedef struct extent
{
COORD width, height;
} EXTENT;
typedef struct point
{
COORD x, y;
} POINT;
typedef struct stamp
{
POINT origin;
FRAME frame;
} STAMP;
typedef struct rect
{
POINT corner;
EXTENT extent;
} RECT;
typedef struct line
{
POINT first, second;
} LINE;
static inline POINT
MAKE_POINT (COORD x, COORD y)
{
POINT pt = {x, y};
return pt;
}
static inline bool
pointsEqual (POINT p1, POINT p2)
{
return p1.x == p2.x && p1.y == p2.y;
}
static inline bool
extentsEqual (EXTENT e1, EXTENT e2)
{
return e1.width == e2.width && e1.height == e2.height;
}
static inline bool
rectsEqual (RECT r1, RECT r2)
{
return pointsEqual (r1.corner, r2.corner)
&& extentsEqual (r1.extent, r2.extent);
}
static inline bool
pointWithinRect (RECT r, POINT p)
{
return p.x >= r.corner.x && p.y >= r.corner.y
&& p.x < r.corner.x + r.extent.width
&& p.y < r.corner.y + r.extent.height;
}
typedef enum
{
ALIGN_LEFT,
ALIGN_CENTER,
ALIGN_RIGHT
} TEXT_ALIGN;
typedef enum
{
VALIGN_TOP,
VALIGN_MIDDLE,
VALIGN_BOTTOM
} TEXT_VALIGN;
typedef struct text
{
POINT baseline;
const UNICODE *pStr;
TEXT_ALIGN align;
COUNT CharCount;
} TEXT;
#include "libs/strlib.h"
typedef STRING_TABLE COLORMAP_REF;
typedef STRING COLORMAP;
// COLORMAPPTR is really a pointer to colortable entry structure
// which is documented in doc/devel/strtab, .ct files section
typedef void *COLORMAPPTR;
#include "graphics/prim.h"
typedef BYTE BATCH_FLAGS;
// This flag is currently unused but it might make sense to restore it
#define BATCH_BUILD_PAGE (BATCH_FLAGS)(1 << 0)
typedef struct
{
TIME_VALUE last_time_val;
POINT EndPoint;
STAMP IntersectStamp;
} INTERSECT_CONTROL;
typedef BYTE INTERSECT_CODE;
#define INTERSECT_LEFT (INTERSECT_CODE)(1 << 0)
#define INTERSECT_TOP (INTERSECT_CODE)(1 << 1)
#define INTERSECT_RIGHT (INTERSECT_CODE)(1 << 2)
#define INTERSECT_BOTTOM (INTERSECT_CODE)(1 << 3)
#define INTERSECT_NOCLIP (INTERSECT_CODE)(1 << 7)
#define INTERSECT_ALL_SIDES (INTERSECT_CODE)(INTERSECT_LEFT | \
INTERSECT_TOP | \
INTERSECT_RIGHT | \
INTERSECT_BOTTOM)
typedef POINT HOT_SPOT;
extern HOT_SPOT MAKE_HOT_SPOT (COORD, COORD);
extern INTERSECT_CODE BoxIntersect (RECT *pr1, RECT *pr2, RECT *printer);
extern void BoxUnion (RECT *pr1, RECT *pr2, RECT *punion);
typedef enum
{
FadeAllToWhite = 250,
FadeSomeToWhite,
FadeAllToBlack,
FadeAllToColor,
FadeSomeToBlack,
FadeSomeToColor
} ScreenFadeType;
typedef enum
{
DRAW_REPLACE = 0,
// Pixels in the target FRAME are replaced entirely.
// Non-stamp primitives with Color.a < 255 to RGB targets are
// equivalent to DRAW_ALPHA with (DrawMode.factor = Color.a),
// except the Text primitives.
// DrawMode.factor: ignored
// Text: supported (except DRAW_ALPHA via Color.a)
// RGBA sources (WANT_ALPHA): per-pixel alpha blending performed
// RGBA targets (WANT_ALPHA): replace directly supported
DRAW_ADDITIVE,
// Pixel channels of the source FRAME or Color channels of
// a primitive are modulated by (DrawMode.factor / 255) and added
// to the pixel channels of the target FRAME.
// DrawMode.factor range: -32767..32767 (negative values make
// draw subtractive); 255 = 1:1 ratio
// Text: not yet supported
// RGBA sources (WANT_ALPHA): alpha channel ignored
// RGBA targets (WANT_ALPHA): not yet supported
DRAW_ALPHA,
// Pixel channels of the source FRAME or Color channels of
// a primitive are modulated by (DrawMode.factor / 255) and added
// to the pixel channels of the target FRAME, modulated by
// (1 - DrawMode.factor / 255)
// DrawMode.factor range: 0..255; 255 = fully opaque
// Text: supported
// RGBA sources (WANT_ALPHA): alpha channel ignored
// RGBA targets (WANT_ALPHA): not yet supported
DRAW_DEFAULT = DRAW_REPLACE,
} DrawKind;
typedef struct
{
BYTE kind;
SWORD factor;
} DrawMode;
#define DRAW_REPLACE_MODE MAKE_DRAW_MODE (DRAW_REPLACE, 0)
#define DRAW_FACTOR_1 0xff
static inline DrawMode
MAKE_DRAW_MODE (DrawKind kind, SWORD factor)
{
DrawMode mode;
mode.kind = kind;
mode.factor = factor;
return mode;
}
extern CONTEXT SetContext (CONTEXT Context);
extern Color SetContextForeGroundColor (Color Color);
extern Color GetContextForeGroundColor (void);
extern Color SetContextBackGroundColor (Color Color);
extern Color GetContextBackGroundColor (void);
extern FRAME SetContextFGFrame (FRAME Frame);
extern FRAME GetContextFGFrame (void);
// Context cliprect defines the drawing bounds. Additionally, all
// drawing positions (x,y) are relative to the cliprect corner.
extern BOOLEAN SetContextClipRect (RECT *pRect);
// The returned rect is always filled in. If the context cliprect
// is undefined, the returned rect has foreground frame dimensions.
extern BOOLEAN GetContextClipRect (RECT *pRect);
// The actual origin will be orgOffset + context ClipRect.corner
extern POINT SetContextOrigin (POINT orgOffset);
extern DrawMode SetContextDrawMode (DrawMode);
extern DrawMode GetContextDrawMode (void);
// 'area' may be NULL to copy the entire CONTEXT cliprect
// 'area' is relative to the CONTEXT cliprect
extern DRAWABLE CopyContextRect (const RECT* area);
extern TIME_VALUE DrawablesIntersect (INTERSECT_CONTROL *pControl0,
INTERSECT_CONTROL *pControl1, TIME_VALUE max_time_val);
extern void DrawStamp (STAMP *pStamp);
extern void DrawFilledStamp (STAMP *pStamp);
extern void DrawPoint (POINT *pPoint);
extern void DrawRectangle (RECT *pRect);
extern void DrawFilledRectangle (RECT *pRect);
extern void DrawLine (LINE *pLine);
extern void font_DrawText (TEXT *pText);
extern void font_DrawTracedText (TEXT *pText, Color text, Color trace);
extern void DrawBatch (PRIMITIVE *pBasePrim, PRIM_LINKS PrimLinks,
BATCH_FLAGS BatchFlags);
extern void BatchGraphics (void);
extern void UnbatchGraphics (void);
extern void FlushGraphics (void);
extern void ClearDrawable (void);
#ifdef DEBUG
extern CONTEXT CreateContextAux (const char *name);
#define CreateContext(name) CreateContextAux((name))
#else /* if !defined(DEBUG) */
extern CONTEXT CreateContextAux (void);
#define CreateContext(name) CreateContextAux()
#endif /* !defined(DEBUG) */
extern BOOLEAN DestroyContext (CONTEXT ContextRef);
extern DRAWABLE CreateDisplay (CREATE_FLAGS CreateFlags, SIZE *pwidth,
SIZE *pheight);
extern DRAWABLE CreateDrawable (CREATE_FLAGS CreateFlags, SIZE width,
SIZE height, COUNT num_frames);
extern BOOLEAN DestroyDrawable (DRAWABLE Drawable);
extern BOOLEAN GetFrameRect (FRAME Frame, RECT *pRect);
#ifdef DEBUG
extern const char *GetContextName (CONTEXT context);
extern CONTEXT GetFirstContext (void);
extern CONTEXT GetNextContext (CONTEXT context);
extern size_t GetContextCount (void);
#endif /* DEBUG */
extern HOT_SPOT SetFrameHot (FRAME Frame, HOT_SPOT HotSpot);
extern HOT_SPOT GetFrameHot (FRAME Frame);
extern BOOLEAN InstallGraphicResTypes (void);
extern DRAWABLE LoadGraphicFile (const char *pStr);
extern FONT LoadFontFile (const char *pStr);
extern void *LoadGraphicInstance (RESOURCE res);
extern DRAWABLE LoadDisplayPixmap (const RECT *area, FRAME frame);
extern FRAME SetContextFontEffect (FRAME EffectFrame);
extern FONT SetContextFont (FONT Font);
extern BOOLEAN DestroyFont (FONT FontRef);
// The returned pRect is relative to the context drawing origin
extern BOOLEAN TextRect (TEXT *pText, RECT *pRect, BYTE *pdelta);
extern BOOLEAN GetContextFontLeading (SIZE *pheight);
extern BOOLEAN GetContextFontLeadingWidth (SIZE *pwidth);
extern COUNT GetFrameCount (FRAME Frame);
extern COUNT GetFrameIndex (FRAME Frame);
extern FRAME SetAbsFrameIndex (FRAME Frame, COUNT FrameIndex);
extern FRAME SetRelFrameIndex (FRAME Frame, SIZE FrameOffs);
extern FRAME SetEquFrameIndex (FRAME DstFrame, FRAME SrcFrame);
extern FRAME IncFrameIndex (FRAME Frame);
extern FRAME DecFrameIndex (FRAME Frame);
extern DRAWABLE CopyFrameRect (FRAME Frame, const RECT *area);
extern DRAWABLE CloneFrame (FRAME Frame);
extern DRAWABLE RotateFrame (FRAME Frame, int angle_deg);
extern DRAWABLE RescaleFrame (FRAME, int width, int height);
// This pair works for both paletted and trucolor frames
extern BOOLEAN ReadFramePixelColors (FRAME frame, Color *pixels,
int width, int height);
extern BOOLEAN WriteFramePixelColors (FRAME frame, const Color *pixels,
int width, int height);
// This pair only works for paletted frames
extern BOOLEAN ReadFramePixelIndexes (FRAME frame, BYTE *pixels,
int width, int height);
extern BOOLEAN WriteFramePixelIndexes (FRAME frame, const BYTE *pixels,
int width, int height);
extern void SetFrameTransparentColor (FRAME, Color);
// If the frame is an active SCREEN_DRAWABLE, this call must be
// preceeded by FlushGraphics() for draw commands to have taken effect
extern Color GetFramePixel (FRAME, POINT pixelPt);
extern FRAME CaptureDrawable (DRAWABLE Drawable);
extern DRAWABLE ReleaseDrawable (FRAME Frame);
extern DRAWABLE GetFrameParentDrawable (FRAME Frame);
extern BOOLEAN SetColorMap (COLORMAPPTR ColorMapPtr);
extern DWORD XFormColorMap (COLORMAPPTR ColorMapPtr, SIZE TimeInterval);
extern DWORD FadeScreen (ScreenFadeType fadeType, SIZE TimeInterval);
extern void FlushColorXForms (void);
#define InitColorMapResources InitStringTableResources
#define LoadColorMapFile LoadStringTableFile
#define LoadColorMapInstance LoadStringTableInstance
#define CaptureColorMap CaptureStringTable
#define ReleaseColorMap ReleaseStringTable
#define DestroyColorMap DestroyStringTable
#define GetColorMapRef GetStringTable
#define GetColorMapCount GetStringTableCount
#define GetColorMapIndex GetStringTableIndex
#define SetAbsColorMapIndex SetAbsStringTableIndex
#define SetRelColorMapIndex SetRelStringTableIndex
#define GetColorMapLength GetStringLengthBin
extern COLORMAPPTR GetColorMapAddress (COLORMAP);
void SetSystemRect (const RECT *pRect);
void ClearSystemRect (void);
#endif /* _GFXLIB_H */

View File

@@ -0,0 +1,9 @@
if [ "$uqm_GFXMODULE" = "sdl" ]; then
uqm_SUBDIRS="sdl"
fi
uqm_CFILES="boxint.c clipline.c cmap.c context.c drawable.c filegfx.c
bbox.c dcqueue.c gfxload.c
font.c frame.c gfx_common.c intersec.c loaddisp.c
pixmap.c resgfx.c tfb_draw.c tfb_prim.c widgets.c"

View File

@@ -0,0 +1,133 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "port.h"
#include "libs/graphics/bbox.h"
TFB_BoundingBox TFB_BBox;
int maxWidth;
int maxHeight;
void
TFB_BBox_Init (int width, int height)
{
maxWidth = width;
maxHeight = height;
TFB_BBox.clip.extent.width = width;
TFB_BBox.clip.extent.height = height;
}
void
TFB_BBox_Reset (void)
{
TFB_BBox.valid = 0;
}
void
TFB_BBox_SetClipRect (const RECT *r)
{
if (!r)
{ /* No clipping -- full rect */
TFB_BBox.clip.corner.x = 0;
TFB_BBox.clip.corner.y = 0;
TFB_BBox.clip.extent.width = maxWidth;
TFB_BBox.clip.extent.height = maxHeight;
return;
}
TFB_BBox.clip = *r;
/* Make sure the cliprect is sane */
if (TFB_BBox.clip.corner.x < 0)
TFB_BBox.clip.corner.x = 0;
if (TFB_BBox.clip.corner.y < 0)
TFB_BBox.clip.corner.y = 0;
if (TFB_BBox.clip.corner.x + TFB_BBox.clip.extent.width > maxWidth)
TFB_BBox.clip.extent.width = maxWidth - TFB_BBox.clip.corner.x;
if (TFB_BBox.clip.corner.y + TFB_BBox.clip.extent.height > maxHeight)
TFB_BBox.clip.extent.height = maxHeight - TFB_BBox.clip.corner.y;
}
void
TFB_BBox_RegisterPoint (int x, int y)
{
int x1 = TFB_BBox.clip.corner.x;
int y1 = TFB_BBox.clip.corner.y;
int x2 = TFB_BBox.clip.corner.x + TFB_BBox.clip.extent.width - 1;
int y2 = TFB_BBox.clip.corner.y + TFB_BBox.clip.extent.height - 1;
/* Constrain coordinates */
if (x < x1) x = x1;
if (x >= x2) x = x2;
if (y < y1) y = y1;
if (y >= y2) y = y2;
/* Is this the first point? If so, set a pixel-region and return. */
if (!TFB_BBox.valid)
{
TFB_BBox.valid = 1;
TFB_BBox.region.corner.x = x;
TFB_BBox.region.corner.y = y;
TFB_BBox.region.extent.width = 1;
TFB_BBox.region.extent.height = 1;
return;
}
/* Otherwise expand the rectangle if necessary. */
x1 = TFB_BBox.region.corner.x;
y1 = TFB_BBox.region.corner.y;
x2 = TFB_BBox.region.corner.x + TFB_BBox.region.extent.width - 1;
y2 = TFB_BBox.region.corner.y + TFB_BBox.region.extent.height - 1;
if (x < x1) {
TFB_BBox.region.corner.x = x;
TFB_BBox.region.extent.width += x1 - x;
}
if (y < y1) {
TFB_BBox.region.corner.y = y;
TFB_BBox.region.extent.height += y1 - y;
}
if (x > x2) {
TFB_BBox.region.extent.width += x - x2;
}
if (y > y2) {
TFB_BBox.region.extent.height += y - y2;
}
}
void
TFB_BBox_RegisterRect (const RECT *r)
{
/* RECT will still register as a corner point of the cliprect even
* if it does not intersect with the cliprect at all. This is not
* a problem, as more is not less. */
TFB_BBox_RegisterPoint (r->corner.x, r->corner.y);
TFB_BBox_RegisterPoint (r->corner.x + r->extent.width - 1,
r->corner.y + r->extent.height - 1);
}
void
TFB_BBox_RegisterCanvas (TFB_Canvas c, int x, int y)
{
RECT r;
r.corner.x = x;
r.corner.y = y;
TFB_DrawCanvas_GetExtent (c, &r.extent);
TFB_BBox_RegisterRect (&r);
}

View File

@@ -0,0 +1,46 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef BBOX_H_INCL__
#define BBOX_H_INCL__
#include "libs/gfxlib.h"
#include "libs/graphics/tfb_draw.h"
/* Bounding Box operations. These operations are NOT synchronized.
* However, they should only be accessed by TFB_FlushGraphics and
* TFB_SwapBuffers, or the routines that they exclusively call -- all
* of which are only callable by the thread that is permitted to touch
* the screen. No explicit locks should therefore be required. */
typedef struct {
int valid; // If zero, the next point registered becomes the region
RECT region; // The actual modified rectangle
RECT clip; // Points outside of this rectangle are pushed to
// the closest border point
} TFB_BoundingBox;
extern TFB_BoundingBox TFB_BBox;
void TFB_BBox_RegisterPoint (int x, int y);
void TFB_BBox_RegisterRect (const RECT *r);
void TFB_BBox_RegisterCanvas (TFB_Canvas c, int x, int y);
void TFB_BBox_Init (int width, int height);
void TFB_BBox_Reset (void);
void TFB_BBox_SetClipRect (const RECT *r);
#endif /* BBOX_H_INCL__ */

View File

@@ -0,0 +1,183 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "gfxintrn.h"
#undef MIN
#define MIN(a, b) (((a) <= (b)) ? (a) : (b))
#undef MAX
#define MAX(a, b) (((a) >= (b)) ? (a) : (b))
INTERSECT_CODE
BoxIntersect (RECT *pr1, RECT *pr2, RECT *pinter)
{
INTERSECT_CODE intersect_code;
COORD x1;
SIZE w1, w2, delta;
intersect_code = INTERSECT_NOCLIP;
x1 = pr1->corner.x - pr2->corner.x;
w1 = pr1->extent.width;
w2 = pr2->extent.width;
if ((delta = w2 - x1) <= w1)
{
if (delta != w1)
{
w1 = delta;
intersect_code &= ~INTERSECT_NOCLIP;
}
intersect_code |= INTERSECT_RIGHT;
}
if (x1 <= 0)
{
if (x1 < 0)
{
w1 += x1;
x1 = 0;
intersect_code &= ~INTERSECT_NOCLIP;
}
intersect_code |= INTERSECT_LEFT;
}
if (w1 > 0)
{
#define h2 w2
COORD y1;
SIZE h1;
y1 = pr1->corner.y - pr2->corner.y;
h1 = pr1->extent.height;
h2 = pr2->extent.height;
if ((delta = h2 - y1) <= h1)
{
if (delta != h1)
{
h1 = delta;
intersect_code &= ~INTERSECT_NOCLIP;
}
intersect_code |= INTERSECT_BOTTOM;
}
if (y1 <= 0)
{
if (y1 < 0)
{
h1 += y1;
y1 = 0;
intersect_code &= ~INTERSECT_NOCLIP;
}
intersect_code |= INTERSECT_TOP;
}
if (h1 > 0)
{
pinter->corner.x = x1 + pr2->corner.x;
pinter->corner.y = y1 + pr2->corner.y;
pinter->extent.width = w1;
pinter->extent.height = h1;
return (intersect_code);
}
#undef h2
}
return ((INTERSECT_CODE)0);
}
void
BoxUnion (RECT *pr1, RECT *pr2, RECT *punion)
{
#if NEVER // Part of lower FIXME.
COORD x2, y2, w2, h2;
#endif // NEVER
// Union is A AND B, put together, correct? Returns a bigger box that
// encompasses the two.
punion->corner.x = MIN(pr1->corner.x, pr2->corner.x);
punion->corner.y = MIN(pr1->corner.y, pr2->corner.y);
punion->extent.width = MAX(pr1->corner.x + pr1->extent.width,
pr2->corner.x + pr2->extent.width) - punion->corner.x;
punion->extent.height = MAX(pr1->corner.y + pr1->extent.height,
pr2->corner.y + pr2->extent.height) - punion->corner.y;
#if NEVER // FIXME - I think this is broken, but keeping it around for reference
// FIXME - just in case.
#if 1 /* alter based on 0 widths */
x2 =
(pr1->corner.x < pr2->corner.x)? pr1->corner.x : pr2->corner.x;
y2 =
(pr1->corner.y < pr2->corner.y)? pr1->corner.y : pr2->corner.y;
w2 = (
((pr1->corner.x + pr1->extent.width) > (pr2->corner.x + pr2->extent.width))?
(pr1->corner.x + pr1->extent.width) : (pr2->corner.x + pr2->extent.width)
) - punion->corner.x;
h2 = (
((pr1->corner.y + pr1->extent.height) > (pr2->corner.y + pr2->extent.height))?
(pr1->corner.y + pr1->extent.height) : (pr2->corner.y + pr2->extent.height)
) - punion->corner.y;
#else
SIZE delta;
COORD x1, y1, w1, h1;
x1 = pr1->corner.x;
w1 = pr1->extent.width;
x2 = pr2->corner.x;
w2 = pr2->extent.width;
if ((delta = x1 - x2) >= 0)
w1 += delta;
else
{
w2 -= delta;
x2 += delta;
}
y1 = pr1->corner.y;
h1 = pr1->extent.height;
y2 = pr2->corner.y;
h2 = pr2->extent.height;
if ((delta = y1 - y2) >= 0)
h1 += delta;
else
{
h2 -= delta;
y2 += delta;
}
if ((delta = w1 - w2) > 0)
w2 += delta;
if ((delta = h1 - h2) > 0)
h2 += delta;
#endif
punion->corner.x = x2;
punion->corner.y = y2;
punion->extent.width = w2;
punion->extent.height = h2;
#endif // NEVER
}

View File

@@ -0,0 +1,241 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "gfxintrn.h"
INTERSECT_CODE
_clip_line (const RECT *pClipRect, BRESENHAM_LINE *pLine)
{
COORD p;
COORD x0, y0, xmin, ymin, xmax, ymax;
SIZE abs_delta_x, abs_delta_y;
INTERSECT_CODE intersect_code;
xmin = pClipRect->corner.x;
ymin = pClipRect->corner.y;
xmax = pClipRect->corner.x + pClipRect->extent.width - 1;
ymax = pClipRect->corner.y + pClipRect->extent.height - 1;
if (pLine->first.x <= pLine->second.x)
pLine->end_points_exchanged = FALSE;
else
{
p = pLine->first.x;
pLine->first.x = pLine->second.x;
pLine->second.x = p;
p = pLine->first.y;
pLine->first.y = pLine->second.y;
pLine->second.y = p;
pLine->end_points_exchanged = TRUE;
}
if (pLine->first.x > xmax || pLine->second.x < xmin ||
(pLine->first.y > ymax && pLine->second.y > ymax) ||
(pLine->first.y < ymin && pLine->second.y < ymin))
return ((INTERSECT_CODE)0);
intersect_code = INTERSECT_NOCLIP;
x0 = y0 = 0;
abs_delta_x = (pLine->second.x - pLine->first.x) << 1;
abs_delta_y = (pLine->second.y - pLine->first.y) << 1;
pLine->abs_delta_x = abs_delta_x;
pLine->abs_delta_y = abs_delta_y;
if (abs_delta_y == 0)
{
if (pLine->first.x < xmin)
{
pLine->first.x = xmin;
intersect_code |= INTERSECT_LEFT;
}
if (pLine->second.x > xmax)
{
pLine->second.x = xmax;
intersect_code |= INTERSECT_RIGHT;
}
}
else if (abs_delta_x == 0)
{
if (abs_delta_y < 0)
{
p = pLine->first.y;
pLine->first.y = pLine->second.y;
pLine->second.y = p;
pLine->abs_delta_y =
abs_delta_y = -abs_delta_y;
}
if (pLine->first.y < ymin)
{
pLine->first.y = ymin;
intersect_code |= INTERSECT_TOP;
}
if (pLine->second.y > ymax)
{
pLine->second.y = ymax;
intersect_code |= INTERSECT_BOTTOM;
}
}
else
{
COORD x1, y1;
p = pLine->first.x;
x1 = pLine->second.x - p;
xmin = xmin - p;
xmax = xmax - p;
p = pLine->first.y;
if (abs_delta_y > 0)
{
y1 = pLine->second.y - p;
ymin = ymin - p;
ymax = ymax - p;
}
else
{
y1 = p - pLine->second.y;
ymin = p - ymin;
ymax = p - ymax;
p = ymin;
ymin = ymax;
ymax = p;
abs_delta_y = -abs_delta_y;
}
if (abs_delta_x > abs_delta_y)
{
SIZE half_dx;
half_dx = abs_delta_x >> 1;
if (x0 < xmin)
{
if ((y0 = (COORD)(((long)abs_delta_y *
(x0 = xmin) + half_dx) / abs_delta_x)) > ymax)
return ((INTERSECT_CODE)0);
intersect_code |= INTERSECT_LEFT;
}
if (x1 > xmax)
{
if ((y1 = (COORD)(((long)abs_delta_y *
(x1 = xmax) + half_dx) / abs_delta_x)) < ymin)
return ((INTERSECT_CODE)0);
intersect_code |= INTERSECT_RIGHT;
}
if (y0 < ymin)
{
if ((x0 = (COORD)(((long)abs_delta_x *
(y0 = ymin) - half_dx + (abs_delta_y - 1)) /
abs_delta_y)) > xmax)
return ((INTERSECT_CODE)0);
intersect_code |= INTERSECT_TOP;
intersect_code &= ~INTERSECT_LEFT;
}
if (y1 > ymax)
{
if ((x1 = (COORD)(((long)abs_delta_x *
((y1 = ymax) + 1) - half_dx + (abs_delta_y - 1)) /
abs_delta_y) - 1) < xmin)
return ((INTERSECT_CODE)0);
intersect_code |= INTERSECT_BOTTOM;
intersect_code &= ~INTERSECT_RIGHT;
}
}
else
{
SIZE half_dy;
half_dy = abs_delta_y >> 1;
if (y0 < ymin)
{
if ((x0 = (COORD)(((long)abs_delta_x *
(y0 = ymin) + half_dy) / abs_delta_y)) > xmax)
return ((INTERSECT_CODE)0);
intersect_code |= INTERSECT_TOP;
}
if (y1 > ymax)
{
if ((x1 = (COORD)(((long)abs_delta_x *
(y1 = ymax) + half_dy) / abs_delta_y)) < xmin)
return ((INTERSECT_CODE)0);
intersect_code |= INTERSECT_BOTTOM;
}
if (x0 < xmin)
{
if ((y0 = (COORD)(((long)abs_delta_y *
(x0 = xmin) - half_dy + (abs_delta_x - 1)) /
abs_delta_x)) > ymax)
return ((INTERSECT_CODE)0);
intersect_code |= INTERSECT_LEFT;
intersect_code &= ~INTERSECT_TOP;
}
if (x1 > xmax)
{
if ((y1 = (COORD)(((long)abs_delta_y *
((x1 = xmax) + 1) - half_dy + (abs_delta_x - 1)) /
abs_delta_x) - 1) < ymin)
return ((INTERSECT_CODE)0);
intersect_code |= INTERSECT_RIGHT;
intersect_code &= ~INTERSECT_BOTTOM;
}
}
pLine->second.x = pLine->first.x + x1;
pLine->first.x += x0;
if (pLine->abs_delta_y > 0)
{
pLine->second.y = pLine->first.y + y1;
pLine->first.y += y0;
}
else
{
INTERSECT_CODE y_code;
pLine->second.y = pLine->first.y - y1;
pLine->first.y -= y0;
y_code = (INTERSECT_CODE)(intersect_code
& (INTERSECT_TOP | INTERSECT_BOTTOM));
if (y_code && y_code != (INTERSECT_TOP | INTERSECT_BOTTOM))
intersect_code ^= (INTERSECT_TOP | INTERSECT_BOTTOM);
}
}
if (!(intersect_code & INTERSECT_ALL_SIDES))
{
if (abs_delta_x > abs_delta_y)
pLine->error_term = -(SIZE)(abs_delta_x >> 1);
else
pLine->error_term = -(SIZE)(abs_delta_y >> 1);
}
else
{
intersect_code &= ~INTERSECT_NOCLIP;
if (abs_delta_x > abs_delta_y)
pLine->error_term = (SIZE)((x0 * (long)abs_delta_y) -
(y0 * (long)abs_delta_x)) - (abs_delta_x >> 1);
else
pLine->error_term = (SIZE)((y0 * (long)abs_delta_x) -
(x0 * (long)abs_delta_y)) - (abs_delta_y >> 1);
}
return (pLine->intersect_code = intersect_code);
}

View File

@@ -0,0 +1,639 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "libs/graphics/cmap.h"
#include "libs/threadlib.h"
#include "libs/timelib.h"
#include "libs/inplib.h"
#include "libs/strlib.h"
// for GetStringAddress()
#include "libs/log.h"
#include <string.h>
#include <stdlib.h>
typedef struct xform_control
{
int CMapIndex; // -1 means unused
COLORMAPPTR CMapPtr;
SIZE Ticks;
DWORD StartTime;
DWORD EndTime;
Color OldCMap[NUMBER_OF_PLUTVALS];
} XFORM_CONTROL;
#define MAX_XFORMS 16
static struct
{
XFORM_CONTROL TaskControl[MAX_XFORMS];
volatile int Highest;
// 'pending' is Highest >= 0
Mutex Lock;
} XFormControl;
static int fadeAmount = FADE_NORMAL_INTENSITY;
static int fadeDelta;
static TimeCount fadeStartTime;
static sint32 fadeInterval;
#define SPARE_COLORMAPS 20
// Colormaps are rapidly replaced in some parts of the game, so
// it pays to have some spares on hand
static TFB_ColorMap *poolhead;
static int poolcount;
static TFB_ColorMap * colormaps[MAX_COLORMAPS];
static int mapcount;
Mutex maplock;
void
InitColorMaps (void)
{
int i;
// init colormaps
maplock = CreateMutex ("Colormaps Lock", SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO);
// init xform control
XFormControl.Highest = -1;
XFormControl.Lock = CreateMutex ("Transform Lock", SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO);
for (i = 0; i < MAX_XFORMS; ++i)
XFormControl.TaskControl[i].CMapIndex = -1;
}
void
UninitColorMaps (void)
{
TFB_ColorMap *next;
// free spares
for ( ; poolhead; poolhead = next)
{
next = poolhead->next;
HFree (poolhead);
}
// uninit xform control
DestroyMutex (XFormControl.Lock);
// uninit colormaps
DestroyMutex (maplock);
}
static inline TFB_ColorMap *
alloc_colormap (void)
// returns an addrefed object
{
TFB_ColorMap *map;
if (poolhead)
{ // have some spares
map = poolhead;
poolhead = map->next;
--poolcount;
}
else
{ // no spares, need a new one
map = HMalloc (sizeof (*map));
map->palette = AllocNativePalette ();
if (!map->palette)
{
HFree (map);
return NULL;
}
}
map->next = NULL;
map->index = -1;
map->refcount = 1;
map->version = 0;
return map;
}
static TFB_ColorMap *
clone_colormap (TFB_ColorMap *from, int index)
// returns an addrefed object
{
TFB_ColorMap *map;
map = alloc_colormap ();
if (!map)
{
log_add (log_Warning, "FATAL: clone_colormap(): "
"could not allocate a map");
exit (EXIT_FAILURE);
}
else
{ // fresh new map
map->index = index;
if (from)
map->version = from->version;
}
map->version++;
return map;
}
static inline void
free_colormap (TFB_ColorMap *map)
{
if (!map)
{
log_add (log_Warning, "free_colormap(): tried to free a NULL map");
return;
}
if (poolcount < SPARE_COLORMAPS)
{ // return to the spare pool
map->next = poolhead;
poolhead = map;
++poolcount;
}
else
{ // don't need any more spares
FreeNativePalette (map->palette);
HFree (map);
}
}
static inline TFB_ColorMap *
get_colormap (int index)
{
TFB_ColorMap *map;
map = colormaps[index];
if (!map)
{
log_add (log_Fatal, "BUG: get_colormap(): map not present");
exit (EXIT_FAILURE);
}
map->refcount++;
return map;
}
static inline void
release_colormap (TFB_ColorMap *map)
{
if (!map)
return;
if (map->refcount <= 0)
{
log_add (log_Warning, "BUG: release_colormap(): refcount not >0");
return;
}
map->refcount--;
if (map->refcount == 0)
free_colormap (map);
}
void
TFB_ReturnColorMap (TFB_ColorMap *map)
{
LockMutex (maplock);
release_colormap (map);
UnlockMutex (maplock);
}
TFB_ColorMap *
TFB_GetColorMap (int index)
{
TFB_ColorMap *map;
LockMutex (maplock);
map = get_colormap (index);
UnlockMutex (maplock);
return map;
}
void
GetColorMapColors (Color *colors, TFB_ColorMap *map)
{
int i;
if (!map)
return;
for (i = 0; i < NUMBER_OF_PLUTVALS; ++i)
colors[i] = GetNativePaletteColor (map->palette, i);
}
BOOLEAN
SetColorMap (COLORMAPPTR map)
{
int start, end;
int total_size;
UBYTE *colors = (UBYTE*)map;
TFB_ColorMap **mpp;
if (!map)
return TRUE;
start = *colors++;
end = *colors++;
if (start > end)
{
log_add (log_Warning, "ERROR: SetColorMap(): "
"starting map (%d) not less or eq ending (%d)",
start, end);
return FALSE;
}
if (start >= MAX_COLORMAPS)
{
log_add (log_Warning, "ERROR: SetColorMap(): "
"starting map (%d) beyond range (0-%d)",
start, (int)MAX_COLORMAPS - 1);
return FALSE;
}
if (end >= MAX_COLORMAPS)
{
log_add (log_Warning, "SetColorMap(): "
"ending map (%d) beyond range (0-%d)\n",
end, (int)MAX_COLORMAPS - 1);
end = MAX_COLORMAPS - 1;
}
total_size = end + 1;
LockMutex (maplock);
if (total_size > mapcount)
mapcount = total_size;
// parse the supplied PLUTs into our colormaps
for (mpp = colormaps + start; start <= end; ++start, ++mpp)
{
int i;
TFB_ColorMap *newmap;
TFB_ColorMap *oldmap;
oldmap = *mpp;
newmap = clone_colormap (oldmap, start);
for (i = 0; i < NUMBER_OF_PLUTVALS; ++i, colors += PLUTVAL_BYTE_SIZE)
{
Color color;
color.a = 0xff;
color.r = colors[PLUTVAL_RED];
color.g = colors[PLUTVAL_GREEN];
color.b = colors[PLUTVAL_BLUE];
SetNativePaletteColor (newmap->palette, i, color);
}
*mpp = newmap;
release_colormap (oldmap);
}
UnlockMutex (maplock);
return TRUE;
}
/* Fade Transforms */
int
GetFadeAmount (void)
{
int newAmount;
LockMutex (XFormControl.Lock);
if (fadeInterval)
{ // have a pending fade
TimeCount Now = GetTimeCounter ();
sint32 elapsed;
elapsed = Now - fadeStartTime;
if (elapsed > fadeInterval)
elapsed = fadeInterval;
newAmount = fadeAmount + (long)fadeDelta * elapsed / fadeInterval;
if (elapsed >= fadeInterval)
{ // fade is over
fadeAmount = newAmount;
fadeInterval = 0;
}
}
else
{ // no fade pending, return the current
newAmount = fadeAmount;
}
UnlockMutex (XFormControl.Lock);
return newAmount;
}
static void
finishPendingFade (void)
{
if (fadeInterval)
{ // end the fade immediately
fadeAmount += fadeDelta;
fadeInterval = 0;
}
}
static void
FlushFadeXForms (void)
{
LockMutex (XFormControl.Lock);
finishPendingFade ();
UnlockMutex (XFormControl.Lock);
}
DWORD
FadeScreen (ScreenFadeType fadeType, SIZE TimeInterval)
{
TimeCount TimeOut;
int FadeEnd;
switch (fadeType)
{
case FadeAllToBlack:
case FadeSomeToBlack:
FadeEnd = FADE_NO_INTENSITY;
break;
case FadeAllToColor:
case FadeSomeToColor:
FadeEnd = FADE_NORMAL_INTENSITY;
break;
case FadeAllToWhite:
case FadeSomeToWhite:
FadeEnd = FADE_FULL_INTENSITY;
break;
default:
return (GetTimeCounter ());
}
// Don't make users wait for fades
if (QuitPosted)
TimeInterval = 0;
LockMutex (XFormControl.Lock);
finishPendingFade ();
if (TimeInterval <= 0)
{ // end the fade immediately
fadeAmount = FadeEnd;
// cancel any pending fades
fadeInterval = 0;
TimeOut = GetTimeCounter ();
}
else
{
fadeInterval = TimeInterval;
fadeDelta = FadeEnd - fadeAmount;
fadeStartTime = GetTimeCounter ();
TimeOut = fadeStartTime + TimeInterval + 1;
}
UnlockMutex (XFormControl.Lock);
return TimeOut;
}
/* Colormap Transforms */
static void
finish_colormap_xform (int which)
{
SetColorMap (XFormControl.TaskControl[which].CMapPtr);
XFormControl.TaskControl[which].CMapIndex = -1;
// check Highest ptr
if (which == XFormControl.Highest)
{
do
--which;
while (which >= 0 && XFormControl.TaskControl[which].CMapIndex == -1);
XFormControl.Highest = which;
}
}
static inline BYTE
blendChan (BYTE c1, BYTE c2, int weight, int scale)
{
return c1 + ((int)c2 - c1) * weight / scale;
}
/* This gives the XFormColorMap task a timeslice to do its thing
* Only one thread should ever be allowed to be calling this at any time
*/
BOOLEAN
XFormColorMap_step (void)
{
BOOLEAN Changed = FALSE;
int x;
DWORD Now = GetTimeCounter ();
LockMutex (XFormControl.Lock);
for (x = 0; x <= XFormControl.Highest; ++x)
{
XFORM_CONTROL *control = &XFormControl.TaskControl[x];
int index = control->CMapIndex;
int TicksLeft = control->EndTime - Now;
TFB_ColorMap *curmap;
if (index < 0)
continue; // unused slot
LockMutex (maplock);
curmap = colormaps[index];
if (!curmap)
{
UnlockMutex (maplock);
log_add (log_Error, "BUG: XFormColorMap_step(): no current map");
finish_colormap_xform (x);
continue;
}
if (TicksLeft > 0)
{
#define XFORM_SCALE 0x10000
TFB_ColorMap *newmap = NULL;
UBYTE *newClr;
Color *oldClr;
int frac;
int i;
newmap = clone_colormap (curmap, index);
oldClr = control->OldCMap;
newClr = (UBYTE*)control->CMapPtr + 2;
frac = (int)(control->Ticks - TicksLeft) * XFORM_SCALE
/ control->Ticks;
for (i = 0; i < NUMBER_OF_PLUTVALS; ++i, ++oldClr,
newClr += PLUTVAL_BYTE_SIZE)
{
Color color;
color.a = 0xff;
color.r = blendChan (oldClr->r, newClr[PLUTVAL_RED],
frac, XFORM_SCALE);
color.g = blendChan (oldClr->g, newClr[PLUTVAL_GREEN],
frac, XFORM_SCALE);
color.b = blendChan (oldClr->b, newClr[PLUTVAL_BLUE],
frac, XFORM_SCALE);
SetNativePaletteColor (newmap->palette, i, color);
}
colormaps[index] = newmap;
release_colormap (curmap);
}
UnlockMutex (maplock);
if (TicksLeft <= 0)
{ // asked for immediate xform or already done
finish_colormap_xform (x);
}
Changed = TRUE;
}
UnlockMutex (XFormControl.Lock);
return Changed;
}
static void
FlushPLUTXForms (void)
{
int i;
LockMutex (XFormControl.Lock);
for (i = 0; i <= XFormControl.Highest; ++i)
{
if (XFormControl.TaskControl[i].CMapIndex >= 0)
finish_colormap_xform (i);
}
XFormControl.Highest = -1; // all gone
UnlockMutex (XFormControl.Lock);
}
static DWORD
XFormPLUT (COLORMAPPTR ColorMapPtr, SIZE TimeInterval)
{
TFB_ColorMap *map;
XFORM_CONTROL *control;
int index;
int x;
int first_avail = -1;
DWORD EndTime;
DWORD Now;
Now = GetTimeCounter ();
index = *(UBYTE*)ColorMapPtr;
LockMutex (XFormControl.Lock);
// Find an available slot, or reuse if required
for (x = 0; x <= XFormControl.Highest
&& index != XFormControl.TaskControl[x].CMapIndex;
++x)
{
if (first_avail == -1 && XFormControl.TaskControl[x].CMapIndex == -1)
first_avail = x;
}
if (index == XFormControl.TaskControl[x].CMapIndex)
{ // already xforming this colormap -- cancel and reuse slot
finish_colormap_xform (x);
}
else if (first_avail >= 0)
{ // picked up a slot along the way
x = first_avail;
}
else if (x >= MAX_XFORMS)
{ // flush some xforms if the queue is full
log_add (log_Debug, "WARNING: XFormPLUT(): no slots available");
x = XFormControl.Highest;
finish_colormap_xform (x);
}
// take next unused one
control = &XFormControl.TaskControl[x];
if (x > XFormControl.Highest)
XFormControl.Highest = x;
// make a copy of the current map
LockMutex (maplock);
map = colormaps[index];
if (!map)
{
UnlockMutex (maplock);
UnlockMutex (XFormControl.Lock);
log_add (log_Warning, "BUG: XFormPLUT(): no current map");
return (0);
}
GetColorMapColors (control->OldCMap, map);
UnlockMutex (maplock);
control->CMapIndex = index;
control->CMapPtr = ColorMapPtr;
control->Ticks = TimeInterval;
if (control->Ticks < 0)
control->Ticks = 0; /* prevent negative fade */
control->StartTime = Now;
control->EndTime = EndTime = Now + control->Ticks;
UnlockMutex (XFormControl.Lock);
return (EndTime);
}
DWORD
XFormColorMap (COLORMAPPTR ColorMapPtr, SIZE TimeInterval)
{
if (!ColorMapPtr)
return (0);
// Don't make users wait for transforms
if (QuitPosted)
TimeInterval = 0;
return XFormPLUT (ColorMapPtr, TimeInterval);
}
void
FlushColorXForms (void)
{
FlushFadeXForms ();
FlushPLUTXForms ();
}
// The type conversions are implicit and will generate errors
// or warnings if types change imcompatibly
COLORMAPPTR
GetColorMapAddress (COLORMAP colormap)
{
return GetStringAddress (colormap);
}

View File

@@ -0,0 +1,77 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef CMAP_H
#define CMAP_H
#include "libs/gfxlib.h"
#define MAX_COLORMAPS 250
// These are pertinent to colortable file format
// We load colormaps as binary and parse them when needed
#define PLUTVAL_BYTE_SIZE 3
// Channel order in colormap tables
#define PLUTVAL_RED 0
#define PLUTVAL_GREEN 1
#define PLUTVAL_BLUE 2
#define NUMBER_OF_PLUTVALS 256
// Size of the colormap in a colortable file
#define PLUT_BYTE_SIZE (PLUTVAL_BYTE_SIZE * NUMBER_OF_PLUTVALS)
#define FADE_NO_INTENSITY 0
#define FADE_NORMAL_INTENSITY 255
#define FADE_FULL_INTENSITY 510
typedef struct NativePalette NativePalette;
typedef struct tfb_colormap
{
int index;
// Colormap index as the game sees it
int version;
// Version goes up every time the colormap changes. This may
// be due to SetColorMap() or at every transformation step
// of XFormColorMap(). Paletted TFB_Images track the last
// colormap version they were drawn with for optimization.
int refcount;
struct tfb_colormap *next;
// for spares linking
NativePalette *palette;
} TFB_ColorMap;
extern int GetFadeAmount (void);
extern void InitColorMaps (void);
extern void UninitColorMaps (void);
extern void GetColorMapColors (Color *colors, TFB_ColorMap *);
extern TFB_ColorMap * TFB_GetColorMap (int index);
extern void TFB_ReturnColorMap (TFB_ColorMap *map);
extern BOOLEAN XFormColorMap_step (void);
// Native
NativePalette* AllocNativePalette (void);
void FreeNativePalette (NativePalette *);
void SetNativePaletteColor (NativePalette *, int index, Color);
Color GetNativePaletteColor (NativePalette *, int index);
#endif /* CMAP_H */

View File

@@ -0,0 +1,398 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "gfxintrn.h"
GRAPHICS_STATUS _GraphicsStatusFlags;
CONTEXT _pCurContext;
#ifdef DEBUG
// We keep track of all contexts
CONTEXT firstContext;
// The first one in the list.
CONTEXT *contextEnd = &firstContext;
// Where to put the next context.
#endif
PRIMITIVE _locPrim;
FONT _CurFontPtr;
#define DEFAULT_FORE_COLOR BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x1F), 0x0F)
#define DEFAULT_BACK_COLOR BUILD_COLOR (MAKE_RGB15 (0x00, 0x00, 0x00), 0x00)
#define DEFAULT_DRAW_MODE MAKE_DRAW_MODE (DRAW_DEFAULT, 255)
CONTEXT
SetContext (CONTEXT Context)
{
CONTEXT LastContext;
LastContext = _pCurContext;
if (Context != LastContext)
{
if (LastContext)
{
UnsetContextFlags (
MAKE_WORD (0, GRAPHICS_ACTIVE | DRAWABLE_ACTIVE));
SetContextFlags (
MAKE_WORD (0, _GraphicsStatusFlags
& (GRAPHICS_ACTIVE | DRAWABLE_ACTIVE)));
DeactivateContext ();
}
_pCurContext = Context;
if (_pCurContext)
{
ActivateContext ();
_GraphicsStatusFlags &= ~(GRAPHICS_ACTIVE | DRAWABLE_ACTIVE);
_GraphicsStatusFlags |= HIBYTE (_get_context_flags ());
SetPrimColor (&_locPrim, _get_context_fg_color ());
_CurFramePtr = _get_context_fg_frame ();
_CurFontPtr = _get_context_font ();
}
}
return (LastContext);
}
#ifdef DEBUG
CONTEXT
CreateContextAux (const char *name)
#else /* if !defined(DEBUG) */
CONTEXT
CreateContextAux (void)
#endif /* !defined(DEBUG) */
{
CONTEXT NewContext;
NewContext = AllocContext ();
if (NewContext)
{
/* initialize context */
#ifdef DEBUG
NewContext->name = name;
NewContext->next = NULL;
*contextEnd = NewContext;
contextEnd = &NewContext->next;
#endif /* DEBUG */
NewContext->Mode = DEFAULT_DRAW_MODE;
NewContext->ForeGroundColor = DEFAULT_FORE_COLOR;
NewContext->BackGroundColor = DEFAULT_BACK_COLOR;
}
return NewContext;
}
#ifdef DEBUG
// Loop through the list of context to the pointer which points to the
// specified context. This is either 'firstContext' or the address of
// the 'next' field of some other context.
static CONTEXT *
FindContextPtr (CONTEXT context) {
CONTEXT *ptr;
for (ptr = &firstContext; *ptr != NULL; ptr = &(*ptr)->next) {
if (*ptr == context)
break;
}
return ptr;
}
#endif /* DEBUG */
BOOLEAN
DestroyContext (CONTEXT ContextRef)
{
if (ContextRef == 0)
return (FALSE);
if (_pCurContext && _pCurContext == ContextRef)
SetContext ((CONTEXT)0);
#ifdef DEBUG
// Unlink the context.
{
CONTEXT *contextPtr = FindContextPtr (ContextRef);
if (contextEnd == &ContextRef->next)
contextEnd = contextPtr;
*contextPtr = ContextRef->next;
}
#endif /* DEBUG */
FreeContext (ContextRef);
return TRUE;
}
Color
SetContextForeGroundColor (Color color)
{
Color oldColor;
if (!ContextActive ())
return DEFAULT_FORE_COLOR;
oldColor = _get_context_fg_color ();
if (!sameColor(oldColor, color))
{
SwitchContextForeGroundColor (color);
if (!(_get_context_fbk_flags () & FBK_IMAGE))
{
SetContextFBkFlags (FBK_DIRTY);
}
}
SetPrimColor (&_locPrim, color);
return (oldColor);
}
Color
GetContextForeGroundColor (void)
{
if (!ContextActive ())
return DEFAULT_FORE_COLOR;
return _get_context_fg_color ();
}
Color
SetContextBackGroundColor (Color color)
{
Color oldColor;
if (!ContextActive ())
return DEFAULT_BACK_COLOR;
oldColor = _get_context_bg_color ();
if (!sameColor(oldColor, color))
SwitchContextBackGroundColor (color);
return oldColor;
}
Color
GetContextBackGroundColor (void)
{
if (!ContextActive ())
return DEFAULT_BACK_COLOR;
return _get_context_bg_color ();
}
DrawMode
SetContextDrawMode (DrawMode mode)
{
DrawMode oldMode;
if (!ContextActive ())
return DEFAULT_DRAW_MODE;
oldMode = _get_context_draw_mode ();
SwitchContextDrawMode (mode);
return oldMode;
}
DrawMode
GetContextDrawMode (void)
{
if (!ContextActive ())
return DEFAULT_DRAW_MODE;
return _get_context_draw_mode ();
}
// Returns a rect based at 0,0 and the size of context foreground frame
static inline RECT
_get_context_fg_rect (void)
{
RECT r = { {0, 0}, {0, 0} };
if (_CurFramePtr)
r.extent = GetFrameBounds (_CurFramePtr);
return r;
}
BOOLEAN
SetContextClipRect (RECT *lpRect)
{
if (!ContextActive ())
return (FALSE);
if (lpRect)
{
if (rectsEqual (*lpRect, _get_context_fg_rect ()))
{ // Cliprect is undefined to mirror GetContextClipRect()
_pCurContext->ClipRect.extent.width = 0;
}
else
{ // We have a cliprect
_pCurContext->ClipRect = *lpRect;
}
}
else
{ // Set cliprect as undefined
_pCurContext->ClipRect.extent.width = 0;
}
return TRUE;
}
BOOLEAN
GetContextClipRect (RECT *lpRect)
{
if (!ContextActive ())
return (FALSE);
*lpRect = _pCurContext->ClipRect;
if (!_pCurContext->ClipRect.extent.width)
{ // Though the cliprect is undefined, drawing will be clipped
// to the extent of the foreground frame
*lpRect = _get_context_fg_rect ();
}
return (_pCurContext->ClipRect.extent.width != 0);
}
POINT
SetContextOrigin (POINT orgOffset)
{
// XXX: This is a hack, kind of. But that's what the original did.
return SetFrameHot (_CurFramePtr, orgOffset);
}
FRAME
SetContextFontEffect (FRAME EffectFrame)
{
FRAME LastEffect;
if (!ContextActive ())
return (NULL);
LastEffect = _get_context_fonteff ();
if (EffectFrame != LastEffect)
{
SwitchContextFontEffect (EffectFrame);
if (EffectFrame != 0)
{
SetContextFBkFlags (FBK_IMAGE);
}
else
{
UnsetContextFBkFlags (FBK_IMAGE);
}
}
return LastEffect;
}
void
FixContextFontEffect (void)
{
SIZE w, h;
TFB_Image* img;
if (!ContextActive () || (_get_context_font_backing () != 0
&& !(_get_context_fbk_flags () & FBK_DIRTY)))
return;
if (!GetContextFontLeading (&h) || !GetContextFontLeadingWidth (&w))
return;
img = _pCurContext->FontBacking;
if (img)
TFB_DrawScreen_DeleteImage (img);
img = TFB_DrawImage_CreateForScreen (w, h, TRUE);
if (_get_context_fbk_flags () & FBK_IMAGE)
{ // image pattern backing
FRAME EffectFrame = _get_context_fonteff ();
TFB_DrawImage_Image (EffectFrame->image,
-EffectFrame->HotSpot.x, -EffectFrame->HotSpot.y,
0, 0, NULL, DRAW_REPLACE_MODE, img);
}
else
{ // solid color backing
RECT r = { {0, 0}, {w, h} };
Color color = _get_context_fg_color ();
TFB_DrawImage_Rect (&r, color, DRAW_REPLACE_MODE, img);
}
_pCurContext->FontBacking = img;
UnsetContextFBkFlags (FBK_DIRTY);
}
// 'area' may be NULL to copy the entire CONTEXT cliprect
// 'area' is relative to the CONTEXT cliprect
DRAWABLE
CopyContextRect (const RECT* area)
{
RECT clipRect;
RECT fgRect;
RECT r;
if (!ContextActive () || !_CurFramePtr)
return NULL;
fgRect = _get_context_fg_rect ();
GetContextClipRect (&clipRect);
r = clipRect;
if (area)
{ // a portion of the context
r.corner.x += area->corner.x;
r.corner.y += area->corner.y;
r.extent = area->extent;
}
// TODO: Should this take CONTEXT origin into account too?
// validate the rect
if (!BoxIntersect (&r, &fgRect, &r))
return NULL;
if (_CurFramePtr->Type == SCREEN_DRAWABLE)
return LoadDisplayPixmap (&r, NULL);
else
return CopyFrameRect (_CurFramePtr, &r);
}
#ifdef DEBUG
const char *
GetContextName (CONTEXT context)
{
return context->name;
}
CONTEXT
GetFirstContext (void)
{
return firstContext;
}
CONTEXT
GetNextContext (CONTEXT context)
{
return context->next;
}
#endif /* DEBUG */

View File

@@ -0,0 +1,147 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _CONTEXT_H
#define _CONTEXT_H
#include "tfb_draw.h"
#include "libs/memlib.h"
typedef UWORD FBK_FLAGS;
#define FBK_DIRTY (1 << 0)
#define FBK_IMAGE (1 << 1)
struct context_desc
{
UWORD Flags;
// Low nibble currently unused
// High nibble contains GRAPHICS_STATUS
Color ForeGroundColor, BackGroundColor;
DrawMode Mode;
FRAME ForeGroundFrame;
FONT Font;
RECT ClipRect;
FRAME FontEffect;
TFB_Image *FontBacking;
FBK_FLAGS BackingFlags;
#ifdef DEBUG
const char *name;
CONTEXT next;
#endif
};
#define AllocContext() HCalloc (sizeof (CONTEXT_DESC))
#define FreeContext HFree
extern CONTEXT _pCurContext;
extern PRIMITIVE _locPrim;
#define _get_context_fg_color() (_pCurContext->ForeGroundColor)
#define _get_context_bg_color() (_pCurContext->BackGroundColor)
#define _get_context_flags() (_pCurContext->Flags)
#define _get_context_fg_frame() (_pCurContext->ForeGroundFrame)
#define _get_context_font() (_pCurContext->Font)
#define _get_context_fbk_flags() (_pCurContext->BackingFlags)
#define _get_context_fonteff() (_pCurContext->FontEffect)
#define _get_context_font_backing() (_pCurContext->FontBacking)
#define _get_context_draw_mode() (_pCurContext->Mode)
#define SwitchContextDrawMode(m) \
{ \
_pCurContext->Mode = (m); \
}
#define SwitchContextForeGroundColor(c) \
{ \
_pCurContext->ForeGroundColor = (c); \
}
#define SwitchContextBackGroundColor(c) \
{ \
_pCurContext->BackGroundColor = (c); \
}
#define SetContextFlags(f) \
{ \
_pCurContext->Flags |= (f); \
}
#define UnsetContextFlags(f) \
{ \
_pCurContext->Flags &= ~(f); \
}
#define SwitchContextFGFrame(f) \
{ \
_pCurContext->ForeGroundFrame = (f); \
}
#define SwitchContextFont(f) \
{ \
_pCurContext->Font = (f); \
SetContextFBkFlags (FBK_DIRTY); \
}
#define SwitchContextBGFunc(f) \
{ \
_pCurContext->BackGroundFunc = (f); \
}
#define SetContextFBkFlags(f) \
{ \
_pCurContext->BackingFlags |= (f); \
}
#define UnsetContextFBkFlags(f) \
{ \
_pCurContext->BackingFlags &= ~(f); \
}
#define SwitchContextFontEffect(f) \
{ \
_pCurContext->FontEffect = (f); \
SetContextFBkFlags (FBK_DIRTY); \
}
typedef BYTE GRAPHICS_STATUS;
extern GRAPHICS_STATUS _GraphicsStatusFlags;
#define GRAPHICS_ACTIVE (GRAPHICS_STATUS)(1 << 0)
#define GRAPHICS_VISIBLE (GRAPHICS_STATUS)(1 << 1)
#define CONTEXT_ACTIVE (GRAPHICS_STATUS)(1 << 2)
#define DRAWABLE_ACTIVE (GRAPHICS_STATUS)(1 << 3)
#define DeactivateGraphics() (_GraphicsStatusFlags &= ~GRAPHICS_ACTIVE)
#define ActivateGraphics() (_GraphicsStatusFlags |= GRAPHICS_ACTIVE)
#define GraphicsActive() (_GraphicsStatusFlags & GRAPHICS_ACTIVE)
#define DeactivateVisible() (_GraphicsStatusFlags &= ~GRAPHICS_VISIBLE)
#define ActivateVisible() (_GraphicsStatusFlags |= GRAPHICS_VISIBLE)
#define DeactivateContext() (_GraphicsStatusFlags &= ~CONTEXT_ACTIVE)
#define ActivateContext() (_GraphicsStatusFlags |= CONTEXT_ACTIVE)
#define ContextActive() (_GraphicsStatusFlags & CONTEXT_ACTIVE)
#define DeactivateDrawable() (_GraphicsStatusFlags &= ~DRAWABLE_ACTIVE)
#define ActivateDrawable() (_GraphicsStatusFlags |= DRAWABLE_ACTIVE)
#define DrawableActive() (_GraphicsStatusFlags & DRAWABLE_ACTIVE)
#define SYSTEM_ACTIVE (GRAPHICS_STATUS)(CONTEXT_ACTIVE | DRAWABLE_ACTIVE)
#define GraphicsSystemActive() \
((_GraphicsStatusFlags & SYSTEM_ACTIVE) == SYSTEM_ACTIVE)
#define GraphicsStatus() \
(_GraphicsStatusFlags & (GRAPHICS_STATUS)(GRAPHICS_ACTIVE \
| GRAPHICS_VISIBLE))
// pValidRect or origin may be NULL
BOOLEAN GetContextValidRect (RECT *pValidRect, POINT *origin);
extern void FixContextFontEffect (void);
#endif /* _CONTEXT_H */

View File

@@ -0,0 +1,589 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "port.h"
#include "libs/threadlib.h"
#include "libs/graphics/drawcmd.h"
#include "libs/graphics/drawable.h"
#include "libs/graphics/context.h"
#include "libs/graphics/dcqueue.h"
#include "libs/graphics/gfx_common.h"
#include "libs/graphics/bbox.h"
#include "libs/timelib.h"
#include "libs/log.h"
#include "libs/misc.h"
// for TFB_DEBUG_HALT
static RecursiveMutex DCQ_Mutex;
CondVar RenderingCond;
TFB_DrawCommand DCQ[DCQ_MAX];
TFB_DrawCommandQueue DrawCommandQueue;
#define FPS_PERIOD (ONE_SECOND / 100)
int RenderedFrames = 0;
// Wait for the queue to be emptied.
static void
TFB_WaitForSpace (int requested_slots)
{
int old_depth, i;
log_add (log_Debug, "DCQ overload (Size = %d, FullSize = %d, "
"Requested = %d). Sleeping until renderer is done.",
DrawCommandQueue.Size, DrawCommandQueue.FullSize,
requested_slots);
// Restore the DCQ locking level. I *think* this is
// always 1, but...
TFB_BatchReset ();
old_depth = GetRecursiveMutexDepth (DCQ_Mutex);
for (i = 0; i < old_depth; i++)
UnlockRecursiveMutex (DCQ_Mutex);
WaitCondVar (RenderingCond);
for (i = 0; i < old_depth; i++)
LockRecursiveMutex (DCQ_Mutex);
log_add (log_Debug, "DCQ clear (Size = %d, FullSize = %d). Continuing.",
DrawCommandQueue.Size, DrawCommandQueue.FullSize);
}
void
Lock_DCQ (int slots)
{
LockRecursiveMutex (DCQ_Mutex);
while (DrawCommandQueue.FullSize >= DCQ_MAX - slots)
{
TFB_WaitForSpace (slots);
}
}
void
Unlock_DCQ (void)
{
UnlockRecursiveMutex (DCQ_Mutex);
}
// Always have the DCQ locked when calling this.
static void
Synchronize_DCQ (void)
{
if (!DrawCommandQueue.Batching)
{
int front = DrawCommandQueue.Front;
int back = DrawCommandQueue.InsertionPoint;
DrawCommandQueue.Back = DrawCommandQueue.InsertionPoint;
if (front <= back)
{
DrawCommandQueue.Size = (back - front);
}
else
{
DrawCommandQueue.Size = (back + DCQ_MAX - front);
}
DrawCommandQueue.FullSize = DrawCommandQueue.Size;
}
}
void
TFB_BatchGraphics (void)
{
LockRecursiveMutex (DCQ_Mutex);
DrawCommandQueue.Batching++;
UnlockRecursiveMutex (DCQ_Mutex);
}
void
TFB_UnbatchGraphics (void)
{
LockRecursiveMutex (DCQ_Mutex);
if (DrawCommandQueue.Batching)
{
DrawCommandQueue.Batching--;
}
Synchronize_DCQ ();
UnlockRecursiveMutex (DCQ_Mutex);
}
// Cancel all pending batch operations, making them unbatched. This will
// cause a small amount of flicker when invoked, but prevents
// batching problems from freezing the game.
void
TFB_BatchReset (void)
{
LockRecursiveMutex (DCQ_Mutex);
DrawCommandQueue.Batching = 0;
Synchronize_DCQ ();
UnlockRecursiveMutex (DCQ_Mutex);
}
// Draw Command Queue Stuff
void
Init_DrawCommandQueue (void)
{
DrawCommandQueue.Back = 0;
DrawCommandQueue.Front = 0;
DrawCommandQueue.InsertionPoint = 0;
DrawCommandQueue.Batching = 0;
DrawCommandQueue.FullSize = 0;
DrawCommandQueue.Size = 0;
TFB_BBox_Init (ScreenWidth, ScreenHeight);
DCQ_Mutex = CreateRecursiveMutex ("DCQ",
SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO);
RenderingCond = CreateCondVar ("DCQ empty",
SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO);
}
void
Uninit_DrawCommandQueue (void)
{
DestroyCondVar (RenderingCond);
DestroyRecursiveMutex (DCQ_Mutex);
}
void
TFB_DrawCommandQueue_Push (TFB_DrawCommand* Command)
{
Lock_DCQ (1);
DCQ[DrawCommandQueue.InsertionPoint] = *Command;
DrawCommandQueue.InsertionPoint = (DrawCommandQueue.InsertionPoint + 1)
% DCQ_MAX;
DrawCommandQueue.FullSize++;
Synchronize_DCQ ();
Unlock_DCQ ();
}
int
TFB_DrawCommandQueue_Pop (TFB_DrawCommand *target)
{
LockRecursiveMutex (DCQ_Mutex);
if (DrawCommandQueue.Size == 0)
{
Unlock_DCQ ();
return (0);
}
if (DrawCommandQueue.Front == DrawCommandQueue.Back &&
DrawCommandQueue.Size != DCQ_MAX)
{
log_add (log_Debug, "Augh! Assertion failure in DCQ! "
"Front == Back, Size != DCQ_MAX");
DrawCommandQueue.Size = 0;
Unlock_DCQ ();
return (0);
}
*target = DCQ[DrawCommandQueue.Front];
DrawCommandQueue.Front = (DrawCommandQueue.Front + 1) % DCQ_MAX;
DrawCommandQueue.Size--;
DrawCommandQueue.FullSize--;
UnlockRecursiveMutex (DCQ_Mutex);
return 1;
}
void
TFB_DrawCommandQueue_Clear ()
{
LockRecursiveMutex (DCQ_Mutex);
DrawCommandQueue.Size = 0;
DrawCommandQueue.Front = 0;
DrawCommandQueue.Back = 0;
DrawCommandQueue.Batching = 0;
DrawCommandQueue.FullSize = 0;
DrawCommandQueue.InsertionPoint = 0;
UnlockRecursiveMutex (DCQ_Mutex);
}
void
TFB_EnqueueDrawCommand (TFB_DrawCommand* DrawCommand)
{
if (TFB_DEBUG_HALT)
{
return;
}
if (DrawCommand->Type <= TFB_DRAWCOMMANDTYPE_COPYTOIMAGE
&& _CurFramePtr->Type == SCREEN_DRAWABLE)
{
static RECT scissor_rect;
// Set the clipping region.
// We allow drawing with no current context set, so the whole screen
if ((_pCurContext && !rectsEqual (scissor_rect, _pCurContext->ClipRect))
|| (!_pCurContext && scissor_rect.extent.width != 0))
{
// Enqueue command to set the glScissor spec
TFB_DrawCommand DC;
if (_pCurContext)
scissor_rect = _pCurContext->ClipRect;
else
scissor_rect.extent.width = 0;
if (scissor_rect.extent.width)
{
DC.Type = TFB_DRAWCOMMANDTYPE_SCISSORENABLE;
DC.data.scissor.rect = scissor_rect;
}
else
{
DC.Type = TFB_DRAWCOMMANDTYPE_SCISSORDISABLE;
}
TFB_EnqueueDrawCommand(&DC);
}
}
TFB_DrawCommandQueue_Push (DrawCommand);
}
static void
computeFPS (void)
{
static TimeCount last_time;
static TimePeriod fps_counter;
TimeCount current_time;
TimePeriod delta_time;
current_time = GetTimeCounter ();
delta_time = current_time - last_time;
last_time = current_time;
fps_counter += delta_time;
if (fps_counter > FPS_PERIOD)
{
log_add (log_User, "fps %.2f, effective %.2f",
(float)ONE_SECOND / delta_time,
(float)ONE_SECOND * RenderedFrames / fps_counter);
fps_counter = 0;
RenderedFrames = 0;
}
}
// Only call from main() thread!!
void
TFB_FlushGraphics (void)
{
int commands_handled;
BOOLEAN livelock_deterrence;
// This is technically a locking violation on DrawCommandQueue.Size,
// but it is likely to not be very destructive.
if (DrawCommandQueue.Size == 0)
{
static int last_fade = 255;
static int last_transition = 255;
int current_fade = GetFadeAmount ();
int current_transition = TransitionAmount;
if ((current_fade != 255 && current_fade != last_fade) ||
(current_transition != 255 &&
current_transition != last_transition) ||
(current_fade == 255 && last_fade != 255) ||
(current_transition == 255 && last_transition != 255))
{
TFB_SwapBuffers (TFB_REDRAW_FADING);
// if fading, redraw every frame
}
else
{
TaskSwitch ();
}
last_fade = current_fade;
last_transition = current_transition;
BroadcastCondVar (RenderingCond);
return;
}
if (GfxFlags & TFB_GFXFLAGS_SHOWFPS)
computeFPS ();
commands_handled = 0;
livelock_deterrence = FALSE;
if (DrawCommandQueue.FullSize > DCQ_FORCE_BREAK_SIZE)
{
TFB_BatchReset ();
}
if (DrawCommandQueue.Size > DCQ_FORCE_SLOWDOWN_SIZE)
{
Lock_DCQ (-1);
livelock_deterrence = TRUE;
}
TFB_BBox_Reset ();
for (;;)
{
TFB_DrawCommand DC;
if (!TFB_DrawCommandQueue_Pop (&DC))
{
// the Queue is now empty.
break;
}
++commands_handled;
if (!livelock_deterrence && commands_handled + DrawCommandQueue.Size
> DCQ_LIVELOCK_MAX)
{
// log_add (log_Debug, "Initiating livelock deterrence!");
livelock_deterrence = TRUE;
Lock_DCQ (-1);
}
switch (DC.Type)
{
case TFB_DRAWCOMMANDTYPE_SETMIPMAP:
{
TFB_DrawCommand_SetMipmap *cmd = &DC.data.setmipmap;
TFB_DrawImage_SetMipmap (cmd->image, cmd->mipmap,
cmd->hotx, cmd->hoty);
break;
}
case TFB_DRAWCOMMANDTYPE_IMAGE:
{
TFB_DrawCommand_Image *cmd = &DC.data.image;
TFB_Image *DC_image = cmd->image;
const int x = cmd->x;
const int y = cmd->y;
TFB_DrawCanvas_Image (DC_image, x, y,
cmd->scale, cmd->scaleMode, cmd->colormap,
cmd->drawMode,
TFB_GetScreenCanvas (cmd->destBuffer));
if (cmd->destBuffer == TFB_SCREEN_MAIN)
{
LockMutex (DC_image->mutex);
if (cmd->scale)
TFB_BBox_RegisterCanvas (DC_image->ScaledImg,
x - DC_image->last_scale_hs.x,
y - DC_image->last_scale_hs.y);
else
TFB_BBox_RegisterCanvas (DC_image->NormalImg,
x - DC_image->NormalHs.x,
y - DC_image->NormalHs.y);
UnlockMutex (DC_image->mutex);
}
break;
}
case TFB_DRAWCOMMANDTYPE_FILLEDIMAGE:
{
TFB_DrawCommand_FilledImage *cmd = &DC.data.filledimage;
TFB_Image *DC_image = cmd->image;
const int x = cmd->x;
const int y = cmd->y;
TFB_DrawCanvas_FilledImage (DC_image, x, y,
cmd->scale, cmd->scaleMode, cmd->color,
cmd->drawMode,
TFB_GetScreenCanvas (cmd->destBuffer));
if (cmd->destBuffer == TFB_SCREEN_MAIN)
{
LockMutex (DC_image->mutex);
if (cmd->scale)
TFB_BBox_RegisterCanvas (DC_image->ScaledImg,
x - DC_image->last_scale_hs.x,
y - DC_image->last_scale_hs.y);
else
TFB_BBox_RegisterCanvas (DC_image->NormalImg,
x - DC_image->NormalHs.x,
y - DC_image->NormalHs.y);
UnlockMutex (DC_image->mutex);
}
break;
}
case TFB_DRAWCOMMANDTYPE_FONTCHAR:
{
TFB_DrawCommand_FontChar *cmd = &DC.data.fontchar;
TFB_Char *DC_char = cmd->fontchar;
const int x = cmd->x;
const int y = cmd->y;
TFB_DrawCanvas_FontChar (DC_char, cmd->backing, x, y,
cmd->drawMode, TFB_GetScreenCanvas (cmd->destBuffer));
if (cmd->destBuffer == TFB_SCREEN_MAIN)
{
RECT r;
r.corner.x = x - DC_char->HotSpot.x;
r.corner.y = y - DC_char->HotSpot.y;
r.extent.width = DC_char->extent.width;
r.extent.height = DC_char->extent.height;
TFB_BBox_RegisterRect (&r);
}
break;
}
case TFB_DRAWCOMMANDTYPE_LINE:
{
TFB_DrawCommand_Line *cmd = &DC.data.line;
if (cmd->destBuffer == TFB_SCREEN_MAIN)
{
TFB_BBox_RegisterPoint (cmd->x1, cmd->y1);
TFB_BBox_RegisterPoint (cmd->x2, cmd->y2);
}
TFB_DrawCanvas_Line (cmd->x1, cmd->y1, cmd->x2, cmd->y2,
cmd->color, cmd->drawMode,
TFB_GetScreenCanvas (cmd->destBuffer));
break;
}
case TFB_DRAWCOMMANDTYPE_RECTANGLE:
{
TFB_DrawCommand_Rect *cmd = &DC.data.rect;
if (cmd->destBuffer == TFB_SCREEN_MAIN)
TFB_BBox_RegisterRect (&cmd->rect);
TFB_DrawCanvas_Rect (&cmd->rect, cmd->color, cmd->drawMode,
TFB_GetScreenCanvas (cmd->destBuffer));
break;
}
case TFB_DRAWCOMMANDTYPE_SCISSORENABLE:
{
TFB_DrawCommand_Scissor *cmd = &DC.data.scissor;
TFB_DrawCanvas_SetClipRect (
TFB_GetScreenCanvas (TFB_SCREEN_MAIN), &cmd->rect);
TFB_BBox_SetClipRect (&DC.data.scissor.rect);
break;
}
case TFB_DRAWCOMMANDTYPE_SCISSORDISABLE:
TFB_DrawCanvas_SetClipRect (
TFB_GetScreenCanvas (TFB_SCREEN_MAIN), NULL);
TFB_BBox_SetClipRect (NULL);
break;
case TFB_DRAWCOMMANDTYPE_COPYTOIMAGE:
{
TFB_DrawCommand_CopyToImage *cmd = &DC.data.copytoimage;
TFB_Image *DC_image = cmd->image;
const POINT dstPt = {0, 0};
if (DC_image == 0)
{
log_add (log_Debug, "DCQ ERROR: COPYTOIMAGE passed null "
"image ptr");
break;
}
LockMutex (DC_image->mutex);
TFB_DrawCanvas_CopyRect (
TFB_GetScreenCanvas (cmd->srcBuffer), &cmd->rect,
DC_image->NormalImg, dstPt);
UnlockMutex (DC_image->mutex);
break;
}
case TFB_DRAWCOMMANDTYPE_COPY:
{
TFB_DrawCommand_Copy *cmd = &DC.data.copy;
const RECT r = cmd->rect;
if (cmd->destBuffer == TFB_SCREEN_MAIN)
TFB_BBox_RegisterRect (&cmd->rect);
TFB_DrawCanvas_CopyRect (
TFB_GetScreenCanvas (cmd->srcBuffer), &r,
TFB_GetScreenCanvas (cmd->destBuffer), r.corner);
break;
}
case TFB_DRAWCOMMANDTYPE_DELETEIMAGE:
{
TFB_Image *DC_image = DC.data.deleteimage.image;
TFB_DrawImage_Delete (DC_image);
break;
}
case TFB_DRAWCOMMANDTYPE_DELETEDATA:
{
void *data = DC.data.deletedata.data;
HFree (data);
break;
}
case TFB_DRAWCOMMANDTYPE_SENDSIGNAL:
ClearSemaphore (DC.data.sendsignal.sem);
break;
case TFB_DRAWCOMMANDTYPE_REINITVIDEO:
{
TFB_DrawCommand_ReinitVideo *cmd = &DC.data.reinitvideo;
int oldDriver = GraphicsDriver;
int oldFlags = GfxFlags;
int oldWidth = ScreenWidthActual;
int oldHeight = ScreenHeightActual;
if (TFB_ReInitGraphics (cmd->driver, cmd->flags,
cmd->width, cmd->height))
{
log_add (log_Error, "Could not provide requested mode: "
"reverting to last known driver.");
// We don't know what exactly failed, so roll it all back
if (TFB_ReInitGraphics (oldDriver, oldFlags,
oldWidth, oldHeight))
{
log_add (log_Fatal,
"Couldn't reinit at that point either. "
"Your video has been somehow tied in knots.");
exit (EXIT_FAILURE);
}
}
TFB_SwapBuffers (TFB_REDRAW_YES);
break;
}
case TFB_DRAWCOMMANDTYPE_CALLBACK:
{
DC.data.callback.callback (DC.data.callback.arg);
break;
}
}
}
if (livelock_deterrence)
Unlock_DCQ ();
TFB_SwapBuffers (TFB_REDRAW_NO);
RenderedFrames++;
BroadcastCondVar (RenderingCond);
}

View File

@@ -0,0 +1,55 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef DCQUEUE_H
#define DCQUEUE_H
// Maximum size of the DCQ. The larger the DCQ, the larger frameskips
// become tolerable before initiating livelock deterrence and game
// slowdown. Other constants for controlling the frameskip/slowdown
// balance may be found in sdl_common.c near TFB_FlushGraphics.
// Livelock deterrance constants. Because the entire screen is rarely
// refreshed, we may not drop draw commands on the floor with abandon.
// Furthermore, if the main program is queuing commands at a speed
// comparable to our processing of the commands, we never finish and
// the game freezes. Thus, if the queue starts out larger than
// DCQ_FORCE_SLOWDOWN_SIZE, or DCQ_LIVELOCK_MAX commands find
// themselves being processed in one go, livelock deterrence is
// enabled, and TFB_FlushGraphics locks the DCQ until it has processed
// all entries. If batched but pending commands exceed DCQ_FORCE_BREAK_SIZE,
// a continuity break is performed. This will effectively slow down the
// game logic, a fate we seek to avoid - however, it seems to be unavoidable
// on slower machines. Even there, it's seems nonexistent outside of
// communications screens. --Michael
#ifdef DCQ_OF_DOOM
#define DCQ_MAX 512
#define DCQ_FORCE_SLOWDOWN_SIZE 128
#define DCQ_FORCE_BREAK_SIZE 512
#define DCQ_LIVELOCK_MAX 256
#else
#define DCQ_MAX 16384
#define DCQ_FORCE_SLOWDOWN_SIZE 4096
#define DCQ_FORCE_BREAK_SIZE 16384
#define DCQ_LIVELOCK_MAX 4096
#endif
extern CondVar RenderingCond;
#endif

View File

@@ -0,0 +1,501 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "libs/gfxlib.h"
#include "libs/graphics/context.h"
#include "libs/graphics/drawable.h"
#include "libs/graphics/tfb_draw.h"
#include "libs/memlib.h"
#include "tfb_draw.h"
#include <math.h>
#ifndef M_PI
# define M_PI 3.14159265358979323846
#endif
FRAME _CurFramePtr;
FRAME
SetContextFGFrame (FRAME Frame)
{
FRAME LastFrame;
if (Frame != (LastFrame = (FRAME)_CurFramePtr))
{
if (LastFrame)
DeactivateDrawable ();
_CurFramePtr = Frame;
if (_CurFramePtr)
ActivateDrawable ();
if (ContextActive ())
{
SwitchContextFGFrame (Frame);
}
}
return (LastFrame);
}
FRAME
GetContextFGFrame (void)
{
return _CurFramePtr;
}
static DRAWABLE
request_drawable (COUNT NumFrames, DRAWABLE_TYPE DrawableType,
CREATE_FLAGS flags, SIZE width, SIZE height)
{
DRAWABLE Drawable;
COUNT i;
Drawable = AllocDrawable (NumFrames);
if (!Drawable)
return NULL;
Drawable->Flags = flags;
Drawable->MaxIndex = NumFrames - 1;
for (i = 0; i < NumFrames; ++i)
{
FRAME FramePtr = &Drawable->Frame[i];
if (DrawableType == RAM_DRAWABLE && width > 0 && height > 0)
{
FramePtr->image = TFB_DrawImage_New (TFB_DrawCanvas_New_TrueColor (
width, height, (flags & WANT_ALPHA) ? TRUE : FALSE));
}
FramePtr->Type = DrawableType;
FramePtr->Index = i;
SetFrameBounds (FramePtr, width, height);
}
return Drawable;
}
DRAWABLE
CreateDisplay (CREATE_FLAGS CreateFlags, SIZE *pwidth, SIZE *pheight)
{
DRAWABLE Drawable;
// TODO: ScreenWidth and ScreenHeight should be passed in
// instead of returned.
Drawable = request_drawable (1, SCREEN_DRAWABLE,
(CreateFlags & (WANT_PIXMAP | WANT_MASK)),
ScreenWidth, ScreenHeight);
if (Drawable)
{
FRAME F;
F = CaptureDrawable (Drawable);
if (F == 0)
DestroyDrawable (Drawable);
else
{
*pwidth = GetFrameWidth (F);
*pheight = GetFrameHeight (F);
ReleaseDrawable (F);
return (Drawable);
}
}
*pwidth = *pheight = 0;
return (0);
}
DRAWABLE
AllocDrawable (COUNT n)
{
DRAWABLE Drawable;
Drawable = (DRAWABLE) HCalloc(sizeof (DRAWABLE_DESC));
if (Drawable)
{
int i;
Drawable->Frame = (FRAME)HMalloc (sizeof (FRAME_DESC) * n);
if (Drawable->Frame == NULL)
{
HFree (Drawable);
return NULL;
}
/* Zero out the newly allocated frames, since HMalloc doesn't have
* MEM_ZEROINIT. */
for (i = 0; i < n; i++) {
FRAME F;
F = &Drawable->Frame[i];
F->parent = Drawable;
F->Type = 0;
F->Index = 0;
F->image = 0;
F->Bounds.width = 0;
F->Bounds.height = 0;
F->HotSpot.x = 0;
F->HotSpot.y = 0;
}
}
return Drawable;
}
DRAWABLE
CreateDrawable (CREATE_FLAGS CreateFlags, SIZE width, SIZE height, COUNT
num_frames)
{
DRAWABLE Drawable;
Drawable = request_drawable (num_frames, RAM_DRAWABLE,
(CreateFlags & (WANT_MASK | WANT_PIXMAP
| WANT_ALPHA | MAPPED_TO_DISPLAY)),
width, height);
if (Drawable)
{
FRAME F;
F = CaptureDrawable (Drawable);
if (F)
{
ReleaseDrawable (F);
return (Drawable);
}
}
return (0);
}
BOOLEAN
DestroyDrawable (DRAWABLE Drawable)
{
if (_CurFramePtr && (Drawable == _CurFramePtr->parent))
SetContextFGFrame ((FRAME)NULL);
if (Drawable)
{
FreeDrawable (Drawable);
return (TRUE);
}
return (FALSE);
}
BOOLEAN
GetFrameRect (FRAME FramePtr, RECT *pRect)
{
if (FramePtr)
{
pRect->corner.x = -FramePtr->HotSpot.x;
pRect->corner.y = -FramePtr->HotSpot.y;
pRect->extent = GetFrameBounds (FramePtr);
return (TRUE);
}
return (FALSE);
}
HOT_SPOT
SetFrameHot (FRAME FramePtr, HOT_SPOT HotSpot)
{
if (FramePtr)
{
HOT_SPOT OldHot;
OldHot = FramePtr->HotSpot;
FramePtr->HotSpot = HotSpot;
return (OldHot);
}
return (MAKE_HOT_SPOT (0, 0));
}
HOT_SPOT
GetFrameHot (FRAME FramePtr)
{
if (FramePtr)
{
return FramePtr->HotSpot;
}
return (MAKE_HOT_SPOT (0, 0));
}
DRAWABLE
RotateFrame (FRAME Frame, int angle_deg)
{
DRAWABLE Drawable;
FRAME RotFramePtr;
double dx, dy;
double d;
double angle = angle_deg * M_PI / 180;
if (!Frame)
return NULL;
assert (Frame->Type != SCREEN_DRAWABLE);
Drawable = request_drawable (1, RAM_DRAWABLE, WANT_PIXMAP, 0, 0);
if (!Drawable)
return 0;
RotFramePtr = CaptureDrawable (Drawable);
if (!RotFramePtr)
{
FreeDrawable (Drawable);
return 0;
}
RotFramePtr->image = TFB_DrawImage_New_Rotated (
Frame->image, angle_deg);
SetFrameBounds (RotFramePtr, RotFramePtr->image->extent.width,
RotFramePtr->image->extent.height);
/* now we need to rotate the hot-spot, eww */
dx = Frame->HotSpot.x - (GetFrameWidth (Frame) / 2);
dy = Frame->HotSpot.y - (GetFrameHeight (Frame) / 2);
d = sqrt ((double)dx*dx + (double)dy*dy);
if ((int)d != 0)
{
double organg = atan2 (-dy, dx);
dx = cos (organg + angle) * d;
dy = -sin (organg + angle) * d;
}
RotFramePtr->HotSpot.x = (GetFrameWidth (RotFramePtr) / 2) + (int)dx;
RotFramePtr->HotSpot.y = (GetFrameHeight (RotFramePtr) / 2) + (int)dy;
ReleaseDrawable (RotFramePtr);
return Drawable;
}
// color.a is ignored
void
SetFrameTransparentColor (FRAME frame, Color color)
{
TFB_Image *img;
if (!frame)
return;
assert (frame->Type != SCREEN_DRAWABLE);
img = frame->image;
LockMutex (img->mutex);
// TODO: This should defer to TFB_DrawImage instead
TFB_DrawCanvas_SetTransparentColor (img->NormalImg, color, FALSE);
UnlockMutex (img->mutex);
}
Color
GetFramePixel (FRAME frame, POINT pixelPt)
{
TFB_Image *img;
Color ret;
if (!frame)
return BUILD_COLOR_RGBA (0, 0, 0, 0);
assert (frame->Type != SCREEN_DRAWABLE);
img = frame->image;
LockMutex (img->mutex);
// TODO: This should defer to TFB_DrawImage instead
ret = TFB_DrawCanvas_GetPixel (img->NormalImg, pixelPt.x, pixelPt.y);
UnlockMutex (img->mutex);
return ret;
}
static FRAME
makeMatchingFrame (FRAME frame, int width, int height)
{
DRAWABLE drawable;
FRAME newFrame;
CREATE_FLAGS flags;
flags = GetFrameParentDrawable (frame)->Flags;
drawable = CreateDrawable (flags, width, height, 1);
if (!drawable)
return NULL;
newFrame = CaptureDrawable (drawable);
if (!newFrame)
{
FreeDrawable (drawable);
return NULL;
}
return newFrame;
}
// Creates an new DRAWABLE containing a copy of specified FRAME's rect
// Source FRAME must not be a SCREEN_DRAWABLE
DRAWABLE
CopyFrameRect (FRAME frame, const RECT *area)
{
FRAME newFrame;
POINT nullPt = MAKE_POINT (0, 0);
if (!frame)
return NULL;
assert (frame->Type != SCREEN_DRAWABLE);
newFrame = makeMatchingFrame (frame, area->extent.width,
area->extent.height);
if (!newFrame)
return NULL;
TFB_DrawImage_CopyRect (frame->image, area, newFrame->image, nullPt);
return ReleaseDrawable (newFrame);
}
// Creates an new DRAWABLE mostly identical to specified FRAME
// Source FRAME must not be a SCREEN_DRAWABLE
DRAWABLE
CloneFrame (FRAME frame)
{
FRAME newFrame;
RECT r;
if (!frame)
return NULL;
assert (frame->Type != SCREEN_DRAWABLE);
GetFrameRect (frame, &r);
r.corner.x = 0;
r.corner.y = 0;
newFrame = CaptureDrawable (CopyFrameRect (frame, &r));
if (!newFrame)
return NULL;
// copy the hot-spot
newFrame->HotSpot = frame->HotSpot;
return ReleaseDrawable (newFrame);
}
// Creates a new DRAWABLE of specified size and scales the passed
// frame onto it. The aspect ratio is not preserved.
DRAWABLE
RescaleFrame (FRAME frame, int width, int height)
{
FRAME newFrame;
TFB_Image *img;
TFB_Canvas src, dst;
if (!frame)
return NULL;
assert (frame->Type != SCREEN_DRAWABLE);
newFrame = makeMatchingFrame (frame, width, height);
if (!newFrame)
return NULL;
// scale the hot-spot
newFrame->HotSpot.x = frame->HotSpot.x * width / frame->Bounds.width;
newFrame->HotSpot.y = frame->HotSpot.y * height / frame->Bounds.height;
img = frame->image;
LockMutex (img->mutex);
// NOTE: We do not lock the target image because nothing has a
// reference to it yet!
src = img->NormalImg;
dst = newFrame->image->NormalImg;
TFB_DrawCanvas_Rescale_Nearest (src, dst, -1, NULL, NULL, NULL);
UnlockMutex (img->mutex);
return ReleaseDrawable (newFrame);
}
BOOLEAN
ReadFramePixelColors (FRAME frame, Color *pixels, int width, int height)
{
TFB_Image *img;
if (!frame)
return FALSE;
assert (frame->Type != SCREEN_DRAWABLE);
// TODO: Do we need to lock the img->mutex here?
img = frame->image;
return TFB_DrawCanvas_GetPixelColors (img->NormalImg, pixels,
width, height);
}
// Warning: this functions bypasses DCQ, which is why it is not a DrawXXX
BOOLEAN
WriteFramePixelColors (FRAME frame, const Color *pixels, int width, int height)
{
TFB_Image *img;
if (!frame)
return FALSE;
assert (frame->Type != SCREEN_DRAWABLE);
// TODO: Do we need to lock the img->mutex here?
img = frame->image;
return TFB_DrawCanvas_SetPixelColors (img->NormalImg, pixels,
width, height);
}
BOOLEAN
ReadFramePixelIndexes (FRAME frame, BYTE *pixels, int width, int height)
{
TFB_Image *img;
if (!frame)
return FALSE;
assert (frame->Type != SCREEN_DRAWABLE);
// TODO: Do we need to lock the img->mutex here?
img = frame->image;
return TFB_DrawCanvas_GetPixelIndexes (img->NormalImg, pixels,
width, height);
}
// Warning: this functions bypasses DCQ, which is why it is not a DrawXXX
BOOLEAN
WriteFramePixelIndexes (FRAME frame, const BYTE *pixels, int width, int height)
{
TFB_Image *img;
if (!frame)
return FALSE;
assert (frame->Type != SCREEN_DRAWABLE);
// TODO: Do we need to lock the img->mutex here?
img = frame->image;
return TFB_DrawCanvas_SetPixelIndexes (img->NormalImg, pixels,
width, height);
}

View File

@@ -0,0 +1,88 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _DRAWABLE_H
#define _DRAWABLE_H
#include <stdio.h>
#include "tfb_draw.h"
#define ValidPrimType(pt) ((pt)<NUM_PRIMS)
typedef struct bresenham_line
{
POINT first, second;
SIZE abs_delta_x, abs_delta_y;
SIZE error_term;
BOOLEAN end_points_exchanged;
INTERSECT_CODE intersect_code;
} BRESENHAM_LINE;
typedef UWORD DRAWABLE_TYPE;
#define ROM_DRAWABLE 0
#define RAM_DRAWABLE 1
#define SCREEN_DRAWABLE 2
struct frame_desc
{
DRAWABLE_TYPE Type;
UWORD Index;
HOT_SPOT HotSpot;
EXTENT Bounds;
TFB_Image *image;
struct drawable_desc *parent;
};
struct drawable_desc
{
CREATE_FLAGS Flags;
UWORD MaxIndex;
FRAME_DESC *Frame;
};
#define GetFrameWidth(f) ((f)->Bounds.width)
#define GetFrameHeight(f) ((f)->Bounds.height)
#define GetFrameBounds(f) ((f)->Bounds)
#define SetFrameBounds(f,w,h) \
((f)->Bounds.width=(w), \
((f))->Bounds.height=(h))
#define DRAWABLE_PRIORITY DEFAULT_MEM_PRIORITY
extern DRAWABLE AllocDrawable (COUNT num_frames);
#define FreeDrawable(D) _ReleaseCelData (D)
typedef struct
{
RECT Box;
FRAME FramePtr;
} IMAGE_BOX;
extern INTERSECT_CODE _clip_line (const RECT *pClipRect,
BRESENHAM_LINE *pLine);
extern void *_GetCelData (uio_Stream *fp, DWORD length);
extern BOOLEAN _ReleaseCelData (void *handle);
extern FRAME _CurFramePtr;
// ClipRect is relative to ctxOrigin
extern void _text_blt (RECT *pClipRect, TEXT *TextPtr, POINT ctxOrigin);
#endif /* _DRAWABLE_H */

View File

@@ -0,0 +1,202 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef DRAWCMD_H
#define DRAWCMD_H
#include "libs/graphics/tfb_draw.h"
enum
{
TFB_DRAWCOMMANDTYPE_LINE,
TFB_DRAWCOMMANDTYPE_RECTANGLE,
TFB_DRAWCOMMANDTYPE_IMAGE,
TFB_DRAWCOMMANDTYPE_FILLEDIMAGE,
TFB_DRAWCOMMANDTYPE_FONTCHAR,
TFB_DRAWCOMMANDTYPE_COPY,
TFB_DRAWCOMMANDTYPE_COPYTOIMAGE,
TFB_DRAWCOMMANDTYPE_SCISSORENABLE,
TFB_DRAWCOMMANDTYPE_SCISSORDISABLE,
TFB_DRAWCOMMANDTYPE_SETMIPMAP,
TFB_DRAWCOMMANDTYPE_DELETEIMAGE,
TFB_DRAWCOMMANDTYPE_DELETEDATA,
TFB_DRAWCOMMANDTYPE_SENDSIGNAL,
TFB_DRAWCOMMANDTYPE_REINITVIDEO,
TFB_DRAWCOMMANDTYPE_CALLBACK,
};
typedef struct tfb_dc_line
{
int x1, y1, x2, y2;
Color color;
DrawMode drawMode;
SCREEN destBuffer;
} TFB_DrawCommand_Line;
typedef struct tfb_dc_rect
{
RECT rect;
Color color;
DrawMode drawMode;
SCREEN destBuffer;
} TFB_DrawCommand_Rect;
typedef struct tfb_dc_img
{
TFB_Image *image;
int x, y;
SCREEN destBuffer;
TFB_ColorMap *colormap;
DrawMode drawMode;
int scale;
int scaleMode;
} TFB_DrawCommand_Image;
typedef struct tfb_dc_filledimg
{
TFB_Image *image;
int x, y;
Color color;
SCREEN destBuffer;
DrawMode drawMode;
int scale;
int scaleMode;
} TFB_DrawCommand_FilledImage;
typedef struct tfb_dc_fontchar
{
TFB_Char *fontchar;
TFB_Image *backing;
int x, y;
DrawMode drawMode;
SCREEN destBuffer;
} TFB_DrawCommand_FontChar;
typedef struct tfb_dc_copy
{
RECT rect;
SCREEN srcBuffer, destBuffer;
} TFB_DrawCommand_Copy;
typedef struct tfb_dc_copyimg
{
TFB_Image *image;
RECT rect;
SCREEN srcBuffer;
} TFB_DrawCommand_CopyToImage;
typedef struct tfb_dc_scissor
{
RECT rect;
} TFB_DrawCommand_Scissor;
typedef struct tfb_dc_setmip
{
TFB_Image *image;
TFB_Image *mipmap;
int hotx, hoty;
} TFB_DrawCommand_SetMipmap;
typedef struct tfb_dc_delimg
{
TFB_Image *image;
} TFB_DrawCommand_DeleteImage;
typedef struct tfb_dc_deldata
{
void *data;
// data must be a result of HXalloc() call
} TFB_DrawCommand_DeleteData;
typedef struct tfb_dc_signal
{
Semaphore sem;
} TFB_DrawCommand_SendSignal;
typedef struct tfb_dc_reinit_video
{
int driver, flags, width, height;
} TFB_DrawCommand_ReinitVideo;
typedef struct tfb_dc_callback
{
void (*callback)(void *arg);
void *arg;
} TFB_DrawCommand_Callback;
typedef struct tfb_drawcommand
{
int Type;
union {
TFB_DrawCommand_Line line;
TFB_DrawCommand_Rect rect;
TFB_DrawCommand_Image image;
TFB_DrawCommand_FilledImage filledimage;
TFB_DrawCommand_FontChar fontchar;
TFB_DrawCommand_Copy copy;
TFB_DrawCommand_CopyToImage copytoimage;
TFB_DrawCommand_Scissor scissor;
TFB_DrawCommand_SetMipmap setmipmap;
TFB_DrawCommand_DeleteImage deleteimage;
TFB_DrawCommand_DeleteData deletedata;
TFB_DrawCommand_SendSignal sendsignal;
TFB_DrawCommand_ReinitVideo reinitvideo;
TFB_DrawCommand_Callback callback;
} data;
} TFB_DrawCommand;
// Queue Stuff
typedef struct tfb_drawcommandqueue
{
int Front;
int Back;
int InsertionPoint;
int Batching;
volatile int FullSize;
volatile int Size;
} TFB_DrawCommandQueue;
void Init_DrawCommandQueue (void);
void Uninit_DrawCommandQueue (void);
void TFB_BatchGraphics (void);
void TFB_UnbatchGraphics (void);
void TFB_BatchReset (void);
void TFB_DrawCommandQueue_Push (TFB_DrawCommand* Command);
int TFB_DrawCommandQueue_Pop (TFB_DrawCommand* Command);
void TFB_DrawCommandQueue_Clear (void);
extern TFB_DrawCommandQueue DrawCommandQueue;
void TFB_EnqueueDrawCommand (TFB_DrawCommand* DrawCommand);
void Lock_DCQ (int slots);
void Unlock_DCQ (void);
#endif

View File

@@ -0,0 +1,72 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "gfxintrn.h"
#include "options.h"
#include "libs/reslib.h"
DRAWABLE
LoadGraphicFile (const char *pStr)
{
uio_Stream *fp;
// FIXME: this theoretically needs a mechanism to prevent races
if (_cur_resfile_name)
// something else is loading resources atm
return 0;
fp = res_OpenResFile (contentDir, pStr, "rb");
if (fp != NULL)
{
DRAWABLE hData;
_cur_resfile_name = pStr;
hData = (DRAWABLE)_GetCelData (fp, LengthResFile (fp));
_cur_resfile_name = 0;
res_CloseResFile (fp);
return hData;
}
return (NULL);
}
FONT
LoadFontFile (const char *pStr)
{
uio_Stream *fp;
// FIXME: this theoretically needs a mechanism to prevent races
if (_cur_resfile_name)
// something else is loading resources atm
return 0;
fp = res_OpenResFile (contentDir, pStr, "rb");
if (fp != NULL)
{
FONT hData;
_cur_resfile_name = pStr;
hData = (FONT)_GetFontData (fp, LengthResFile (fp));
_cur_resfile_name = 0;
res_CloseResFile (fp);
return hData;
}
return (0);
}

View File

@@ -0,0 +1,334 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "gfxintrn.h"
#include "tfb_prim.h"
#include "libs/log.h"
static inline TFB_Char *getCharFrame (FONT_DESC *fontPtr, UniChar ch);
FONT
SetContextFont (FONT Font)
{
FONT LastFont;
LastFont = _CurFontPtr;
_CurFontPtr = Font;
if (ContextActive ())
SwitchContextFont (Font);
return (LastFont);
}
BOOLEAN
DestroyFont (FONT FontRef)
{
if (FontRef == NULL)
return (FALSE);
if (_CurFontPtr && _CurFontPtr == FontRef)
SetContextFont ((FONT)NULL);
return (FreeFont (FontRef));
}
// XXX: Should be in frame.c (renamed to something decent?)
void
font_DrawText (TEXT *lpText)
{
RECT ClipRect;
POINT origin;
TEXT text;
FixContextFontEffect ();
if (!GraphicsSystemActive () || !GetContextValidRect (NULL, &origin))
return;
// TextRect() clobbers TEXT.CharCount so we have to make a copy
text = *lpText;
if (!TextRect (&text, &ClipRect, NULL))
return;
// ClipRect is relative to origin
_text_blt (&ClipRect, &text, origin);
}
/* Draw the stroke by drawing the same text in the
* background color one pixel shifted to all 4 directions.
*/
void
font_DrawTracedText (TEXT *pText, Color text, Color trace)
{
// Preserve current foreground color for full correctness
Color oldfg = SetContextForeGroundColor (trace);
pText->baseline.x--;
font_DrawText (pText);
pText->baseline.x += 2;
font_DrawText (pText);
pText->baseline.x--;
pText->baseline.y--;
font_DrawText (pText);
pText->baseline.y += 2;
font_DrawText (pText);
pText->baseline.y--;
SetContextForeGroundColor (text);
font_DrawText (pText);
SetContextForeGroundColor (oldfg);
}
BOOLEAN
GetContextFontLeading (SIZE *pheight)
{
if (_CurFontPtr != 0)
{
*pheight = (SIZE)_CurFontPtr->Leading;
return (TRUE);
}
*pheight = 0;
return (FALSE);
}
BOOLEAN
GetContextFontLeadingWidth (SIZE *pwidth)
{
if (_CurFontPtr != 0)
{
*pwidth = (SIZE)_CurFontPtr->LeadingWidth;
return (TRUE);
}
*pwidth = 0;
return (FALSE);
}
BOOLEAN
TextRect (TEXT *lpText, RECT *pRect, BYTE *pdelta)
{
BYTE char_delta_array[MAX_DELTAS];
FONT FontPtr;
FontPtr = _CurFontPtr;
if (FontPtr != 0 && lpText->CharCount != 0)
{
COORD top_y, bot_y;
SIZE width;
UniChar next_ch = 0;
const char *pStr;
COUNT num_chars;
num_chars = lpText->CharCount;
/* At this point lpText->CharCount contains the *maximum* number of
* characters that lpText->pStr may contain.
* After the while loop below, it will contain the actual number.
*/
if (pdelta == 0)
{
pdelta = char_delta_array;
if (num_chars > MAX_DELTAS)
{
num_chars = MAX_DELTAS;
lpText->CharCount = MAX_DELTAS;
}
}
top_y = 0;
bot_y = 0;
width = 0;
pStr = lpText->pStr;
if (num_chars > 0)
{
next_ch = getCharFromString (&pStr);
if (next_ch == '\0')
num_chars = 0;
}
while (num_chars--)
{
UniChar ch;
SIZE last_width;
TFB_Char *charFrame;
last_width = width;
ch = next_ch;
if (num_chars > 0)
{
next_ch = getCharFromString (&pStr);
if (next_ch == '\0')
{
lpText->CharCount -= num_chars;
num_chars = 0;
}
}
charFrame = getCharFrame (FontPtr, ch);
if (charFrame != NULL && charFrame->disp.width)
{
COORD y;
y = -charFrame->HotSpot.y;
if (y < top_y)
top_y = y;
y += charFrame->disp.height;
if (y > bot_y)
bot_y = y;
width += charFrame->disp.width;
#if 0
if (num_chars && next_ch < (UNICODE) MAX_CHARS
&& !(FontPtr->KernTab[ch]
& (FontPtr->KernTab[next_ch] >> 2)))
width -= FontPtr->KernAmount;
#endif
}
*pdelta++ = (BYTE)(width - last_width);
}
if (width > 0 && (bot_y -= top_y) > 0)
{
/* subtract off default character spacing */
if (pdelta[-1] > 0)
{
--pdelta[-1];
--width;
}
if (lpText->align == ALIGN_LEFT)
pRect->corner.x = 0;
else if (lpText->align == ALIGN_CENTER)
pRect->corner.x = -(width >> 1);
else
pRect->corner.x = -width;
pRect->corner.y = top_y;
pRect->extent.width = width;
pRect->extent.height = bot_y;
pRect->corner.x += lpText->baseline.x;
pRect->corner.y += lpText->baseline.y;
return (TRUE);
}
}
pRect->corner = lpText->baseline;
pRect->extent.width = 0;
pRect->extent.height = 0;
return (FALSE);
}
void
_text_blt (RECT *pClipRect, TEXT *TextPtr, POINT ctxOrigin)
{
FONT FontPtr;
COUNT num_chars;
UniChar next_ch;
const char *pStr;
POINT origin;
TFB_Image *backing;
DrawMode mode = _get_context_draw_mode ();
FontPtr = _CurFontPtr;
if (FontPtr == NULL)
return;
backing = _get_context_font_backing ();
if (!backing)
return;
origin.x = pClipRect->corner.x;
origin.y = TextPtr->baseline.y;
num_chars = TextPtr->CharCount;
if (num_chars == 0)
return;
pStr = TextPtr->pStr;
next_ch = getCharFromString (&pStr);
if (next_ch == '\0')
num_chars = 0;
while (num_chars--)
{
UniChar ch;
TFB_Char* fontChar;
ch = next_ch;
if (num_chars > 0)
{
next_ch = getCharFromString (&pStr);
if (next_ch == '\0')
num_chars = 0;
}
fontChar = getCharFrame (FontPtr, ch);
if (fontChar != NULL && fontChar->disp.width)
{
RECT r;
r.corner.x = origin.x - fontChar->HotSpot.x;
r.corner.y = origin.y - fontChar->HotSpot.y;
r.extent.width = fontChar->disp.width;
r.extent.height = fontChar->disp.height;
if (BoxIntersect (&r, pClipRect, &r))
{
TFB_Prim_FontChar (origin, fontChar, backing, mode,
ctxOrigin);
}
origin.x += fontChar->disp.width;
#if 0
if (num_chars && next_ch < (UNICODE) MAX_CHARS
&& !(FontPtr->KernTab[ch]
& (FontPtr->KernTab[next_ch] >> 2)))
origin.x -= FontPtr->KernAmount;
#endif
}
}
}
static inline TFB_Char *
getCharFrame (FONT_DESC *fontPtr, UniChar ch)
{
UniChar pageStart = ch & CHARACTER_PAGE_MASK;
size_t charIndex;
FONT_PAGE *page = fontPtr->fontPages;
for (;;)
{
if (page == NULL)
return NULL;
if (page->pageStart == pageStart)
break;
page = page->next;
}
charIndex = ch - page->firstChar;
if (ch >= page->firstChar && charIndex < page->numChars
&& page->charDesc[charIndex].data)
{
return &page->charDesc[charIndex];
}
else
{
//log_add (log_Debug, "Character %u not present", (unsigned int) ch);
return NULL;
}
}

View File

@@ -0,0 +1,71 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _FONT_H
#define _FONT_H
#include "libs/memlib.h"
#define MAX_DELTAS 100
typedef struct FontPage
{
struct FontPage *next;
UniChar pageStart;
#define CHARACTER_PAGE_MASK 0xfffff800
UniChar firstChar;
size_t numChars;
TFB_Char *charDesc;
} FONT_PAGE;
static inline FONT_PAGE *
AllocFontPage (int numChars)
{
FONT_PAGE *result = HMalloc (sizeof (FONT_PAGE));
result->charDesc = HCalloc (numChars * sizeof *result->charDesc);
return result;
}
static inline void
FreeFontPage (FONT_PAGE *page)
{
HFree (page->charDesc);
HFree (page);
}
struct font_desc
{
UWORD Leading;
UWORD LeadingWidth;
FONT_PAGE *fontPages;
};
#define CHAR_DESCPTR PCHAR_DESC
#define FONT_PRIORITY DEFAULT_MEM_PRIORITY
#define AllocFont(size) (FONT)HCalloc (sizeof (FONT_DESC) + (size))
#define FreeFont _ReleaseFontData
extern FONT _CurFontPtr;
extern void *_GetFontData (uio_Stream *fp, DWORD length);
extern BOOLEAN _ReleaseFontData (void *handle);
#endif /* _FONT_H */

View File

@@ -0,0 +1,266 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "gfxintrn.h"
#include "gfx_common.h"
#include "tfb_draw.h"
#include "tfb_prim.h"
HOT_SPOT
MAKE_HOT_SPOT (COORD x, COORD y)
{
HOT_SPOT hs;
hs.x = x;
hs.y = y;
return hs;
}
// XXX: INTERNAL_PRIMITIVE and INTERNAL_PRIM_DESC are not used
typedef union
{
POINT Point;
STAMP Stamp;
BRESENHAM_LINE Line;
TEXT Text;
RECT Rect;
} INTERNAL_PRIM_DESC;
typedef struct
{
PRIM_LINKS Links;
GRAPHICS_PRIM Type;
Color Color;
INTERNAL_PRIM_DESC Object;
} INTERNAL_PRIMITIVE;
// pValidRect or origin may be NULL
BOOLEAN
GetContextValidRect (RECT *pValidRect, POINT *origin)
{
RECT tempRect;
POINT tempPt;
if (!pValidRect)
pValidRect = &tempRect;
if (!origin)
origin = &tempPt;
// Start with a rect the size of foreground frame
pValidRect->corner.x = 0;
pValidRect->corner.y = 0;
pValidRect->extent = GetFrameBounds (_CurFramePtr);
*origin = _CurFramePtr->HotSpot;
if (_pCurContext->ClipRect.extent.width)
{
// If the cliprect is completely outside of the valid frame
// bounds we have nothing to draw
if (!BoxIntersect (&_pCurContext->ClipRect,
pValidRect, pValidRect))
return (FALSE);
// Foreground frame hotspot defines a drawing position offset
// WRT the context cliprect
origin->x += _pCurContext->ClipRect.corner.x;
origin->y += _pCurContext->ClipRect.corner.y;
}
return (TRUE);
}
static void
ClearBackGround (RECT *pClipRect)
{
RECT clearRect;
Color color = _get_context_bg_color ();
clearRect.corner.x = 0;
clearRect.corner.y = 0;
clearRect.extent = pClipRect->extent;
TFB_Prim_FillRect (&clearRect, color, DRAW_REPLACE_MODE,
pClipRect->corner);
}
void
DrawBatch (PRIMITIVE *lpBasePrim, PRIM_LINKS PrimLinks,
BATCH_FLAGS BatchFlags)
{
RECT ValidRect;
POINT origin;
if (GraphicsSystemActive () && GetContextValidRect (&ValidRect, &origin))
{
COUNT CurIndex;
PRIMITIVE *lpPrim;
DrawMode mode = _get_context_draw_mode ();
BatchGraphics ();
if (BatchFlags & BATCH_BUILD_PAGE)
{
ClearBackGround (&ValidRect);
}
CurIndex = GetPredLink (PrimLinks);
for (; CurIndex != END_OF_LIST;
CurIndex = GetSuccLink (GetPrimLinks (lpPrim)))
{
GRAPHICS_PRIM PrimType;
PRIMITIVE *lpWorkPrim;
RECT ClipRect;
Color color;
lpPrim = &lpBasePrim[CurIndex];
PrimType = GetPrimType (lpPrim);
if (!ValidPrimType (PrimType))
continue;
lpWorkPrim = lpPrim;
switch (PrimType)
{
case POINT_PRIM:
color = GetPrimColor (lpWorkPrim);
TFB_Prim_Point (&lpWorkPrim->Object.Point, color,
mode, origin);
break;
case STAMP_PRIM:
TFB_Prim_Stamp (&lpWorkPrim->Object.Stamp, mode, origin);
break;
case STAMPFILL_PRIM:
color = GetPrimColor (lpWorkPrim);
TFB_Prim_StampFill (&lpWorkPrim->Object.Stamp, color,
mode, origin);
break;
case LINE_PRIM:
color = GetPrimColor (lpWorkPrim);
TFB_Prim_Line (&lpWorkPrim->Object.Line, color,
mode, origin);
break;
case TEXT_PRIM:
if (!TextRect (&lpWorkPrim->Object.Text, &ClipRect, NULL))
continue;
// ClipRect is relative to origin
_text_blt (&ClipRect, &lpWorkPrim->Object.Text, origin);
break;
case RECT_PRIM:
color = GetPrimColor (lpWorkPrim);
TFB_Prim_Rect (&lpWorkPrim->Object.Rect, color,
mode, origin);
break;
case RECTFILL_PRIM:
color = GetPrimColor (lpWorkPrim);
TFB_Prim_FillRect (&lpWorkPrim->Object.Rect, color,
mode, origin);
break;
}
}
UnbatchGraphics ();
}
}
void
ClearDrawable (void)
{
RECT ValidRect;
if (GraphicsSystemActive () && GetContextValidRect (&ValidRect, NULL))
{
ClearBackGround (&ValidRect);
}
}
void
DrawPoint (POINT *lpPoint)
{
POINT origin;
if (GraphicsSystemActive () && GetContextValidRect (NULL, &origin))
{
Color color = GetPrimColor (&_locPrim);
DrawMode mode = _get_context_draw_mode ();
TFB_Prim_Point (lpPoint, color, mode, origin);
}
}
void
DrawRectangle (RECT *lpRect)
{
POINT origin;
if (GraphicsSystemActive () && GetContextValidRect (NULL, &origin))
{
Color color = GetPrimColor (&_locPrim);
DrawMode mode = _get_context_draw_mode ();
TFB_Prim_Rect (lpRect, color, mode, origin);
}
}
void
DrawFilledRectangle (RECT *lpRect)
{
POINT origin;
if (GraphicsSystemActive () && GetContextValidRect (NULL, &origin))
{
Color color = GetPrimColor (&_locPrim);
DrawMode mode = _get_context_draw_mode ();
TFB_Prim_FillRect (lpRect, color, mode, origin);
}
}
void
DrawLine (LINE *lpLine)
{
POINT origin;
if (GraphicsSystemActive () && GetContextValidRect (NULL, &origin))
{
Color color = GetPrimColor (&_locPrim);
DrawMode mode = _get_context_draw_mode ();
TFB_Prim_Line (lpLine, color, mode, origin);
}
}
void
DrawStamp (STAMP *stmp)
{
POINT origin;
if (GraphicsSystemActive () && GetContextValidRect (NULL, &origin))
{
DrawMode mode = _get_context_draw_mode ();
TFB_Prim_Stamp (stmp, mode, origin);
}
}
void
DrawFilledStamp (STAMP *stmp)
{
POINT origin;
if (GraphicsSystemActive () && GetContextValidRect (NULL, &origin))
{
Color color = GetPrimColor (&_locPrim);
DrawMode mode = _get_context_draw_mode ();
TFB_Prim_StampFill (stmp, color, mode, origin);
}
}

View File

@@ -0,0 +1,196 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "gfxintrn.h"
#include "libs/graphics/gfx_common.h"
#include "libs/graphics/drawcmd.h"
#include "libs/timelib.h"
#include "libs/misc.h"
// for TFB_DEBUG_HALT
int ScreenWidth;
int ScreenHeight;
int ScreenWidthActual;
int ScreenHeightActual;
int ScreenColorDepth;
int GraphicsDriver;
int TFB_DEBUG_HALT = 0;
volatile int TransitionAmount = 255;
RECT TransitionClipRect;
static int gscale = GSCALE_IDENTITY;
static int gscale_mode = TFB_SCALE_NEAREST;
void
DrawFromExtraScreen (RECT *r)
{
TFB_DrawScreen_Copy(r, TFB_SCREEN_EXTRA, TFB_SCREEN_MAIN);
}
void
LoadIntoExtraScreen (RECT *r)
{
TFB_DrawScreen_Copy(r, TFB_SCREEN_MAIN, TFB_SCREEN_EXTRA);
}
int
SetGraphicScale (int scale)
{
int old_scale = gscale;
gscale = (scale ? scale : GSCALE_IDENTITY);
return old_scale;
}
int
GetGraphicScale (void)
{
return gscale;
}
int
SetGraphicScaleMode (int mode)
{
int old_mode = gscale_mode;
assert (mode >= TFB_SCALE_NEAREST && mode <= TFB_SCALE_TRILINEAR);
gscale_mode = mode;
return old_mode;
}
int
GetGraphicScaleMode (void)
{
return gscale_mode;
}
/* Batching and Unbatching functions. A "Batch" is a collection of
DrawCommands that will never be flipped to the screen half-rendered.
BatchGraphics and UnbatchGraphics function vaguely like a non-blocking
recursive lock to do this respect. */
void
BatchGraphics (void)
{
TFB_BatchGraphics ();
}
void
UnbatchGraphics (void)
{
TFB_UnbatchGraphics ();
}
/* Sleeps this thread until all Draw Commands queued by that thread have
been processed. */
void
FlushGraphics ()
{
TFB_DrawScreen_WaitForSignal ();
}
static void
ExpandRect (RECT *rect, int expansion)
{
if (rect->corner.x - expansion >= 0)
{
rect->extent.width += expansion;
rect->corner.x -= expansion;
}
else
{
rect->extent.width += rect->corner.x;
rect->corner.x = 0;
}
if (rect->corner.y - expansion >= 0)
{
rect->extent.height += expansion;
rect->corner.y -= expansion;
}
else
{
rect->extent.height += rect->corner.y;
rect->corner.y = 0;
}
if (rect->corner.x + rect->extent.width + expansion <= ScreenWidth)
rect->extent.width += expansion;
else
rect->extent.width = ScreenWidth - rect->corner.x;
if (rect->corner.y + rect->extent.height + expansion <= ScreenHeight)
rect->extent.height += expansion;
else
rect->extent.height = ScreenHeight - rect->corner.y;
}
void
SetTransitionSource (const RECT *pRect)
{
RECT ActualRect;
if (pRect)
{ /* expand the rect to accomodate scalers in OpenGL mode */
ActualRect = *pRect;
pRect = &ActualRect;
ExpandRect (&ActualRect, 2);
}
TFB_DrawScreen_Copy (pRect, TFB_SCREEN_MAIN, TFB_SCREEN_TRANSITION);
}
// ScreenTransition() is synchronous (does not return until transition done)
void
ScreenTransition (int TransType, const RECT *pRect)
{
const TimePeriod DURATION = ONE_SECOND * 31 / 60;
TimeCount startTime;
(void) TransType; /* dodge compiler warning */
if (pRect)
{
TransitionClipRect = *pRect;
}
else
{
TransitionClipRect.corner.x = 0;
TransitionClipRect.corner.y = 0;
TransitionClipRect.extent.width = ScreenWidth;
TransitionClipRect.extent.height = ScreenHeight;
}
TFB_UploadTransitionScreen ();
TransitionAmount = 0;
FlushGraphics ();
startTime = GetTimeCounter ();
while (TransitionAmount < 255)
{
TimePeriod deltaT;
int newAmount;
SleepThread (ONE_SECOND / 100);
deltaT = GetTimeCounter () - startTime;
newAmount = deltaT * 255 / DURATION;
if (newAmount > 255)
newAmount = 255;
TransitionAmount = newAmount;
}
}

View File

@@ -0,0 +1,109 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef GFX_COMMON_H
#define GFX_COMMON_H
#include <stdio.h>
#include <stdlib.h>
#include "libs/gfxlib.h"
// driver for TFB_InitGraphics
enum
{
TFB_GFXDRIVER_SDL_OPENGL,
TFB_GFXDRIVER_SDL_PURE,
};
// forced redraw
enum
{
TFB_REDRAW_NO = 0,
TFB_REDRAW_FADING,
TFB_REDRAW_EXPOSE,
TFB_REDRAW_YES
};
// flags for TFB_InitGraphics
#define TFB_GFXFLAGS_FULLSCREEN (1<<0)
#define TFB_GFXFLAGS_SHOWFPS (1<<1)
#define TFB_GFXFLAGS_SCANLINES (1<<2)
#define TFB_GFXFLAGS_SCALE_BILINEAR (1<<3)
#define TFB_GFXFLAGS_SCALE_BIADAPT (1<<4)
#define TFB_GFXFLAGS_SCALE_BIADAPTADV (1<<5)
#define TFB_GFXFLAGS_SCALE_TRISCAN (1<<6)
#define TFB_GFXFLAGS_SCALE_HQXX (1<<7)
#define TFB_GFXFLAGS_SCALE_ANY \
( TFB_GFXFLAGS_SCALE_BILINEAR | \
TFB_GFXFLAGS_SCALE_BIADAPT | \
TFB_GFXFLAGS_SCALE_BIADAPTADV | \
TFB_GFXFLAGS_SCALE_TRISCAN | \
TFB_GFXFLAGS_SCALE_HQXX )
#define TFB_GFXFLAGS_SCALE_SOFT_ONLY \
( TFB_GFXFLAGS_SCALE_ANY & ~TFB_GFXFLAGS_SCALE_BILINEAR )
// The flag variable itself
extern int GfxFlags;
// The following functions are driver-defined
void TFB_PreInit (void);
int TFB_InitGraphics (int driver, int flags, int width, int height);
int TFB_ReInitGraphics (int driver, int flags, int width, int height);
void TFB_UninitGraphics (void);
void TFB_ProcessEvents (void);
void TFB_SetGamma (float gamma);
void TFB_UploadTransitionScreen (void);
// This function should not be called directly
void TFB_SwapBuffers (int force_full_redraw);
#define GSCALE_IDENTITY 256
typedef enum {
TFB_SCALE_STEP, /* not really a scaler */
TFB_SCALE_NEAREST,
TFB_SCALE_BILINEAR,
TFB_SCALE_TRILINEAR
} SCALE;
void LoadIntoExtraScreen (RECT *r);
void DrawFromExtraScreen (RECT *r);
int SetGraphicScale (int scale);
int GetGraphicScale (void);
int SetGraphicScaleMode (int mode /* enum SCALE */);
int GetGraphicScaleMode (void);
void SetTransitionSource (const RECT *pRect);
void ScreenTransition (int transition, const RECT *pRect);
// TODO: there should be accessor functions for these
extern volatile int TransitionAmount;
extern RECT TransitionClipRect;
extern float FrameRate;
extern int FrameRateTickBase;
void TFB_FlushGraphics (void); // Only call from main thread!!
extern int ScreenWidth;
extern int ScreenHeight;
extern int ScreenWidthActual;
extern int ScreenHeightActual;
extern int ScreenColorDepth;
extern int GraphicsDriver;
#endif

View File

@@ -0,0 +1,32 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _GFXINTRN_H
#define _GFXINTRN_H
#include <stdio.h>
#include <string.h>
#include "libs/gfxlib.h"
#include "libs/reslib.h"
#include "context.h"
#include "drawable.h"
#include "font.h"
#endif /* _GFXINTRN_H */

View File

@@ -0,0 +1,605 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <string.h>
#include <stdio.h>
#include "options.h"
#include "port.h"
#include "libs/uio.h"
#include "libs/reslib.h"
// for _cur_resfile_name
#include "libs/log.h"
#include "libs/memlib.h"
#include "libs/graphics/tfb_draw.h"
#include "libs/graphics/drawable.h"
#include "libs/graphics/font.h"
typedef struct anidata
{
int transparent_color;
int colormap_index;
int hotspot_x;
int hotspot_y;
} AniData;
extern uio_Repository *repository;
static uio_AutoMount *autoMount[] = { NULL };
static void
process_image (FRAME FramePtr, TFB_Canvas img[], AniData *ani, int cel_ct)
{
TFB_Image *tfbimg;
int hx, hy;
FramePtr->Type = ROM_DRAWABLE;
FramePtr->Index = cel_ct;
// handle transparency cases
if (TFB_DrawCanvas_IsPaletted (img[cel_ct]))
{ // indexed color image
if (ani[cel_ct].transparent_color >= 0)
{
TFB_DrawCanvas_SetTransparentIndex (img[cel_ct],
ani[cel_ct].transparent_color, FALSE);
}
}
else
{ // special transparency cases for truecolor images
if (ani[cel_ct].transparent_color == 0)
{ // make RGB=0,0,0 transparent
Color color = {0, 0, 0, 0};
TFB_DrawCanvas_SetTransparentColor (img[cel_ct], color, FALSE);
}
}
if (ani[cel_ct].transparent_color == -1)
{ // enforce -1 to mean 'no transparency'
TFB_DrawCanvas_SetTransparentIndex (img[cel_ct], -1, FALSE);
// set transparent_color == -2 to use PNG tRNS transparency
}
hx = ani[cel_ct].hotspot_x;
hy = ani[cel_ct].hotspot_y;
FramePtr->image = TFB_DrawImage_New (img[cel_ct]);
tfbimg = FramePtr->image;
tfbimg->colormap_index = ani[cel_ct].colormap_index;
img[cel_ct] = tfbimg->NormalImg;
FramePtr->HotSpot = MAKE_HOT_SPOT (hx, hy);
SetFrameBounds (FramePtr, tfbimg->extent.width, tfbimg->extent.height);
#ifdef CLIPDEBUG
{
/* for debugging clipping:
draws white (or most matching color from palette) pixels to
every corner of the image
*/
Color color = {0xff, 0xff, 0xff, 0xff};
RECT r = {{0, 0}, {1, 1}};
if (tfbimg->extent.width > 2 && tfbimg->extent.height > 2)
{
TFB_DrawImage_Rect (&r, color, tfbimg);
r.corner.x = tfbimg->extent.width - 1;
TFB_DrawImage_Rect (&r, color, tfbimg);
r.corner.y = tfbimg->extent.height - 1;
TFB_DrawImage_Rect (&r, color, tfbimg);
r.corner.x = 0;
TFB_DrawImage_Rect (&r, color, tfbimg);
}
}
#endif
}
static void
processFontChar (TFB_Char* CharPtr, TFB_Canvas canvas)
{
BYTE* newdata;
size_t dpitch;
TFB_DrawCanvas_GetExtent (canvas, &CharPtr->extent);
// Currently, each font char has its own separate data
// but that can change to common mem area
dpitch = CharPtr->extent.width;
newdata = HMalloc (dpitch * CharPtr->extent.height * sizeof (BYTE));
TFB_DrawCanvas_GetFontCharData (canvas, newdata, dpitch);
CharPtr->data = newdata;
CharPtr->pitch = dpitch;
CharPtr->disp.width = CharPtr->extent.width + 1;
CharPtr->disp.height = CharPtr->extent.height + 1;
// XXX: why the +1?
// I brought it into this function from the only calling
// function, but I don't know why it was there in the first
// place.
// XXX: the +1 appears to be for character and line spacing
// text_blt just adds the frame width to move to the next char
{
// This tunes the font positioning to be about what it should
// TODO: prolly needs a little tweaking still
int tune_amount = 0;
if (CharPtr->extent.height == 8)
tune_amount = -1;
else if (CharPtr->extent.height == 9)
tune_amount = -2;
else if (CharPtr->extent.height > 9)
tune_amount = -3;
CharPtr->HotSpot = MAKE_HOT_SPOT (0,
CharPtr->extent.height + tune_amount);
}
}
void *
_GetCelData (uio_Stream *fp, DWORD length)
{
int cel_total, cel_index, n;
DWORD opos;
char CurrentLine[1024], filename[PATH_MAX];
TFB_Canvas *img;
AniData *ani;
DRAWABLE Drawable;
uio_MountHandle *aniMount = 0;
uio_DirHandle *aniDir = 0;
uio_Stream *aniFile = 0;
opos = uio_ftell (fp);
{
char *s1, *s2;
char aniDirName[PATH_MAX];
const char *aniFileName;
uint8 buf[4] = { 0, 0, 0, 0 };
uint32 header;
if (_cur_resfile_name == 0
|| (((s2 = 0), (s1 = strrchr (_cur_resfile_name, '/')) == 0)
&& (s2 = strrchr (_cur_resfile_name, '\\')) == 0))
{
n = 0;
}
else
{
if (s2 > s1)
s1 = s2;
n = s1 - _cur_resfile_name + 1;
}
uio_fread(buf, 4, 1, fp);
header = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
if (_cur_resfile_name && header == 0x04034b50)
{
// zipped ani file
if (n)
{
strncpy (aniDirName, _cur_resfile_name, n - 1);
aniDirName[n - 1] = 0;
aniFileName = _cur_resfile_name + n;
}
else
{
strcpy(aniDirName, ".");
aniFileName = _cur_resfile_name;
}
aniDir = uio_openDir (repository, aniDirName, 0);
aniMount = uio_mountDir (repository, aniDirName, uio_FSTYPE_ZIP,
aniDir, aniFileName, "/", autoMount,
uio_MOUNT_RDONLY | uio_MOUNT_TOP,
NULL);
aniFile = uio_fopen (aniDir, aniFileName, "r");
opos = 0;
n = 0;
}
else
{
// unpacked ani file
strncpy (filename, _cur_resfile_name, n);
aniFile = fp;
aniDir = contentDir;
}
}
cel_total = 0;
uio_fseek (aniFile, opos, SEEK_SET);
while (uio_fgets (CurrentLine, sizeof (CurrentLine), aniFile))
{
++cel_total;
}
img = HMalloc (sizeof (TFB_Canvas) * cel_total);
ani = HMalloc (sizeof (AniData) * cel_total);
if (!img || !ani)
{
log_add (log_Warning, "Couldn't allocate space for '%s'", _cur_resfile_name);
if (aniMount)
{
uio_fclose(aniFile);
uio_closeDir(aniDir);
uio_unmountDir(aniMount);
}
HFree (img);
HFree (ani);
return NULL;
}
cel_index = 0;
uio_fseek (aniFile, opos, SEEK_SET);
while (uio_fgets (CurrentLine, sizeof (CurrentLine), aniFile) && cel_index < cel_total)
{
sscanf (CurrentLine, "%s %d %d %d %d", &filename[n],
&ani[cel_index].transparent_color, &ani[cel_index].colormap_index,
&ani[cel_index].hotspot_x, &ani[cel_index].hotspot_y);
img[cel_index] = TFB_DrawCanvas_LoadFromFile (aniDir, filename);
if (img[cel_index] == NULL)
{
const char *err;
err = TFB_DrawCanvas_GetError ();
log_add (log_Warning, "_GetCelData: Unable to load image!");
if (err != NULL)
log_add (log_Warning, "Gfx Driver reports: %s", err);
}
else
{
++cel_index;
}
if ((int)uio_ftell (aniFile) - (int)opos >= (int)length)
break;
}
Drawable = NULL;
if (cel_index && (Drawable = AllocDrawable (cel_index)))
{
if (!Drawable)
{
while (cel_index--)
TFB_DrawCanvas_Delete (img[cel_index]);
HFree (Drawable);
Drawable = NULL;
}
else
{
FRAME FramePtr;
Drawable->Flags = WANT_PIXMAP;
Drawable->MaxIndex = cel_index - 1;
FramePtr = &Drawable->Frame[cel_index];
while (--FramePtr, cel_index--)
process_image (FramePtr, img, ani, cel_index);
}
}
if (Drawable == NULL)
log_add (log_Warning, "Couldn't get cel data for '%s'",
_cur_resfile_name);
if (aniMount)
{
uio_fclose(aniFile);
uio_closeDir(aniDir);
uio_unmountDir(aniMount);
}
HFree (img);
HFree (ani);
return Drawable;
}
BOOLEAN
_ReleaseCelData (void *handle)
{
DRAWABLE DrawablePtr;
int cel_ct;
FRAME FramePtr = NULL;
if ((DrawablePtr = handle) == 0)
return (FALSE);
cel_ct = DrawablePtr->MaxIndex + 1;
if (DrawablePtr->Frame)
{
FramePtr = DrawablePtr->Frame;
if (FramePtr->Type == SCREEN_DRAWABLE)
{
FramePtr = NULL;
}
}
HFree (handle);
if (FramePtr)
{
int i;
for (i = 0; i < cel_ct; i++)
{
TFB_Image *img = FramePtr[i].image;
if (img)
{
FramePtr[i].image = NULL;
TFB_DrawScreen_DeleteImage (img);
}
}
HFree (FramePtr);
}
return (TRUE);
}
typedef struct BuildCharDesc
{
TFB_Canvas canvas;
UniChar index;
} BuildCharDesc;
static int
compareBCDIndex (const void *arg1, const void *arg2)
{
const BuildCharDesc *bcd1 = (const BuildCharDesc *) arg1;
const BuildCharDesc *bcd2 = (const BuildCharDesc *) arg2;
return (int) bcd1->index - (int) bcd2->index;
}
void *
_GetFontData (uio_Stream *fp, DWORD length)
{
COUNT numDirEntries;
DIRENTRY fontDir = NULL;
BuildCharDesc *bcds = NULL;
size_t numBCDs = 0;
int dirEntryI;
uio_DirHandle *fontDirHandle = NULL;
uio_MountHandle *fontMount = NULL;
FONT fontPtr = NULL;
if (_cur_resfile_name == 0)
goto err;
if (fp != (uio_Stream*)~0)
{
// font is zipped instead of being in a directory
char *s1, *s2;
int n;
const char *fontZipName;
char fontDirName[PATH_MAX];
if ((((s2 = 0), (s1 = strrchr (_cur_resfile_name, '/')) == 0)
&& (s2 = strrchr (_cur_resfile_name, '\\')) == 0))
{
strcpy(fontDirName, ".");
fontZipName = _cur_resfile_name;
}
else
{
if (s2 > s1)
s1 = s2;
n = s1 - _cur_resfile_name + 1;
strncpy (fontDirName, _cur_resfile_name, n - 1);
fontDirName[n - 1] = 0;
fontZipName = _cur_resfile_name + n;
}
fontDirHandle = uio_openDir (repository, fontDirName, 0);
fontMount = uio_mountDir (repository, _cur_resfile_name, uio_FSTYPE_ZIP,
fontDirHandle, fontZipName, "/", autoMount,
uio_MOUNT_RDONLY | uio_MOUNT_TOP,
NULL);
uio_closeDir (fontDirHandle);
}
fontDir = CaptureDirEntryTable (LoadDirEntryTable (contentDir,
_cur_resfile_name, ".", match_MATCH_SUBSTRING));
if (fontDir == 0)
goto err;
numDirEntries = GetDirEntryTableCount (fontDir);
fontDirHandle = uio_openDirRelative (contentDir, _cur_resfile_name, 0);
if (fontDirHandle == NULL)
goto err;
bcds = HMalloc (numDirEntries * sizeof (BuildCharDesc));
if (bcds == NULL)
goto err;
// Load the surfaces for all dir Entries
for (dirEntryI = 0; dirEntryI < numDirEntries; dirEntryI++)
{
char *char_name;
unsigned int charIndex;
TFB_Canvas canvas;
EXTENT size;
char_name = GetDirEntryAddress (SetAbsDirEntryTableIndex (
fontDir, dirEntryI));
if (sscanf (char_name, "%x.", &charIndex) != 1)
continue;
if (charIndex > 0xffff)
continue;
canvas = TFB_DrawCanvas_LoadFromFile (fontDirHandle, char_name);
if (canvas == NULL)
continue;
TFB_DrawCanvas_GetExtent (canvas, &size);
if (size.width == 0 || size.height == 0)
{
TFB_DrawCanvas_Delete (canvas);
continue;
}
bcds[numBCDs].canvas = canvas;
bcds[numBCDs].index = charIndex;
numBCDs++;
}
uio_closeDir (fontDirHandle);
DestroyDirEntryTable (ReleaseDirEntryTable (fontDir));
if (fontMount != 0)
uio_unmountDir(fontMount);
#if 0
if (numBCDs == 0)
goto err;
#endif
// sort on the character index
qsort (bcds, numBCDs, sizeof (BuildCharDesc), compareBCDIndex);
fontPtr = AllocFont (0);
if (fontPtr == NULL)
goto err;
fontPtr->Leading = 0;
fontPtr->LeadingWidth = 0;
{
size_t startBCD = 0;
UniChar pageStart;
FONT_PAGE **pageEndPtr = &fontPtr->fontPages;
while (startBCD < numBCDs)
{
// Process one character page.
size_t endBCD;
pageStart = bcds[startBCD].index & CHARACTER_PAGE_MASK;
endBCD = startBCD;
while (endBCD < numBCDs &&
(bcds[endBCD].index & CHARACTER_PAGE_MASK) == pageStart)
endBCD++;
{
size_t bcdI;
int numChars = bcds[endBCD - 1].index + 1
- bcds[startBCD].index;
FONT_PAGE *page = AllocFontPage (numChars);
page->pageStart = pageStart;
page->firstChar = bcds[startBCD].index;
page->numChars = numChars;
*pageEndPtr = page;
pageEndPtr = &page->next;
for (bcdI = startBCD; bcdI < endBCD; bcdI++)
{
// Process one character.
BuildCharDesc *bcd = &bcds[bcdI];
TFB_Char *destChar =
&page->charDesc[bcd->index - page->firstChar];
if (destChar->data != NULL)
{
// There's already an image for this character.
log_add (log_Debug, "Duplicate image for character %d "
"for font %s.", (int) bcd->index,
_cur_resfile_name);
TFB_DrawCanvas_Delete (bcd->canvas);
continue;
}
processFontChar (destChar, bcd->canvas);
TFB_DrawCanvas_Delete (bcd->canvas);
if (destChar->disp.height > fontPtr->Leading)
fontPtr->Leading = destChar->disp.height;
if (destChar->disp.width > fontPtr->LeadingWidth)
fontPtr->LeadingWidth = destChar->disp.width;
}
}
startBCD = endBCD;
}
*pageEndPtr = NULL;
}
fontPtr->Leading++;
HFree (bcds);
(void) fp; /* Satisfying compiler (unused parameter) */
(void) length; /* Satisfying compiler (unused parameter) */
return fontPtr;
err:
if (fontPtr != 0)
HFree (fontPtr);
if (bcds != NULL)
{
size_t bcdI;
for (bcdI = 0; bcdI < numBCDs; bcdI++)
TFB_DrawCanvas_Delete (bcds[bcdI].canvas);
HFree (bcds);
}
if (fontDirHandle != NULL)
uio_closeDir (fontDirHandle);
if (fontDir != 0)
DestroyDirEntryTable (ReleaseDirEntryTable (fontDir));
if (fontMount != 0)
uio_unmountDir(fontMount);
return 0;
}
BOOLEAN
_ReleaseFontData (void *handle)
{
FONT font = (FONT) handle;
if (font == NULL)
return FALSE;
{
FONT_PAGE *page;
FONT_PAGE *nextPage;
for (page = font->fontPages; page != NULL; page = nextPage)
{
size_t charI;
for (charI = 0; charI < page->numChars; charI++)
{
TFB_Char *c = &page->charDesc[charI];
if (c->data == NULL)
continue;
// XXX: fix this if fonts get per-page data
// rather than per-char
TFB_DrawScreen_DeleteData (c->data);
}
nextPage = page->next;
FreeFontPage (page);
}
}
HFree (font);
return TRUE;
}

View File

@@ -0,0 +1,415 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "libs/graphics/context.h"
#include "libs/graphics/drawable.h"
#include "libs/graphics/tfb_draw.h"
#include "libs/log.h"
//#define DEBUG_INTERSEC
static inline BOOLEAN
images_intersect (IMAGE_BOX *box1, IMAGE_BOX *box2, const RECT *rect)
{
return TFB_DrawImage_Intersect (box1->FramePtr->image, box1->Box.corner,
box2->FramePtr->image, box2->Box.corner, rect);
}
static TIME_VALUE
frame_intersect (INTERSECT_CONTROL *pControl0, RECT *pr0,
INTERSECT_CONTROL *pControl1, RECT *pr1, TIME_VALUE t0,
TIME_VALUE t1)
{
SIZE time_error0, time_error1;
SIZE cycle0, cycle1;
SIZE dx_0, dy_0, dx_1, dy_1;
SIZE xincr0, yincr0, xincr1, yincr1;
SIZE xerror0, xerror1, yerror0, yerror1;
RECT r_intersect;
IMAGE_BOX IB0, IB1;
BOOLEAN check0, check1;
IB0.FramePtr = pControl0->IntersectStamp.frame;
IB0.Box.corner = pr0->corner;
IB0.Box.extent.width = GetFrameWidth (IB0.FramePtr);
IB0.Box.extent.height = GetFrameHeight (IB0.FramePtr);
IB1.FramePtr = pControl1->IntersectStamp.frame;
IB1.Box.corner = pr1->corner;
IB1.Box.extent.width = GetFrameWidth (IB1.FramePtr);
IB1.Box.extent.height = GetFrameHeight (IB1.FramePtr);
dx_0 = pr0->extent.width;
dy_0 = pr0->extent.height;
if (dx_0 >= 0)
xincr0 = 1;
else
{
xincr0 = -1;
dx_0 = -dx_0;
}
if (dy_0 >= 0)
yincr0 = 1;
else
{
yincr0 = -1;
dy_0 = -dy_0;
}
if (dx_0 >= dy_0)
cycle0 = dx_0;
else
cycle0 = dy_0;
xerror0 = yerror0 = cycle0;
dx_1 = pr1->extent.width;
dy_1 = pr1->extent.height;
if (dx_1 >= 0)
xincr1 = 1;
else
{
xincr1 = -1;
dx_1 = -dx_1;
}
if (dy_1 >= 0)
yincr1 = 1;
else
{
yincr1 = -1;
dy_1 = -dy_1;
}
if (dx_1 >= dy_1)
cycle1 = dx_1;
else
cycle1 = dy_1;
xerror1 = yerror1 = cycle1;
check0 = check1 = FALSE;
if (t0 <= 1)
{
time_error0 = time_error1 = 0;
if (t0 == 0)
{
++t0;
goto CheckFirstIntersection;
}
}
else
{
SIZE delta;
COUNT start;
long error;
start = (COUNT)cycle0 * (COUNT)(t0 - 1);
time_error0 = start & ((1 << TIME_SHIFT) - 1);
if ((start >>= (COUNT)TIME_SHIFT) > 0)
{
if ((error = (long)xerror0
- (long)dx_0 * (long)start) > 0)
xerror0 = (SIZE)error;
else
{
delta = -(SIZE)(error / (long)cycle0) + 1;
IB0.Box.corner.x += xincr0 * delta;
xerror0 = (SIZE)(error + (long)cycle0 * (long)delta);
}
if ((error = (long)yerror0
- (long)dy_0 * (long)start) > 0)
yerror0 = (SIZE)error;
else
{
delta = -(SIZE)(error / (long)cycle0) + 1;
IB0.Box.corner.y += yincr0 * delta;
yerror0 = (SIZE)(error + (long)cycle0 * (long)delta);
}
pr0->corner = IB0.Box.corner;
}
start = (COUNT)cycle1 * (COUNT)(t0 - 1);
time_error1 = start & ((1 << TIME_SHIFT) - 1);
if ((start >>= (COUNT)TIME_SHIFT) > 0)
{
if ((error = (long)xerror1
- (long)dx_1 * (long)start) > 0)
xerror1 = (SIZE)error;
else
{
delta = -(SIZE)(error / (long)cycle1) + 1;
IB1.Box.corner.x += xincr1 * delta;
xerror1 = (SIZE)(error + (long)cycle1 * (long)delta);
}
if ((error = (long)yerror1
- (long)dy_1 * (long)start) > 0)
yerror1 = (SIZE)error;
else
{
delta = -(SIZE)(error / (long)cycle1) + 1;
IB1.Box.corner.y += yincr1 * delta;
yerror1 = (SIZE)(error + (long)cycle1 * (long)delta);
}
pr1->corner = IB1.Box.corner;
}
}
pControl0->last_time_val = pControl1->last_time_val = t0;
do
{
++t0;
if ((time_error0 += cycle0) >= (1 << TIME_SHIFT))
{
if ((xerror0 -= dx_0) <= 0)
{
IB0.Box.corner.x += xincr0;
xerror0 += cycle0;
}
if ((yerror0 -= dy_0) <= 0)
{
IB0.Box.corner.y += yincr0;
yerror0 += cycle0;
}
check0 = TRUE;
time_error0 -= (1 << TIME_SHIFT);
}
if ((time_error1 += cycle1) >= (1 << TIME_SHIFT))
{
if ((xerror1 -= dx_1) <= 0)
{
IB1.Box.corner.x += xincr1;
xerror1 += cycle1;
}
if ((yerror1 -= dy_1) <= 0)
{
IB1.Box.corner.y += yincr1;
yerror1 += cycle1;
}
check1 = TRUE;
time_error1 -= (1 << TIME_SHIFT);
}
if (check0 || check1)
{ /* if check0 && check1, this may not be quite right --
* if shapes had a pixel's separation to begin with
* and both moved toward each other, you would actually
* get a pixel overlap but since the last positions were
* separated by a pixel, the shapes wouldn't be touching
* each other.
*/
CheckFirstIntersection:
if (BoxIntersect (&IB0.Box, &IB1.Box, &r_intersect)
&& images_intersect (&IB0, &IB1, &r_intersect))
return (t0);
if (check0)
{
pr0->corner = IB0.Box.corner;
pControl0->last_time_val = t0;
check0 = FALSE;
}
if (check1)
{
pr1->corner = IB1.Box.corner;
pControl1->last_time_val = t0;
check1 = FALSE;
}
}
} while (t0 <= t1);
return ((TIME_VALUE)0);
}
TIME_VALUE
DrawablesIntersect (INTERSECT_CONTROL *pControl0,
INTERSECT_CONTROL *pControl1, TIME_VALUE max_time_val)
{
SIZE dy;
SIZE time_y_0, time_y_1;
RECT r0, r1;
FRAME FramePtr0, FramePtr1;
if (!ContextActive () || max_time_val == 0)
return ((TIME_VALUE)0);
else if (max_time_val > MAX_TIME_VALUE)
max_time_val = MAX_TIME_VALUE;
pControl0->last_time_val = pControl1->last_time_val = 0;
r0.corner = pControl0->IntersectStamp.origin;
r1.corner = pControl1->IntersectStamp.origin;
r0.extent.width = pControl0->EndPoint.x - r0.corner.x;
r0.extent.height = pControl0->EndPoint.y - r0.corner.y;
r1.extent.width = pControl1->EndPoint.x - r1.corner.x;
r1.extent.height = pControl1->EndPoint.y - r1.corner.y;
FramePtr0 = pControl0->IntersectStamp.frame;
if (FramePtr0 == 0)
return(0);
r0.corner.x -= FramePtr0->HotSpot.x;
r0.corner.y -= FramePtr0->HotSpot.y;
FramePtr1 = pControl1->IntersectStamp.frame;
if (FramePtr1 == 0)
return(0);
r1.corner.x -= FramePtr1->HotSpot.x;
r1.corner.y -= FramePtr1->HotSpot.y;
dy = r1.corner.y - r0.corner.y;
time_y_0 = dy - GetFrameHeight (FramePtr0) + 1;
time_y_1 = dy + GetFrameHeight (FramePtr1) - 1;
dy = r0.extent.height - r1.extent.height;
if ((time_y_0 <= 0 && time_y_1 >= 0)
|| (time_y_0 > 0 && dy >= time_y_0)
|| (time_y_1 < 0 && dy <= time_y_1))
{
SIZE dx;
SIZE time_x_0, time_x_1;
dx = r1.corner.x - r0.corner.x;
time_x_0 = dx - GetFrameWidth (FramePtr0) + 1;
time_x_1 = dx + GetFrameWidth (FramePtr1) - 1;
dx = r0.extent.width - r1.extent.width;
if ((time_x_0 <= 0 && time_x_1 >= 0)
|| (time_x_0 > 0 && dx >= time_x_0)
|| (time_x_1 < 0 && dx <= time_x_1))
{
TIME_VALUE intersect_time;
if (dx == 0 && dy == 0)
time_y_0 = time_y_1 = 0;
else
{
SIZE t;
long time_beg, time_end, fract;
if (time_y_1 < 0)
{
t = time_y_0;
time_y_0 = -time_y_1;
time_y_1 = -t;
}
else if (time_y_0 <= 0)
{
if (dy < 0)
time_y_1 = -time_y_0;
time_y_0 = 0;
}
if (dy < 0)
dy = -dy;
if (dy < time_y_1)
time_y_1 = dy;
/* just to be safe, widen search area */
--time_y_0;
++time_y_1;
if (time_x_1 < 0)
{
t = time_x_0;
time_x_0 = -time_x_1;
time_x_1 = -t;
}
else if (time_x_0 <= 0)
{
if (dx < 0)
time_x_1 = -time_x_0;
time_x_0 = 0;
}
if (dx < 0)
dx = -dx;
if (dx < time_x_1)
time_x_1 = dx;
/* just to be safe, widen search area */
--time_x_0;
++time_x_1;
#ifdef DEBUG_INTERSEC
log_add (log_Debug, "FramePtr0<%d, %d> --> <%d, %d>",
GetFrameWidth (FramePtr0), GetFrameHeight (FramePtr0),
r0.corner.x, r0.corner.y);
log_add (log_Debug, "FramePtr1<%d, %d> --> <%d, %d>",
GetFrameWidth (FramePtr1), GetFrameHeight (FramePtr1),
r1.corner.x, r1.corner.y);
log_add (log_Debug, "time_x(%d, %d)-%d, time_y(%d, %d)-%d",
time_x_0, time_x_1, dx, time_y_0, time_y_1, dy);
#endif /* DEBUG_INTERSEC */
if (dx == 0)
{
time_beg = time_y_0;
time_end = time_y_1;
fract = dy;
}
else if (dy == 0)
{
time_beg = time_x_0;
time_end = time_x_1;
fract = dx;
}
else
{
long time_x, time_y;
time_x = (long)time_x_0 * (long)dy;
time_y = (long)time_y_0 * (long)dx;
time_beg = time_x < time_y ? time_y : time_x;
time_x = (long)time_x_1 * (long)dy;
time_y = (long)time_y_1 * (long)dx;
time_end = time_x > time_y ? time_y : time_x;
fract = (long)dx * (long)dy;
}
if ((time_beg <<= TIME_SHIFT) < fract)
time_y_0 = 0;
else
time_y_0 = (SIZE)(time_beg / fract);
if (time_end >= fract /* just in case of overflow */
|| (time_end <<= TIME_SHIFT) >=
fract * (long)max_time_val)
time_y_1 = max_time_val - 1;
else
time_y_1 = (SIZE)((time_end + fract - 1) / fract) - 1;
}
#ifdef DEBUG_INTERSEC
log_add (log_Debug, "start_time = %d, end_time = %d",
time_y_0, time_y_1);
#endif /* DEBUG_INTERSEC */
if (time_y_0 <= time_y_1
&& (intersect_time = frame_intersect (
pControl0, &r0, pControl1, &r1,
(TIME_VALUE)time_y_0, (TIME_VALUE)time_y_1)))
{
FramePtr0 = pControl0->IntersectStamp.frame;
pControl0->EndPoint.x = r0.corner.x + FramePtr0->HotSpot.x;
pControl0->EndPoint.y = r0.corner.y + FramePtr0->HotSpot.y;
FramePtr1 = pControl1->IntersectStamp.frame;
pControl1->EndPoint.x = r1.corner.x + FramePtr1->HotSpot.x;
pControl1->EndPoint.y = r1.corner.y + FramePtr1->HotSpot.y;
return (intersect_time);
}
}
}
return ((TIME_VALUE)0);
}

View File

@@ -0,0 +1,65 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "libs/gfxlib.h"
#include "libs/graphics/drawable.h"
#include "libs/log.h"
// Reads a piece of screen into a passed FRAME or a newly created one
DRAWABLE
LoadDisplayPixmap (const RECT *area, FRAME frame)
{
// TODO: This should just return a FRAME instead of DRAWABLE
DRAWABLE buffer = GetFrameParentDrawable (frame);
COUNT index;
if (!buffer)
{ // asked to create a new DRAWABLE instead
buffer = CreateDrawable (WANT_PIXMAP | MAPPED_TO_DISPLAY,
area->extent.width, area->extent.height, 1);
if (!buffer)
return NULL;
index = 0;
}
else
{
index = GetFrameIndex (frame);
}
frame = SetAbsFrameIndex (CaptureDrawable (buffer), index);
if (_CurFramePtr->Type != SCREEN_DRAWABLE
|| frame->Type == SCREEN_DRAWABLE
|| !(GetFrameParentDrawable (frame)->Flags & MAPPED_TO_DISPLAY))
{
log_add (log_Warning, "Unimplemented function activated: "
"LoadDisplayPixmap()");
}
else
{
TFB_Image *img = frame->image;
TFB_DrawScreen_CopyToImage (img, area, TFB_SCREEN_MAIN);
}
ReleaseDrawable (frame);
return buffer;
}

View File

@@ -0,0 +1,170 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "gfxintrn.h"
#include "libs/log.h"
DRAWABLE
GetFrameParentDrawable (FRAME f)
{
if (f != NULL)
{
return f->parent;
}
return NULL;
}
FRAME
CaptureDrawable (DRAWABLE DrawablePtr)
{
if (DrawablePtr)
{
return &DrawablePtr->Frame[0];
}
return NULL;
}
DRAWABLE
ReleaseDrawable (FRAME FramePtr)
{
if (FramePtr != 0)
{
DRAWABLE Drawable;
Drawable = GetFrameParentDrawable (FramePtr);
return (Drawable);
}
return NULL;
}
COUNT
GetFrameCount (FRAME FramePtr)
{
DRAWABLE_DESC *DrawablePtr;
if (FramePtr == 0)
return (0);
DrawablePtr = GetFrameParentDrawable (FramePtr);
return DrawablePtr->MaxIndex + 1;
}
COUNT
GetFrameIndex (FRAME FramePtr)
{
if (FramePtr == 0)
return (0);
return FramePtr->Index;
}
FRAME
SetAbsFrameIndex (FRAME FramePtr, COUNT FrameIndex)
{
if (FramePtr != 0)
{
DRAWABLE_DESC *DrawablePtr;
DrawablePtr = GetFrameParentDrawable (FramePtr);
FrameIndex = FrameIndex % (DrawablePtr->MaxIndex + 1);
FramePtr = &DrawablePtr->Frame[FrameIndex];
}
return FramePtr;
}
FRAME
SetRelFrameIndex (FRAME FramePtr, SIZE FrameOffs)
{
if (FramePtr != 0)
{
COUNT num_frames;
DRAWABLE_DESC *DrawablePtr;
DrawablePtr = GetFrameParentDrawable (FramePtr);
num_frames = DrawablePtr->MaxIndex + 1;
if (FrameOffs < 0)
{
while ((FrameOffs += num_frames) < 0)
;
}
FrameOffs = ((SWORD)FramePtr->Index + FrameOffs) % num_frames;
FramePtr = &DrawablePtr->Frame[FrameOffs];
}
return FramePtr;
}
FRAME
SetEquFrameIndex (FRAME DstFramePtr, FRAME SrcFramePtr)
{
COUNT Index;
if (!DstFramePtr || !SrcFramePtr)
return 0;
Index = GetFrameIndex (SrcFramePtr);
#ifdef DEBUG
{
DRAWABLE_DESC *DrawablePtr = GetFrameParentDrawable (DstFramePtr);
if (Index > DrawablePtr->MaxIndex)
log_add (log_Debug, "SetEquFrameIndex: source index (%d) beyond "
"destination range (%d)", (int)Index,
(int)DrawablePtr->MaxIndex);
}
#endif
return SetAbsFrameIndex (DstFramePtr, Index);
}
FRAME
IncFrameIndex (FRAME FramePtr)
{
DRAWABLE_DESC *DrawablePtr;
if (FramePtr == 0)
return (0);
DrawablePtr = GetFrameParentDrawable (FramePtr);
if (FramePtr->Index < DrawablePtr->MaxIndex)
return ++FramePtr;
else
return DrawablePtr->Frame;
}
FRAME
DecFrameIndex (FRAME FramePtr)
{
if (FramePtr == 0)
return (0);
if (FramePtr->Index > 0)
return --FramePtr;
else
{
DRAWABLE_DESC *DrawablePtr;
DrawablePtr = GetFrameParentDrawable (FramePtr);
return &DrawablePtr->Frame[DrawablePtr->MaxIndex];
}
}

View File

@@ -0,0 +1,80 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _PRIM_H
#define _PRIM_H
enum gfx_object
{
POINT_PRIM = 0,
STAMP_PRIM,
STAMPFILL_PRIM,
LINE_PRIM,
TEXT_PRIM,
RECT_PRIM,
RECTFILL_PRIM,
NUM_PRIMS
};
typedef BYTE GRAPHICS_PRIM;
typedef union
{
POINT Point;
STAMP Stamp;
LINE Line;
TEXT Text;
RECT Rect;
} PRIM_DESC;
typedef DWORD PRIM_LINKS;
typedef struct
{
PRIM_LINKS Links;
GRAPHICS_PRIM Type;
Color color;
PRIM_DESC Object;
} PRIMITIVE;
#define END_OF_LIST ((COUNT)0xFFFF)
#define GetPredLink(l) LOWORD(l)
#define GetSuccLink(l) HIWORD(l)
#define MakeLinks MAKE_DWORD
#define SetPrimLinks(pPrim,p,s) ((pPrim)->Links = MakeLinks (p, s))
#define GetPrimLinks(pPrim) ((pPrim)->Links)
#define SetPrimType(pPrim,t) ((pPrim)->Type = t)
#define GetPrimType(pPrim) ((pPrim)->Type)
#define SetPrimColor(pPrim,c) ((pPrim)->color = c)
#define GetPrimColor(pPrim) ((pPrim)->color)
static inline void
SetPrimNextLink (PRIMITIVE *pPrim, COUNT Link)
{
SetPrimLinks (pPrim, END_OF_LIST, Link);
}
static inline COUNT
GetPrimNextLink (PRIMITIVE *pPrim)
{
return GetSuccLink (GetPrimLinks (pPrim));
}
#endif /* PRIM_H */

View File

@@ -0,0 +1,54 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "gfxintrn.h"
static void
GetCelFileData (const char *pathname, RESOURCE_DATA *resdata)
{
resdata->ptr = LoadResourceFromPath (pathname, _GetCelData);
}
static void
GetFontFileData (const char *pathname, RESOURCE_DATA *resdata)
{
resdata->ptr = LoadResourceFromPath (pathname, _GetFontData);
}
BOOLEAN
InstallGraphicResTypes (void)
{
InstallResTypeVectors ("GFXRES", GetCelFileData, _ReleaseCelData, NULL);
InstallResTypeVectors ("FONTRES", GetFontFileData, _ReleaseFontData, NULL);
return (TRUE);
}
/* Needs to be void * because it could be either a DRAWABLE or a FONT. */
void *
LoadGraphicInstance (RESOURCE res)
{
void *hData;
hData = res_GetResource (res);
if (hData)
res_DetachResource (res);
return (hData);
}

View File

@@ -0,0 +1,260 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "libs/graphics/sdl/sdl_common.h"
#include "types.h"
#include "scalers.h"
#include "scaleint.h"
#include "2xscalers.h"
// Scaler function lookup table
//
const Scale_FuncDef_t
Scale_C_Functions[] =
{
{TFB_GFXFLAGS_SCALE_BILINEAR, Scale_BilinearFilter},
{TFB_GFXFLAGS_SCALE_BIADAPT, Scale_BiAdaptFilter},
{TFB_GFXFLAGS_SCALE_BIADAPTADV, Scale_BiAdaptAdvFilter},
{TFB_GFXFLAGS_SCALE_TRISCAN, Scale_TriScanFilter},
{TFB_GFXFLAGS_SCALE_HQXX, Scale_HqFilter},
// Default
{0, Scale_Nearest}
};
// See
// nearest2x.c -- Nearest Neighboor scaling
// bilinear2x.c -- Bilinear scaling
// biadv2x.c -- Advanced Biadapt scaling
// triscan2x.c -- Triscan scaling
// Biadapt scaling to 2x
void
SCALE_(BiAdaptFilter) (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
{
int x, y;
const int w = src->w, h = src->h;
int xend, yend;
int dsrc, ddst;
SDL_Rect *region = r;
SDL_Rect limits;
SDL_PixelFormat *fmt = dst->format;
const int sp = src->pitch, dp = dst->pitch;
const int bpp = fmt->BytesPerPixel;
const int slen = sp / bpp, dlen = dp / bpp;
Uint32 *src_p = (Uint32 *)src->pixels;
Uint32 *dst_p = (Uint32 *)dst->pixels;
Uint32 pixval_tl, pixval_tr, pixval_bl, pixval_br;
// these macros are for clarity; they make the current pixel (0,0)
// and allow to access pixels in all directions
#define SRC(x, y) (src_p + (x) + ((y) * slen))
SCALE_(PlatInit) ();
// expand updated region if necessary
// pixels neighbooring the updated region may
// change as a result of updates
limits.x = 0;
limits.y = 0;
limits.w = src->w;
limits.h = src->h;
Scale_ExpandRect (region, 2, &limits);
xend = region->x + region->w;
yend = region->y + region->h;
dsrc = slen - region->w;
ddst = (dlen - region->w) * 2;
// move ptrs to the first updated pixel
src_p += slen * region->y + region->x;
dst_p += (dlen * region->y + region->x) * 2;
for (y = region->y; y < yend; ++y, dst_p += ddst, src_p += dsrc)
{
for (x = region->x; x < xend; ++x, ++src_p, ++dst_p)
{
pixval_tl = SCALE_GETPIX (SRC (0, 0));
SCALE_SETPIX (dst_p, pixval_tl);
if (y + 1 < h)
{
// check pixel below the current one
pixval_bl = SCALE_GETPIX (SRC (0, 1));
if (pixval_tl == pixval_bl)
SCALE_SETPIX (dst_p + dlen, pixval_tl);
else
SCALE_SETPIX (dst_p + dlen, Scale_Blend_11 (
pixval_tl, pixval_bl)
);
}
else
{
// last pixel in column - propagate
SCALE_SETPIX (dst_p + dlen, pixval_tl);
pixval_bl = pixval_tl;
}
++dst_p;
if (x + 1 >= w)
{
// last pixel in row - propagate
SCALE_SETPIX (dst_p, pixval_tl);
if (pixval_tl == pixval_bl)
SCALE_SETPIX (dst_p + dlen, pixval_tl);
else
SCALE_SETPIX (dst_p + dlen, Scale_Blend_11 (
pixval_tl, pixval_bl)
);
continue;
}
// check pixel to the right from the current one
pixval_tr = SCALE_GETPIX (SRC (1, 0));
if (pixval_tl == pixval_tr)
SCALE_SETPIX (dst_p, pixval_tr);
else
SCALE_SETPIX (dst_p, Scale_Blend_11 (
pixval_tl, pixval_tr)
);
if (y + 1 >= h)
{
// last pixel in column - propagate
SCALE_SETPIX (dst_p + dlen, pixval_tl);
continue;
}
// check pixel to the bottom-right
pixval_br = SCALE_GETPIX (SRC (1, 1));
if (pixval_tl == pixval_br && pixval_tr == pixval_bl)
{
int cl, cr;
Uint32 clr;
if (pixval_tl == pixval_tr)
{
// all 4 are equal - propagate
SCALE_SETPIX (dst_p + dlen, pixval_tl);
continue;
}
// both pairs are equal, have to resolve the pixel
// race; we try detecting which color is
// the background by looking for a line or an edge
// examine 8 pixels surrounding the current quad
cl = cr = 1;
if (x > 0)
{
clr = SCALE_GETPIX (SRC (-1, 0));
if (clr == pixval_tl)
cl++;
else if (clr == pixval_tr)
cr++;
clr = SCALE_GETPIX (SRC (-1, 1));
if (clr == pixval_tl)
cl++;
else if (clr == pixval_tr)
cr++;
}
if (y > 0)
{
clr = SCALE_GETPIX (SRC (0, -1));
if (clr == pixval_tl)
cl++;
else if (clr == pixval_tr)
cr++;
clr = SCALE_GETPIX (SRC (1, -1));
if (clr == pixval_tl)
cl++;
else if (clr == pixval_tr)
cr++;
}
if (x + 2 < w)
{
clr = SCALE_GETPIX (SRC (2, 0));
if (clr == pixval_tl)
cl++;
else if (clr == pixval_tr)
cr++;
clr = SCALE_GETPIX (SRC (2, 1));
if (clr == pixval_tl)
cl++;
else if (clr == pixval_tr)
cr++;
}
if (y + 2 < h)
{
clr = SCALE_GETPIX (SRC (0, 2));
if (clr == pixval_tl)
cl++;
else if (clr == pixval_tr)
cr++;
clr = SCALE_GETPIX (SRC (1, 2));
if (clr == pixval_tl)
cl++;
else if (clr == pixval_tr)
cr++;
}
// least count wins
if (cl > cr)
SCALE_SETPIX (dst_p + dlen, pixval_tr);
else if (cr > cl)
SCALE_SETPIX (dst_p + dlen, pixval_tl);
else
SCALE_SETPIX (dst_p + dlen,
Scale_Blend_11 (pixval_tl, pixval_tr));
}
else if (pixval_tl == pixval_br)
{
// main diagonal is same color
// use its value
SCALE_SETPIX (dst_p + dlen, pixval_tl);
}
else if (pixval_tr == pixval_bl)
{
// 2nd diagonal is same color
// use its value
SCALE_SETPIX (dst_p + dlen, pixval_tr);
}
else
{
// blend all 4
SCALE_SETPIX (dst_p + dlen, Scale_Blend_1111 (
pixval_tl, pixval_bl, pixval_tr, pixval_br
));
}
}
}
SCALE_(PlatDone) ();
}

View File

@@ -0,0 +1,30 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _2XSCALERS_H_
#define _2XSCALERS_H_
void Scale_Nearest (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
void Scale_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
void Scale_BiAdaptFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
void Scale_BiAdaptAdvFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
void Scale_TriScanFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
void Scale_HqFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
extern const Scale_FuncDef_t Scale_C_Functions[];
#endif /* _2XSCALERS_H_ */

View File

@@ -0,0 +1,102 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "port.h"
#include "libs/platform.h"
#if defined(MMX_ASM)
#include "libs/graphics/sdl/sdl_common.h"
#include "types.h"
#include "scalers.h"
#include "scaleint.h"
#include "2xscalers.h"
#include "2xscalers_mmx.h"
// 3DNow! name for all functions
#undef SCALE_
#define SCALE_(name) Scale ## _3DNow_ ## name
// Tell them which opcodes we want to support
#undef USE_MOVNTQ
#define USE_PREFETCH AMD_PREFETCH
#undef USE_PSADBW
// Bring in inline asm functions
#include "scalemmx.h"
// Scaler function lookup table
//
const Scale_FuncDef_t
Scale_3DNow_Functions[] =
{
{TFB_GFXFLAGS_SCALE_BILINEAR, Scale_3DNow_BilinearFilter},
{TFB_GFXFLAGS_SCALE_BIADAPT, Scale_BiAdaptFilter},
{TFB_GFXFLAGS_SCALE_BIADAPTADV, Scale_MMX_BiAdaptAdvFilter},
{TFB_GFXFLAGS_SCALE_TRISCAN, Scale_MMX_TriScanFilter},
{TFB_GFXFLAGS_SCALE_HQXX, Scale_MMX_HqFilter},
// Default
{0, Scale_3DNow_Nearest}
};
void
Scale_3DNow_PrepPlatform (const SDL_PixelFormat* fmt)
{
Scale_MMX_PrepPlatform (fmt);
}
// Nearest Neighbor scaling to 2x
// void Scale_3DNow_Nearest (SDL_Surface *src,
// SDL_Surface *dst, SDL_Rect *r)
#include "nearest2x.c"
// Bilinear scaling to 2x
// void Scale_3DNow_BilinearFilter (SDL_Surface *src,
// SDL_Surface *dst, SDL_Rect *r)
#include "bilinear2x.c"
#if 0 && NO_IMPROVEMENT
// Advanced Biadapt scaling to 2x
// void Scale_3DNow_BiAdaptAdvFilter (SDL_Surface *src,
// SDL_Surface *dst, SDL_Rect *r)
#include "biadv2x.c"
// Triscan scaling to 2x
// derivative of scale2x -- scale2x.sf.net
// void Scale_3DNow_TriScanFilter (SDL_Surface *src,
// SDL_Surface *dst, SDL_Rect *r)
#include "triscan2x.c"
// Hq2x scaling
// (adapted from 'hq2x' by Maxim Stepin -- www.hiend3d.com/hq2x.html)
// void Scale_3DNow_HqFilter (SDL_Surface *src,
// SDL_Surface *dst, SDL_Rect *r)
#include "hq2x.c"
#endif /* NO_IMPROVEMENT */
#endif /* MMX_ASM */

View File

@@ -0,0 +1,136 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "port.h"
#include "libs/platform.h"
#if defined(MMX_ASM)
#include "libs/graphics/sdl/sdl_common.h"
#include "types.h"
#include "scalers.h"
#include "scaleint.h"
#include "2xscalers.h"
#include "2xscalers_mmx.h"
// MMX name for all functions
#undef SCALE_
#define SCALE_(name) Scale ## _MMX_ ## name
// Tell them which opcodes we want to support
#undef USE_MOVNTQ
#undef USE_PREFETCH
#undef USE_PSADBW
// And Bring in inline asm functions
#include "scalemmx.h"
// Scaler function lookup table
//
const Scale_FuncDef_t
Scale_MMX_Functions[] =
{
{TFB_GFXFLAGS_SCALE_BILINEAR, Scale_MMX_BilinearFilter},
{TFB_GFXFLAGS_SCALE_BIADAPT, Scale_BiAdaptFilter},
{TFB_GFXFLAGS_SCALE_BIADAPTADV, Scale_MMX_BiAdaptAdvFilter},
{TFB_GFXFLAGS_SCALE_TRISCAN, Scale_MMX_TriScanFilter},
{TFB_GFXFLAGS_SCALE_HQXX, Scale_MMX_HqFilter},
// Default
{0, Scale_MMX_Nearest}
};
// MMX transformation multipliers
Uint64 mmx_888to555_mult;
Uint64 mmx_Y_mult;
Uint64 mmx_U_mult;
Uint64 mmx_V_mult;
// Uint64 mmx_YUV_threshold = 0x00300706; original hq2x threshold
//Uint64 mmx_YUV_threshold = 0x0030100e;
Uint64 mmx_YUV_threshold = 0x0040120c;
void
Scale_MMX_PrepPlatform (const SDL_PixelFormat* fmt)
{
// prepare the channel-shuffle multiplier
mmx_888to555_mult = ((Uint64)0x0400) << (fmt->Rshift * 2)
| ((Uint64)0x0020) << (fmt->Gshift * 2)
| ((Uint64)0x0001) << (fmt->Bshift * 2);
// prepare the RGB->YUV multipliers
mmx_Y_mult = ((Uint64)(uint16)YUV_matrix[YUV_XFORM_R][YUV_XFORM_Y])
<< (fmt->Rshift * 2)
| ((Uint64)(uint16)YUV_matrix[YUV_XFORM_G][YUV_XFORM_Y])
<< (fmt->Gshift * 2)
| ((Uint64)(uint16)YUV_matrix[YUV_XFORM_B][YUV_XFORM_Y])
<< (fmt->Bshift * 2);
mmx_U_mult = ((Uint64)(uint16)YUV_matrix[YUV_XFORM_R][YUV_XFORM_U])
<< (fmt->Rshift * 2)
| ((Uint64)(uint16)YUV_matrix[YUV_XFORM_G][YUV_XFORM_U])
<< (fmt->Gshift * 2)
| ((Uint64)(uint16)YUV_matrix[YUV_XFORM_B][YUV_XFORM_U])
<< (fmt->Bshift * 2);
mmx_V_mult = ((Uint64)(uint16)YUV_matrix[YUV_XFORM_R][YUV_XFORM_V])
<< (fmt->Rshift * 2)
| ((Uint64)(uint16)YUV_matrix[YUV_XFORM_G][YUV_XFORM_V])
<< (fmt->Gshift * 2)
| ((Uint64)(uint16)YUV_matrix[YUV_XFORM_B][YUV_XFORM_V])
<< (fmt->Bshift * 2);
mmx_YUV_threshold = (SCALE_DIFFYUV_TY << 16) | (SCALE_DIFFYUV_TU << 8)
| SCALE_DIFFYUV_TV;
}
// Nearest Neighbor scaling to 2x
// void Scale_MMX_Nearest (SDL_Surface *src,
// SDL_Surface *dst, SDL_Rect *r)
#include "nearest2x.c"
// Bilinear scaling to 2x
// void Scale_MMX_BilinearFilter (SDL_Surface *src,
// SDL_Surface *dst, SDL_Rect *r)
#include "bilinear2x.c"
// Advanced Biadapt scaling to 2x
// void Scale_MMX_BiAdaptAdvFilter (SDL_Surface *src,
// SDL_Surface *dst, SDL_Rect *r)
#include "biadv2x.c"
// Triscan scaling to 2x
// derivative of 'scale2x' -- scale2x.sf.net
// void Scale_MMX_TriScanFilter (SDL_Surface *src,
// SDL_Surface *dst, SDL_Rect *r)
#include "triscan2x.c"
// Hq2x scaling
// (adapted from 'hq2x' by Maxim Stepin -- www.hiend3d.com/hq2x.html)
// void Scale_MMX_HqFilter (SDL_Surface *src,
// SDL_Surface *dst, SDL_Rect *r)
#include "hq2x.c"
#endif /* MMX_ASM */

View File

@@ -0,0 +1,56 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _2XSCALERS_MMX_H_
#define _2XSCALERS_MMX_H_
// MMX versions
void Scale_MMX_PrepPlatform (const SDL_PixelFormat* fmt);
void Scale_MMX_Nearest (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
void Scale_MMX_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
void Scale_MMX_BiAdaptAdvFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
void Scale_MMX_TriScanFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
void Scale_MMX_HqFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
extern const Scale_FuncDef_t Scale_MMX_Functions[];
// SSE (Intel)/MMX Ext (Athlon) versions
void Scale_SSE_PrepPlatform (const SDL_PixelFormat* fmt);
void Scale_SSE_Nearest (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
void Scale_SSE_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
void Scale_SSE_BiAdaptAdvFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
void Scale_SSE_TriScanFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
void Scale_SSE_HqFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
extern const Scale_FuncDef_t Scale_SSE_Functions[];
// 3DNow (AMD K6/Athlon) versions
void Scale_3DNow_PrepPlatform (const SDL_PixelFormat* fmt);
void Scale_3DNow_Nearest (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
void Scale_3DNow_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
void Scale_3DNow_BiAdaptAdvFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
void Scale_3DNow_TriScanFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
void Scale_3DNow_HqFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
extern const Scale_FuncDef_t Scale_3DNow_Functions[];
#endif /* _2XSCALERS_MMX_H_ */

View File

@@ -0,0 +1,100 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "port.h"
#include "libs/platform.h"
#if defined(MMX_ASM)
#include "libs/graphics/sdl/sdl_common.h"
#include "types.h"
#include "scalers.h"
#include "scaleint.h"
#include "2xscalers.h"
#include "2xscalers_mmx.h"
// SSE name for all functions
#undef SCALE_
#define SCALE_(name) Scale ## _SSE_ ## name
// Tell them which opcodes we want to support
#define USE_MOVNTQ
#define USE_PREFETCH INTEL_PREFETCH
#define USE_PSADBW
// Bring in inline asm functions
#include "scalemmx.h"
// Scaler function lookup table
//
const Scale_FuncDef_t
Scale_SSE_Functions[] =
{
{TFB_GFXFLAGS_SCALE_BILINEAR, Scale_SSE_BilinearFilter},
{TFB_GFXFLAGS_SCALE_BIADAPT, Scale_BiAdaptFilter},
{TFB_GFXFLAGS_SCALE_BIADAPTADV, Scale_SSE_BiAdaptAdvFilter},
{TFB_GFXFLAGS_SCALE_TRISCAN, Scale_SSE_TriScanFilter},
{TFB_GFXFLAGS_SCALE_HQXX, Scale_MMX_HqFilter},
// Default
{0, Scale_SSE_Nearest}
};
void
Scale_SSE_PrepPlatform (const SDL_PixelFormat* fmt)
{
Scale_MMX_PrepPlatform (fmt);
}
// Nearest Neighbor scaling to 2x
// void Scale_SSE_Nearest (SDL_Surface *src,
// SDL_Surface *dst, SDL_Rect *r)
#include "nearest2x.c"
// Bilinear scaling to 2x
// void Scale_SSE_BilinearFilter (SDL_Surface *src,
// SDL_Surface *dst, SDL_Rect *r)
#include "bilinear2x.c"
// Advanced Biadapt scaling to 2x
// void Scale_SSE_BiAdaptAdvFilter (SDL_Surface *src,
// SDL_Surface *dst, SDL_Rect *r)
#include "biadv2x.c"
// Triscan scaling to 2x
// derivative of scale2x -- scale2x.sf.net
// void Scale_SSE_TriScanFilter (SDL_Surface *src,
// SDL_Surface *dst, SDL_Rect *r)
#include "triscan2x.c"
#if 0 && NO_IMPROVEMENT
// Hq2x scaling
// (adapted from 'hq2x' by Maxim Stepin -- www.hiend3d.com/hq2x.html)
// void Scale_SSE_HqFilter (SDL_Surface *src,
// SDL_Surface *dst, SDL_Rect *r)
#include "hq2x.c"
#endif
#endif /* MMX_ASM */

View File

@@ -0,0 +1,5 @@
uqm_CFILES="opengl.c palette.c primitives.c pure.c sdl_common.c
scalers.c 2xscalers.c
2xscalers_mmx.c 2xscalers_sse.c 2xscalers_3dnow.c
nearest2x.c bilinear2x.c biadv2x.c triscan2x.c hq2x.c
canvas.c sdluio.c rotozoom.c"

View File

@@ -0,0 +1,532 @@
/*
* Portions Copyright (C) 2003-2005 Alex Volkov (codepro@usa.net)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// Core algorithm of the Advanced BiAdaptive screen scaler
// Template
// When this file is built standalone is produces a plain C version
// Also #included by 2xscalers_mmx.c for an MMX version
#include "libs/graphics/sdl/sdl_common.h"
#include "types.h"
#include "scalers.h"
#include "scaleint.h"
#include "2xscalers.h"
// Advanced biadapt scaling to 2x
// The name expands to either
// Scale_BiAdaptAdvFilter (for plain C) or
// Scale_MMX_BiAdaptAdvFilter (for MMX)
// [others when platforms are added]
void
SCALE_(BiAdaptAdvFilter) (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
{
int x, y;
const int w = src->w, h = src->h;
int xend, yend;
int dsrc, ddst;
SDL_Rect *region = r;
SDL_Rect limits;
SDL_PixelFormat *fmt = dst->format;
const int sp = src->pitch, dp = dst->pitch;
const int bpp = fmt->BytesPerPixel;
const int slen = sp / bpp, dlen = dp / bpp;
// for clarity purposes, the 'pixels' array here is transposed
Uint32 pixels[4][4];
static int resolve_coord[][2] =
{
{0, -1}, {1, -1}, { 2, 0}, { 2, 1},
{1, 2}, {0, 2}, {-1, 1}, {-1, 0},
{100, 100} // term
};
Uint32 *src_p = (Uint32 *)src->pixels;
Uint32 *dst_p = (Uint32 *)dst->pixels;
// these macros are for clarity; they make the current pixel (0,0)
// and allow to access pixels in all directions
#define PIX(x, y) (pixels[1 + (x)][1 + (y)])
#define SRC(x, y) (src_p + (x) + ((y) * slen))
// commonly used operations, for clarity also
// others are defined at their respective bpp levels
#define BIADAPT_RGBHIGH 8000
#define BIADAPT_YUVLOW 30
#define BIADAPT_YUVMED 70
#define BIADAPT_YUVHIGH 130
// high tolerance pixel comparison
#define BIADAPT_CMPRGB_HIGH(p1, p2) \
(p1 == p2 || SCALE_CMPRGB (p1, p2) <= BIADAPT_RGBHIGH)
// low tolerance pixel comparison
#define BIADAPT_CMPYUV_LOW(p1, p2) \
(p1 == p2 || SCALE_CMPYUV (p1, p2, BIADAPT_YUVLOW))
// medium tolerance pixel comparison
#define BIADAPT_CMPYUV_MED(p1, p2) \
(p1 == p2 || SCALE_CMPYUV (p1, p2, BIADAPT_YUVMED))
// high tolerance pixel comparison
#define BIADAPT_CMPYUV_HIGH(p1, p2) \
(p1 == p2 || SCALE_CMPYUV (p1, p2, BIADAPT_YUVHIGH))
SCALE_(PlatInit) ();
// expand updated region if necessary
// pixels neighbooring the updated region may
// change as a result of updates
limits.x = 0;
limits.y = 0;
limits.w = src->w;
limits.h = src->h;
Scale_ExpandRect (region, 2, &limits);
xend = region->x + region->w;
yend = region->y + region->h;
dsrc = slen - region->w;
ddst = (dlen - region->w) * 2;
#define SCALE_GETPIX(p) ( *(Uint32 *)(p) )
#define SCALE_SETPIX(p, c) ( *(Uint32 *)(p) = (c) )
// move ptrs to the first updated pixel
src_p += slen * region->y + region->x;
dst_p += (dlen * region->y + region->x) * 2;
for (y = region->y; y < yend; ++y, dst_p += ddst, src_p += dsrc)
{
for (x = region->x; x < xend; ++x, ++src_p, ++dst_p)
{
// pixel equality counter
int cmatch;
// most pixels will fall into 'all 4 equal'
// pattern, so we check it first
cmatch = 0;
PIX (0, 0) = SCALE_GETPIX (SRC (0, 0));
SCALE_SETPIX (dst_p, PIX (0, 0));
if (y + 1 < h)
{
// check pixel below the current one
PIX (0, 1) = SCALE_GETPIX (SRC (0, 1));
if (PIX (0, 0) == PIX (0, 1))
{
SCALE_SETPIX (dst_p + dlen, PIX (0, 0));
cmatch |= 1;
}
}
else
{
// last pixel in column - propagate
PIX (0, 1) = PIX (0, 0);
SCALE_SETPIX (dst_p + dlen, PIX (0, 0));
cmatch |= 1;
}
if (x + 1 < w)
{
// check pixel to the right from the current one
PIX (1, 0) = SCALE_GETPIX (SRC (1, 0));
if (PIX (0, 0) == PIX (1, 0))
{
SCALE_SETPIX (dst_p + 1, PIX (0, 0));
cmatch |= 2;
}
}
else
{
// last pixel in row - propagate
PIX (1, 0) = PIX (0, 0);
SCALE_SETPIX (dst_p + 1, PIX (0, 0));
cmatch |= 2;
}
if (cmatch == 3)
{
if (y + 1 >= h || x + 1 >= w)
{
// last pixel in row/column and nearest
// neighboor is identical
dst_p++;
SCALE_SETPIX (dst_p + dlen, PIX (0, 0));
continue;
}
// check pixel to the bottom-right
PIX (1, 1) = SCALE_GETPIX (SRC (1, 1));
if (PIX (0, 0) == PIX (1, 1))
{
// all 4 are equal - propagate
dst_p++;
SCALE_SETPIX (dst_p + dlen, PIX (0, 0));
continue;
}
}
// some neighboors are different, lets check them
if (x > 0)
PIX (-1, 0) = SCALE_GETPIX (SRC (-1, 0));
else
PIX (-1, 0) = PIX (0, 0);
if (x + 2 < w)
PIX (2, 0) = SCALE_GETPIX (SRC (2, 0));
else
PIX (2, 0) = PIX (1, 0);
if (y + 1 < h)
{
if (x > 0)
PIX (-1, 1) = SCALE_GETPIX (SRC (-1, 1));
else
PIX (-1, 1) = PIX (0, 1);
if (x + 2 < w)
{
PIX (1, 1) = SCALE_GETPIX (SRC (1, 1));
PIX (2, 1) = SCALE_GETPIX (SRC (2, 1));
}
else if (x + 1 < w)
{
PIX (1, 1) = SCALE_GETPIX (SRC (1, 1));
PIX (2, 1) = PIX (1, 1);
}
else
{
PIX (1, 1) = PIX (0, 1);
PIX (2, 1) = PIX (0, 1);
}
}
else
{
// last pixel in column
PIX (-1, 1) = PIX (-1, 0);
PIX (1, 1) = PIX (1, 0);
PIX (2, 1) = PIX (2, 0);
}
if (y + 2 < h)
{
PIX (0, 2) = SCALE_GETPIX (SRC (0, 2));
if (x > 0)
PIX (-1, 2) = SCALE_GETPIX (SRC (-1, 2));
else
PIX (-1, 2) = PIX (0, 2);
if (x + 2 < w)
{
PIX (1, 2) = SCALE_GETPIX (SRC (1, 2));
PIX (2, 2) = SCALE_GETPIX (SRC (2, 2));
}
else if (x + 1 < w)
{
PIX (1, 2) = SCALE_GETPIX (SRC (1, 2));
PIX (2, 2) = PIX (1, 2);
}
else
{
PIX (1, 2) = PIX (0, 2);
PIX (2, 2) = PIX (0, 2);
}
}
else
{
// last pixel in column
PIX (-1, 2) = PIX (-1, 1);
PIX (0, 2) = PIX (0, 1);
PIX (1, 2) = PIX (1, 1);
PIX (2, 2) = PIX (2, 1);
}
if (y > 0)
{
PIX (0, -1) = SCALE_GETPIX (SRC (0, -1));
if (x > 0)
PIX (-1, -1) = SCALE_GETPIX (SRC (-1, -1));
else
PIX (-1, -1) = PIX (0, -1);
if (x + 2 < w)
{
PIX (1, -1) = SCALE_GETPIX (SRC (1, -1));
PIX (2, -1) = SCALE_GETPIX (SRC (2, -1));
}
else if (x + 1 < w)
{
PIX (1, -1) = SCALE_GETPIX (SRC (1, -1));
PIX (2, -1) = PIX (1, -1);
}
else
{
PIX (1, -1) = PIX (0, -1);
PIX (2, -1) = PIX (0, -1);
}
}
else
{
PIX (-1, -1) = PIX (-1, 0);
PIX (0, -1) = PIX (0, 0);
PIX (1, -1) = PIX (1, 0);
PIX (2, -1) = PIX (2, 0);
}
// check pixel below the current one
if (!(cmatch & 1))
{
if (SCALE_CMPYUV (PIX (0, 0), PIX (0, 1), BIADAPT_YUVLOW))
{
SCALE_SETPIX (dst_p + dlen, Scale_Blend_11 (
PIX (0, 0), PIX (0, 1))
);
cmatch |= 1;
}
// detect a 2:1 line going across the current pixel
else if ( (PIX (0, 0) == PIX (-1, 0)
&& PIX (0, 0) == PIX (1, 1)
&& PIX (0, 0) == PIX (2, 1) &&
((!BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (-1, -1))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (0, -1))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (1, 0))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (2, 0))) ||
(!BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (-1, 1))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (1, 2))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (2, 2))))) ||
(PIX (0, 0) == PIX (1, 0)
&& PIX (0, 0) == PIX (-1, 1)
&& PIX (0, 0) == PIX (2, -1) &&
((!BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (-1, 0))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (0, -1))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (1, -1))) ||
(!BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (-1, 2))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (1, 1))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (2, 0))))) )
{
SCALE_SETPIX (dst_p + dlen, PIX (0, 0));
}
// detect a 2:1 line going across the pixel below current
else if ( (PIX (0, 1) == PIX (-1, 0)
&& PIX (0, 1) == PIX (1, 1)
&& PIX (0, 1) == PIX (2, 2) &&
((!BIADAPT_CMPRGB_HIGH (PIX (0, 1), PIX (-1, -1))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 1), PIX (1, 0))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 1), PIX (2, 1))) ||
(!BIADAPT_CMPRGB_HIGH (PIX (0, 1), PIX (-1, 1))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 1), PIX (0, 2))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 1), PIX (1, 2))))) ||
(PIX (0, 1) == PIX (1, 0)
&& PIX (0, 1) == PIX (-1, 1)
&& PIX (0, 1) == PIX (2, 0) &&
((!BIADAPT_CMPRGB_HIGH (PIX (0, 1), PIX (-1, 0))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 1), PIX (1, -1))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 1), PIX (2, -1))) ||
(!BIADAPT_CMPRGB_HIGH (PIX (0, 1), PIX (-1, 2))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 1), PIX (0, 2))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 1), PIX (1, 1))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 1), PIX (2, 1))))) )
{
SCALE_SETPIX (dst_p + dlen, PIX (0, 1));
}
else
SCALE_SETPIX (dst_p + dlen, Scale_Blend_11 (
PIX (0, 0), PIX (0, 1))
);
}
dst_p++;
// check pixel to the right from the current one
if (!(cmatch & 2))
{
if (SCALE_CMPYUV (PIX (0, 0), PIX (1, 0), BIADAPT_YUVLOW))
{
SCALE_SETPIX (dst_p, Scale_Blend_11 (
PIX (0, 0), PIX (1, 0))
);
cmatch |= 2;
}
// detect a 1:2 line going across the current pixel
else if ( (PIX (0, 0) == PIX (1, -1)
&& PIX (0, 0) == PIX (0, 1)
&& PIX (0, 0) == PIX (-1, 2) &&
((!BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (0, -1))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (-1, 0))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (-1, 1))) ||
(!BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (2, -1))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (1, 1))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (0, 2))))) ||
(PIX (0, 0) == PIX (0, -1)
&& PIX (0, 0) == PIX (1, 1)
&& PIX (0, 0) == PIX (1, 2) &&
((!BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (-1, -1))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (-1, 0))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (0, 1))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (0, 2))) ||
(!BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (1, -1))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (2, 1))
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (2, 2))))) )
{
SCALE_SETPIX (dst_p, PIX (0, 0));
}
// detect a 1:2 line going across the pixel to the right
else if ( (PIX (1, 0) == PIX (1, -1)
&& PIX (1, 0) == PIX (0, 1)
&& PIX (1, 0) == PIX (0, 2) &&
((!BIADAPT_CMPRGB_HIGH (PIX (1, 0), PIX (0, -1))
&& !BIADAPT_CMPRGB_HIGH (PIX (1, 0), PIX (-1, 1))
&& !BIADAPT_CMPRGB_HIGH (PIX (1, 0), PIX (-1, 2))) ||
(!BIADAPT_CMPRGB_HIGH (PIX (1, 0), PIX (2, -1))
&& !BIADAPT_CMPRGB_HIGH (PIX (1, 0), PIX (2, 0))
&& !BIADAPT_CMPRGB_HIGH (PIX (1, 0), PIX (1, 1))
&& !BIADAPT_CMPRGB_HIGH (PIX (1, 0), PIX (1, 2))))) ||
(PIX (1, 0) == PIX (0, -1)
&& PIX (1, 0) == PIX (1, 1)
&& PIX (1, 0) == PIX (2, 2) &&
((!BIADAPT_CMPRGB_HIGH (PIX (1, 0), PIX (-1, -1))
&& !BIADAPT_CMPRGB_HIGH (PIX (1, 0), PIX (0, 1))
&& !BIADAPT_CMPRGB_HIGH (PIX (1, 0), PIX (1, 2))) ||
(!BIADAPT_CMPRGB_HIGH (PIX (1, 0), PIX (1, -1))
&& !BIADAPT_CMPRGB_HIGH (PIX (1, 0), PIX (2, 0))
&& !BIADAPT_CMPRGB_HIGH (PIX (1, 0), PIX (2, 1))))) )
{
SCALE_SETPIX (dst_p, PIX (1, 0));
}
else
SCALE_SETPIX (dst_p, Scale_Blend_11 (
PIX (0, 0), PIX (1, 0))
);
}
if (PIX (0, 0) == PIX (1, 1) && PIX (1, 0) == PIX (0, 1))
{
// diagonals are equal
int *coord;
int cl, cr;
Uint32 clr;
// both pairs are equal, have to resolve the pixel
// race; we try detecting which color is
// the background by looking for a line or an edge
// examine 8 pixels surrounding the current quad
cl = cr = 2;
for (coord = resolve_coord[0]; *coord < 100; coord += 2)
{
clr = PIX (coord[0], coord[1]);
if (BIADAPT_CMPYUV_MED (clr, PIX (0, 0)))
cl++;
else if (BIADAPT_CMPYUV_MED (clr, PIX (1, 0)))
cr++;
}
// least count wins
if (cl > cr)
clr = PIX (1, 0);
else if (cr > cl)
clr = PIX (0, 0);
else
clr = Scale_Blend_11 (PIX (0, 0), PIX (1, 0));
SCALE_SETPIX (dst_p + dlen, clr);
continue;
}
if (cmatch == 3
|| (BIADAPT_CMPYUV_LOW (PIX (1, 0), PIX (0, 1))
&& BIADAPT_CMPYUV_LOW (PIX (1, 0), PIX (1, 1))))
{
SCALE_SETPIX (dst_p + dlen, Scale_Blend_11 (
PIX (0, 1), PIX (1, 0))
);
continue;
}
else if (cmatch && BIADAPT_CMPYUV_LOW (PIX (0, 0), PIX (1, 1)))
{
SCALE_SETPIX (dst_p + dlen, Scale_Blend_11 (
PIX (0, 0), PIX (1, 1))
);
continue;
}
// check pixel to the bottom-right
if (BIADAPT_CMPYUV_HIGH (PIX (0, 0), PIX (1, 1))
&& BIADAPT_CMPYUV_HIGH (PIX (1, 0), PIX (0, 1)))
{
if (SCALE_GETY (PIX (0, 0)) > SCALE_GETY (PIX (1, 0)))
{
SCALE_SETPIX (dst_p + dlen, Scale_Blend_11 (
PIX (0, 0), PIX (1, 1))
);
}
else
{
SCALE_SETPIX (dst_p + dlen, Scale_Blend_11 (
PIX (1, 0), PIX (0, 1))
);
}
}
else if (BIADAPT_CMPYUV_HIGH (PIX (0, 0), PIX (1, 1)))
{
// main diagonal is same color
// use its value
SCALE_SETPIX (dst_p + dlen, Scale_Blend_11 (
PIX (0, 0), PIX (1, 1))
);
}
else if (BIADAPT_CMPYUV_HIGH (PIX (1, 0), PIX (0, 1)))
{
// 2nd diagonal is same color
// use its value
SCALE_SETPIX (dst_p + dlen, Scale_Blend_11 (
PIX (1, 0), PIX (0, 1))
);
}
else
{
// blend all 4
SCALE_SETPIX (dst_p + dlen, Scale_Blend_1111 (
PIX (0, 0), PIX (0, 1),
PIX (1, 0), PIX (1, 1)
));
}
}
}
SCALE_(PlatDone) ();
}

View File

@@ -0,0 +1,112 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// Core algorithm of the BiLinear screen scaler
// Template
// When this file is built standalone is produces a plain C version
// Also #included by 2xscalers_mmx.c for an MMX version
#include "libs/graphics/sdl/sdl_common.h"
#include "types.h"
#include "scalers.h"
#include "scaleint.h"
#include "2xscalers.h"
// Bilinear scaling to 2x
// The name expands to either
// Scale_BilinearFilter (for plain C) or
// Scale_MMX_BilinearFilter (for MMX)
// Scale_SSE_BilinearFilter (for SSE)
// [others when platforms are added]
void
SCALE_(BilinearFilter) (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
{
int x, y;
const int w = src->w, h = src->h;
int xend, yend;
int dsrc, ddst;
SDL_Rect *region = r;
SDL_Rect limits;
SDL_PixelFormat *fmt = dst->format;
const int pitch = src->pitch, dp = dst->pitch;
const int bpp = fmt->BytesPerPixel;
const int len = pitch / bpp, dlen = dp / bpp;
Uint32 p[4]; // influential pixels array
Uint32 *srow0 = (Uint32 *) src->pixels;
Uint32 *dst_p = (Uint32 *) dst->pixels;
SCALE_(PlatInit) ();
// expand updated region if necessary
// pixels neighbooring the updated region may
// change as a result of updates
limits.x = 0;
limits.y = 0;
limits.w = w;
limits.h = h;
Scale_ExpandRect (region, 1, &limits);
xend = region->x + region->w;
yend = region->y + region->h;
dsrc = len - region->w;
ddst = (dlen - region->w) * 2;
// move ptrs to the first updated pixel
srow0 += len * region->y + region->x;
dst_p += (dlen * region->y + region->x) * 2;
for (y = region->y; y < yend; ++y, dst_p += ddst, srow0 += dsrc)
{
Uint32 *srow1;
SCALE_(Prefetch) (srow0 + 16);
SCALE_(Prefetch) (srow0 + 32);
if (y < h - 1)
srow1 = srow0 + len;
else
srow1 = srow0;
SCALE_(Prefetch) (srow1 + 16);
SCALE_(Prefetch) (srow1 + 32);
for (x = region->x; x < xend; ++x, ++srow0, ++srow1, dst_p += 2)
{
if (x < w - 1)
{ // can blend directly from pixels
SCALE_BILINEAR_BLEND4 (srow0, srow1, dst_p, dlen);
}
else
{ // need to make temp pixel rows
p[0] = srow0[0];
p[1] = p[0];
p[2] = srow1[0];
p[3] = p[2];
SCALE_BILINEAR_BLEND4 (&p[0], &p[2], dst_p, dlen);
}
}
SCALE_(Prefetch) (srow0 + dsrc);
SCALE_(Prefetch) (srow0 + dsrc + 16);
SCALE_(Prefetch) (srow1 + dsrc);
SCALE_(Prefetch) (srow1 + dsrc + 16);
}
SCALE_(PlatDone) ();
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,207 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// Core algorithm of the BiLinear screen scaler
// Template
// When this file is built standalone is produces a plain C version
// Also #included by 2xscalers_mmx.c for an MMX version
#include "libs/graphics/sdl/sdl_common.h"
#include "types.h"
#include "scalers.h"
#include "scaleint.h"
#include "2xscalers.h"
// Nearest Neighbor scaling to 2x
// The name expands to
// Scale_Nearest (for plain C)
// Scale_MMX_Nearest (for MMX)
// Scale_SSE_Nearest (for SSE)
// [others when platforms are added]
void
SCALE_(Nearest) (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
{
int y;
const int rw = r->w, rh = r->h;
const int sp = src->pitch, dp = dst->pitch;
const int bpp = dst->format->BytesPerPixel;
const int slen = sp / bpp, dlen = dp / bpp;
const int dsrc = slen-rw, ddst = (dlen-rw) * 2;
Uint32 *src_p = (Uint32 *)src->pixels;
Uint32 *dst_p = (Uint32 *)dst->pixels;
// guard asm code against such atrocities
if (rw == 0 || rh == 0)
return;
SCALE_(PlatInit) ();
// move ptrs to the first updated pixel
src_p += slen * r->y + r->x;
dst_p += (dlen * r->y + r->x) * 2;
#if defined(MMX_ASM) && defined(MSVC_ASM)
// Just about everything has to be done in asm for MSVC
// to actually take advantage of asm here
// MSVC does not support beautiful GCC-like asm templates
y = rh;
__asm
{
// setup vars
mov esi, src_p
mov edi, dst_p
PREFETCH (esi + 0x40)
PREFETCH (esi + 0x80)
PREFETCH (esi + 0xc0)
mov edx, dlen
lea edx, [edx * 4]
mov eax, dsrc
lea eax, [eax * 4]
mov ebx, ddst
lea ebx, [ebx * 4]
mov ecx, rw
loop_y:
test ecx, 1
jz even_x
// one-pixel transfer
movd mm1, [esi]
punpckldq mm1, mm1 // pix1 | pix1 -> mm1
add esi, 4
MOVNTQ (edi, mm1)
add edi, 8
MOVNTQ (edi - 8 + edx, mm1)
even_x:
shr ecx, 1 // x = rw / 2
jz end_x // rw was 1
loop_x:
// two-pixel transfer
movq mm1, [esi]
movq mm2, mm1
PREFETCH (esi + 0x100)
punpckldq mm1, mm1 // pix1 | pix1 -> mm1
add esi, 8
MOVNTQ (edi, mm1)
punpckhdq mm2, mm2 // pix2 | pix2 -> mm2
MOVNTQ (edi + edx, mm1)
add edi, 16
MOVNTQ (edi - 8, mm2)
MOVNTQ (edi - 8 + edx, mm2)
dec ecx
jnz loop_x
end_x:
// try to prefetch as early as possible to have it on time
PREFETCH (esi + eax)
mov ecx, rw
add esi, eax
PREFETCH (esi + 0x40)
PREFETCH (esi + 0x80)
PREFETCH (esi + 0xc0)
add edi, ebx
dec y
jnz loop_y
}
#elif defined(MMX_ASM) && defined(GCC_ASM)
SCALE_(Prefetch) (src_p + 16);
SCALE_(Prefetch) (src_p + 32);
SCALE_(Prefetch) (src_p + 48);
for (y = rh; y; --y)
{
int x = rw;
if (x & 1)
{ // one-pixel transfer
__asm__ (
"movd (%0), %%mm1 \n\t"
"punpckldq %%mm1, %%mm1 \n\t"
MOVNTQ (%%mm1, (%1)) "\n\t"
MOVNTQ (%%mm1, (%1,%2)) "\n\t"
: /* nothing */
: /*0*/"r" (src_p), /*1*/"r" (dst_p), /*2*/"r" (dlen*sizeof(Uint32))
);
++src_p;
dst_p += 2;
--x;
}
for (x >>= 1; x; --x, src_p += 2, dst_p += 4)
{ // two-pixel transfer
__asm__ (
"movq (%0), %%mm1 \n\t"
"movq %%mm1, %%mm2 \n\t"
PREFETCH (0x100(%0)) "\n\t"
"punpckldq %%mm1, %%mm1 \n\t"
MOVNTQ (%%mm1, (%1)) "\n\t"
MOVNTQ (%%mm1, (%1,%2)) "\n\t"
"punpckhdq %%mm2, %%mm2 \n\t"
MOVNTQ (%%mm2, 8(%1)) "\n\t"
MOVNTQ (%%mm2, 8(%1,%2)) "\n\t"
: /* nothing */
: /*0*/"r" (src_p), /*1*/"r" (dst_p), /*2*/"r" (dlen*sizeof(Uint32))
);
}
src_p += dsrc;
// try to prefetch as early as possible to have it on time
SCALE_(Prefetch) (src_p);
dst_p += ddst;
SCALE_(Prefetch) (src_p + 16);
SCALE_(Prefetch) (src_p + 32);
SCALE_(Prefetch) (src_p + 48);
}
#else
// Plain C version
for (y = 0; y < rh; ++y)
{
int x;
for (x = 0; x < rw; ++x, ++src_p, dst_p += 2)
{
Uint32 pix = *src_p;
dst_p[0] = pix;
dst_p[1] = pix;
dst_p[dlen] = pix;
dst_p[dlen + 1] = pix;
}
dst_p += ddst;
src_p += dsrc;
}
#endif
SCALE_(PlatDone) ();
}

View File

@@ -0,0 +1,581 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_OPENGL
#include "libs/graphics/sdl/opengl.h"
#include "libs/graphics/bbox.h"
#include "scalers.h"
#include "options.h"
#include "libs/log.h"
typedef struct _gl_screeninfo {
SDL_Surface *scaled;
GLuint texture;
BOOLEAN dirty, active;
SDL_Rect updated;
} TFB_GL_SCREENINFO;
static TFB_GL_SCREENINFO GL_Screens[TFB_GFX_NUMSCREENS];
static int ScreenFilterMode;
static TFB_ScaleFunc scaler = NULL;
static BOOLEAN first_init = TRUE;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
#define R_MASK 0xff000000
#define G_MASK 0x00ff0000
#define B_MASK 0x0000ff00
#define A_MASK 0x000000ff
#else
#define R_MASK 0x000000ff
#define G_MASK 0x0000ff00
#define B_MASK 0x00ff0000
#define A_MASK 0xff000000
#endif
static void TFB_GL_Preprocess (int force_full_redraw, int transition_amount, int fade_amount);
static void TFB_GL_Postprocess (void);
static void TFB_GL_Scaled_ScreenLayer (SCREEN screen, Uint8 a, SDL_Rect *rect);
static void TFB_GL_Unscaled_ScreenLayer (SCREEN screen, Uint8 a, SDL_Rect *rect);
static void TFB_GL_ColorLayer (Uint8 r, Uint8 g, Uint8 b, Uint8 a, SDL_Rect *rect);
static TFB_GRAPHICS_BACKEND opengl_scaled_backend = {
TFB_GL_Preprocess,
TFB_GL_Postprocess,
TFB_GL_Scaled_ScreenLayer,
TFB_GL_ColorLayer };
static TFB_GRAPHICS_BACKEND opengl_unscaled_backend = {
TFB_GL_Preprocess,
TFB_GL_Postprocess,
TFB_GL_Unscaled_ScreenLayer,
TFB_GL_ColorLayer };
static SDL_Surface *
Create_Screen (SDL_Surface *template, int w, int h)
{
SDL_Surface *newsurf = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
template->format->BitsPerPixel,
template->format->Rmask, template->format->Gmask,
template->format->Bmask, 0);
if (newsurf == 0) {
log_add (log_Error, "Couldn't create screen buffers: %s",
SDL_GetError());
}
return newsurf;
}
static int
ReInit_Screen (SDL_Surface **screen, SDL_Surface *template, int w, int h)
{
if (*screen)
SDL_FreeSurface (*screen);
*screen = Create_Screen (template, w, h);
return *screen == 0 ? -1 : 0;
}
static int
AttemptColorDepth (int flags, int width, int height, int bpp)
{
int videomode_flags;
ScreenColorDepth = bpp;
ScreenWidthActual = width;
ScreenHeightActual = height;
switch (bpp) {
case 15:
SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 5);
SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 5);
SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 5);
break;
case 16:
SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 5);
SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 6);
SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 5);
break;
case 24:
SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 8);
break;
case 32:
SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 8);
break;
default:
break;
}
SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 0);
SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1);
videomode_flags = SDL_OPENGL;
if (flags & TFB_GFXFLAGS_FULLSCREEN)
videomode_flags |= SDL_FULLSCREEN;
videomode_flags |= SDL_ANYFORMAT;
SDL_Video = SDL_SetVideoMode (ScreenWidthActual, ScreenHeightActual,
bpp, videomode_flags);
if (SDL_Video == NULL)
{
log_add (log_Error, "Couldn't set OpenGL %ix%ix%i video mode: %s",
ScreenWidthActual, ScreenHeightActual, bpp,
SDL_GetError ());
return -1;
}
else
{
log_add (log_Info, "Set the resolution to: %ix%ix%i"
" (surface reports %ix%ix%i)",
width, height, bpp,
SDL_GetVideoSurface()->w, SDL_GetVideoSurface()->h,
SDL_GetVideoSurface()->format->BitsPerPixel);
log_add (log_Info, "OpenGL renderer: %s version: %s",
glGetString (GL_RENDERER), glGetString (GL_VERSION));
}
return 0;
}
int
TFB_GL_ConfigureVideo (int driver, int flags, int width, int height, int togglefullscreen)
{
int i, texture_width, texture_height;
GraphicsDriver = driver;
if (AttemptColorDepth (flags, width, height, 32) &&
AttemptColorDepth (flags, width, height, 24) &&
AttemptColorDepth (flags, width, height, 16))
{
log_add (log_Error, "Couldn't set any OpenGL %ix%i video mode!",
width, height);
return -1;
}
if (!togglefullscreen)
{
if (format_conv_surf)
SDL_FreeSurface (format_conv_surf);
format_conv_surf = SDL_CreateRGBSurface (SDL_SWSURFACE, 0, 0, 32,
R_MASK, G_MASK, B_MASK, A_MASK);
if (format_conv_surf == NULL)
{
log_add (log_Error, "Couldn't create format_conv_surf: %s",
SDL_GetError());
return -1;
}
for (i = 0; i < TFB_GFX_NUMSCREENS; i++)
{
if (0 != ReInit_Screen (&SDL_Screens[i], format_conv_surf,
ScreenWidth, ScreenHeight))
return -1;
}
SDL_Screen = SDL_Screens[0];
TransitionScreen = SDL_Screens[2];
if (first_init)
{
for (i = 0; i < TFB_GFX_NUMSCREENS; i++)
{
GL_Screens[i].scaled = NULL;
GL_Screens[i].dirty = TRUE;
GL_Screens[i].active = TRUE;
}
GL_Screens[1].active = FALSE;
first_init = FALSE;
}
}
if (GfxFlags & TFB_GFXFLAGS_SCALE_SOFT_ONLY)
{
if (!togglefullscreen)
{
for (i = 0; i < TFB_GFX_NUMSCREENS; i++)
{
if (!GL_Screens[i].active)
continue;
if (0 != ReInit_Screen (&GL_Screens[i].scaled, format_conv_surf,
ScreenWidth * 2, ScreenHeight * 2))
return -1;
}
scaler = Scale_PrepPlatform (flags, SDL_Screen->format);
}
texture_width = 1024;
texture_height = 512;
graphics_backend = &opengl_scaled_backend;
}
else
{
texture_width = 512;
texture_height = 256;
scaler = NULL;
graphics_backend = &opengl_unscaled_backend;
}
if (GfxFlags & TFB_GFXFLAGS_SCALE_ANY)
ScreenFilterMode = GL_LINEAR;
else
ScreenFilterMode = GL_NEAREST;
glViewport (0, 0, ScreenWidthActual, ScreenHeightActual);
glClearColor (0,0,0,0);
glClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
SDL_GL_SwapBuffers ();
glClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glDisable (GL_DITHER);
glDepthMask(GL_FALSE);
for (i = 0; i < TFB_GFX_NUMSCREENS; i++)
{
if (!GL_Screens[i].active)
continue;
glGenTextures (1, &GL_Screens[i].texture);
glBindTexture (GL_TEXTURE_2D, GL_Screens[i].texture);
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, texture_width, texture_height,
0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
}
return 0;
}
int
TFB_GL_InitGraphics (int driver, int flags, int width, int height)
{
char VideoName[256];
log_add (log_Info, "Initializing SDL with OpenGL support.");
SDL_VideoDriverName (VideoName, sizeof (VideoName));
log_add (log_Info, "SDL driver used: %s", VideoName);
log_add (log_Info, "SDL initialized.");
log_add (log_Info, "Initializing Screen.");
ScreenWidth = 320;
ScreenHeight = 240;
if (TFB_GL_ConfigureVideo (driver, flags, width, height, 0))
{
log_add (log_Fatal, "Could not initialize video: "
"no fallback at start of program!");
exit (EXIT_FAILURE);
}
// Initialize scalers (let them precompute whatever)
Scale_Init ();
return 0;
}
void TFB_GL_UploadTransitionScreen (void)
{
GL_Screens[TFB_SCREEN_TRANSITION].updated.x = 0;
GL_Screens[TFB_SCREEN_TRANSITION].updated.y = 0;
GL_Screens[TFB_SCREEN_TRANSITION].updated.w = ScreenWidth;
GL_Screens[TFB_SCREEN_TRANSITION].updated.h = ScreenHeight;
GL_Screens[TFB_SCREEN_TRANSITION].dirty = TRUE;
}
void
TFB_GL_ScanLines (void)
{
int y;
glDisable (GL_TEXTURE_2D);
glEnable (GL_BLEND);
glBlendFunc (GL_DST_COLOR, GL_ZERO);
glColor3f (0.85f, 0.85f, 0.85f);
for (y = 0; y < ScreenHeightActual; y += 2)
{
glBegin (GL_LINES);
glVertex2i (0, y);
glVertex2i (ScreenWidthActual, y);
glEnd ();
}
glBlendFunc (GL_DST_COLOR, GL_ONE);
glColor3f (0.2f, 0.2f, 0.2f);
for (y = 1; y < ScreenHeightActual; y += 2)
{
glBegin (GL_LINES);
glVertex2i (0, y);
glVertex2i (ScreenWidthActual, y);
glEnd ();
}
}
static void
TFB_GL_DrawQuad (SDL_Rect *r)
{
BOOLEAN keep_aspect_ratio = optKeepAspectRatio;
int x1 = 0, y1 = 0, x2 = ScreenWidthActual, y2 = ScreenHeightActual;
int sx = 0, sy = 0;
int sw, sh;
float sx_multiplier = 1;
float sy_multiplier = 1;
if (keep_aspect_ratio)
{
float threshold = 0.75f;
float ratio = ScreenHeightActual / (float)ScreenWidthActual;
if (ratio > threshold)
{
// screen is narrower than 4:3
int height = (int)(ScreenWidthActual * threshold);
y1 = (ScreenHeightActual - height) / 2;
y2 = ScreenHeightActual - y1;
if (r != NULL)
{
sx_multiplier = ScreenWidthActual / (float)ScreenWidth;
sy_multiplier = height / (float)ScreenHeight;
sx = (int)(r->x * sx_multiplier);
sy = (int)(((ScreenHeight - (r->y + r->h)) * sy_multiplier) + y1);
}
}
else if (ratio < threshold)
{
// screen is wider than 4:3
int width = (int)(ScreenHeightActual / threshold);
x1 = (ScreenWidthActual - width) / 2;
x2 = ScreenWidthActual - x1;
if (r != NULL)
{
sx_multiplier = width / (float)ScreenWidth;
sy_multiplier = ScreenHeightActual / (float)ScreenHeight;
sx = (int)((r->x * sx_multiplier) + x1);
sy = (int)((ScreenHeight - (r->y + r->h)) * sy_multiplier);
}
}
else
{
// screen is 4:3
keep_aspect_ratio = 0;
}
}
if (r != NULL)
{
if (!keep_aspect_ratio)
{
sx_multiplier = ScreenWidthActual / (float)ScreenWidth;
sy_multiplier = ScreenHeightActual / (float)ScreenHeight;
sx = (int)(r->x * sx_multiplier);
sy = (int)((ScreenHeight - (r->y + r->h)) * sy_multiplier);
}
sw = (int)(r->w * sx_multiplier);
sh = (int)(r->h * sy_multiplier);
glScissor (sx, sy, sw, sh);
glEnable (GL_SCISSOR_TEST);
}
glBegin (GL_TRIANGLE_FAN);
glTexCoord2f (0, 0);
glVertex2i (x1, y1);
glTexCoord2f (ScreenWidth / 512.0f, 0);
glVertex2i (x2, y1);
glTexCoord2f (ScreenWidth / 512.0f, ScreenHeight / 256.0f);
glVertex2i (x2, y2);
glTexCoord2f (0, ScreenHeight / 256.0f);
glVertex2i (x1, y2);
glEnd ();
if (r != NULL)
{
glDisable (GL_SCISSOR_TEST);
}
}
static void
TFB_GL_Preprocess (int force_full_redraw, int transition_amount, int fade_amount)
{
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glOrtho (0,ScreenWidthActual,ScreenHeightActual, 0, -1, 1);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
if (optKeepAspectRatio)
glClear (GL_COLOR_BUFFER_BIT);
(void) transition_amount;
(void) fade_amount;
if (force_full_redraw == TFB_REDRAW_YES)
{
GL_Screens[TFB_SCREEN_MAIN].updated.x = 0;
GL_Screens[TFB_SCREEN_MAIN].updated.y = 0;
GL_Screens[TFB_SCREEN_MAIN].updated.w = ScreenWidth;
GL_Screens[TFB_SCREEN_MAIN].updated.h = ScreenHeight;
GL_Screens[TFB_SCREEN_MAIN].dirty = TRUE;
}
else if (TFB_BBox.valid)
{
GL_Screens[TFB_SCREEN_MAIN].updated.x = TFB_BBox.region.corner.x;
GL_Screens[TFB_SCREEN_MAIN].updated.y = TFB_BBox.region.corner.y;
GL_Screens[TFB_SCREEN_MAIN].updated.w = TFB_BBox.region.extent.width;
GL_Screens[TFB_SCREEN_MAIN].updated.h = TFB_BBox.region.extent.height;
GL_Screens[TFB_SCREEN_MAIN].dirty = TRUE;
}
}
static void
TFB_GL_Unscaled_ScreenLayer (SCREEN screen, Uint8 a, SDL_Rect *rect)
{
glBindTexture (GL_TEXTURE_2D, GL_Screens[screen].texture);
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
if (GL_Screens[screen].dirty)
{
int PitchWords = SDL_Screens[screen]->pitch / 4;
glPixelStorei (GL_UNPACK_ROW_LENGTH, PitchWords);
/* Matrox OpenGL drivers do not handle GL_UNPACK_SKIP_*
correctly */
glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
SDL_LockSurface (SDL_Screens[screen]);
glTexSubImage2D (GL_TEXTURE_2D, 0, GL_Screens[screen].updated.x,
GL_Screens[screen].updated.y,
GL_Screens[screen].updated.w,
GL_Screens[screen].updated.h,
GL_RGBA, GL_UNSIGNED_BYTE,
(Uint32 *)SDL_Screens[screen]->pixels +
(GL_Screens[screen].updated.y * PitchWords +
GL_Screens[screen].updated.x));
SDL_UnlockSurface (SDL_Screens[screen]);
GL_Screens[screen].dirty = FALSE;
}
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, ScreenFilterMode);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, ScreenFilterMode);
glEnable (GL_TEXTURE_2D);
if (a == 255)
{
glDisable (GL_BLEND);
glColor4f (1, 1, 1, 1);
}
else
{
float a_f = a / 255.0f;
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable (GL_BLEND);
glColor4f (1, 1, 1, a_f);
}
TFB_GL_DrawQuad (rect);
}
static void
TFB_GL_Scaled_ScreenLayer (SCREEN screen, Uint8 a, SDL_Rect *rect)
{
glBindTexture (GL_TEXTURE_2D, GL_Screens[screen].texture);
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
if (GL_Screens[screen].dirty)
{
int PitchWords = GL_Screens[screen].scaled->pitch / 4;
scaler (SDL_Screens[screen], GL_Screens[screen].scaled, &GL_Screens[screen].updated);
glPixelStorei (GL_UNPACK_ROW_LENGTH, PitchWords);
/* Matrox OpenGL drivers do not handle GL_UNPACK_SKIP_*
correctly */
glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
SDL_LockSurface (GL_Screens[screen].scaled);
glTexSubImage2D (GL_TEXTURE_2D, 0, GL_Screens[screen].updated.x * 2,
GL_Screens[screen].updated.y * 2,
GL_Screens[screen].updated.w * 2,
GL_Screens[screen].updated.h * 2,
GL_RGBA, GL_UNSIGNED_BYTE,
(Uint32 *)GL_Screens[screen].scaled->pixels +
(GL_Screens[screen].updated.y * 2 * PitchWords +
GL_Screens[screen].updated.x * 2));
SDL_UnlockSurface (GL_Screens[screen].scaled);
GL_Screens[screen].dirty = FALSE;
}
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, ScreenFilterMode);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, ScreenFilterMode);
glEnable (GL_TEXTURE_2D);
if (a == 255)
{
glDisable (GL_BLEND);
glColor4f (1, 1, 1, 1);
}
else
{
float a_f = a / 255.0f;
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable (GL_BLEND);
glColor4f (1, 1, 1, a_f);
}
TFB_GL_DrawQuad (rect);
}
static void
TFB_GL_ColorLayer (Uint8 r, Uint8 g, Uint8 b, Uint8 a, SDL_Rect *rect)
{
float r_f = r / 255.0f;
float g_f = g / 255.0f;
float b_f = b / 255.0f;
float a_f = a / 255.0f;
glColor4f(r_f, g_f, b_f, a_f);
glDisable (GL_TEXTURE_2D);
if (a != 255)
{
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable (GL_BLEND);
}
else
{
glDisable (GL_BLEND);
}
TFB_GL_DrawQuad (rect);
}
static void
TFB_GL_Postprocess (void)
{
if (GfxFlags & TFB_GFXFLAGS_SCANLINES)
TFB_GL_ScanLines ();
SDL_GL_SwapBuffers ();
}
#endif

View File

@@ -0,0 +1,88 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef OPENGL_H
#define OPENGL_H
#include "libs/graphics/sdl/sdl_common.h"
int TFB_GL_InitGraphics (int driver, int flags, int width, int height);
int TFB_GL_ConfigureVideo (int driver, int flags, int width, int height, int togglefullscreen);
void TFB_GL_UploadTransitionScreen (void);
#ifdef HAVE_OPENGL
#ifdef WIN32
#ifdef _MSC_VER
#pragma comment (lib, "opengl32.lib")
#pragma comment (lib, "glu32.lib")
#endif
/* To avoid including windows.h,
Win32's <GL/gl.h> needs APIENTRY and WINGDIAPI defined properly. */
#ifndef APIENTRY
#define GLUT_APIENTRY_DEFINED
#if __MINGW32__ || (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED)
#define APIENTRY __stdcall
#else
#define APIENTRY
#endif
#endif
#ifndef WINAPI
#define GLUT_WINAPI_DEFINED
#if __MINGW32__ || (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED)
#define WINAPI __stdcall
#else
#define WINAPI
#endif
#endif
/* This is from Win32's <winnt.h> */
#ifndef CALLBACK
#if (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS)
#define CALLBACK __stdcall
#else
#define CALLBACK
#endif
#endif
/* This is from Win32's <wingdi.h> and <winnt.h> */
#ifndef WINGDIAPI
#define GLUT_WINGDIAPI_DEFINED
#define WINGDIAPI __declspec(dllimport)
#endif
/* This is from Win32's <ctype.h> */
#ifndef _WCHAR_T_DEFINED
typedef unsigned short wchar_t;
#define _WCHAR_T_DEFINED
#endif
#include "GL/glu.h"
#else /* !defined(WIN32) */
#include "port.h"
#include SDL_INCLUDE(SDL_opengl.h)
#endif /* WIN32 */
#endif /* HAVE_OPENGL */
#endif

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2009 Alex Volkov <codepro@usa.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "palette.h"
#include "libs/memlib.h"
#include "libs/log.h"
NativePalette *
AllocNativePalette (void)
{
return HCalloc (sizeof (NativePalette));
}
void
FreeNativePalette (NativePalette *palette)
{
HFree (palette);
}
void
SetNativePaletteColor (NativePalette *palette, int index, Color color)
{
assert (index < NUMBER_OF_PLUTVALS);
palette->colors[index] = ColorToNative (color);
}
Color
GetNativePaletteColor (NativePalette *palette, int index)
{
assert (index < NUMBER_OF_PLUTVALS);
return NativeToColor (palette->colors[index]);
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2009 Alex Volkov <codepro@usa.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef PALETTE_H_INCL__
#define PALETTE_H_INCL__
#include "port.h"
#include SDL_INCLUDE(SDL.h)
#include "libs/graphics/cmap.h"
struct NativePalette
{
SDL_Color colors[NUMBER_OF_PLUTVALS];
};
static inline Color
NativeToColor (SDL_Color native)
{
Color color;
color.r = native.r;
color.g = native.g;
color.b = native.b;
color.a = 0xff; // fully opaque
return color;
}
static inline SDL_Color
ColorToNative (Color color)
{
SDL_Color native;
native.r = color.r;
native.g = color.g;
native.b = color.b;
native.unused = 0;
return native;
}
#endif /* PALETTE_H_INCL__ */

View File

@@ -0,0 +1,635 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "port.h"
#include "sdl_common.h"
#include "primitives.h"
// Pixel drawing routines
static Uint32
getpixel_8(SDL_Surface *surface, int x, int y)
{
/* Here p is the address to the pixel we want to retrieve */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x;
return *p;
}
static void
putpixel_8(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
/* Here p is the address to the pixel we want to set */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * 1;
*p = pixel;
}
static Uint32
getpixel_16(SDL_Surface *surface, int x, int y)
{
/* Here p is the address to the pixel we want to retrieve */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * 2;
return *(Uint16 *)p;
}
static void
putpixel_16(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
/* Here p is the address to the pixel we want to set */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * 2;
*(Uint16 *)p = pixel;
}
static Uint32
getpixel_24_be(SDL_Surface *surface, int x, int y)
{
/* Here p is the address to the pixel we want to retrieve */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
return p[0] << 16 | p[1] << 8 | p[2];
}
static void
putpixel_24_be(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
/* Here p is the address to the pixel we want to set */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
p[0] = (pixel >> 16) & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = pixel & 0xff;
}
static Uint32
getpixel_24_le(SDL_Surface *surface, int x, int y)
{
/* Here p is the address to the pixel we want to retrieve */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
return p[0] | p[1] << 8 | p[2] << 16;
}
static void
putpixel_24_le(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
/* Here p is the address to the pixel we want to set */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
p[0] = pixel & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = (pixel >> 16) & 0xff;
}
static Uint32
getpixel_32(SDL_Surface *surface, int x, int y)
{
/* Here p is the address to the pixel we want to retrieve */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * 4;
return *(Uint32 *)p;
}
static void
putpixel_32(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
/* Here p is the address to the pixel we want to set */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * 4;
*(Uint32 *)p = pixel;
}
GetPixelFn
getpixel_for(SDL_Surface *surface)
{
int bpp = surface->format->BytesPerPixel;
switch (bpp) {
case 1:
return &getpixel_8;
case 2:
return &getpixel_16;
case 3:
if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
return &getpixel_24_be;
} else {
return &getpixel_24_le;
}
case 4:
return &getpixel_32;
}
return NULL;
}
PutPixelFn
putpixel_for(SDL_Surface *surface)
{
int bpp = surface->format->BytesPerPixel;
switch (bpp) {
case 1:
return &putpixel_8;
case 2:
return &putpixel_16;
case 3:
if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
return &putpixel_24_be;
} else {
return &putpixel_24_le;
}
case 4:
return &putpixel_32;
}
return NULL;
}
static void
renderpixel_replace(SDL_Surface *surface, int x, int y, Uint32 pixel,
int factor)
{
(void) factor; // ignored
putpixel_32(surface, x, y, pixel);
}
static inline Uint8
clip_channel(int c)
{
if (c < 0)
c = 0;
else if (c > 255)
c = 255;
return c;
}
static inline Uint8
modulated_sum(Uint8 dc, Uint8 sc, int factor)
{
// We use >> 8 instead of / 255 because it is faster, but it does
// not work 100% correctly. It should be safe because this should
// not be called for factor==255
int b = dc + ((sc * factor) >> 8);
return clip_channel(b);
}
static inline Uint8
alpha_blend(Uint8 dc, Uint8 sc, int alpha)
{
// We use >> 8 instead of / 255 because it is faster, but it does
// not work 100% correctly. It should be safe because this should
// not be called for alpha==255
// No need to clip since we should never get values outside of 0..255
// range, unless alpha is over 255, which is not supported.
return (((sc - dc) * alpha) >> 8) + dc;
}
// Assumes 8 bits/channel, a safe assumption for 32bpp surfaces
#define UNPACK_PIXEL_32(p, fmt, r, g, b) \
do { \
(r) = ((p) >> (fmt)->Rshift) & 0xff; \
(g) = ((p) >> (fmt)->Gshift) & 0xff; \
(b) = ((p) >> (fmt)->Bshift) & 0xff; \
} while (0)
// Assumes the channels already clipped to 8 bits
static inline Uint32
PACK_PIXEL_32(const SDL_PixelFormat *fmt,
Uint8 r, Uint8 g, Uint8 b)
{
return ((Uint32)r << fmt->Rshift) | ((Uint32)g << fmt->Gshift)
| ((Uint32)b << fmt->Bshift);
}
static void
renderpixel_additive(SDL_Surface *surface, int x, int y, Uint32 pixel,
int factor)
{
const SDL_PixelFormat *fmt = surface->format;
Uint32 *p;
Uint32 sp;
Uint8 sr, sg, sb;
int r, g, b;
p = (Uint32 *) ((Uint8 *)surface->pixels + y * surface->pitch + x * 4);
sp = *p;
UNPACK_PIXEL_32(sp, fmt, sr, sg, sb);
UNPACK_PIXEL_32(pixel, fmt, r, g, b);
// TODO: We may need a special case for factor == -ADDITIVE_FACTOR_1 too,
// but it is not important enough right now to care ;)
if (factor == ADDITIVE_FACTOR_1)
{ // no need to modulate the 'pixel', and modulation does not
// work correctly with factor==255 anyway
sr = clip_channel(sr + r);
sg = clip_channel(sg + g);
sb = clip_channel(sb + b);
}
else
{
sr = modulated_sum(sr, r, factor);
sg = modulated_sum(sg, g, factor);
sb = modulated_sum(sb, b, factor);
}
*p = PACK_PIXEL_32(fmt, sr, sg, sb);
}
static void
renderpixel_alpha(SDL_Surface *surface, int x, int y, Uint32 pixel,
int factor)
{
const SDL_PixelFormat *fmt = surface->format;
Uint32 *p;
Uint32 sp;
Uint8 sr, sg, sb;
int r, g, b;
if (factor == FULLY_OPAQUE_ALPHA)
{ // alpha == 255 is equivalent to 'replace' and blending does not
// work correctly anyway because we use >> 8 instead of / 255
putpixel_32(surface, x, y, pixel);
return;
}
p = (Uint32 *) ((Uint8 *)surface->pixels + y * surface->pitch + x * 4);
sp = *p;
UNPACK_PIXEL_32(sp, fmt, sr, sg, sb);
UNPACK_PIXEL_32(pixel, fmt, r, g, b);
sr = alpha_blend(sr, r, factor);
sg = alpha_blend(sg, g, factor);
sb = alpha_blend(sb, b, factor);
*p = PACK_PIXEL_32(fmt, sr, sg, sb);
}
RenderPixelFn
renderpixel_for(SDL_Surface *surface, RenderKind kind)
{
const SDL_PixelFormat *fmt = surface->format;
// The only supported rendering is to 32bpp surfaces
if (fmt->BytesPerPixel != 4)
return NULL;
// Rendering other than REPLACE is not supported on RGBA surfaces
if (fmt->Amask != 0 && kind != renderReplace)
return NULL;
switch (kind)
{
case renderReplace:
return &renderpixel_replace;
case renderAdditive:
return &renderpixel_additive;
case renderAlpha:
return &renderpixel_alpha;
}
// should not ever get here
return NULL;
}
/* Line drawing routine
* Adapted from Paul Heckbert's implementation of Bresenham's algorithm,
* 3 Sep 85; taken from Graphics Gems I */
void
line_prim(int x1, int y1, int x2, int y2, Uint32 color, RenderPixelFn plot,
int factor, SDL_Surface *dst)
{
int d, x, y, ax, ay, sx, sy, dx, dy;
SDL_Rect clip_r;
SDL_GetClipRect (dst, &clip_r);
if (!clip_line (&x1, &y1, &x2, &y2, &clip_r))
return; // line is completely outside clipping rectangle
dx = x2-x1;
ax = ((dx < 0) ? -dx : dx) << 1;
sx = (dx < 0) ? -1 : 1;
dy = y2-y1;
ay = ((dy < 0) ? -dy : dy) << 1;
sy = (dy < 0) ? -1 : 1;
x = x1;
y = y1;
if (ax > ay) {
d = ay - (ax >> 1);
for (;;) {
(*plot)(dst, x, y, color, factor);
if (x == x2)
return;
if (d >= 0) {
y += sy;
d -= ax;
}
x += sx;
d += ay;
}
} else {
d = ax - (ay >> 1);
for (;;) {
(*plot)(dst, x, y, color, factor);
if (y == y2)
return;
if (d >= 0) {
x += sx;
d -= ay;
}
y += sy;
d += ax;
}
}
}
// Clips line against rectangle using Cohen-Sutherland algorithm
enum {C_TOP = 0x1, C_BOTTOM = 0x2, C_RIGHT = 0x4, C_LEFT = 0x8};
static int
compute_code (float x, float y, float xmin, float ymin, float xmax, float ymax)
{
int c = 0;
if (y > ymax)
c |= C_TOP;
else if (y < ymin)
c |= C_BOTTOM;
if (x > xmax)
c |= C_RIGHT;
else if (x < xmin)
c |= C_LEFT;
return c;
}
int
clip_line (int *lx1, int *ly1, int *lx2, int *ly2, const SDL_Rect *r)
{
int C0, C1, C;
float x, y, x0, y0, x1, y1, xmin, ymin, xmax, ymax;
x0 = (float)*lx1;
y0 = (float)*ly1;
x1 = (float)*lx2;
y1 = (float)*ly2;
xmin = (float)r->x;
ymin = (float)r->y;
xmax = (float)r->x + r->w - 1;
ymax = (float)r->y + r->h - 1;
C0 = compute_code (x0, y0, xmin, ymin, xmax, ymax);
C1 = compute_code (x1, y1, xmin, ymin, xmax, ymax);
for (;;) {
/* trivial accept: both ends in rectangle */
if ((C0 | C1) == 0)
{
*lx1 = (int)x0;
*ly1 = (int)y0;
*lx2 = (int)x1;
*ly2 = (int)y1;
return 1;
}
/* trivial reject: both ends on the external side of the rectangle */
if ((C0 & C1) != 0)
return 0;
/* normal case: clip end outside rectangle */
C = C0 ? C0 : C1;
if (C & C_TOP)
{
x = x0 + (x1 - x0) * (ymax - y0) / (y1 - y0);
y = ymax;
}
else if (C & C_BOTTOM)
{
x = x0 + (x1 - x0) * (ymin - y0) / (y1 - y0);
y = ymin;
}
else if (C & C_RIGHT)
{
x = xmax;
y = y0 + (y1 - y0) * (xmax - x0) / (x1 - x0);
}
else
{
x = xmin;
y = y0 + (y1 - y0) * (xmin - x0) / (x1 - x0);
}
/* set new end point and iterate */
if (C == C0)
{
x0 = x; y0 = y;
C0 = compute_code (x0, y0, xmin, ymin, xmax, ymax);
}
else
{
x1 = x; y1 = y;
C1 = compute_code (x1, y1, xmin, ymin, xmax, ymax);
}
}
}
void
fillrect_prim(SDL_Rect r, Uint32 color, RenderPixelFn plot, int factor,
SDL_Surface *dst)
{
int x, y;
int x1, y1;
SDL_Rect clip_r;
SDL_GetClipRect (dst, &clip_r);
if (!clip_rect (&r, &clip_r))
return; // rect is completely outside clipping rectangle
// TODO: calculate destination pointer directly instead of
// using the plot(x,y) version
x1 = r.x + r.w;
y1 = r.y + r.h;
for (y = r.y; y < y1; ++y)
{
for (x = r.x; x < x1; ++x)
plot(dst, x, y, color, factor);
}
}
// clip the rectangle against the clip rectangle
int
clip_rect(SDL_Rect *r, const SDL_Rect *clip_r)
{
// NOTE: the following clipping code is copied in part
// from SDL-1.2.4 sources
int dx, dy;
int w = r->w;
int h = r->h;
// SDL_Rect.w and .h are unsigned, we need signed
dx = clip_r->x - r->x;
if (dx > 0)
{
w -= dx;
r->x += dx;
}
dx = r->x + w - clip_r->x - clip_r->w;
if (dx > 0)
w -= dx;
dy = clip_r->y - r->y;
if (dy > 0)
{
h -= dy;
r->y += dy;
}
dy = r->y + h - clip_r->y - clip_r->h;
if (dy > 0)
h -= dy;
if (w <= 0 || h <= 0)
{
r->w = 0;
r->h = 0;
return 0;
}
r->w = w;
r->h = h;
return 1;
}
void
blt_prim(SDL_Surface *src, SDL_Rect src_r, RenderPixelFn plot, int factor,
SDL_Surface *dst, SDL_Rect dst_r)
{
SDL_PixelFormat *srcfmt = src->format;
SDL_Palette *srcpal = srcfmt->palette;
SDL_PixelFormat *dstfmt = dst->format;
Uint32 mask = 0;
Uint32 key = ~0;
GetPixelFn getpix = getpixel_for(src);
SDL_Rect clip_r;
int x, y;
SDL_GetClipRect (dst, &clip_r);
if (!clip_blt_rects (&src_r, &dst_r, &clip_r))
return; // rect is completely outside clipping rectangle
if (src_r.x >= src->w || src_r.y >= src->h)
return; // rect is completely outside source bounds
if (src_r.x + src_r.w > src->w)
src_r.w = src->w - src_r.x;
if (src_r.y + src_r.h > src->h)
src_r.h = src->h - src_r.y;
// use colorkeys where appropriate
if (srcfmt->Amask)
{ // alpha transparency
mask = srcfmt->Amask;
key = 0;
}
else if (src->flags & SDL_SRCCOLORKEY)
{ // colorkey transparency
mask = ~srcfmt->Amask;
key = srcfmt->colorkey & mask;
}
// TODO: calculate the source and destination pointers directly
// instead of using the plot(x,y) version
for (y = 0; y < src_r.h; ++y)
{
for (x = 0; x < src_r.w; ++x)
{
Uint8 r, g, b, a;
Uint32 p;
p = getpix(src, src_r.x + x, src_r.y + y);
if (srcpal)
{ // source is paletted, colorkey does not use mask
if (p == key)
continue; // transparent pixel
}
else
{ // source is RGB(A), colorkey uses mask
if ((p & mask) == key)
continue; // transparent pixel
}
// convert pixel format to destination
SDL_GetRGBA(p, srcfmt, &r, &g, &b, &a);
// TODO: handle source pixel alpha; plot() should probably
// get a source alpha parameter
p = SDL_MapRGBA(dstfmt, r, g, b, a);
plot(dst, dst_r.x + x, dst_r.y + y, p, factor);
}
}
}
// clip the source and destination rectangles against the clip rectangle
int
clip_blt_rects(SDL_Rect *src_r, SDL_Rect *dst_r, const SDL_Rect *clip_r)
{
// NOTE: the following clipping code is copied in part
// from SDL-1.2.4 sources
int w, h;
int dx, dy;
// clip the source rectangle to the source surface
w = src_r->w;
if (src_r->x < 0)
{
w += src_r->x;
dst_r->x -= src_r->x;
src_r->x = 0;
}
h = src_r->h;
if (src_r->y < 0)
{
h += src_r->y;
dst_r->y -= src_r->y;
src_r->y = 0;
}
// clip the destination rectangle against the clip rectangle,
// minding the source rectangle in the process
dx = clip_r->x - dst_r->x;
if (dx > 0)
{
w -= dx;
dst_r->x += dx;
src_r->x += dx;
}
dx = dst_r->x + w - clip_r->x - clip_r->w;
if (dx > 0)
w -= dx;
dy = clip_r->y - dst_r->y;
if (dy > 0)
{
h -= dy;
dst_r->y += dy;
src_r->y += dy;
}
dy = dst_r->y + h - clip_r->y - clip_r->h;
if (dy > 0)
h -= dy;
if (w <= 0 || h <= 0)
{
src_r->w = 0;
src_r->h = 0;
return 0;
}
src_r->w = w;
src_r->h = h;
return 1;
}

View File

@@ -0,0 +1,62 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef PRIMITIVES_H
#define PRIMITIVES_H
/* Function types for the pixel functions */
typedef Uint32 (*GetPixelFn)(SDL_Surface *, int x, int y);
// 'pixel' is in destination surface format
typedef void (*PutPixelFn)(SDL_Surface *, int x, int y, Uint32 pixel);
GetPixelFn getpixel_for(SDL_Surface *surface);
PutPixelFn putpixel_for(SDL_Surface *surface);
// This currently matches gfxlib.h:DrawKind for simplicity
typedef enum
{
renderReplace = 0,
renderAdditive,
renderAlpha,
} RenderKind;
#define FULLY_OPAQUE_ALPHA 255
#define ADDITIVE_FACTOR_1 255
// 'pixel' is in destination surface format
// See gfxlib.h:DrawKind for 'factor' spec
typedef void (*RenderPixelFn)(SDL_Surface *, int x, int y, Uint32 pixel,
int factor);
RenderPixelFn renderpixel_for(SDL_Surface *surface, RenderKind);
void line_prim(int x1, int y1, int x2, int y2, Uint32 color,
RenderPixelFn plot, int factor, SDL_Surface *dst);
void fillrect_prim(SDL_Rect r, Uint32 color,
RenderPixelFn plot, int factor, SDL_Surface *dst);
void blt_prim(SDL_Surface *src, SDL_Rect src_r,
RenderPixelFn plot, int factor,
SDL_Surface *dst, SDL_Rect dst_r);
int clip_line(int *lx1, int *ly1, int *lx2, int *ly2, const SDL_Rect *clip_r);
int clip_rect(SDL_Rect *r, const SDL_Rect *clip_r);
int clip_blt_rects(SDL_Rect *src_r, SDL_Rect *dst_r, const SDL_Rect *clip_r);
#endif /* PRIMITIVES_H */

View File

@@ -0,0 +1,484 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "pure.h"
#include "libs/graphics/bbox.h"
#include "scalers.h"
#include "libs/log.h"
static SDL_Surface *fade_color_surface = NULL;
static SDL_Surface *fade_temp = NULL;
static SDL_Surface *scaled_display = NULL;
static TFB_ScaleFunc scaler = NULL;
static Uint32 fade_color;
static void TFB_Pure_Scaled_Preprocess (int force_full_redraw, int transition_amount, int fade_amount);
static void TFB_Pure_Scaled_Postprocess (void);
static void TFB_Pure_Unscaled_Preprocess (int force_full_redraw, int transition_amount, int fade_amount);
static void TFB_Pure_Unscaled_Postprocess (void);
static void TFB_Pure_ScreenLayer (SCREEN screen, Uint8 a, SDL_Rect *rect);
static void TFB_Pure_ColorLayer (Uint8 r, Uint8 g, Uint8 b, Uint8 a, SDL_Rect *rect);
static TFB_GRAPHICS_BACKEND pure_scaled_backend = {
TFB_Pure_Scaled_Preprocess,
TFB_Pure_Scaled_Postprocess,
TFB_Pure_ScreenLayer,
TFB_Pure_ColorLayer };
static TFB_GRAPHICS_BACKEND pure_unscaled_backend = {
TFB_Pure_Unscaled_Preprocess,
TFB_Pure_Unscaled_Postprocess,
TFB_Pure_ScreenLayer,
TFB_Pure_ColorLayer };
static SDL_Surface *
Create_Screen (SDL_Surface *template, int w, int h)
{
SDL_Surface *newsurf = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
template->format->BitsPerPixel,
template->format->Rmask, template->format->Gmask,
template->format->Bmask, 0);
if (newsurf == 0) {
log_add (log_Error, "Couldn't create screen buffers: %s",
SDL_GetError());
}
return newsurf;
}
static int
ReInit_Screen (SDL_Surface **screen, SDL_Surface *template, int w, int h)
{
if (*screen)
SDL_FreeSurface (*screen);
*screen = Create_Screen (template, w, h);
return *screen == 0 ? -1 : 0;
}
// We cannot rely on SDL_DisplayFormatAlpha() anymore. It can return
// formats that we do not expect (SDL v1.2.14 on Mac OSX). Mac likes
// ARGB surfaces, but SDL_DisplayFormatAlpha thinks that only RGBA are fast.
// This is a generic replacement that gives what we want.
static void
CalcAlphaFormat (const SDL_PixelFormat* video, SDL_PixelFormat* ours)
{
int valid = 0;
// We use 32-bit surfaces internally
ours->BitsPerPixel = 32;
// Try to get as close to the video format as possible
if (video->BitsPerPixel == 15 || video->BitsPerPixel == 16)
{ // At least match the channel order
ours->Rshift = video->Rshift / 5 * 8;
ours->Gshift = video->Gshift / 5 * 8;
ours->Bshift = video->Bshift / 5 * 8;
valid = 1;
}
else if (video->BitsPerPixel == 24 || video->BitsPerPixel == 32)
{
// We can only use channels aligned on byte boundary
if (video->Rshift % 8 == 0 && video->Gshift % 8 == 0
&& video->Bshift % 8 == 0)
{ // Match RGB in video
ours->Rshift = video->Rshift;
ours->Gshift = video->Gshift;
ours->Bshift = video->Bshift;
valid = 1;
}
}
if (valid)
{ // For alpha, use the unoccupied byte
ours->Ashift = 48 - (ours->Rshift + ours->Gshift + ours->Bshift);
// Set channels according to byte positions
ours->Rmask = 0xff << ours->Rshift;
ours->Gmask = 0xff << ours->Gshift;
ours->Bmask = 0xff << ours->Bshift;
ours->Amask = 0xff << ours->Ashift;
return;
}
// Fallback case. It does not matter what we set, but SDL likes
// Alpha to be the highest.
ours->Rmask = 0x000000ff;
ours->Gmask = 0x0000ff00;
ours->Bmask = 0x00ff0000;
ours->Amask = 0xff000000;
}
int
TFB_Pure_ConfigureVideo (int driver, int flags, int width, int height, int togglefullscreen)
{
int i, videomode_flags;
SDL_PixelFormat conv_fmt;
int BPP = 32;
GraphicsDriver = driver;
// must use SDL_SWSURFACE, HWSURFACE doesn't work properly
// with fades/scaling
if (width == 320 && height == 240)
{
videomode_flags = SDL_SWSURFACE;
ScreenWidthActual = 320;
ScreenHeightActual = 240;
graphics_backend = &pure_unscaled_backend;
}
else
{
videomode_flags = SDL_SWSURFACE;
ScreenWidthActual = 640;
ScreenHeightActual = 480;
graphics_backend = &pure_scaled_backend;
if (width != 640 || height != 480)
log_add (log_Error, "Screen resolution of %dx%d not supported "
"under pure SDL, using 640x480", width, height);
}
#ifdef ANDROID
videomode_flags = SDL_SWSURFACE;
ScreenWidthActual = 320;
ScreenHeightActual = 240;
graphics_backend = &pure_unscaled_backend;
BPP = 16;
#endif
videomode_flags |= SDL_ANYFORMAT;
if (flags & TFB_GFXFLAGS_FULLSCREEN)
videomode_flags |= SDL_FULLSCREEN;
/* We'll ask for a 32bpp frame, but it doesn't really matter, because we've set
SDL_ANYFORMAT */
SDL_Video = SDL_SetVideoMode (ScreenWidthActual, ScreenHeightActual,
BPP, videomode_flags);
if (SDL_Video == NULL)
{
log_add (log_Error, "Couldn't set %ix%i video mode: %s",
ScreenWidthActual, ScreenHeightActual,
SDL_GetError ());
return -1;
}
else
{
const SDL_Surface *video = SDL_GetVideoSurface ();
const SDL_PixelFormat* fmt = video->format;
ScreenColorDepth = fmt->BitsPerPixel;
log_add (log_Info, "Set the resolution to: %ix%ix%i",
video->w, video->h, ScreenColorDepth);
log_add (log_Info, " Video: R %08x, G %08x, B %08x, A %08x",
fmt->Rmask, fmt->Gmask, fmt->Bmask, fmt->Amask);
if (togglefullscreen)
{
// NOTE: We cannot change the format_conv_surf now because we
// have already loaded lots of graphics and changing it now
// will only lead to chaos.
// Just check if channel order has changed significantly
CalcAlphaFormat (fmt, &conv_fmt);
fmt = format_conv_surf->format;
if (conv_fmt.Rmask != fmt->Rmask || conv_fmt.Bmask != fmt->Bmask)
log_add (log_Warning, "Warning: pixel format has changed "
"significantly. Rendering will be slow.");
return 0;
}
}
// Create a 32bpp surface in a compatible format which will supply
// the format information to all other surfaces used in the game
if (format_conv_surf)
{
SDL_FreeSurface (format_conv_surf);
format_conv_surf = NULL;
}
CalcAlphaFormat (SDL_Video->format, &conv_fmt);
format_conv_surf = SDL_CreateRGBSurface (SDL_SWSURFACE, 0, 0,
conv_fmt.BitsPerPixel, conv_fmt.Rmask, conv_fmt.Gmask,
conv_fmt.Bmask, conv_fmt.Amask);
if (!format_conv_surf)
{
log_add (log_Error, "Couldn't create format_conv_surf: %s",
SDL_GetError());
return -1;
}
else
{
const SDL_PixelFormat* fmt = format_conv_surf->format;
log_add (log_Info, " Internal: R %08x, G %08x, B %08x, A %08x",
fmt->Rmask, fmt->Gmask, fmt->Bmask, fmt->Amask);
}
for (i = 0; i < TFB_GFX_NUMSCREENS; i++)
{
if (0 != ReInit_Screen (&SDL_Screens[i], format_conv_surf,
ScreenWidth, ScreenHeight))
return -1;
}
SDL_Screen = SDL_Screens[0];
TransitionScreen = SDL_Screens[2];
if (0 != ReInit_Screen (&fade_color_surface, format_conv_surf,
ScreenWidth, ScreenHeight))
return -1;
fade_color = SDL_MapRGB (fade_color_surface->format, 0, 0, 0);
SDL_FillRect (fade_color_surface, NULL, fade_color);
if (0 != ReInit_Screen (&fade_temp, format_conv_surf,
ScreenWidth, ScreenHeight))
return -1;
if (ScreenWidthActual > ScreenWidth || ScreenHeightActual > ScreenHeight)
{
if (0 != ReInit_Screen (&scaled_display, format_conv_surf,
ScreenWidthActual, ScreenHeightActual))
return -1;
scaler = Scale_PrepPlatform (flags, SDL_Screen->format);
}
else
{ // no need to scale
scaler = NULL;
}
return 0;
}
int
TFB_Pure_InitGraphics (int driver, int flags, int width, int height)
{
char VideoName[256];
log_add (log_Info, "Initializing Pure-SDL graphics.");
SDL_VideoDriverName (VideoName, sizeof (VideoName));
log_add (log_Info, "SDL driver used: %s", VideoName);
// Set the environment variable SDL_VIDEODRIVER to override
// For Linux: x11 (default), dga, fbcon, directfb, svgalib,
// ggi, aalib
// For Windows: directx (default), windib
log_add (log_Info, "SDL initialized.");
log_add (log_Info, "Initializing Screen.");
ScreenWidth = 320;
ScreenHeight = 240;
if (TFB_Pure_ConfigureVideo (driver, flags, width, height, 0))
{
log_add (log_Fatal, "Could not initialize video: "
"no fallback at start of program!");
exit (EXIT_FAILURE);
}
// Initialize scalers (let them precompute whatever)
Scale_Init ();
return 0;
}
static void
ScanLines (SDL_Surface *dst, SDL_Rect *r)
{
const int rw = r->w * 2;
const int rh = r->h * 2;
SDL_PixelFormat *fmt = dst->format;
const int pitch = dst->pitch;
const int len = pitch / fmt->BytesPerPixel;
int ddst;
Uint32 *p = (Uint32 *) dst->pixels;
int x, y;
p += len * (r->y * 2) + (r->x * 2);
ddst = len + len - rw;
for (y = rh; y; y -= 2, p += ddst)
{
for (x = rw; x; --x, ++p)
{
// we ignore the lower bits as the difference
// of 1 in 255 is negligible
*p = ((*p >> 1) & 0x7f7f7f7f) + ((*p >> 2) & 0x3f3f3f3f);
}
}
}
static SDL_Surface *backbuffer = NULL, *scalebuffer = NULL;
static SDL_Rect updated;
static void
TFB_Pure_Scaled_Preprocess (int force_full_redraw, int transition_amount, int fade_amount)
{
if (force_full_redraw != TFB_REDRAW_NO)
{
updated.x = updated.y = 0;
updated.w = ScreenWidth;
updated.h = ScreenHeight;
}
else
{
updated.x = TFB_BBox.region.corner.x;
updated.y = TFB_BBox.region.corner.y;
updated.w = TFB_BBox.region.extent.width;
updated.h = TFB_BBox.region.extent.height;
}
if (transition_amount == 255 && fade_amount == 255)
backbuffer = SDL_Screens[TFB_SCREEN_MAIN];
else
backbuffer = fade_temp;
// we can scale directly onto SDL_Video if video is compatible
if (SDL_Video->format->BitsPerPixel == SDL_Screen->format->BitsPerPixel
&& SDL_Video->format->Rmask == SDL_Screen->format->Rmask
&& SDL_Video->format->Bmask == SDL_Screen->format->Bmask)
scalebuffer = SDL_Video;
else
scalebuffer = scaled_display;
}
static void
TFB_Pure_Unscaled_Preprocess (int force_full_redraw, int transition_amount, int fade_amount)
{
if (force_full_redraw != TFB_REDRAW_NO)
{
updated.x = updated.y = 0;
updated.w = ScreenWidth;
updated.h = ScreenHeight;
}
else
{
updated.x = TFB_BBox.region.corner.x;
updated.y = TFB_BBox.region.corner.y;
updated.w = TFB_BBox.region.extent.width;
updated.h = TFB_BBox.region.extent.height;
}
backbuffer = SDL_Video;
(void)transition_amount;
(void)fade_amount;
}
static void
TFB_Pure_Scaled_Postprocess (void)
{
SDL_LockSurface (scalebuffer);
SDL_LockSurface (backbuffer);
if (scaler)
scaler (backbuffer, scalebuffer, &updated);
if (GfxFlags & TFB_GFXFLAGS_SCANLINES)
ScanLines (scalebuffer, &updated);
SDL_UnlockSurface (backbuffer);
SDL_UnlockSurface (scalebuffer);
updated.x *= 2;
updated.y *= 2;
updated.w *= 2;
updated.h *= 2;
if (scalebuffer != SDL_Video)
SDL_BlitSurface (scalebuffer, &updated, SDL_Video, &updated);
SDL_UpdateRects (SDL_Video, 1, &updated);
}
static void
TFB_Pure_Unscaled_Postprocess (void)
{
SDL_UpdateRect (SDL_Video, updated.x, updated.y,
updated.w, updated.h);
}
static void
TFB_Pure_ScreenLayer (SCREEN screen, Uint8 a, SDL_Rect *rect)
{
if (SDL_Screens[screen] == backbuffer)
return;
SDL_SetAlpha (SDL_Screens[screen], SDL_SRCALPHA, a);
SDL_BlitSurface (SDL_Screens[screen], rect, backbuffer, rect);
}
static void
TFB_Pure_ColorLayer (Uint8 r, Uint8 g, Uint8 b, Uint8 a, SDL_Rect *rect)
{
Uint32 col = SDL_MapRGB (fade_color_surface->format, r, g, b);
if (col != fade_color)
{
fade_color = col;
SDL_FillRect (fade_color_surface, NULL, fade_color);
}
SDL_SetAlpha (fade_color_surface, SDL_SRCALPHA, a);
SDL_BlitSurface (fade_color_surface, rect, backbuffer, rect);
}
void
Scale_PerfTest (void)
{
TimeCount TimeStart, TimeIn;
TimeCount Now = 0;
SDL_Rect updated = {0, 0, ScreenWidth, ScreenHeight};
int i;
if (!scaler)
{
log_add (log_Error, "No scaler configured! "
"Run with larger resolution, please");
return;
}
if (!scaled_display)
{
log_add (log_Error, "Run scaler performance tests "
"in Pure mode, please");
return;
}
SDL_LockSurface (SDL_Screen);
SDL_LockSurface (scaled_display);
TimeStart = TimeIn = SDL_GetTicks ();
for (i = 1; i < 1001; ++i) // run for 1000 frames
{
scaler (SDL_Screen, scaled_display, &updated);
if (GfxFlags & TFB_GFXFLAGS_SCANLINES)
ScanLines (scaled_display, &updated);
if (i % 100 == 0)
{
Now = SDL_GetTicks ();
log_add (log_Debug, "%03d(%04u) ", 100*1000 / (Now - TimeIn),
Now - TimeIn);
TimeIn = Now;
}
}
log_add (log_Debug, "Full frames scaled: %d; over %u ms; %d fps\n",
(i - 1), Now - TimeStart, i * 1000 / (Now - TimeStart));
SDL_UnlockSurface (scaled_display);
SDL_UnlockSurface (SDL_Screen);
}

View File

@@ -0,0 +1,28 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef PURE_H
#define PURE_H
#include "libs/graphics/sdl/sdl_common.h"
int TFB_Pure_InitGraphics (int driver, int flags, int width, int height);
int TFB_Pure_ConfigureVideo (int driver, int flags, int width, int height, int togglefullscreen);
void Scale_PerfTest (void);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,96 @@
/*
rotozoom.h - rotozoomer for 32bit or 8bit surfaces
LGPL (c) A. Schiffler
Note by sc2 developers:
Taken from SDL_gfx library and modified, original code can be downloaded
from http://www.ferzkopp.net/Software/SDL_gfx-2.0/
*/
#ifndef ROTOZOOM_H
#define ROTOZOOM_H
#include <math.h>
#ifndef M_PI
#define M_PI 3.141592654
#endif
#include "port.h"
#include SDL_INCLUDE(SDL.h)
/* ---- Defines */
#define SMOOTHING_OFF 0
#define SMOOTHING_ON 1
/* ---- Structures */
typedef struct tColorRGBA {
Uint8 r;
Uint8 g;
Uint8 b;
Uint8 a;
} tColorRGBA;
typedef struct tColorY {
Uint8 y;
} tColorY;
/* ---- Prototypes */
/*
zoomSurfaceRGBA()
Zoom the src surface into dst. The zoom amount is determined
by the dimensions of src and dst
*/
int zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int smooth);
/*
rotozoomSurface()
Rotates and zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
'angle' is the rotation in degrees. 'zoom' a scaling factor. If 'smooth' is 1
then the destination 32bit surface is anti-aliased. If the surface is not 8bit
or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
*/
SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom,
int smooth);
int rotateSurface(SDL_Surface * src, SDL_Surface * dst, double angle,
int smooth);
/* Returns the size of the target surface for a rotozoomSurface() call */
void rotozoomSurfaceSize(int width, int height, double angle, double zoom,
int *dstwidth, int *dstheight);
/*
zoomSurface()
Zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
'zoomx' and 'zoomy' are scaling factors for width and height. If 'smooth' is 1
then the destination 32bit surface is anti-aliased. If the surface is not 8bit
or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
*/
SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy,
int smooth);
/* Returns the size of the target surface for a zoomSurface() call */
void zoomSurfaceSize(int width, int height, double zoomx, double zoomy,
int *dstwidth, int *dstheight);
#endif

View File

@@ -0,0 +1,433 @@
/*
* Copyright (C) 2005 Alex Volkov (codepro@usa.net)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// Scalers Internals
#ifndef SCALEINT_H_
#define SCALEINT_H_
#include "libs/graphics/sdl/sdl_common.h"
#include "types.h"
// Plain C names
#define SCALE_(name) Scale ## _ ## name
// These are defaults
#define SCALE_GETPIX(p) ( *(Uint32 *)(p) )
#define SCALE_SETPIX(p, c) ( *(Uint32 *)(p) = (c) )
// Plain C defaults
#define SCALE_CMPRGB(p1, p2) \
SCALE_(GetRGBDelta) (fmt, p1, p2)
#define SCALE_TOYUV(p) \
SCALE_(RGBtoYUV) (fmt, p)
#define SCALE_CMPYUV(p1, p2, toler) \
SCALE_(CmpYUV) (fmt, p1, p2, toler)
#define SCALE_DIFFYUV(p1, p2) \
SCALE_(DiffYUV) (p1, p2)
#define SCALE_DIFFYUV_TY 0x40
#define SCALE_DIFFYUV_TU 0x12
#define SCALE_DIFFYUV_TV 0x0c
#define SCALE_GETY(p) \
SCALE_(GetPixY) (fmt, p)
#define SCALE_BILINEAR_BLEND4(r0, r1, dst, dlen) \
SCALE_(Blend_bilinear) (r0, r1, dst, dlen)
#define NO_PREFETCH 0
#define INTEL_PREFETCH 1
#define AMD_PREFETCH 2
typedef enum
{
YUV_XFORM_R = 0,
YUV_XFORM_G = 1,
YUV_XFORM_B = 2,
YUV_XFORM_Y = 0,
YUV_XFORM_U = 1,
YUV_XFORM_V = 2
} RGB_YUV_INDEX;
extern const int YUV_matrix[3][3];
// pre-computed transformations for 8 bits per channel
extern int RGB_to_YUV[/*RGB*/ 3][/*YUV*/ 3][ /*mult-res*/ 256];
extern sint16 dRGB_to_dYUV[/*RGB*/ 3][/*YUV*/ 3][ /*mult-res*/ 512];
typedef Uint32 YUV_VECTOR;
// pre-computed transformations for RGB555
extern YUV_VECTOR RGB15_to_YUV[0x8000];
// Platform+Scaler function lookups
//
typedef struct
{
int flag;
TFB_ScaleFunc func;
} Scale_FuncDef_t;
// expands the given rectangle in all directions by 'expansion'
// guarded by 'limits'
extern void Scale_ExpandRect (SDL_Rect* rect, int expansion,
const SDL_Rect* limits);
// Standard plain C versions of support functions
// Initialize various platform-specific features
static inline void
SCALE_(PlatInit) (void)
{
}
// Finish with various platform-specific features
static inline void
SCALE_(PlatDone) (void)
{
}
#if 0
static inline void
SCALE_(Prefetch) (const void* p)
{
/* no-op in pure C */
(void)p;
}
#else
# define Scale_Prefetch(p)
#endif
// compute the RGB distance squared between 2 pixels
// Plain C version
static inline int
SCALE_(GetRGBDelta) (const SDL_PixelFormat* fmt, Uint32 pix1, Uint32 pix2)
{
int c;
int delta;
c = ((pix1 >> fmt->Rshift) & 0xff) - ((pix2 >> fmt->Rshift) & 0xff);
delta = c * c;
c = ((pix1 >> fmt->Gshift) & 0xff) - ((pix2 >> fmt->Gshift) & 0xff);
delta += c * c;
c = ((pix1 >> fmt->Bshift) & 0xff) - ((pix2 >> fmt->Bshift) & 0xff);
delta += c * c;
return delta;
}
// retrieve the Y (intensity) component of pixel's YUV
// Plain C version
static inline int
SCALE_(GetPixY) (const SDL_PixelFormat* fmt, Uint32 pix)
{
Uint32 r, g, b;
r = (pix >> fmt->Rshift) & 0xff;
g = (pix >> fmt->Gshift) & 0xff;
b = (pix >> fmt->Bshift) & 0xff;
return RGB_to_YUV [YUV_XFORM_R][YUV_XFORM_Y][r]
+ RGB_to_YUV [YUV_XFORM_G][YUV_XFORM_Y][g]
+ RGB_to_YUV [YUV_XFORM_B][YUV_XFORM_Y][b];
}
static inline YUV_VECTOR
SCALE_(RGBtoYUV) (const SDL_PixelFormat* fmt, Uint32 pix)
{
return RGB15_to_YUV[
(((pix >> (fmt->Rshift + 3)) & 0x1f) << 10) |
(((pix >> (fmt->Gshift + 3)) & 0x1f) << 5) |
(((pix >> (fmt->Bshift + 3)) & 0x1f) )
];
}
// compare 2 pixels with respect to their YUV representations
// tolerance set by toler arg
// returns true: close; false: distant (-gt toler)
// Plain C version
static inline bool
SCALE_(CmpYUV) (const SDL_PixelFormat* fmt, Uint32 pix1, Uint32 pix2, int toler)
#if 1
{
int dr, dg, db;
int delta;
dr = ((pix1 >> fmt->Rshift) & 0xff) - ((pix2 >> fmt->Rshift) & 0xff) + 255;
dg = ((pix1 >> fmt->Gshift) & 0xff) - ((pix2 >> fmt->Gshift) & 0xff) + 255;
db = ((pix1 >> fmt->Bshift) & 0xff) - ((pix2 >> fmt->Bshift) & 0xff) + 255;
// compute Y delta
delta = abs (dRGB_to_dYUV [YUV_XFORM_R][YUV_XFORM_Y][dr]
+ dRGB_to_dYUV [YUV_XFORM_G][YUV_XFORM_Y][dg]
+ dRGB_to_dYUV [YUV_XFORM_B][YUV_XFORM_Y][db]);
if (delta > toler)
return false;
// compute U delta
delta += abs (dRGB_to_dYUV [YUV_XFORM_R][YUV_XFORM_U][dr]
+ dRGB_to_dYUV [YUV_XFORM_G][YUV_XFORM_U][dg]
+ dRGB_to_dYUV [YUV_XFORM_B][YUV_XFORM_U][db]);
if (delta > toler)
return false;
// compute V delta
delta += abs (dRGB_to_dYUV [YUV_XFORM_R][YUV_XFORM_V][dr]
+ dRGB_to_dYUV [YUV_XFORM_G][YUV_XFORM_V][dg]
+ dRGB_to_dYUV [YUV_XFORM_B][YUV_XFORM_V][db]);
return delta <= toler;
}
#else
{
int delta;
Uint32 yuv1, yuv2;
yuv1 = RGB15_to_YUV[
(((pix1 >> (fmt->Rshift + 3)) & 0x1f) << 10) |
(((pix1 >> (fmt->Gshift + 3)) & 0x1f) << 5) |
(((pix1 >> (fmt->Bshift + 3)) & 0x1f) )
];
yuv2 = RGB15_to_YUV[
(((pix2 >> (fmt->Rshift + 3)) & 0x1f) << 10) |
(((pix2 >> (fmt->Gshift + 3)) & 0x1f) << 5) |
(((pix2 >> (fmt->Bshift + 3)) & 0x1f) )
];
// compute Y delta
delta = abs ((yuv1 & 0xff0000) - (yuv2 & 0xff0000)) >> 16;
if (delta > toler)
return false;
// compute U delta
delta += abs ((yuv1 & 0x00ff00) - (yuv2 & 0x00ff00)) >> 8;
if (delta > toler)
return false;
// compute V delta
delta += abs ((yuv1 & 0x0000ff) - (yuv2 & 0x0000ff));
return delta <= toler;
}
#endif
// Check if 2 pixels are different with respect to their
// YUV representations
// returns 0: close; ~0: distant
static inline int
SCALE_(DiffYUV) (Uint32 yuv1, Uint32 yuv2)
{
// non-branching version -- assumes 2's complement integers
// delta math only needs 25 bits and we have 32 available;
// only interested in the sign bits after subtraction
sint32 delta, ret;
if (yuv1 == yuv2)
return 0;
// compute Y delta
delta = abs ((yuv1 & 0xff0000) - (yuv2 & 0xff0000));
ret = (SCALE_DIFFYUV_TY << 16) - delta; // save sign bit
// compute U delta
delta = abs ((yuv1 & 0x00ff00) - (yuv2 & 0x00ff00));
ret |= (SCALE_DIFFYUV_TU << 8) - delta; // save sign bit
// compute V delta
delta = abs ((yuv1 & 0x0000ff) - (yuv2 & 0x0000ff));
ret |= SCALE_DIFFYUV_TV - delta; // save sign bit
return (ret >> 31);
}
// blends two pixels with 1:1 ratio
static inline Uint32
SCALE_(Blend_11) (Uint32 pix1, Uint32 pix2)
{
/* (pix1 + pix2) >> 1 */
return
/* lower bits can be safely ignored - the error is minimal
expression that calcs them is left for posterity
(pix1 & pix2 & low_mask) +
*/
((pix1 & 0xfefefefe) >> 1) + ((pix2 & 0xfefefefe) >> 1);
}
// blends four pixels with 1:1:1:1 ratio
static inline Uint32
SCALE_(Blend_1111) (Uint32 pix1, Uint32 pix2,
Uint32 pix3, Uint32 pix4)
{
/* (pix1 + pix2 + pix3 + pix4) >> 2 */
return
/* lower bits can be safely ignored - the error is minimal
expression that calcs them is left for posterity
((((pix1 & low_mask) + (pix2 & low_mask) +
(pix3 & low_mask) + (pix4 & low_mask)
) >> 2) & low_mask) +
*/
((pix1 & 0xfcfcfcfc) >> 2) + ((pix2 & 0xfcfcfcfc) >> 2) +
((pix3 & 0xfcfcfcfc) >> 2) + ((pix4 & 0xfcfcfcfc) >> 2);
}
// blends pixels with 3:1 ratio
static inline Uint32
Scale_Blend_31 (Uint32 pix1, Uint32 pix2)
{
/* (pix1 * 3 + pix2) / 4 */
/* lower bits can be safely ignored - the error is minimal */
return ((pix1 & 0xfefefefe) >> 1) + ((pix1 & 0xfcfcfcfc) >> 2) +
((pix2 & 0xfcfcfcfc) >> 2);
}
// blends pixels with 2:1:1 ratio
static inline Uint32
Scale_Blend_211 (Uint32 pix1, Uint32 pix2, Uint32 pix3)
{
/* (pix1 * 2 + pix2 + pix3) / 4 */
/* lower bits can be safely ignored - the error is minimal */
return ((pix1 & 0xfefefefe) >> 1) +
((pix2 & 0xfcfcfcfc) >> 2) +
((pix3 & 0xfcfcfcfc) >> 2);
}
// blends pixels with 5:2:1 ratio
static inline Uint32
Scale_Blend_521 (Uint32 pix1, Uint32 pix2, Uint32 pix3)
{
/* (pix1 * 5 + pix2 * 2 + pix3) / 8 */
/* lower bits can be safely ignored - the error is minimal */
return ((pix1 & 0xfefefefe) >> 1) + ((pix1 & 0xf8f8f8f8) >> 3) +
((pix2 & 0xfcfcfcfc) >> 2) +
((pix3 & 0xf8f8f8f8) >> 3) +
0x02020202 /* half-error */;
}
// blends pixels with 6:1:1 ratio
static inline Uint32
Scale_Blend_611 (Uint32 pix1, Uint32 pix2, Uint32 pix3)
{
/* (pix1 * 6 + pix2 + pix3) / 8 */
/* lower bits can be safely ignored - the error is minimal */
return ((pix1 & 0xfefefefe) >> 1) + ((pix1 & 0xfcfcfcfc) >> 2) +
((pix2 & 0xf8f8f8f8) >> 3) +
((pix3 & 0xf8f8f8f8) >> 3) +
0x02020202 /* half-error */;
}
// blends pixels with 2:3:3 ratio
static inline Uint32
Scale_Blend_233 (Uint32 pix1, Uint32 pix2, Uint32 pix3)
{
/* (pix1 * 2 + pix2 * 3 + pix3 * 3) / 8 */
/* lower bits can be safely ignored - the error is minimal */
return ((pix1 & 0xfcfcfcfc) >> 2) +
((pix2 & 0xfcfcfcfc) >> 2) + ((pix2 & 0xf8f8f8f8) >> 3) +
((pix3 & 0xfcfcfcfc) >> 2) + ((pix3 & 0xf8f8f8f8) >> 3) +
0x02020202 /* half-error */;
}
// blends pixels with 14:1:1 ratio
static inline Uint32
Scale_Blend_e11 (Uint32 pix1, Uint32 pix2, Uint32 pix3)
{
/* (pix1 * 14 + pix2 + pix3) >> 4 */
/* lower bits can be safely ignored - the error is minimal */
return ((pix1 & 0xfefefefe) >> 1) + ((pix1 & 0xfcfcfcfc) >> 2) +
((pix1 & 0xf8f8f8f8) >> 3) +
((pix2 & 0xf0f0f0f0) >> 4) +
((pix3 & 0xf0f0f0f0) >> 4) +
0x03030303 /* half-error */;
}
// Halfs the pixel's intensity
static inline Uint32
SCALE_(HalfPixel) (Uint32 pix)
{
return ((pix & 0xfefefefe) >> 1);
}
// Bilinear weighted blend of four pixels
// Function produces 4 blended pixels and writes them
// out to the surface (in 2x2 matrix)
// Pixels are computed using expanded weight matrix like so:
// ('sp' - source pixel, 'dp' - destination pixel)
// dp[0] = (9*sp[0] + 3*sp[1] + 3*sp[2] + 1*sp[3]) / 16
// dp[1] = (3*sp[0] + 9*sp[1] + 1*sp[2] + 3*sp[3]) / 16
// dp[2] = (3*sp[0] + 1*sp[1] + 9*sp[2] + 3*sp[3]) / 16
// dp[3] = (1*sp[0] + 3*sp[1] + 3*sp[2] + 9*sp[3]) / 16
static inline void
SCALE_(Blend_bilinear) (const Uint32* row0, const Uint32* row1,
Uint32* dst_p, Uint32 dlen)
{
// We loose some lower bits here and try to compensate for
// that by adding half-error values.
// In general, the error is minimal (+-7)
// The >>4 reduction is achieved gradually
# define BL_PACKED_HALF(p) \
(((p) & 0xfefefefe) >> 1)
# define BL_SUM(p1, p2) \
(BL_PACKED_HALF(p1) + BL_PACKED_HALF(p2))
# define BL_HALF_ERR 0x01010101
# define BL_SUM_WERR(p1, p2) \
(BL_PACKED_HALF(p1) + BL_PACKED_HALF(p2) + BL_HALF_ERR)
Uint32 sum1111, sum1331, sum3113;
// cache p[0] + 3*(p[1] + p[2]) + p[3] in sum1331
// cache p[1] + 3*(p[0] + p[3]) + p[2] in sum3113
sum1331 = BL_SUM (row0[1], row1[0]);
sum3113 = BL_SUM (row0[0], row1[1]);
// cache p[0] + p[1] + p[2] + p[3] in sum1111
sum1111 = BL_SUM_WERR (sum1331, sum3113);
sum1331 = BL_SUM_WERR (sum1331, sum1111);
sum1331 = BL_PACKED_HALF (sum1331);
sum3113 = BL_SUM_WERR (sum3113, sum1111);
sum3113 = BL_PACKED_HALF (sum3113);
// pixel 0 math -- (9*p[0] + 3*(p[1] + p[2]) + p[3]) / 16
dst_p[0] = BL_PACKED_HALF (row0[0]) + sum1331;
// pixel 1 math -- (9*p[1] + 3*(p[0] + p[3]) + p[2]) / 16
dst_p[1] = BL_PACKED_HALF (row0[1]) + sum3113;
// pixel 2 math -- (9*p[2] + 3*(p[0] + p[3]) + p[1]) / 16
dst_p[dlen] = BL_PACKED_HALF (row1[0]) + sum3113;
// pixel 3 math -- (9*p[3] + 3*(p[1] + p[2]) + p[0]) / 16
dst_p[dlen + 1] = BL_PACKED_HALF (row1[1]) + sum1331;
# undef BL_PACKED_HALF
# undef BL_SUM
# undef BL_HALF_ERR
# undef BL_SUM_WERR
}
#endif /* SCALEINT_H_ */

View File

@@ -0,0 +1,793 @@
/*
* Copyright (C) 2005 Alex Volkov (codepro@usa.net)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef SCALEMMX_H_
#define SCALEMMX_H_
#if !defined(SCALE_)
# error Please define SCALE_(name) before including scalemmx.h
#endif
#if !defined(MSVC_ASM) && !defined(GCC_ASM)
# error Please define target assembler (MSVC_ASM, GCC_ASM) before including scalemmx.h
#endif
// MMX defaults (no Format param)
#undef SCALE_CMPRGB
#define SCALE_CMPRGB(p1, p2) \
SCALE_(GetRGBDelta) (p1, p2)
#undef SCALE_TOYUV
#define SCALE_TOYUV(p) \
SCALE_(RGBtoYUV) (p)
#undef SCALE_CMPYUV
#define SCALE_CMPYUV(p1, p2, toler) \
SCALE_(CmpYUV) (p1, p2, toler)
#undef SCALE_GETY
#define SCALE_GETY(p) \
SCALE_(GetPixY) (p)
// MMX transformation multipliers
extern Uint64 mmx_888to555_mult;
extern Uint64 mmx_Y_mult;
extern Uint64 mmx_U_mult;
extern Uint64 mmx_V_mult;
extern Uint64 mmx_YUV_threshold;
#define USE_YUV_LOOKUP
#if defined(MSVC_ASM)
// MSVC inline assembly versions
#if defined(USE_MOVNTQ)
# define MOVNTQ(addr, val) movntq [addr], val
#else
# define MOVNTQ(addr, val) movq [addr], val
#endif
#if USE_PREFETCH == INTEL_PREFETCH
// using Intel SSE non-temporal prefetch
# define PREFETCH(addr) prefetchnta [addr]
# define HAVE_PREFETCH
#elif USE_PREFETCH == AMD_PREFETCH
// using AMD 3DNOW! prefetch
# define PREFETCH(addr) prefetch [addr]
# define HAVE_PREFETCH
#else
// no prefetch -- too bad for poor MMX-only souls
# define PREFETCH(addr)
# undef HAVE_PREFETCH
#endif
#if defined(_MSC_VER) && (_MSC_VER >= 1300)
# pragma warning( disable : 4799 )
#endif
static inline void
SCALE_(PlatInit) (void)
{
__asm
{
// mm0 will be kept == 0 throughout
// 0 is needed for bytes->words unpack instructions
pxor mm0, mm0
}
}
static inline void
SCALE_(PlatDone) (void)
{
// finish with MMX registers and yield them to FPU
__asm
{
emms
}
}
#if defined(HAVE_PREFETCH)
static inline void
SCALE_(Prefetch) (const void* p)
{
__asm
{
mov eax, p
PREFETCH (eax)
}
}
#else /* Not HAVE_PREFETCH */
static inline void
SCALE_(Prefetch) (const void* p)
{
(void)p; // silence compiler
/* no-op */
}
#endif /* HAVE_PREFETCH */
// compute the RGB distance squared between 2 pixels
static inline int
SCALE_(GetRGBDelta) (Uint32 pix1, Uint32 pix2)
{
__asm
{
// load pixels
movd mm1, pix1
punpcklbw mm1, mm0
movd mm2, pix2
punpcklbw mm2, mm0
// get the difference between RGBA components
psubw mm1, mm2
// squared and sumed
pmaddwd mm1, mm1
// finish suming the squares
movq mm2, mm1
punpckhdq mm2, mm0
paddd mm1, mm2
// store result
movd eax, mm1
}
}
// retrieve the Y (intensity) component of pixel's YUV
static inline int
SCALE_(GetPixY) (Uint32 pix)
{
__asm
{
// load pixel
movd mm1, pix
punpcklbw mm1, mm0
// process
pmaddwd mm1, mmx_Y_mult // RGB * Yvec
movq mm2, mm1 // finish suming
punpckhdq mm2, mm0 // ditto
paddd mm1, mm2 // ditto
// store result
movd eax, mm1
shr eax, 14
}
}
#ifdef USE_YUV_LOOKUP
// convert pixel RGB vector into YUV representation vector
static inline YUV_VECTOR
SCALE_(RGBtoYUV) (Uint32 pix)
{
__asm
{
// convert RGB888 to 555
movd mm1, pix
punpcklbw mm1, mm0
psrlw mm1, 3 // 8->5 bit
pmaddwd mm1, mmx_888to555_mult // shuffle into the right channel order
movq mm2, mm1 // finish shuffling
punpckhdq mm2, mm0 // ditto
por mm1, mm2 // ditto
// lookup the YUV vector
movd eax, mm1
mov eax, [RGB15_to_YUV + eax * 4]
}
}
// compare 2 pixels with respect to their YUV representations
// tolerance set by toler arg
// returns true: close; false: distant (-gt toler)
static inline bool
SCALE_(CmpYUV) (Uint32 pix1, Uint32 pix2, int toler)
{
__asm
{
// convert RGB888 to 555
movd mm1, pix1
punpcklbw mm1, mm0
psrlw mm1, 3 // 8->5 bit
movd mm3, pix2
punpcklbw mm3, mm0
psrlw mm3, 3 // 8->5 bit
pmaddwd mm1, mmx_888to555_mult // shuffle into the right channel order
movq mm2, mm1 // finish shuffling
pmaddwd mm3, mmx_888to555_mult // shuffle into the right channel order
movq mm4, mm3 // finish shuffling
punpckhdq mm2, mm0 // ditto
por mm1, mm2 // ditto
punpckhdq mm4, mm0 // ditto
por mm3, mm4 // ditto
// lookup the YUV vector
movd eax, mm1
movd edx, mm3
movd mm1, [RGB15_to_YUV + eax * 4]
movq mm4, mm1
movd mm2, [RGB15_to_YUV + edx * 4]
// get abs difference between YUV components
#ifdef USE_PSADBW
// we can use PSADBW and save us some grief
psadbw mm1, mm2
movd edx, mm1
#else
// no PSADBW -- have to do it the hard way
psubusb mm1, mm2
psubusb mm2, mm4
por mm1, mm2
// sum the differences
// XXX: technically, this produces a MAX diff of 510
// but we do not need anything bigger, currently
movq mm2, mm1
psrlq mm2, 8
paddusb mm1, mm2
psrlq mm2, 8
paddusb mm1, mm2
movd edx, mm1
and edx, 0xff
#endif /* USE_PSADBW */
xor eax, eax
shl edx, 1
cmp edx, toler
// store result
setle al
}
}
#else /* Not USE_YUV_LOOKUP */
// convert pixel RGB vector into YUV representation vector
static inline YUV_VECTOR
SCALE_(RGBtoYUV) (Uint32 pix)
{
__asm
{
movd mm1, pix
punpcklbw mm1, mm0
movq mm2, mm1
// Y vector multiply
pmaddwd mm1, mmx_Y_mult
movq mm4, mm1
punpckhdq mm4, mm0
punpckldq mm1, mm0 // clear out the high dword
paddd mm1, mm4
psrad mm1, 15
movq mm3, mm2
// U vector multiply
pmaddwd mm2, mmx_U_mult
psrad mm2, 10
// V vector multiply
pmaddwd mm3, mmx_V_mult
psrad mm3, 10
// load (1|1|1|1) into mm4
pcmpeqw mm4, mm4
psrlw mm4, 15
packssdw mm3, mm2
pmaddwd mm3, mm4
psrad mm3, 5
// load (64|64) into mm4
punpcklwd mm4, mm0
pslld mm4, 6
paddd mm3, mm4
packssdw mm3, mm1
packuswb mm3, mm0
movd eax, mm3
}
}
// compare 2 pixels with respect to their YUV representations
// tolerance set by toler arg
// returns true: close; false: distant (-gt toler)
static inline bool
SCALE_(CmpYUV) (Uint32 pix1, Uint32 pix2, int toler)
{
__asm
{
movd mm1, pix1
punpcklbw mm1, mm0
movd mm2, pix2
punpcklbw mm2, mm0
psubw mm1, mm2
movq mm2, mm1
// Y vector multiply
pmaddwd mm1, mmx_Y_mult
movq mm4, mm1
punpckhdq mm4, mm0
paddd mm1, mm4
// abs()
movq mm4, mm1
psrad mm4, 31
pxor mm4, mm1
psubd mm1, mm4
movq mm3, mm2
// U vector multiply
pmaddwd mm2, mmx_U_mult
movq mm4, mm2
punpckhdq mm4, mm0
paddd mm2, mm4
// abs()
movq mm4, mm2
psrad mm4, 31
pxor mm4, mm2
psubd mm2, mm4
paddd mm1, mm2
// V vector multiply
pmaddwd mm3, mmx_V_mult
movq mm4, mm3
punpckhdq mm3, mm0
paddd mm3, mm4
// abs()
movq mm4, mm3
psrad mm4, 31
pxor mm4, mm3
psubd mm3, mm4
paddd mm1, mm3
movd edx, mm1
xor eax, eax
shr edx, 14
cmp edx, toler
// store result
setle al
}
}
#endif /* USE_YUV_LOOKUP */
// Check if 2 pixels are different with respect to their
// YUV representations
// returns 0: close; ~0: distant
static inline int
SCALE_(DiffYUV) (Uint32 yuv1, Uint32 yuv2)
{
__asm
{
// load YUV pixels
movd mm1, yuv1
movq mm4, mm1
movd mm2, yuv2
// abs difference between channels
psubusb mm1, mm2
psubusb mm2, mm4
por mm1, mm2
// compare to threshold
psubusb mm1, mmx_YUV_threshold
movd edx, mm1
// transform eax to 0 or ~0
xor eax, eax
or edx, edx
setz al
dec eax
}
}
// bilinear weighted blend of four pixels
// MSVC asm version
static inline void
SCALE_(Blend_bilinear) (const Uint32* row0, const Uint32* row1,
Uint32* dst_p, Uint32 dlen)
{
__asm
{
// EL0: setup vars
mov ebx, row0 // EL0
// EL0: load pixels
movq mm1, [ebx] // EL0
movq mm2, mm1 // EL0: p[1] -> mm2
PREFETCH (ebx + 0x80)
punpckhbw mm2, mm0 // EL0: p[1] -> mm2
mov ebx, row1
punpcklbw mm1, mm0 // EL0: p[0] -> mm1
movq mm3, [ebx]
movq mm4, mm3 // EL0: p[3] -> mm4
movq mm6, mm2 // EL1.1: p[1] -> mm6
PREFETCH (ebx + 0x80)
punpcklbw mm3, mm0 // EL0: p[2] -> mm3
movq mm5, mm1 // EL1.1: p[0] -> mm5
punpckhbw mm4, mm0 // EL0: p[3] -> mm4
mov edi, dst_p // EL0
// EL1: cache p[0] + 3*(p[1] + p[2]) + p[3] in mm6
paddw mm6, mm3 // EL1.2: p[1] + p[2] -> mm6
// EL1: cache p[0] + p[1] + p[2] + p[3] in mm7
movq mm7, mm6 // EL1.3: p[1] + p[2] -> mm7
// EL1: cache p[1] + 3*(p[0] + p[3]) + p[2] in mm5
paddw mm5, mm4 // EL1.2: p[0] + p[3] -> mm5
psllw mm6, 1 // EL1.4: 2*(p[1] + p[2]) -> mm6
paddw mm7, mm5 // EL1.4: sum(p[]) -> mm7
psllw mm5, 1 // EL1.5: 2*(p[0] + p[3]) -> mm5
paddw mm6, mm7 // EL1.5: p[0] + 3*(p[1] + p[2]) + p[3] -> mm6
paddw mm5, mm7 // EL1.6: p[1] + 3*(p[0] + p[3]) + p[2] -> mm5
// EL2: pixel 0 math -- (9*p[0] + 3*(p[1] + p[2]) + p[3]) / 16
psllw mm1, 3 // EL2.1: 8*p[0] -> mm1
paddw mm1, mm6 // EL2.2: 9*p[0] + 3*(p[1] + p[2]) + p[3] -> mm1
psrlw mm1, 4 // EL2.3: sum[0]/16 -> mm1
mov edx, dlen // EL0
// EL3: pixel 1 math -- (9*p[1] + 3*(p[0] + p[3]) + p[2]) / 16
psllw mm2, 3 // EL3.1: 8*p[1] -> mm2
paddw mm2, mm5 // EL3.2: 9*p[1] + 3*(p[0] + p[3]) + p[2] -> mm2
psrlw mm2, 4 // EL3.3: sum[1]/16 -> mm5
// EL2/3: store pixels 0 & 1
packuswb mm1, mm2 // EL2/3: pack into bytes
MOVNTQ (edi, mm1) // EL2/3: store 2 pixels
// EL4: pixel 2 math -- (9*p[2] + 3*(p[0] + p[3]) + p[1]) / 16
psllw mm3, 3 // EL4.1: 8*p[2] -> mm3
paddw mm3, mm5 // EL4.2: 9*p[2] + 3*(p[0] + p[3]) + p[1] -> mm3
psrlw mm3, 4 // EL4.3: sum[2]/16 -> mm3
// EL5: pixel 3 math -- (9*p[3] + 3*(p[1] + p[2]) + p[0]) / 16
psllw mm4, 3 // EL5.1: 8*p[3] -> mm4
paddw mm4, mm6 // EL5.2: 9*p[3] + 3*(p[1] + p[2]) + p[0] -> mm4
psrlw mm4, 4 // EL5.3: sum[3]/16 -> mm4
// EL4/5: store pixels 2 & 3
packuswb mm3, mm4 // EL4/5: pack into bytes
MOVNTQ (edi + edx*4, mm3) // EL4/5: store 2 pixels
}
}
// End MSVC_ASM
#elif defined(GCC_ASM)
// GCC inline assembly versions
#if defined(USE_MOVNTQ)
# define MOVNTQ(val, addr) "movntq " #val "," #addr
#else
# define MOVNTQ(val, addr) "movq " #val "," #addr
#endif
#if USE_PREFETCH == INTEL_PREFETCH
// using Intel SSE non-temporal prefetch
# define PREFETCH(addr) "prefetchnta " #addr
#elif USE_PREFETCH == AMD_PREFETCH
// using AMD 3DNOW! prefetch
# define PREFETCH(addr) "prefetch " #addr
#else
// no prefetch -- too bad for poor MMX-only souls
# define PREFETCH(addr)
#endif
#if defined(__x86_64__)
# define A_REG "rax"
# define D_REG "rdx"
# define CLR_UPPER32(r) "xor " "%%" r "," "%%" r
#else
# define A_REG "eax"
# define D_REG "edx"
# define CLR_UPPER32(r)
#endif
static inline void
SCALE_(PlatInit) (void)
{
__asm__ (
// mm0 will be kept == 0 throughout
// 0 is needed for bytes->words unpack instructions
"pxor %%mm0, %%mm0 \n\t"
: /* nothing */
: /* nothing */
);
}
static inline void
SCALE_(PlatDone) (void)
{
// finish with MMX registers and yield them to FPU
__asm__ (
"emms \n\t"
: /* nothing */ : /* nothing */
);
}
static inline void
SCALE_(Prefetch) (const void* p)
{
__asm__ __volatile__ ("" PREFETCH (%0) : /*nothing*/ : "m" (p) );
}
// compute the RGB distance squared between 2 pixels
static inline int
SCALE_(GetRGBDelta) (Uint32 pix1, Uint32 pix2)
{
int res;
__asm__ (
// load pixels
"movd %1, %%mm1 \n\t"
"punpcklbw %%mm0, %%mm1 \n\t"
"movd %2, %%mm2 \n\t"
"punpcklbw %%mm0, %%mm2 \n\t"
// get the difference between RGBA components
"psubw %%mm2, %%mm1 \n\t"
// squared and sumed
"pmaddwd %%mm1, %%mm1 \n\t"
// finish suming the squares
"movq %%mm1, %%mm2 \n\t"
"punpckhdq %%mm0, %%mm2 \n\t"
"paddd %%mm2, %%mm1 \n\t"
// store result
"movd %%mm1, %0 \n\t"
: /*0*/"=rm" (res)
: /*1*/"rm" (pix1), /*2*/"rm" (pix2)
);
return res;
}
// retrieve the Y (intensity) component of pixel's YUV
static inline int
SCALE_(GetPixY) (Uint32 pix)
{
int ret;
__asm__ (
// load pixel
"movd %1, %%mm1 \n\t"
"punpcklbw %%mm0, %%mm1 \n\t"
// process
"pmaddwd %2, %%mm1 \n\t" // R,G,B * Yvec
"movq %%mm1, %%mm2 \n\t" // finish suming
"punpckhdq %%mm0, %%mm2 \n\t" // ditto
"paddd %%mm2, %%mm1 \n\t" // ditto
// store index
"movd %%mm1, %0 \n\t"
: /*0*/"=r" (ret)
: /*1*/"rm" (pix), /*2*/"m" (mmx_Y_mult)
);
return ret >> 14;
}
#ifdef USE_YUV_LOOKUP
// convert pixel RGB vector into YUV representation vector
static inline YUV_VECTOR
SCALE_(RGBtoYUV) (Uint32 pix)
{
int i;
__asm__ (
// convert RGB888 to 555
"movd %1, %%mm1 \n\t"
"punpcklbw %%mm0, %%mm1 \n\t"
"psrlw $3, %%mm1 \n\t" // 8->5 bit
"pmaddwd %2, %%mm1 \n\t" // shuffle into the right channel order
"movq %%mm1, %%mm2 \n\t" // finish shuffling
"punpckhdq %%mm0, %%mm2 \n\t" // ditto
"por %%mm2, %%mm1 \n\t" // ditto
"movd %%mm1, %0 \n\t"
: /*0*/"=rm" (i)
: /*1*/"rm" (pix), /*2*/"m" (mmx_888to555_mult)
);
return RGB15_to_YUV[i];
}
// compare 2 pixels with respect to their YUV representations
// tolerance set by toler arg
// returns true: close; false: distant (-gt toler)
static inline bool
SCALE_(CmpYUV) (Uint32 pix1, Uint32 pix2, int toler)
{
int delta;
__asm__ (
"movd %1, %%mm1 \n\t"
"movd %2, %%mm3 \n\t"
// convert RGB888 to 555
// this is somewhat parallelized
"punpcklbw %%mm0, %%mm1 \n\t"
CLR_UPPER32 (A_REG) "\n\t"
"psrlw $3, %%mm1 \n\t" // 8->5 bit
"punpcklbw %%mm0, %%mm3 \n\t"
"psrlw $3, %%mm3 \n\t" // 8->5 bit
"pmaddwd %4, %%mm1 \n\t" // shuffle into the right channel order
"movq %%mm1, %%mm2 \n\t" // finish shuffling
"pmaddwd %4, %%mm3 \n\t" // shuffle into the right channel order
CLR_UPPER32 (D_REG) "\n\t"
"movq %%mm3, %%mm4 \n\t" // finish shuffling
"punpckhdq %%mm0, %%mm2 \n\t" // ditto
"por %%mm2, %%mm1 \n\t" // ditto
"punpckhdq %%mm0, %%mm4 \n\t" // ditto
"por %%mm4, %%mm3 \n\t" // ditto
// lookup the YUV vector
"movd %%mm1, %%eax \n\t"
"movd %%mm3, %%edx \n\t"
"movd (%3, %%" A_REG ", 4), %%mm1 \n\t"
"movq %%mm1, %%mm4 \n\t"
"movd (%3, %%" D_REG ", 4), %%mm2 \n\t"
// get abs difference between YUV components
#ifdef USE_PSADBW
// we can use PSADBW and save us some grief
"psadbw %%mm2, %%mm1 \n\t"
"movd %%mm1, %0 \n\t"
#else
// no PSADBW -- have to do it the hard way
"psubusb %%mm2, %%mm1 \n\t"
"psubusb %%mm4, %%mm2 \n\t"
"por %%mm2, %%mm1 \n\t"
// sum the differences
// technically, this produces a MAX diff of 510
// but we do not need anything bigger, currently
"movq %%mm1, %%mm2 \n\t"
"psrlq $8, %%mm2 \n\t"
"paddusb %%mm2, %%mm1 \n\t"
"psrlq $8, %%mm2 \n\t"
"paddusb %%mm2, %%mm1 \n\t"
// store intermediate delta
"movd %%mm1, %0 \n\t"
"andl $0xff, %0 \n\t"
#endif /* USE_PSADBW */
: /*0*/"=rm" (delta)
: /*1*/"rm" (pix1), /*2*/"rm" (pix2),
/*3*/ "r" (RGB15_to_YUV),
/*4*/"m" (mmx_888to555_mult)
: "%" A_REG, "%" D_REG, "cc"
);
return (delta << 1) <= toler;
}
#endif /* USE_YUV_LOOKUP */
// Check if 2 pixels are different with respect to their
// YUV representations
// returns 0: close; ~0: distant
static inline int
SCALE_(DiffYUV) (Uint32 yuv1, Uint32 yuv2)
{
sint32 ret;
__asm__ (
// load YUV pixels
"movd %1, %%mm1 \n\t"
"movq %%mm1, %%mm4 \n\t"
"movd %2, %%mm2 \n\t"
// abs difference between channels
"psubusb %%mm2, %%mm1 \n\t"
"psubusb %%mm4, %%mm2 \n\t"
CLR_UPPER32(D_REG) "\n\t"
"por %%mm2, %%mm1 \n\t"
// compare to threshold
"psubusb %3, %%mm1 \n\t"
"movd %%mm1, %%edx \n\t"
// transform eax to 0 or ~0
"xor %%" A_REG ", %%" A_REG "\n\t"
"or %%" D_REG ", %%" D_REG "\n\t"
"setz %%al \n\t"
"dec %%" A_REG " \n\t"
: /*0*/"=a" (ret)
: /*1*/"rm" (yuv1), /*2*/"rm" (yuv2),
/*3*/"m" (mmx_YUV_threshold)
: "%" D_REG, "cc"
);
return ret;
}
// Bilinear weighted blend of four pixels
// Function produces 4 blended pixels (in 2x2 matrix) and writes them
// out to the surface
// Last version
static inline void
SCALE_(Blend_bilinear) (const Uint32* row0, const Uint32* row1,
Uint32* dst_p, Uint32 dlen)
{
__asm__ (
// EL0: load pixels
"movq %0, %%mm1 \n\t" // EL0
"movq %%mm1, %%mm2 \n\t" // EL0: p[1] -> mm2
PREFETCH (0x80%0) "\n\t"
"punpckhbw %%mm0, %%mm2 \n\t" // EL0: p[1] -> mm2
"punpcklbw %%mm0, %%mm1 \n\t" // EL0: p[0] -> mm1
"movq %1, %%mm3 \n\t"
"movq %%mm3, %%mm4 \n\t" // EL0: p[3] -> mm4
"movq %%mm2, %%mm6 \n\t" // EL1.1: p[1] -> mm6
PREFETCH (0x80%1) "\n\t"
"punpcklbw %%mm0, %%mm3 \n\t" // EL0: p[2] -> mm3
"movq %%mm1, %%mm5 \n\t" // EL1.1: p[0] -> mm5
"punpckhbw %%mm0, %%mm4 \n\t" // EL0: p[3] -> mm4
// EL1: cache p[0] + 3*(p[1] + p[2]) + p[3] in mm6
"paddw %%mm3, %%mm6 \n\t" // EL1.2: p[1] + p[2] -> mm6
// EL1: cache p[0] + p[1] + p[2] + p[3] in mm7
"movq %%mm6, %%mm7 \n\t" // EL1.3: p[1] + p[2] -> mm7
// EL1: cache p[1] + 3*(p[0] + p[3]) + p[2] in mm5
"paddw %%mm4, %%mm5 \n\t" // EL1.2: p[0] + p[3] -> mm5
"psllw $1, %%mm6 \n\t" // EL1.4: 2*(p[1] + p[2]) -> mm6
"paddw %%mm5, %%mm7 \n\t" // EL1.4: sum(p[]) -> mm7
"psllw $1, %%mm5 \n\t" // EL1.5: 2*(p[0] + p[3]) -> mm5
"paddw %%mm7, %%mm6 \n\t" // EL1.5: p[0] + 3*(p[1] + p[2]) + p[3] -> mm6
"paddw %%mm7, %%mm5 \n\t" // EL1.6: p[1] + 3*(p[0] + p[3]) + p[2] -> mm5
// EL2: pixel 0 math -- (9*p[0] + 3*(p[1] + p[2]) + p[3]) / 16
"psllw $3, %%mm1 \n\t" // EL2.1: 8*p[0] -> mm1
"paddw %%mm6, %%mm1 \n\t" // EL2.2: 9*p[0] + 3*(p[1] + p[2]) + p[3] -> mm1
"psrlw $4, %%mm1 \n\t" // EL2.3: sum[0]/16 -> mm1
// EL3: pixel 1 math -- (9*p[1] + 3*(p[0] + p[3]) + p[2]) / 16
"psllw $3, %%mm2 \n\t" // EL3.1: 8*p[1] -> mm2
"paddw %%mm5, %%mm2 \n\t" // EL3.2: 9*p[1] + 3*(p[0] + p[3]) + p[2] -> mm5
"psrlw $4, %%mm2 \n\t" // EL3.3: sum[1]/16 -> mm5
// EL2/4: store pixels 0 & 1
"packuswb %%mm2, %%mm1 \n\t" // EL2/4: pack into bytes
MOVNTQ (%%mm1, (%2)) "\n\t" // EL2/4: store 2 pixels
// EL4: pixel 2 math -- (9*p[2] + 3*(p[0] + p[3]) + p[1]) / 16
"psllw $3, %%mm3 \n\t" // EL4.1: 8*p[2] -> mm3
"paddw %%mm5, %%mm3 \n\t" // EL4.2: 9*p[2] + 3*(p[0] + p[3]) + p[1] -> mm3
"psrlw $4, %%mm3 \n\t" // EL4.3: sum[2]/16 -> mm3
// EL5: pixel 3 math -- (9*p[3] + 3*(p[1] + p[2]) + p[0]) / 16
"psllw $3, %%mm4 \n\t" // EL5.1: 8*p[3] -> mm4
"paddw %%mm6, %%mm4 \n\t" // EL5.2: 9*p[3] + 3*(p[1] + p[2]) + p[0] -> mm4
"psrlw $4, %%mm4 \n\t" // EL5.3: sum[3]/16 -> mm4
// EL4/5: store pixels 2 & 3
"packuswb %%mm4, %%mm3 \n\t" // EL4/5: pack into bytes
MOVNTQ (%%mm3, (%2,%3,4)) "\n\t" // EL4/5: store 2 pixels
: /* nothing */
: /*0*/"m" (*row0), /*1*/"m" (*row1), /*2*/"r" (dst_p),
/*3*/"r" ((unsigned long)dlen) /* 'long' is for proper reg alloc on amd64 */
: "memory"
);
}
#undef A_REG
#undef D_REG
#undef CLR_UPPER32
#endif // GCC_ASM
#endif /* SCALEMMX_H_ */

View File

@@ -0,0 +1,286 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "types.h"
#include "libs/graphics/sdl/sdl_common.h"
#include "libs/platform.h"
#include "libs/log.h"
#include "scalers.h"
#include "scaleint.h"
#include "2xscalers.h"
#ifdef USE_PLATFORM_ACCEL
# ifndef __APPLE__
// MacOS X framework has no SDL_cpuinfo.h for some reason
# include SDL_INCLUDE(SDL_cpuinfo.h)
# endif
# ifdef MMX_ASM
# include "2xscalers_mmx.h"
# endif /* MMX_ASM */
#endif /* USE_PLATFORM_ACCEL */
typedef enum
{
SCALEPLAT_NULL = PLATFORM_NULL,
SCALEPLAT_C = PLATFORM_C,
SCALEPLAT_MMX = PLATFORM_MMX,
SCALEPLAT_SSE = PLATFORM_SSE,
SCALEPLAT_3DNOW = PLATFORM_3DNOW,
SCALEPLAT_ALTIVEC = PLATFORM_ALTIVEC,
SCALEPLAT_C_RGBA,
SCALEPLAT_C_BGRA,
SCALEPLAT_C_ARGB,
SCALEPLAT_C_ABGR,
} Scale_PlatType_t;
// RGB -> YUV transformation
// the RGB vector is multiplied by the transformation matrix
// to get the YUV vector
#if 0
// original table -- not used
const int YUV_matrix[3][3] =
{
/* Y U V */
/* R */ {0.2989, -0.1687, 0.5000},
/* G */ {0.5867, -0.3312, -0.4183},
/* B */ {0.1144, 0.5000, -0.0816}
};
#else
// scaled up by a 2^14 factor, with Y doubled
const int YUV_matrix[3][3] =
{
/* Y U V */
/* R */ { 9794, -2764, 8192},
/* G */ {19224, -5428, -6853},
/* B */ { 3749, 8192, -1339}
};
#endif
// pre-computed transformations for 8 bits per channel
int RGB_to_YUV[/*RGB*/ 3][/*YUV*/ 3][ /*mult-res*/ 256];
sint16 dRGB_to_dYUV[/*RGB*/ 3][/*YUV*/ 3][ /*mult-res*/ 512];
// pre-computed transformations for RGB555
YUV_VECTOR RGB15_to_YUV[0x8000];
PLATFORM_TYPE force_platform = PLATFORM_NULL;
Scale_PlatType_t Scale_Platform = SCALEPLAT_NULL;
// pre-compute the RGB->YUV transformations
void
Scale_Init (void)
{
int i1, i2, i3;
for (i1 = 0; i1 < 3; i1++) // enum R,G,B
for (i2 = 0; i2 < 3; i2++) // enum Y,U,V
for (i3 = 0; i3 < 256; i3++) // enum possible channel vals
{
RGB_to_YUV[i1][i2][i3] =
(YUV_matrix[i1][i2] * i3) >> 14;
}
for (i1 = 0; i1 < 3; i1++) // enum R,G,B
for (i2 = 0; i2 < 3; i2++) // enum Y,U,V
for (i3 = -255; i3 < 256; i3++) // enum possible channel delta vals
{
dRGB_to_dYUV[i1][i2][i3 + 255] =
(YUV_matrix[i1][i2] * i3) >> 14;
}
for (i1 = 0; i1 < 32; ++i1)
for (i2 = 0; i2 < 32; ++i2)
for (i3 = 0; i3 < 32; ++i3)
{
int y, u, v;
// adding upper bits halved for error correction
int r = (i1 << 3) | (i1 >> 3);
int g = (i2 << 3) | (i2 >> 3);
int b = (i3 << 3) | (i3 >> 3);
y = ( r * YUV_matrix[YUV_XFORM_R][YUV_XFORM_Y]
+ g * YUV_matrix[YUV_XFORM_G][YUV_XFORM_Y]
+ b * YUV_matrix[YUV_XFORM_B][YUV_XFORM_Y]
) >> 15; // we dont need Y doubled, need Y to fit 8 bits
// U and V are half the importance of Y
u = 64+(( r * YUV_matrix[YUV_XFORM_R][YUV_XFORM_U]
+ g * YUV_matrix[YUV_XFORM_G][YUV_XFORM_U]
+ b * YUV_matrix[YUV_XFORM_B][YUV_XFORM_U]
) >> 15); // halved
v = 64+(( r * YUV_matrix[YUV_XFORM_R][YUV_XFORM_V]
+ g * YUV_matrix[YUV_XFORM_G][YUV_XFORM_V]
+ b * YUV_matrix[YUV_XFORM_B][YUV_XFORM_V]
) >> 15); // halved
RGB15_to_YUV[(i1 << 10) | (i2 << 5) | i3] = (y << 16) | (u << 8) | v;
}
}
// expands the given rectangle in all directions by 'expansion'
// guarded by 'limits'
void
Scale_ExpandRect (SDL_Rect* rect, int expansion, const SDL_Rect* limits)
{
if (rect->x - expansion >= limits->x)
{
rect->w += expansion;
rect->x -= expansion;
}
else
{
rect->w += rect->x - limits->x;
rect->x = limits->x;
}
if (rect->y - expansion >= limits->y)
{
rect->h += expansion;
rect->y -= expansion;
}
else
{
rect->h += rect->y - limits->y;
rect->y = limits->y;
}
if (rect->x + rect->w + expansion <= limits->w)
rect->w += expansion;
else
rect->w = limits->w - rect->x;
if (rect->y + rect->h + expansion <= limits->h)
rect->h += expansion;
else
rect->h = limits->h - rect->y;
}
// Platform+Scaler function lookups
typedef struct
{
Scale_PlatType_t platform;
const Scale_FuncDef_t* funcdefs;
} Scale_PlatDef_t;
static const Scale_PlatDef_t
Scale_PlatDefs[] =
{
#if defined(MMX_ASM)
{SCALEPLAT_SSE, Scale_SSE_Functions},
{SCALEPLAT_3DNOW, Scale_3DNow_Functions},
{SCALEPLAT_MMX, Scale_MMX_Functions},
#endif /* MMX_ASM */
// Default
{SCALEPLAT_NULL, Scale_C_Functions}
};
TFB_ScaleFunc
Scale_PrepPlatform (int flags, const SDL_PixelFormat* fmt)
{
const Scale_PlatDef_t* pdef;
const Scale_FuncDef_t* fdef;
(void)flags;
Scale_Platform = SCALEPLAT_NULL;
// first match wins
// add better platform techs to the top
#ifdef MMX_ASM
if ( (!force_platform && (SDL_HasSSE () || SDL_HasMMXExt ()))
|| force_platform == SCALEPLAT_SSE)
{
log_add (log_Info, "Screen scalers are using SSE/MMX-Ext/MMX code");
Scale_Platform = SCALEPLAT_SSE;
Scale_SSE_PrepPlatform (fmt);
}
else
if ( (!force_platform && SDL_HasAltiVec ())
|| force_platform == SCALEPLAT_ALTIVEC)
{
log_add (log_Info, "Screen scalers would use AltiVec code "
"if someone actually wrote it");
//Scale_Platform = SCALEPLAT_ALTIVEC;
}
else
if ( (!force_platform && SDL_Has3DNow ())
|| force_platform == SCALEPLAT_3DNOW)
{
log_add (log_Info, "Screen scalers are using 3DNow/MMX code");
Scale_Platform = SCALEPLAT_3DNOW;
Scale_3DNow_PrepPlatform (fmt);
}
else
if ( (!force_platform && SDL_HasMMX ())
|| force_platform == SCALEPLAT_MMX)
{
log_add (log_Info, "Screen scalers are using MMX code");
Scale_Platform = SCALEPLAT_MMX;
Scale_MMX_PrepPlatform (fmt);
}
#endif
if (Scale_Platform == SCALEPLAT_NULL)
{ // Plain C versions
if (fmt->Rmask == 0xff000000 && fmt->Bmask == 0x0000ff00)
Scale_Platform = SCALEPLAT_C_RGBA;
else if (fmt->Rmask == 0x00ff0000 && fmt->Bmask == 0x000000ff)
Scale_Platform = SCALEPLAT_C_ARGB;
else if (fmt->Rmask == 0x0000ff00 && fmt->Bmask == 0xff000000)
Scale_Platform = SCALEPLAT_C_BGRA;
else if (fmt->Rmask == 0x000000ff && fmt->Bmask == 0x00ff0000)
Scale_Platform = SCALEPLAT_C_ABGR;
else
{ // use slowest default
log_add (log_Warning, "Scale_PrepPlatform(): unknown masks "
"(Red %08x, Blue %08x)", fmt->Rmask, fmt->Bmask);
Scale_Platform = SCALEPLAT_C;
}
if (Scale_Platform == SCALEPLAT_C)
log_add (log_Info, "Screen scalers are using slow generic C code");
else
log_add (log_Info, "Screen scalers are using optimized C code");
}
// Lookup the scaling function
// First find the right platform
for (pdef = Scale_PlatDefs;
pdef->platform != Scale_Platform && pdef->platform != SCALEPLAT_NULL;
++pdef)
;
// Next find the right function
for (fdef = pdef->funcdefs;
(flags & fdef->flag) != fdef->flag;
++fdef)
;
return fdef->func;
}

View File

@@ -0,0 +1,27 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef SCALERS_H_
#define SCALERS_H_
void Scale_Init (void);
typedef void (* TFB_ScaleFunc) (SDL_Surface *src, SDL_Surface *dst,
SDL_Rect *r);
TFB_ScaleFunc Scale_PrepPlatform (int flags, const SDL_PixelFormat* fmt);
#endif /* SCALERS_H_ */

View File

@@ -0,0 +1,607 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sdl_common.h"
#include "opengl.h"
#include "pure.h"
#include "primitives.h"
#include "options.h"
#include "uqmversion.h"
#include "libs/graphics/drawcmd.h"
#include "libs/graphics/dcqueue.h"
#include "libs/graphics/cmap.h"
#include "libs/input/sdl/input.h"
// for ProcessInputEvent()
#include "libs/graphics/bbox.h"
#include "port.h"
#include "libs/uio.h"
#include "libs/log.h"
#include "libs/memlib.h"
#include "libs/vidlib.h"
#include SDL_INCLUDE(SDL_thread.h)
SDL_Surface *SDL_Video;
SDL_Surface *SDL_Screen;
SDL_Surface *TransitionScreen;
SDL_Surface *SDL_Screens[TFB_GFX_NUMSCREENS];
SDL_Surface *format_conv_surf = NULL;
static volatile BOOLEAN abortFlag = FALSE;
int GfxFlags = 0;
TFB_GRAPHICS_BACKEND *graphics_backend = NULL;
volatile int QuitPosted = 0;
volatile int GameActive = 1; // Track the SDL_ACTIVEEVENT state SDL_APPACTIVE
void
TFB_PreInit (void)
{
log_add (log_Info, "Initializing base SDL functionality.");
log_add (log_Info, "Using SDL version %d.%d.%d (compiled with "
"%d.%d.%d)", SDL_Linked_Version ()->major,
SDL_Linked_Version ()->minor, SDL_Linked_Version ()->patch,
SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL);
#if 0
if (SDL_Linked_Version ()->major != SDL_MAJOR_VERSION ||
SDL_Linked_Version ()->minor != SDL_MINOR_VERSION ||
SDL_Linked_Version ()->patch != SDL_PATCHLEVEL) {
log_add (log_Warning, "The used SDL library is not the same version "
"as the one used to compile The Ur-Quan Masters with! "
"If you experience any crashes, this would be an excellent "
"suspect.");
}
#endif
if ((SDL_Init (SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) == -1))
{
log_add (log_Fatal, "Could not initialize SDL: %s.", SDL_GetError ());
exit (EXIT_FAILURE);
}
}
int
TFB_ReInitGraphics (int driver, int flags, int width, int height)
{
int result;
int togglefullscreen = 0;
char caption[200];
if (GfxFlags == (flags ^ TFB_GFXFLAGS_FULLSCREEN) &&
driver == GraphicsDriver &&
width == ScreenWidthActual && height == ScreenHeightActual)
{
togglefullscreen = 1;
}
GfxFlags = flags;
if (driver == TFB_GFXDRIVER_SDL_OPENGL)
{
#ifdef HAVE_OPENGL
result = TFB_GL_ConfigureVideo (driver, flags, width, height,
togglefullscreen);
#else
driver = TFB_GFXDRIVER_SDL_PURE;
log_add (log_Warning, "OpenGL support not compiled in,"
" so using pure SDL driver");
result = TFB_Pure_ConfigureVideo (driver, flags, width, height,
togglefullscreen);
#endif
}
else
{
result = TFB_Pure_ConfigureVideo (driver, flags, width, height,
togglefullscreen);
}
sprintf (caption, "The Ur-Quan Masters v%d.%d.%d%s",
UQM_MAJOR_VERSION, UQM_MINOR_VERSION,
UQM_PATCH_VERSION, UQM_EXTRA_VERSION);
SDL_WM_SetCaption (caption, NULL);
if (flags & TFB_GFXFLAGS_FULLSCREEN)
SDL_ShowCursor (SDL_DISABLE);
else
SDL_ShowCursor (SDL_ENABLE);
return result;
}
int
TFB_InitGraphics (int driver, int flags, int width, int height)
{
int result, i;
char caption[200];
/* Null out screen pointers the first time */
for (i = 0; i < TFB_GFX_NUMSCREENS; i++)
{
SDL_Screens[i] = NULL;
}
GfxFlags = flags;
if (driver == TFB_GFXDRIVER_SDL_OPENGL)
{
#ifdef HAVE_OPENGL
result = TFB_GL_InitGraphics (driver, flags, width, height);
#else
driver = TFB_GFXDRIVER_SDL_PURE;
log_add (log_Warning, "OpenGL support not compiled in,"
" so using pure SDL driver");
result = TFB_Pure_InitGraphics (driver, flags, width, height);
#endif
}
else
{
result = TFB_Pure_InitGraphics (driver, flags, width, height);
}
sprintf (caption, "The Ur-Quan Masters v%d.%d.%d%s",
UQM_MAJOR_VERSION, UQM_MINOR_VERSION,
UQM_PATCH_VERSION, UQM_EXTRA_VERSION);
SDL_WM_SetCaption (caption, NULL);
if (flags & TFB_GFXFLAGS_FULLSCREEN)
SDL_ShowCursor (SDL_DISABLE);
Init_DrawCommandQueue ();
TFB_DrawCanvas_Initialize ();
atexit (TFB_UninitGraphics);
return 0;
}
void
TFB_UninitGraphics (void)
{
Uninit_DrawCommandQueue ();
// TODO: Uninit whatever the drivers have set up for us
SDL_Quit ();
}
void
TFB_ProcessEvents ()
{
SDL_Event Event;
while (SDL_PollEvent (&Event))
{
/* Run through the InputEvent filter. */
ProcessInputEvent (&Event);
/* Handle graphics and exposure events. */
switch (Event.type) {
case SDL_ACTIVEEVENT: /* Lose/gain visibility or focus */
/* Up to three different state changes can occur in one event. */
/* Here, disregard least significant change (mouse focus). */
#if 0 /* Currently disabled in mainline */
// This controls the automatic sleep/pause when minimized.
// On small displays (e.g. mobile devices), APPINPUTFOCUS would
// be an appropriate substitution for APPACTIVE:
// if (Event.active.state & SDL_APPINPUTFOCUS)
if (Event.active.state & SDL_APPACTIVE)
GameActive = Event.active.gain;
#endif
break;
case SDL_QUIT:
QuitPosted = 1;
break;
case SDL_VIDEORESIZE: /* User resized video mode */
// TODO
break;
case SDL_VIDEOEXPOSE: /* Screen needs to be redrawn */
TFB_SwapBuffers (TFB_REDRAW_EXPOSE);
break;
default:
break;
}
}
}
static BOOLEAN system_box_active = 0;
static SDL_Rect system_box;
void
SetSystemRect (const RECT *r)
{
system_box_active = TRUE;
system_box.x = r->corner.x;
system_box.y = r->corner.y;
system_box.w = r->extent.width;
system_box.h = r->extent.height;
}
void
ClearSystemRect (void)
{
system_box_active = FALSE;
}
void
TFB_SwapBuffers (int force_full_redraw)
{
static int last_fade_amount = 255, last_transition_amount = 255;
static int fade_amount = 255, transition_amount = 255;
fade_amount = GetFadeAmount ();
transition_amount = TransitionAmount;
if (force_full_redraw == TFB_REDRAW_NO && !TFB_BBox.valid &&
fade_amount == 255 && transition_amount == 255 &&
last_fade_amount == 255 && last_transition_amount == 255)
return;
if (force_full_redraw == TFB_REDRAW_NO &&
(fade_amount != 255 || transition_amount != 255 ||
last_fade_amount != 255 || last_transition_amount != 255))
force_full_redraw = TFB_REDRAW_FADING;
last_fade_amount = fade_amount;
last_transition_amount = transition_amount;
graphics_backend->preprocess (force_full_redraw, transition_amount,
fade_amount);
graphics_backend->screen (TFB_SCREEN_MAIN, 255, NULL);
if (transition_amount != 255)
{
SDL_Rect r;
r.x = TransitionClipRect.corner.x;
r.y = TransitionClipRect.corner.y;
r.w = TransitionClipRect.extent.width;
r.h = TransitionClipRect.extent.height;
graphics_backend->screen (TFB_SCREEN_TRANSITION,
255 - transition_amount, &r);
}
if (fade_amount != 255)
{
if (fade_amount < 255)
{
graphics_backend->color (0, 0, 0, 255 - fade_amount, NULL);
}
else
{
graphics_backend->color (255, 255, 255,
fade_amount - 255, NULL);
}
}
if (system_box_active)
{
graphics_backend->screen (TFB_SCREEN_MAIN, 255, &system_box);
}
graphics_backend->postprocess ();
}
/* Probably ought to clean this away at some point. */
SDL_Surface *
TFB_DisplayFormatAlpha (SDL_Surface *surface)
{
SDL_Surface* newsurf;
SDL_PixelFormat* dstfmt;
const SDL_PixelFormat* srcfmt = surface->format;
// figure out what format to use (alpha/no alpha)
if (surface->format->Amask)
dstfmt = format_conv_surf->format;
else
dstfmt = SDL_Screen->format;
if (srcfmt->BytesPerPixel == dstfmt->BytesPerPixel &&
srcfmt->Rmask == dstfmt->Rmask &&
srcfmt->Gmask == dstfmt->Gmask &&
srcfmt->Bmask == dstfmt->Bmask &&
srcfmt->Amask == dstfmt->Amask)
return surface; // no conversion needed
newsurf = SDL_ConvertSurface (surface, dstfmt, surface->flags);
// SDL_SRCCOLORKEY and SDL_SRCALPHA cannot work at the same time,
// so we need to disable one of them
if ((surface->flags & SDL_SRCCOLORKEY) && newsurf
&& (newsurf->flags & SDL_SRCCOLORKEY)
&& (newsurf->flags & SDL_SRCALPHA))
SDL_SetAlpha (newsurf, 0, 255);
return newsurf;
}
// This function should only be called from the graphics thread,
// like from a TFB_DrawCommand_Callback command.
TFB_Canvas
TFB_GetScreenCanvas (SCREEN screen)
{
return SDL_Screens[screen];
}
void
TFB_BlitSurface (SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst,
SDL_Rect *dstrect, int blend_numer, int blend_denom)
{
BOOLEAN has_colorkey;
int x, y, x1, y1, x2, y2, dst_x2, dst_y2, nr, ng, nb;
int srcx, srcy, w, h;
Uint8 sr, sg, sb, dr, dg, db;
Uint32 src_pixval, dst_pixval, colorkey;
GetPixelFn src_getpix, dst_getpix;
PutPixelFn putpix;
SDL_Rect fulldst;
if (blend_numer == blend_denom)
{
// normal blit: dst = src
// log_add (log_Debug, "normal blit\n");
SDL_BlitSurface (src, srcrect, dst, dstrect);
return;
}
// NOTE: following clipping code is copied from SDL-1.2.4 sources
// If the destination rectangle is NULL, use the entire dest surface
if (dstrect == NULL)
{
fulldst.x = fulldst.y = 0;
dstrect = &fulldst;
}
// clip the source rectangle to the source surface
if (srcrect)
{
int maxw, maxh;
srcx = srcrect->x;
w = srcrect->w;
if (srcx < 0)
{
w += srcx;
dstrect->x -= srcx;
srcx = 0;
}
maxw = src->w - srcx;
if (maxw < w)
w = maxw;
srcy = srcrect->y;
h = srcrect->h;
if (srcy < 0)
{
h += srcy;
dstrect->y -= srcy;
srcy = 0;
}
maxh = src->h - srcy;
if (maxh < h)
h = maxh;
}
else
{
srcx = 0;
srcy = 0;
w = src->w;
h = src->h;
}
// clip the destination rectangle against the clip rectangle
{
SDL_Rect *clip = &dst->clip_rect;
int dx, dy;
dx = clip->x - dstrect->x;
if (dx > 0)
{
w -= dx;
dstrect->x += dx;
srcx += dx;
}
dx = dstrect->x + w - clip->x - clip->w;
if (dx > 0)
w -= dx;
dy = clip->y - dstrect->y;
if (dy > 0)
{
h -= dy;
dstrect->y += dy;
srcy += dy;
}
dy = dstrect->y + h - clip->y - clip->h;
if (dy > 0)
h -= dy;
}
dstrect->w = w;
dstrect->h = h;
if (w <= 0 || h <= 0)
return;
x1 = srcx;
y1 = srcy;
x2 = srcx + w;
y2 = srcy + h;
if (src->flags & SDL_SRCCOLORKEY)
{
has_colorkey = TRUE;
colorkey = src->format->colorkey;
}
else
{
has_colorkey = FALSE;
colorkey = 0; /* Satisfying compiler */
}
src_getpix = getpixel_for (src);
dst_getpix = getpixel_for (dst);
putpix = putpixel_for (dst);
if (blend_denom < 0)
{
// additive blit: dst = src + dst
#if 0
log_add (log_Debug, "additive blit %d %d, src %d %d %d %d dst %d %d,"
" srcbpp %d", blend_numer, blend_denom, x1, y1, x2, y2,
dstrect->x, dstrect->y, src->format->BitsPerPixel);
#endif
for (y = y1; y < y2; ++y)
{
dst_y2 = dstrect->y + (y - y1);
for (x = x1; x < x2; ++x)
{
dst_x2 = dstrect->x + (x - x1);
src_pixval = src_getpix (src, x, y);
if (has_colorkey && src_pixval == colorkey)
continue;
dst_pixval = dst_getpix (dst, dst_x2, dst_y2);
SDL_GetRGB (src_pixval, src->format, &sr, &sg, &sb);
SDL_GetRGB (dst_pixval, dst->format, &dr, &dg, &db);
nr = sr + dr;
ng = sg + dg;
nb = sb + db;
if (nr > 255)
nr = 255;
if (ng > 255)
ng = 255;
if (nb > 255)
nb = 255;
putpix (dst, dst_x2, dst_y2,
SDL_MapRGB (dst->format, nr, ng, nb));
}
}
}
else if (blend_numer < 0)
{
// subtractive blit: dst = src - dst
#if 0
log_add (log_Debug, "subtractive blit %d %d, src %d %d %d %d"
" dst %d %d, srcbpp %d", blend_numer, blend_denom,
x1, y1, x2, y2, dstrect->x, dstrect->y,
src->format->BitsPerPixel);
#endif
for (y = y1; y < y2; ++y)
{
dst_y2 = dstrect->y + (y - y1);
for (x = x1; x < x2; ++x)
{
dst_x2 = dstrect->x + (x - x1);
src_pixval = src_getpix (src, x, y);
if (has_colorkey && src_pixval == colorkey)
continue;
dst_pixval = dst_getpix (dst, dst_x2, dst_y2);
SDL_GetRGB (src_pixval, src->format, &sr, &sg, &sb);
SDL_GetRGB (dst_pixval, dst->format, &dr, &dg, &db);
nr = sr - dr;
ng = sg - dg;
nb = sb - db;
if (nr < 0)
nr = 0;
if (ng < 0)
ng = 0;
if (nb < 0)
nb = 0;
putpix (dst, dst_x2, dst_y2,
SDL_MapRGB (dst->format, nr, ng, nb));
}
}
}
else
{
// modulated blit: dst = src * (blend_numer / blend_denom)
float f = blend_numer / (float)blend_denom;
#if 0
log_add (log_Debug, "modulated blit %d %d, f %f, src %d %d %d %d"
" dst %d %d, srcbpp %d\n", blend_numer, blend_denom, f,
x1, y1, x2, y2, dstrect->x, dstrect->y,
src->format->BitsPerPixel);
#endif
for (y = y1; y < y2; ++y)
{
dst_y2 = dstrect->y + (y - y1);
for (x = x1; x < x2; ++x)
{
dst_x2 = dstrect->x + (x - x1);
src_pixval = src_getpix (src, x, y);
if (has_colorkey && src_pixval == colorkey)
continue;
SDL_GetRGB (src_pixval, src->format, &sr, &sg, &sb);
nr = (int)(sr * f);
ng = (int)(sg * f);
nb = (int)(sb * f);
if (nr > 255)
nr = 255;
if (ng > 255)
ng = 255;
if (nb > 255)
nb = 255;
putpix (dst, dst_x2, dst_y2,
SDL_MapRGB (dst->format, nr, ng, nb));
}
}
}
}
void
TFB_UploadTransitionScreen (void)
{
#ifdef HAVE_OPENGL
if (GraphicsDriver == TFB_GFXDRIVER_SDL_OPENGL)
{
TFB_GL_UploadTransitionScreen ();
}
#endif
}
void
TFB_SetGamma (float gamma)
{
if (SDL_SetGamma (gamma, gamma, gamma) == -1)
{
log_add (log_Warning, "Unable to set gamma correction.");
}
else
{
log_add (log_Info, "Gamma correction set to %1.4f.", gamma);
}
}

View File

@@ -0,0 +1,51 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef SDL_COMMON_H
#define SDL_COMMON_H
#include "port.h"
#include SDL_INCLUDE(SDL.h)
#include SDL_INCLUDE(SDL_byteorder.h)
#include SDL_IMAGE_INCLUDE(SDL_image.h)
#include "../gfxintrn.h"
#include "libs/graphics/tfb_draw.h"
#include "libs/graphics/gfx_common.h"
// The Graphics Backend vtable
typedef struct _tfb_graphics_backend {
void (*preprocess) (int force_redraw, int transition_amount, int fade_amount);
void (*postprocess) (void);
void (*screen) (SCREEN screen, Uint8 alpha, SDL_Rect *rect);
void (*color) (Uint8 r, Uint8 g, Uint8 b, Uint8 a, SDL_Rect *rect);
} TFB_GRAPHICS_BACKEND;
extern TFB_GRAPHICS_BACKEND *graphics_backend;
extern SDL_Surface *SDL_Video;
extern SDL_Surface *SDL_Screen;
extern SDL_Surface *TransitionScreen;
extern SDL_Surface *SDL_Screens[TFB_GFX_NUMSCREENS];
extern SDL_Surface *format_conv_surf;
SDL_Surface* TFB_DisplayFormatAlpha (SDL_Surface *surface);
#endif

View File

@@ -0,0 +1,133 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sdluio.h"
#include "port.h"
#include "libs/uio.h"
#include SDL_INCLUDE(SDL.h)
#include SDL_INCLUDE(SDL_error.h)
#include SDL_INCLUDE(SDL_rwops.h)
#include SDL_IMAGE_INCLUDE(SDL_image.h)
#include "libs/memlib.h"
#include <errno.h>
#include <string.h>
static SDL_RWops *sdluio_makeRWops (uio_Stream *stream);
#if 0
// For use for initialisation, using structure assignment.
static SDL_RWops sdluio_templateRWops =
{
.seek = sdluio_seek,
.read = sdluio_read,
.write = sdluio_write,
.close = sdluio_close,
};
#endif
SDL_Surface *
sdluio_loadImage (uio_DirHandle *dir, const char *fileName) {
uio_Stream *stream;
SDL_RWops *rwops;
SDL_Surface *result;
stream = uio_fopen (dir, fileName, "rb");
if (stream == NULL)
{
SDL_SetError ("Couldn't open '%s': %s", fileName,
strerror(errno));
return NULL;
}
rwops = sdluio_makeRWops (stream);
result = IMG_Load_RW (rwops, 1);
return result;
}
int
sdluio_seek (SDL_RWops *context, int offset, int whence) {
if (uio_fseek ((uio_Stream *) context->hidden.unknown.data1, offset,
whence) == -1)
{
SDL_SetError ("Error seeking in uio_Stream: %s",
strerror(errno));
return -1;
}
return uio_ftell ((uio_Stream *) context->hidden.unknown.data1);
}
int
sdluio_read (SDL_RWops *context, void *ptr, int size, int maxnum) {
size_t numRead;
numRead = uio_fread (ptr, (size_t) size, (size_t) maxnum,
(uio_Stream *) context->hidden.unknown.data1);
if (numRead == 0 && uio_ferror ((uio_Stream *)
context->hidden.unknown.data1))
{
SDL_SetError ("Error reading from uio_Stream: %s",
strerror(errno));
return 0;
}
return (int) numRead;
}
int
sdluio_write (SDL_RWops *context, const void *ptr, int size, int num) {
size_t numWritten;
numWritten = uio_fwrite (ptr, (size_t) size, (size_t) num,
(uio_Stream *) context->hidden.unknown.data1);
if (numWritten == 0 && uio_ferror ((uio_Stream *)
context->hidden.unknown.data1))
{
SDL_SetError ("Error writing to uio_Stream: %s",
strerror(errno));
return 0;
}
return (size_t) numWritten;
}
int
sdluio_close (SDL_RWops *context) {
int result;
result = uio_fclose ((uio_Stream *) context->hidden.unknown.data1);
HFree (context);
return result;
}
static SDL_RWops *
sdluio_makeRWops (uio_Stream *stream) {
SDL_RWops *result;
result = HMalloc (sizeof (SDL_RWops));
#if 0
*(struct SDL_RWops *) result = sdluio_templateRWops;
// structure assignment
#endif
result->seek = sdluio_seek;
result->read = sdluio_read;
result->write = sdluio_write;
result->close = sdluio_close;
result->hidden.unknown.data1 = stream;
return result;
}

View File

@@ -0,0 +1,33 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _SDLUIO_H
#define _SDLUIO_H
#include "port.h"
#include "libs/uio.h"
#include SDL_INCLUDE(SDL.h)
#include SDL_INCLUDE(SDL_rwops.h)
SDL_Surface *sdluio_loadImage (uio_DirHandle *dir, const char *fileName);
int sdluio_seek (SDL_RWops *context, int offset, int whence);
int sdluio_read (SDL_RWops *context, void *ptr, int size, int maxnum);
int sdluio_write (SDL_RWops *context, const void *ptr, int size, int num);
int sdluio_close (SDL_RWops *context);
#endif /* _SDLUIO_H */

View File

@@ -0,0 +1,155 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// Core algorithm of the Triscan screen scaler (based on Scale2x)
// (for scale2x please see http://scale2x.sf.net)
// Template
// When this file is built standalone is produces a plain C version
// Also #included by 2xscalers_mmx.c for an MMX version
#include "libs/graphics/sdl/sdl_common.h"
#include "types.h"
#include "scalers.h"
#include "scaleint.h"
#include "2xscalers.h"
// Triscan scaling to 2x
// derivative of scale2x -- scale2x.sf.net
// The name expands to either
// Scale_TriScanFilter (for plain C) or
// Scale_MMX_TriScanFilter (for MMX)
// [others when platforms are added]
void
SCALE_(TriScanFilter) (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
{
int x, y;
const int w = src->w, h = src->h;
int xend, yend;
int dsrc, ddst;
SDL_Rect *region = r;
SDL_Rect limits;
SDL_PixelFormat *fmt = dst->format;
const int sp = src->pitch, dp = dst->pitch;
const int bpp = fmt->BytesPerPixel;
const int slen = sp / bpp, dlen = dp / bpp;
// for clarity purposes, the 'pixels' array here is transposed
Uint32 pixels[3][3];
Uint32 *src_p = (Uint32 *)src->pixels;
Uint32 *dst_p = (Uint32 *)dst->pixels;
int prevline, nextline;
// these macros are for clarity; they make the current pixel (0,0)
// and allow to access pixels in all directions
#define PIX(x, y) (pixels[1 + (x)][1 + (y)])
#define TRISCAN_YUV_MED 100
// medium tolerance pixel comparison
#define TRISCAN_CMPYUV(p1, p2) \
(PIX p1 == PIX p2 || SCALE_CMPYUV (PIX p1, PIX p2, TRISCAN_YUV_MED))
SCALE_(PlatInit) ();
// expand updated region if necessary
// pixels neighbooring the updated region may
// change as a result of updates
limits.x = 0;
limits.y = 0;
limits.w = src->w;
limits.h = src->h;
Scale_ExpandRect (region, 1, &limits);
xend = region->x + region->w;
yend = region->y + region->h;
dsrc = slen - region->w;
ddst = (dlen - region->w) * 2;
// move ptrs to the first updated pixel
src_p += slen * region->y + region->x;
dst_p += (dlen * region->y + region->x) * 2;
for (y = region->y; y < yend; ++y, dst_p += ddst, src_p += dsrc)
{
if (y > 0)
prevline = -slen;
else
prevline = 0;
if (y < h - 1)
nextline = slen;
else
nextline = 0;
// prime the (tiny) sliding-window pixel arrays
PIX( 1, 0) = src_p[0];
if (region->x > 0)
PIX( 0, 0) = src_p[-1];
else
PIX( 0, 0) = PIX( 1, 0);
for (x = region->x; x < xend; ++x, ++src_p, dst_p += 2)
{
// slide the window
PIX(-1, 0) = PIX( 0, 0);
PIX( 0, -1) = src_p[prevline];
PIX( 0, 0) = PIX( 1, 0);
PIX( 0, 1) = src_p[nextline];
if (x < w - 1)
PIX( 1, 0) = src_p[1];
else
PIX( 1, 0) = PIX( 0, 0);
if (!TRISCAN_CMPYUV (( 0, -1), ( 0, 1)) &&
!TRISCAN_CMPYUV ((-1, 0), ( 1, 0)))
{
if (TRISCAN_CMPYUV ((-1, 0), ( 0, -1)))
dst_p[0] = Scale_Blend_11 (PIX(-1, 0), PIX(0, -1));
else
dst_p[0] = PIX(0, 0);
if (TRISCAN_CMPYUV (( 1, 0), ( 0, -1)))
dst_p[1] = Scale_Blend_11 (PIX(1, 0), PIX(0, -1));
else
dst_p[1] = PIX(0, 0);
if (TRISCAN_CMPYUV ((-1, 0), ( 0, 1)))
dst_p[dlen] = Scale_Blend_11 (PIX(-1, 0), PIX(0, 1));
else
dst_p[dlen] = PIX(0, 0);
if (TRISCAN_CMPYUV (( 1, 0), ( 0, 1)))
dst_p[dlen+1] = Scale_Blend_11 (PIX(1, 0), PIX(0, 1));
else
dst_p[dlen+1] = PIX(0, 0);
}
else
{
dst_p[0] = PIX(0, 0);
dst_p[1] = PIX(0, 0);
dst_p[dlen] = PIX(0, 0);
dst_p[dlen+1] = PIX(0, 0);
}
}
}
SCALE_(PlatDone) ();
}

View File

@@ -0,0 +1,484 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "gfx_common.h"
#include "tfb_draw.h"
#include "drawcmd.h"
#include "libs/log.h"
#include "libs/memlib.h"
static const HOT_SPOT NullHs = {0, 0};
void
TFB_DrawScreen_Line (int x1, int y1, int x2, int y2, Color color,
DrawMode mode, SCREEN dest)
{
TFB_DrawCommand DC;
DC.Type = TFB_DRAWCOMMANDTYPE_LINE;
DC.data.line.x1 = x1;
DC.data.line.y1 = y1;
DC.data.line.x2 = x2;
DC.data.line.y2 = y2;
DC.data.line.color = color;
DC.data.line.drawMode = mode;
DC.data.line.destBuffer = dest;
TFB_EnqueueDrawCommand (&DC);
}
void
TFB_DrawScreen_Rect (RECT *rect, Color color, DrawMode mode, SCREEN dest)
{
RECT locRect;
TFB_DrawCommand DC;
if (!rect)
{
locRect.corner.x = locRect.corner.y = 0;
locRect.extent.width = ScreenWidth;
locRect.extent.height = ScreenHeight;
rect = &locRect;
}
DC.Type = TFB_DRAWCOMMANDTYPE_RECTANGLE;
DC.data.rect.rect = *rect;
DC.data.rect.color = color;
DC.data.rect.drawMode = mode;
DC.data.rect.destBuffer = dest;
TFB_EnqueueDrawCommand (&DC);
}
void
TFB_DrawScreen_Image (TFB_Image *img, int x, int y, int scale,
int scaleMode, TFB_ColorMap *cmap, DrawMode mode, SCREEN dest)
{
TFB_DrawCommand DC;
DC.Type = TFB_DRAWCOMMANDTYPE_IMAGE;
DC.data.image.image = img;
DC.data.image.colormap = cmap;
DC.data.image.x = x;
DC.data.image.y = y;
DC.data.image.scale = (scale == GSCALE_IDENTITY) ? 0 : scale;
DC.data.image.scaleMode = scaleMode;
DC.data.image.drawMode = mode;
DC.data.image.destBuffer = dest;
TFB_EnqueueDrawCommand (&DC);
}
void
TFB_DrawScreen_FilledImage (TFB_Image *img, int x, int y, int scale,
int scaleMode, Color color, DrawMode mode, SCREEN dest)
{
TFB_DrawCommand DC;
DC.Type = TFB_DRAWCOMMANDTYPE_FILLEDIMAGE;
DC.data.filledimage.image = img;
DC.data.filledimage.x = x;
DC.data.filledimage.y = y;
DC.data.filledimage.scale = (scale == GSCALE_IDENTITY) ? 0 : scale;
DC.data.filledimage.scaleMode = scaleMode;
DC.data.filledimage.color = color;
DC.data.filledimage.drawMode = mode;
DC.data.filledimage.destBuffer = dest;
TFB_EnqueueDrawCommand (&DC);
}
void
TFB_DrawScreen_FontChar (TFB_Char *fontChar, TFB_Image *backing,
int x, int y, DrawMode mode, SCREEN dest)
{
TFB_DrawCommand DC;
DC.Type = TFB_DRAWCOMMANDTYPE_FONTCHAR;
DC.data.fontchar.fontchar = fontChar;
DC.data.fontchar.backing = backing;
DC.data.fontchar.x = x;
DC.data.fontchar.y = y;
DC.data.fontchar.drawMode = mode;
DC.data.fontchar.destBuffer = dest;
TFB_EnqueueDrawCommand (&DC);
}
void
TFB_DrawScreen_CopyToImage (TFB_Image *img, const RECT *r, SCREEN src)
{
TFB_DrawCommand DC;
DC.Type = TFB_DRAWCOMMANDTYPE_COPYTOIMAGE;
DC.data.copytoimage.rect = *r;
DC.data.copytoimage.image = img;
DC.data.copytoimage.srcBuffer = src;
TFB_EnqueueDrawCommand (&DC);
}
void
TFB_DrawScreen_Copy (const RECT *r, SCREEN src, SCREEN dest)
{
RECT locRect;
TFB_DrawCommand DC;
if (!r)
{
locRect.corner.x = locRect.corner.y = 0;
locRect.extent.width = ScreenWidth;
locRect.extent.height = ScreenHeight;
r = &locRect;
}
DC.Type = TFB_DRAWCOMMANDTYPE_COPY;
DC.data.copy.rect = *r;
DC.data.copy.srcBuffer = src;
DC.data.copy.destBuffer = dest;
TFB_EnqueueDrawCommand (&DC);
}
void
TFB_DrawScreen_SetMipmap (TFB_Image *img, TFB_Image *mmimg, int hotx, int hoty)
{
TFB_DrawCommand DC;
DC.Type = TFB_DRAWCOMMANDTYPE_SETMIPMAP;
DC.data.setmipmap.image = img;
DC.data.setmipmap.mipmap = mmimg;
DC.data.setmipmap.hotx = hotx;
DC.data.setmipmap.hoty = hoty;
TFB_EnqueueDrawCommand (&DC);
}
void
TFB_DrawScreen_DeleteImage (TFB_Image *img)
{
if (img)
{
TFB_DrawCommand DC;
DC.Type = TFB_DRAWCOMMANDTYPE_DELETEIMAGE;
DC.data.deleteimage.image = img;
TFB_EnqueueDrawCommand (&DC);
}
}
void
TFB_DrawScreen_DeleteData (void *data)
// data must be a result of HXalloc() call
{
if (data)
{
TFB_DrawCommand DC;
DC.Type = TFB_DRAWCOMMANDTYPE_DELETEDATA;
DC.data.deletedata.data = data;
TFB_EnqueueDrawCommand (&DC);
}
}
void
TFB_DrawScreen_WaitForSignal (void)
{
TFB_DrawCommand DrawCommand;
Semaphore s;
s = GetMyThreadLocal ()->flushSem;
DrawCommand.Type = TFB_DRAWCOMMANDTYPE_SENDSIGNAL;
DrawCommand.data.sendsignal.sem = s;
Lock_DCQ (1);
TFB_BatchReset ();
TFB_EnqueueDrawCommand (&DrawCommand);
Unlock_DCQ();
SetSemaphore (s);
}
void
TFB_DrawScreen_ReinitVideo (int driver, int flags, int width, int height)
{
TFB_DrawCommand DrawCommand;
DrawCommand.Type = TFB_DRAWCOMMANDTYPE_REINITVIDEO;
DrawCommand.data.reinitvideo.driver = driver;
DrawCommand.data.reinitvideo.flags = flags;
DrawCommand.data.reinitvideo.width = width;
DrawCommand.data.reinitvideo.height = height;
TFB_EnqueueDrawCommand (&DrawCommand);
}
void
TFB_DrawScreen_Callback (void (*callback) (void *arg), void *arg)
{
TFB_DrawCommand DrawCommand;
DrawCommand.Type = TFB_DRAWCOMMANDTYPE_CALLBACK;
DrawCommand.data.callback.callback = callback;
DrawCommand.data.callback.arg = arg;
TFB_EnqueueDrawCommand(&DrawCommand);
}
void
TFB_DrawImage_Line (int x1, int y1, int x2, int y2, Color color,
DrawMode mode, TFB_Image *target)
{
LockMutex (target->mutex);
TFB_DrawCanvas_Line (x1, y1, x2, y2, color, mode, target->NormalImg);
target->dirty = TRUE;
UnlockMutex (target->mutex);
}
void
TFB_DrawImage_Rect (RECT *rect, Color color, DrawMode mode, TFB_Image *target)
{
LockMutex (target->mutex);
TFB_DrawCanvas_Rect (rect, color, mode, target->NormalImg);
target->dirty = TRUE;
UnlockMutex (target->mutex);
}
void
TFB_DrawImage_Image (TFB_Image *img, int x, int y, int scale,
int scaleMode, TFB_ColorMap *cmap, DrawMode mode, TFB_Image *target)
{
LockMutex (target->mutex);
TFB_DrawCanvas_Image (img, x, y, scale, scaleMode, cmap,
mode, target->NormalImg);
target->dirty = TRUE;
UnlockMutex (target->mutex);
}
void
TFB_DrawImage_FilledImage (TFB_Image *img, int x, int y, int scale,
int scaleMode, Color color, DrawMode mode, TFB_Image *target)
{
LockMutex (target->mutex);
TFB_DrawCanvas_FilledImage (img, x, y, scale, scaleMode, color,
mode, target->NormalImg);
target->dirty = TRUE;
UnlockMutex (target->mutex);
}
void
TFB_DrawImage_FontChar (TFB_Char *fontChar, TFB_Image *backing,
int x, int y, DrawMode mode, TFB_Image *target)
{
LockMutex (target->mutex);
TFB_DrawCanvas_FontChar (fontChar, backing, x, y, mode, target->NormalImg);
target->dirty = TRUE;
UnlockMutex (target->mutex);
}
TFB_Image *
TFB_DrawImage_New (TFB_Canvas canvas)
{
TFB_Image *img = HMalloc (sizeof (TFB_Image));
img->mutex = CreateMutex ("image lock", SYNC_CLASS_VIDEO);
img->ScaledImg = NULL;
img->MipmapImg = NULL;
img->FilledImg = NULL;
img->colormap_index = -1;
img->colormap_version = 0;
img->NormalHs = NullHs;
img->MipmapHs = NullHs;
img->last_scale_hs = NullHs;
img->last_scale_type = -1;
img->last_scale = 0;
TFB_DrawCanvas_GetExtent (canvas, &img->extent);
if (TFB_DrawCanvas_IsPaletted (canvas))
{
img->NormalImg = canvas;
}
else
{
img->NormalImg = TFB_DrawCanvas_ToScreenFormat (canvas);
}
return img;
}
TFB_Image*
TFB_DrawImage_CreateForScreen (int w, int h, BOOLEAN withalpha)
{
TFB_Image* img = HMalloc (sizeof (TFB_Image));
img->mutex = CreateMutex ("image lock", SYNC_CLASS_VIDEO);
img->ScaledImg = NULL;
img->MipmapImg = NULL;
img->FilledImg = NULL;
img->colormap_index = -1;
img->colormap_version = 0;
img->NormalHs = NullHs;
img->MipmapHs = NullHs;
img->last_scale_hs = NullHs;
img->last_scale_type = -1;
img->last_scale = 0;
img->extent.width = w;
img->extent.height = h;
img->NormalImg = TFB_DrawCanvas_New_ForScreen (w, h, withalpha);
return img;
}
TFB_Image *
TFB_DrawImage_New_Rotated (TFB_Image *img, int angle)
{
TFB_Canvas dst;
EXTENT size;
TFB_Image* newimg;
/* sanity check */
if (!img->NormalImg)
{
log_add (log_Warning, "TFB_DrawImage_New_Rotated: "
"source canvas is NULL! Failing.");
return NULL;
}
TFB_DrawCanvas_GetRotatedExtent (img->NormalImg, angle, &size);
dst = TFB_DrawCanvas_New_RotationTarget (img->NormalImg, angle);
if (!dst)
{
log_add (log_Warning, "TFB_DrawImage_New_Rotated: "
"rotation target canvas not created! Failing.");
return NULL;
}
TFB_DrawCanvas_Rotate (img->NormalImg, dst, angle, size);
newimg = TFB_DrawImage_New (dst);
return newimg;
}
void
TFB_DrawImage_SetMipmap (TFB_Image *img, TFB_Image *mmimg, int hotx, int hoty)
{
bool imgpal;
bool mmpal;
if (!img || !mmimg)
return;
LockMutex (img->mutex);
LockMutex (mmimg->mutex);
// Either both images must be using the same colormap, or mipmap image
// must not be paletted. This restriction is due to the current
// implementation of fill-stamp, which replaces the palette with
// fill color.
imgpal = TFB_DrawCanvas_IsPaletted (img->NormalImg);
mmpal = TFB_DrawCanvas_IsPaletted (mmimg->NormalImg);
if (!mmpal || (mmpal && imgpal &&
img->colormap_index == mmimg->colormap_index))
{
img->MipmapImg = mmimg->NormalImg;
img->MipmapHs.x = hotx;
img->MipmapHs.y = hoty;
}
else
{
img->MipmapImg = NULL;
}
UnlockMutex (mmimg->mutex);
UnlockMutex (img->mutex);
}
void
TFB_DrawImage_Delete (TFB_Image *image)
{
if (image == 0)
{
log_add (log_Warning, "INTERNAL ERROR: Tried to delete a null image!");
/* Should we die here? */
return;
}
LockMutex (image->mutex);
TFB_DrawCanvas_Delete (image->NormalImg);
if (image->ScaledImg) {
TFB_DrawCanvas_Delete (image->ScaledImg);
}
UnlockMutex (image->mutex);
DestroyMutex (image->mutex);
HFree (image);
}
void
TFB_DrawImage_FixScaling (TFB_Image *image, int target, int type)
{
if (image->dirty || !image->ScaledImg ||
target != image->last_scale ||
type != image->last_scale_type)
{
image->dirty = FALSE;
image->ScaledImg = TFB_DrawCanvas_New_ScaleTarget (image->NormalImg,
image->ScaledImg, type, image->last_scale_type);
if (type == TFB_SCALE_NEAREST)
TFB_DrawCanvas_Rescale_Nearest (image->NormalImg,
image->ScaledImg, target, &image->NormalHs,
&image->extent, &image->last_scale_hs);
else if (type == TFB_SCALE_BILINEAR)
TFB_DrawCanvas_Rescale_Bilinear (image->NormalImg,
image->ScaledImg, target, &image->NormalHs,
&image->extent, &image->last_scale_hs);
else
TFB_DrawCanvas_Rescale_Trilinear (image->NormalImg,
image->MipmapImg, image->ScaledImg, target,
&image->NormalHs, &image->MipmapHs,
&image->extent, &image->last_scale_hs);
image->last_scale_type = type;
image->last_scale = target;
}
}
BOOLEAN
TFB_DrawImage_Intersect (TFB_Image *img1, POINT img1org,
TFB_Image *img2, POINT img2org, const RECT *interRect)
{
BOOLEAN ret;
LockMutex (img1->mutex);
LockMutex (img2->mutex);
ret = TFB_DrawCanvas_Intersect (img1->NormalImg, img1org,
img2->NormalImg, img2org, interRect);
UnlockMutex (img2->mutex);
UnlockMutex (img1->mutex);
return ret;
}
void
TFB_DrawImage_CopyRect (TFB_Image *source, const RECT *srcRect,
TFB_Image *target, POINT dstPt)
{
LockMutex (source->mutex);
LockMutex (target->mutex);
TFB_DrawCanvas_CopyRect (source->NormalImg, srcRect,
target->NormalImg, dstPt);
target->dirty = TRUE;
UnlockMutex (target->mutex);
UnlockMutex (source->mutex);
}

View File

@@ -0,0 +1,199 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef TFB_DRAW_H
#define TFB_DRAW_H
#include "libs/threadlib.h"
typedef void *TFB_Canvas;
typedef enum {
TFB_SCREEN_MAIN,
TFB_SCREEN_EXTRA,
TFB_SCREEN_TRANSITION,
TFB_GFX_NUMSCREENS
} SCREEN;
#include "libs/graphics/gfx_common.h"
#include "libs/graphics/cmap.h"
typedef struct tfb_image
{
TFB_Canvas NormalImg;
TFB_Canvas ScaledImg;
TFB_Canvas MipmapImg;
TFB_Canvas FilledImg;
int colormap_index;
int colormap_version;
HOT_SPOT NormalHs;
HOT_SPOT MipmapHs;
HOT_SPOT last_scale_hs;
int last_scale;
int last_scale_type;
Color last_fill;
EXTENT extent;
Mutex mutex;
BOOLEAN dirty;
} TFB_Image;
typedef struct tfb_char
{
EXTENT extent;
EXTENT disp;
// Display extent
HOT_SPOT HotSpot;
BYTE* data;
DWORD pitch;
// Pitch is for storing all chars of a page
// in one rectangular pixel matrix
} TFB_Char;
// we do not support paletted format for now
typedef struct tfb_pixelformat
{
int BitsPerPixel;
int BytesPerPixel;
DWORD Rmask, Gmask, Bmask, Amask;
DWORD Rshift, Gshift, Bshift, Ashift;
DWORD Rloss, Gloss, Bloss, Aloss;
} TFB_PixelFormat;
// Drawing commands
void TFB_DrawScreen_Line (int x1, int y1, int x2, int y2, Color color,
DrawMode, SCREEN dest);
void TFB_DrawScreen_Rect (RECT *rect, Color, DrawMode, SCREEN dest);
void TFB_DrawScreen_Image (TFB_Image *img, int x, int y, int scale,
int scaleMode, TFB_ColorMap *, DrawMode, SCREEN dest);
void TFB_DrawScreen_Copy (const RECT *r, SCREEN src, SCREEN dest);
void TFB_DrawScreen_FilledImage (TFB_Image *img, int x, int y, int scale,
int scaleMode, Color, DrawMode, SCREEN dest);
void TFB_DrawScreen_FontChar (TFB_Char *, TFB_Image *backing, int x, int y,
DrawMode, SCREEN dest);
void TFB_DrawScreen_CopyToImage (TFB_Image *img, const RECT *r, SCREEN src);
void TFB_DrawScreen_SetMipmap (TFB_Image *img, TFB_Image *mmimg, int hotx,
int hoty);
void TFB_DrawScreen_DeleteImage (TFB_Image *img);
void TFB_DrawScreen_DeleteData (void *);
void TFB_DrawScreen_WaitForSignal (void);
void TFB_DrawScreen_ReinitVideo (int driver, int flags, int width, int height);
void TFB_DrawScreen_Callback (void (*callback) (void *arg), void *arg);
TFB_Image *TFB_DrawImage_New (TFB_Canvas canvas);
TFB_Image *TFB_DrawImage_CreateForScreen (int w, int h, BOOLEAN withalpha);
TFB_Image *TFB_DrawImage_New_Rotated (TFB_Image *img, int angle);
void TFB_DrawImage_SetMipmap (TFB_Image *img, TFB_Image *mmimg, int hotx,
int hoty);
void TFB_DrawImage_Delete (TFB_Image *image);
void TFB_DrawImage_FixScaling (TFB_Image *image, int target, int type);
BOOLEAN TFB_DrawImage_Intersect (TFB_Image *img1, POINT img1org,
TFB_Image *img2, POINT img2org, const RECT *interRect);
void TFB_DrawImage_CopyRect (TFB_Image *source, const RECT *srcRect,
TFB_Image *target, POINT dstPt);
void TFB_DrawImage_Line (int x1, int y1, int x2, int y2, Color color,
DrawMode, TFB_Image *target);
void TFB_DrawImage_Rect (RECT *rect, Color, DrawMode, TFB_Image *target);
void TFB_DrawImage_Image (TFB_Image *img, int x, int y, int scale,
int scaleMode, TFB_ColorMap *, DrawMode, TFB_Image *target);
void TFB_DrawImage_FilledImage (TFB_Image *img, int x, int y, int scale,
int scaleMode, Color, DrawMode, TFB_Image *target);
void TFB_DrawImage_FontChar (TFB_Char *, TFB_Image *backing, int x, int y,
DrawMode, TFB_Image *target);
TFB_Canvas TFB_DrawCanvas_LoadFromFile (void *dir, const char *fileName);
TFB_Canvas TFB_DrawCanvas_New_TrueColor (int w, int h, BOOLEAN hasalpha);
TFB_Canvas TFB_DrawCanvas_New_ForScreen (int w, int h, BOOLEAN withalpha);
TFB_Canvas TFB_DrawCanvas_New_Paletted (int w, int h, Color palette[256],
int transparent_index);
TFB_Canvas TFB_DrawCanvas_New_ScaleTarget (TFB_Canvas canvas,
TFB_Canvas oldcanvas, int type, int last_type);
TFB_Canvas TFB_DrawCanvas_New_RotationTarget (TFB_Canvas src, int angle);
TFB_Canvas TFB_DrawCanvas_ToScreenFormat (TFB_Canvas canvas);
BOOLEAN TFB_DrawCanvas_IsPaletted (TFB_Canvas canvas);
void TFB_DrawCanvas_Rescale_Nearest (TFB_Canvas src, TFB_Canvas dst,
int scale, HOT_SPOT* src_hs, EXTENT* size, HOT_SPOT* dst_hs);
void TFB_DrawCanvas_Rescale_Bilinear (TFB_Canvas src, TFB_Canvas dst,
int scale, HOT_SPOT* src_hs, EXTENT* size, HOT_SPOT* dst_hs);
void TFB_DrawCanvas_Rescale_Trilinear (TFB_Canvas src, TFB_Canvas mipmap,
TFB_Canvas dst, int scale, HOT_SPOT* src_hs, HOT_SPOT* mm_hs,
EXTENT* size, HOT_SPOT* dst_hs);
void TFB_DrawCanvas_GetScaledExtent (TFB_Canvas src_canvas, HOT_SPOT* src_hs,
TFB_Canvas src_mipmap, HOT_SPOT* mm_hs,
int scale, int type, EXTENT *size, HOT_SPOT *hs);
void TFB_DrawCanvas_Rotate (TFB_Canvas src, TFB_Canvas dst, int angle,
EXTENT size);
void TFB_DrawCanvas_GetRotatedExtent (TFB_Canvas src, int angle, EXTENT *size);
void TFB_DrawCanvas_GetExtent (TFB_Canvas canvas, EXTENT *size);
void TFB_DrawCanvas_SetClipRect (TFB_Canvas canvas, const RECT *clipRect);
void TFB_DrawCanvas_Delete (TFB_Canvas canvas);
void TFB_DrawCanvas_Line (int x1, int y1, int x2, int y2, Color color,
DrawMode, TFB_Canvas target);
void TFB_DrawCanvas_Rect (RECT *rect, Color, DrawMode, TFB_Canvas target);
void TFB_DrawCanvas_Image (TFB_Image *img, int x, int y, int scale,
int scaleMode, TFB_ColorMap *, DrawMode, TFB_Canvas target);
void TFB_DrawCanvas_FilledImage (TFB_Image *img, int x, int y, int scale,
int scaleMode, Color, DrawMode, TFB_Canvas target);
void TFB_DrawCanvas_FontChar (TFB_Char *, TFB_Image *backing, int x, int y,
DrawMode, TFB_Canvas target);
void TFB_DrawCanvas_CopyRect (TFB_Canvas source, const RECT *srcRect,
TFB_Canvas target, POINT dstPt);
BOOLEAN TFB_DrawCanvas_GetFontCharData (TFB_Canvas canvas, BYTE *outData,
unsigned dataPitch);
Color *TFB_DrawCanvas_ExtractPalette (TFB_Canvas canvas);
void TFB_DrawCanvas_SetPalette (TFB_Canvas target, Color palette[256]);
int TFB_DrawCanvas_GetTransparentIndex (TFB_Canvas canvas);
void TFB_DrawCanvas_SetTransparentIndex (TFB_Canvas canvas, int i,
BOOLEAN rleaccel);
BOOLEAN TFB_DrawCanvas_GetTransparentColor (TFB_Canvas canvas,
Color *color);
void TFB_DrawCanvas_SetTransparentColor (TFB_Canvas canvas,
Color color, BOOLEAN rleaccel);
void TFB_DrawCanvas_CopyTransparencyInfo (TFB_Canvas src, TFB_Canvas dst);
void TFB_DrawCanvas_Initialize (void);
void TFB_DrawCanvas_Lock (TFB_Canvas canvas);
void TFB_DrawCanvas_Unlock (TFB_Canvas canvas);
void TFB_DrawCanvas_GetScreenFormat (TFB_PixelFormat *fmt);
int TFB_DrawCanvas_GetStride (TFB_Canvas canvas);
void *TFB_DrawCanvas_GetLine (TFB_Canvas canvas, int line);
Color TFB_DrawCanvas_GetPixel (TFB_Canvas canvas, int x, int y);
BOOLEAN TFB_DrawCanvas_Intersect (TFB_Canvas canvas1, POINT c1org,
TFB_Canvas canvas2, POINT c2org, const RECT *interRect);
BOOLEAN TFB_DrawCanvas_GetPixelColors (TFB_Canvas, Color *pixels,
int width, int height);
BOOLEAN TFB_DrawCanvas_SetPixelColors (TFB_Canvas, const Color *pixels,
int width, int height);
BOOLEAN TFB_DrawCanvas_GetPixelIndexes (TFB_Canvas, BYTE *data,
int width, int height);
BOOLEAN TFB_DrawCanvas_SetPixelIndexes (TFB_Canvas, const BYTE *data,
int width, int height);
const char *TFB_DrawCanvas_GetError (void);
TFB_Canvas TFB_GetScreenCanvas (SCREEN screen);
#endif

View File

@@ -0,0 +1,237 @@
// Copyright Michael Martin, 2003
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* The original Primitive routines do various elaborate checks to
* ensure we're within bounds for the clipping. Since clipping is
* handled by the underlying TFB_Canvas implementation, we need not
* worry about this. */
#include "gfxintrn.h"
#include "gfx_common.h"
#include "tfb_draw.h"
#include "tfb_prim.h"
#include "cmap.h"
#include "libs/log.h"
void
TFB_Prim_Point (POINT *p, Color color, DrawMode mode, POINT ctxOrigin)
{
RECT r;
// The caller must scale the origin!
r.corner.x = p->x + ctxOrigin.x;
r.corner.y = p->y + ctxOrigin.y;
r.extent.width = r.extent.height = 1;
if (_CurFramePtr->Type == SCREEN_DRAWABLE)
TFB_DrawScreen_Rect (&r, color, mode, TFB_SCREEN_MAIN);
else
TFB_DrawImage_Rect (&r, color, mode, _CurFramePtr->image);
}
void
TFB_Prim_Rect (RECT *r, Color color, DrawMode mode, POINT ctxOrigin)
{
RECT arm;
int gscale;
// XXX: Rect prim scaling is currently unused
// We scale the rect size just to be consistent with stamp prim,
// which does same. The caller must scale the origin!
gscale = GetGraphicScale ();
arm = *r;
arm.extent.width = r->extent.width;
arm.extent.height = 1;
TFB_Prim_FillRect (&arm, color, mode, ctxOrigin);
arm.extent.height = r->extent.height;
arm.extent.width = 1;
TFB_Prim_FillRect (&arm, color, mode, ctxOrigin);
// rounding error correction here
arm.corner.x += ((r->extent.width * gscale + (GSCALE_IDENTITY >> 1))
/ GSCALE_IDENTITY) - 1;
TFB_Prim_FillRect (&arm, color, mode, ctxOrigin);
arm.corner.x = r->corner.x;
arm.corner.y += ((r->extent.height * gscale + (GSCALE_IDENTITY >> 1))
/ GSCALE_IDENTITY) - 1;
arm.extent.width = r->extent.width;
arm.extent.height = 1;
TFB_Prim_FillRect (&arm, color, mode, ctxOrigin);
}
void
TFB_Prim_FillRect (RECT *r, Color color, DrawMode mode, POINT ctxOrigin)
{
RECT rect;
int gscale;
rect.corner.x = r->corner.x + ctxOrigin.x;
rect.corner.y = r->corner.y + ctxOrigin.y;
rect.extent.width = r->extent.width;
rect.extent.height = r->extent.height;
// XXX: Rect prim scaling is currently unused
// We scale the rect size just to be consistent with stamp prim,
// which does same. The caller must scale the origin!
gscale = GetGraphicScale ();
if (gscale != GSCALE_IDENTITY)
{ // rounding error correction here
rect.extent.width = (rect.extent.width * gscale
+ (GSCALE_IDENTITY >> 1)) / GSCALE_IDENTITY;
rect.extent.height = (rect.extent.height * gscale
+ (GSCALE_IDENTITY >> 1)) / GSCALE_IDENTITY;
}
if (_CurFramePtr->Type == SCREEN_DRAWABLE)
TFB_DrawScreen_Rect (&rect, color, mode, TFB_SCREEN_MAIN);
else
TFB_DrawImage_Rect (&rect, color, mode, _CurFramePtr->image);
}
void
TFB_Prim_Line (LINE *line, Color color, DrawMode mode, POINT ctxOrigin)
{
int x1, y1, x2, y2;
// The caller must scale the origins!
x1=line->first.x + ctxOrigin.x;
y1=line->first.y + ctxOrigin.y;
x2=line->second.x + ctxOrigin.x;
y2=line->second.y + ctxOrigin.y;
if (_CurFramePtr->Type == SCREEN_DRAWABLE)
TFB_DrawScreen_Line (x1, y1, x2, y2, color, mode, TFB_SCREEN_MAIN);
else
TFB_DrawImage_Line (x1, y1, x2, y2, color, mode, _CurFramePtr->image);
}
void
TFB_Prim_Stamp (STAMP *stmp, DrawMode mode, POINT ctxOrigin)
{
int x, y;
FRAME SrcFramePtr;
TFB_Image *img;
TFB_ColorMap *cmap = NULL;
SrcFramePtr = stmp->frame;
if (!SrcFramePtr)
{
log_add (log_Warning, "TFB_Prim_Stamp: Tried to draw a NULL frame"
" (Stamp address = %p)", stmp);
return;
}
img = SrcFramePtr->image;
if (!img)
{
log_add (log_Warning, "Non-existent image to TFB_Prim_Stamp()");
return;
}
LockMutex (img->mutex);
img->NormalHs = SrcFramePtr->HotSpot;
// We scale the image size here, but the caller must scale the origin!
x = stmp->origin.x + ctxOrigin.x;
y = stmp->origin.y + ctxOrigin.y;
if (TFB_DrawCanvas_IsPaletted(img->NormalImg) && img->colormap_index != -1)
{
// returned cmap is addrefed, must release later
cmap = TFB_GetColorMap (img->colormap_index);
}
UnlockMutex (img->mutex);
if (_CurFramePtr->Type == SCREEN_DRAWABLE)
{
TFB_DrawScreen_Image (img, x, y, GetGraphicScale (),
GetGraphicScaleMode (), cmap, mode, TFB_SCREEN_MAIN);
}
else
{
TFB_DrawImage_Image (img, x, y, GetGraphicScale (),
GetGraphicScaleMode (), cmap, mode, _CurFramePtr->image);
}
}
void
TFB_Prim_StampFill (STAMP *stmp, Color color, DrawMode mode, POINT ctxOrigin)
{
int x, y;
FRAME SrcFramePtr;
TFB_Image *img;
SrcFramePtr = stmp->frame;
if (!SrcFramePtr)
{
log_add (log_Warning, "TFB_Prim_StampFill: Tried to draw a NULL frame"
" (Stamp address = %p)", stmp);
return;
}
img = SrcFramePtr->image;
if (!img)
{
log_add (log_Warning, "Non-existent image to TFB_Prim_StampFill()");
return;
}
LockMutex (img->mutex);
img->NormalHs = SrcFramePtr->HotSpot;
// We scale the image size here, but the caller must scale the origin!
x = stmp->origin.x + ctxOrigin.x;
y = stmp->origin.y + ctxOrigin.y;
UnlockMutex (img->mutex);
if (_CurFramePtr->Type == SCREEN_DRAWABLE)
{
TFB_DrawScreen_FilledImage (img, x, y, GetGraphicScale (),
GetGraphicScaleMode (), color, mode, TFB_SCREEN_MAIN);
}
else
{
TFB_DrawImage_FilledImage (img, x, y, GetGraphicScale (),
GetGraphicScaleMode (), color, mode, _CurFramePtr->image);
}
}
void
TFB_Prim_FontChar (POINT charOrigin, TFB_Char *fontChar, TFB_Image *backing,
DrawMode mode, POINT ctxOrigin)
{
int x, y;
// Text prim does not scale
x = charOrigin.x + ctxOrigin.x;
y = charOrigin.y + ctxOrigin.y;
if (_CurFramePtr->Type == SCREEN_DRAWABLE)
{
TFB_DrawScreen_FontChar (fontChar, backing, x, y, mode,
TFB_SCREEN_MAIN);
}
else
{
TFB_DrawImage_FontChar (fontChar, backing, x, y, mode,
_CurFramePtr->image);
}
}
// Text rendering is in font.c, under the name _text_blt

Some files were not shown because too many files have changed in this diff Show More