Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a477b137e7 | ||
|
|
ba1ae34855 | ||
|
|
bc047cd89e | ||
|
|
863bb2a34b | ||
|
|
14c3044acf | ||
|
|
4b4d2b7819 | ||
|
|
9e1f448e0f | ||
|
|
457f5d04e4 | ||
|
|
999419dfe1 | ||
|
|
be6b472472 | ||
|
|
aa078f4d46 | ||
|
|
dbaa6eea2c | ||
|
|
a82b67faa4 | ||
|
|
efe46e2864 | ||
|
|
60d639f3a7 | ||
|
|
ddaefafa1a | ||
|
|
9f764018d3 | ||
|
|
6200e5ed56 | ||
|
|
be245523c9 | ||
|
|
11a00a6e74 | ||
|
|
af96d52c5a | ||
|
|
5a4f9f4dc4 | ||
|
|
df4ec9794a | ||
|
|
db9f2c0203 | ||
|
|
88fcd48481 | ||
|
|
5e295c06b2 | ||
|
|
4dd7a3af39 | ||
|
|
1aab8f6619 | ||
|
|
27ec4d5567 | ||
|
|
a64b1288a5 | ||
|
|
77907499a4 | ||
|
|
cf00e62c5a | ||
|
|
5086a5c82f | ||
|
|
b84ed7496b | ||
|
|
b4bd8bd4b7 | ||
|
|
c1e7496d21 | ||
|
|
674831b370 | ||
|
|
8cc2272b50 | ||
|
|
2e2d8c143c | ||
|
|
a8ca88640b | ||
|
|
9bdfb26f7e |
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -10,3 +10,6 @@
|
|||||||
[submodule "external/lodepng"]
|
[submodule "external/lodepng"]
|
||||||
path = external/lodepng
|
path = external/lodepng
|
||||||
url = https://github.com/lvandeve/lodepng
|
url = https://github.com/lvandeve/lodepng
|
||||||
|
[submodule "external/coveralls-cmake"]
|
||||||
|
path = external/coveralls-cmake
|
||||||
|
url = https://github.com/Godzil/coveralls-cmake.git
|
||||||
|
|||||||
36
.travis.yml
Normal file
36
.travis.yml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
dist: bionic
|
||||||
|
language: c
|
||||||
|
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- lcov
|
||||||
|
|
||||||
|
os:
|
||||||
|
- linux
|
||||||
|
- osx
|
||||||
|
compiler:
|
||||||
|
- clang
|
||||||
|
- gcc
|
||||||
|
|
||||||
|
script:
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- cmake ..
|
||||||
|
- make
|
||||||
|
- make test
|
||||||
|
- ./tests/testMyRays
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
include:
|
||||||
|
- stage: "Coverage"
|
||||||
|
os: linux
|
||||||
|
compiler: gcc
|
||||||
|
script:
|
||||||
|
- mkdir coverage
|
||||||
|
- cd coverage
|
||||||
|
- cmake .. -DCOVERALLS=ON -DCMAKE_BUILD_TYPE=Debug
|
||||||
|
- cmake --build .
|
||||||
|
- cmake --build . --target coveralls
|
||||||
|
after_success:
|
||||||
|
- bash <(curl -s https://codecov.io/bash)
|
||||||
@@ -6,19 +6,36 @@ project(DoRayMe)
|
|||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
|
|
||||||
|
option(COVERALLS "Generate coveralls data" OFF)
|
||||||
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/external/coveralls-cmake/cmake)
|
||||||
|
|
||||||
|
option(PACKAGE_TESTS "Build the tests" ON)
|
||||||
|
|
||||||
|
if (COVERALLS)
|
||||||
|
include(Coveralls)
|
||||||
|
coveralls_turn_on_coverage()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
# LodePNG don't make a .a or .so, so let's build a library here
|
# LodePNG don't make a .a or .so, so let's build a library here
|
||||||
add_library(LodePNG STATIC)
|
add_library(LodePNG STATIC)
|
||||||
set(LODEPNG_INCLUDE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR}/external/lodepng)
|
set(LODEPNG_INCLUDE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR}/external/lodepng)
|
||||||
target_sources(LodePNG PRIVATE external/lodepng/lodepng.cpp external/lodepng/lodepng.h)
|
target_sources(LodePNG PRIVATE external/lodepng/lodepng.cpp external/lodepng/lodepng.h)
|
||||||
|
|
||||||
|
|
||||||
# Main app
|
# Main app
|
||||||
add_subdirectory(source)
|
add_subdirectory(source)
|
||||||
|
|
||||||
option(PACKAGE_TESTS "Build the tests" ON)
|
if(PACKAGE_TESTS OR COVERALLS)
|
||||||
if(PACKAGE_TESTS)
|
|
||||||
enable_testing()
|
enable_testing()
|
||||||
include(GoogleTest)
|
include(GoogleTest)
|
||||||
add_subdirectory("${PROJECT_SOURCE_DIR}/external/googletest" "external/googletest")
|
add_subdirectory("${PROJECT_SOURCE_DIR}/external/googletest" "external/googletest")
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (COVERALLS)
|
||||||
|
# Create the coveralls target.
|
||||||
|
coveralls_setup(
|
||||||
|
"${COVERAGE_SRCS}" # The source files.
|
||||||
|
ON # If we should upload.
|
||||||
|
) # (Optional) Alternate project cmake module path.
|
||||||
|
endif()
|
||||||
340
COPYING
Normal file
340
COPYING
Normal file
@@ -0,0 +1,340 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
|
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Library General
|
||||||
|
Public License instead of this License.
|
||||||
14
LICENSE
Normal file
14
LICENSE
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
Copyright (C) 2020 Manoel <Godzil> Trapier
|
||||||
|
|
||||||
|
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; version 2 of the License.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
[](https://codecov.io/gh/Godzil/DoRayMe) [](https://www.codacy.com/manual/Godzil/DoRayMe?utm_source=github.com&utm_medium=referral&utm_content=Godzil/DoRayMe&utm_campaign=Badge_Grade) [](https://coveralls.io/github/Godzil/DoRayMe?branch=master) [](https://travis-ci.org/Godzil/DoRayMe)
|
||||||
|
|
||||||
|
DoRayMe
|
||||||
|
=======
|
||||||
|
|
||||||
|
A Quick and dirty raytracer.
|
||||||
1
external/coveralls-cmake
vendored
Submodule
1
external/coveralls-cmake
vendored
Submodule
Submodule external/coveralls-cmake added at 01e3f08d60
@@ -3,13 +3,10 @@
|
|||||||
# First most is build as a library
|
# First most is build as a library
|
||||||
add_library(rayonnement STATIC)
|
add_library(rayonnement STATIC)
|
||||||
|
|
||||||
set(RAY_HEADERS include/tuple.h include/math_helper.h include/colour.h include/canvas.h
|
file(GLOB RAY_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h)
|
||||||
include/matrix.h include/transformation.h include/intersect.h include/intersection.h
|
|
||||||
include/light.h include/material.h
|
file(GLOB RAY_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/shapes/*.cpp
|
||||||
include/object.h include/ray.h include/sphere.h)
|
${CMAKE_CURRENT_SOURCE_DIR}/worldbuilder/*.cpp)
|
||||||
set(RAY_SOURCES tuple.cpp math_helper.cpp colour.cpp canvas.cpp matrix.cpp transformation.cpp intersect.cpp
|
|
||||||
objects/light.cpp objects/material.cpp
|
|
||||||
objects/object.cpp objects/ray.cpp objects/sphere.cpp)
|
|
||||||
|
|
||||||
target_include_directories(rayonnement PUBLIC include)
|
target_include_directories(rayonnement PUBLIC include)
|
||||||
target_sources(rayonnement PRIVATE ${RAY_HEADERS} ${RAY_SOURCES})
|
target_sources(rayonnement PRIVATE ${RAY_HEADERS} ${RAY_SOURCES})
|
||||||
@@ -19,3 +16,7 @@ target_link_libraries(rayonnement LodePNG)
|
|||||||
add_executable(dorayme main.cpp)
|
add_executable(dorayme main.cpp)
|
||||||
target_include_directories(rayonnement PUBLIC include ${LODEPNG_INCLUDE_FOLDER})
|
target_include_directories(rayonnement PUBLIC include ${LODEPNG_INCLUDE_FOLDER})
|
||||||
target_link_libraries(dorayme rayonnement)
|
target_link_libraries(dorayme rayonnement)
|
||||||
|
|
||||||
|
if (COVERALLS)
|
||||||
|
set(COVERAGE_SRCS ${RAY_HEADERS} ${RAY_SOURCES} ${COVERAGE_SRCS} PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
74
source/camera.cpp
Normal file
74
source/camera.cpp
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Camera implementation
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <matrix.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <ray.h>
|
||||||
|
#include <camera.h>
|
||||||
|
|
||||||
|
Camera::Camera(uint32_t hsize, uint32_t vsize, double fov) : verticalSize(vsize), horizontalSize(hsize), fieldOfView(fov)
|
||||||
|
{
|
||||||
|
double aspectRatio = (double)hsize / (double)vsize;
|
||||||
|
double halfView = tan(fov / 2.0);
|
||||||
|
|
||||||
|
if (aspectRatio >= 1)
|
||||||
|
{
|
||||||
|
this->halfWidth = halfView;
|
||||||
|
this->halfHeight = halfView / aspectRatio;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->halfWidth = halfView * aspectRatio;
|
||||||
|
this->halfHeight = halfView;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->pixelSize = (this->halfWidth * 2) / this->horizontalSize;
|
||||||
|
|
||||||
|
this->setTransform(Matrix4().identity());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera::setTransform(Matrix transform)
|
||||||
|
{
|
||||||
|
this->transformMatrix = transform;
|
||||||
|
this->inverseTransform = transform.inverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ray Camera::rayForPixel(uint32_t pixelX, uint32_t pixelY)
|
||||||
|
{
|
||||||
|
double xOffset = ((double)pixelX + 0.5) * this->pixelSize;
|
||||||
|
double yOffset = ((double)pixelY + 0.5) * this->pixelSize;
|
||||||
|
|
||||||
|
double worldX = this->halfWidth - xOffset;
|
||||||
|
double worldY = this->halfHeight - yOffset;
|
||||||
|
|
||||||
|
Tuple pixel = this->inverseTransform * Point(worldX, worldY, -1);
|
||||||
|
Tuple origin = this->inverseTransform * Point(0, 0, 0);
|
||||||
|
Tuple direction = (pixel - origin).normalise();
|
||||||
|
|
||||||
|
return Ray(origin, direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
Canvas Camera::render(World world)
|
||||||
|
{
|
||||||
|
uint32_t x, y;
|
||||||
|
Canvas image = Canvas(this->horizontalSize, this->verticalSize);
|
||||||
|
|
||||||
|
for(y = 0; y < this->verticalSize; y++)
|
||||||
|
{
|
||||||
|
for(x = 0; x < this->horizontalSize; x++)
|
||||||
|
{
|
||||||
|
Ray r = this->rayForPixel(x, y);
|
||||||
|
Tuple colour = world.colourAt(r);
|
||||||
|
image.putPixel(x, y, colour);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
@@ -22,6 +22,24 @@ Canvas::Canvas(uint32_t width, uint32_t height) : width(width), height(height)
|
|||||||
this->stride = BytePP * width;
|
this->stride = BytePP * width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Canvas::Canvas(const Canvas &b)
|
||||||
|
{
|
||||||
|
this->width = b.width;
|
||||||
|
this->height = b.height;
|
||||||
|
this->stride = b.stride;
|
||||||
|
this->bitmap = (uint8_t *)calloc(4, b.width * b.height);
|
||||||
|
memcpy(this->bitmap, b.bitmap, 4 * b.width * b.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
Canvas::Canvas(const Canvas *b)
|
||||||
|
{
|
||||||
|
this->width = b->width;
|
||||||
|
this->height = b->height;
|
||||||
|
this->stride = b->stride;
|
||||||
|
this->bitmap = (uint8_t *)calloc(4, b->width * b->height);
|
||||||
|
memcpy(this->bitmap, b->bitmap, 4 * b->width * b->height);
|
||||||
|
}
|
||||||
|
|
||||||
Canvas::~Canvas()
|
Canvas::~Canvas()
|
||||||
{
|
{
|
||||||
if (this->bitmap != nullptr)
|
if (this->bitmap != nullptr)
|
||||||
@@ -30,28 +48,23 @@ Canvas::~Canvas()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::put_pixel(uint32_t x, uint32_t y, Colour c)
|
void Canvas::putPixel(uint32_t x, uint32_t y, Tuple colour)
|
||||||
{
|
{
|
||||||
uint32_t offset = y * this->stride + x * BytePP;
|
uint32_t offset = y * this->stride + x * BytePP;
|
||||||
this->bitmap[offset + 0] = MAX(MIN(c.red() * 255, 255), 0);
|
this->bitmap[offset + 0] = MAX(MIN(colour.x * 255, 255), 0);
|
||||||
this->bitmap[offset + 1] = MAX(MIN(c.green() * 255, 255), 0);
|
this->bitmap[offset + 1] = MAX(MIN(colour.y * 255, 255), 0);
|
||||||
this->bitmap[offset + 2] = MAX(MIN(c.blue() * 255, 255), 0);
|
this->bitmap[offset + 2] = MAX(MIN(colour.z * 255, 255), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Colour Canvas::get_pixel(uint32_t x, uint32_t y)
|
Colour Canvas::getPixel(uint32_t x, uint32_t y)
|
||||||
{
|
{
|
||||||
uint32_t offset = y * this->stride + x * BytePP;
|
uint32_t offset = y * this->stride + x * BytePP;
|
||||||
return Colour(this->bitmap[offset + 0] / 255, this->bitmap[offset + 1] / 255, this->bitmap[offset + 2] / 255);
|
return Colour(this->bitmap[offset + 0] / 255.0, this->bitmap[offset + 1] / 255.0, this->bitmap[offset + 2] / 255.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Canvas::SaveAsPNG(const char *filename)
|
bool Canvas::SaveAsPNG(const char *filename)
|
||||||
{
|
{
|
||||||
uint32_t ret = lodepng_encode24_file(filename, this->bitmap, this->width, this->height);
|
uint32_t ret = lodepng_encode24_file(filename, this->bitmap, this->width, this->height);
|
||||||
|
|
||||||
if (ret > 0)
|
|
||||||
{
|
|
||||||
printf("lodepng_encode_file returned %d!\n", ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret == 0;
|
return ret == 0;
|
||||||
}
|
}
|
||||||
38
source/include/camera.h
Normal file
38
source/include/camera.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Camera header
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef DORAYME_CAMERA_H
|
||||||
|
#define DORAYME_CAMERA_H
|
||||||
|
|
||||||
|
#include <matrix.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <ray.h>
|
||||||
|
#include <canvas.h>
|
||||||
|
#include <world.h>
|
||||||
|
|
||||||
|
class Camera
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
double halfWidth;
|
||||||
|
double halfHeight;
|
||||||
|
public:
|
||||||
|
uint32_t verticalSize;
|
||||||
|
uint32_t horizontalSize;
|
||||||
|
double fieldOfView;
|
||||||
|
double pixelSize;
|
||||||
|
Matrix transformMatrix;
|
||||||
|
Matrix inverseTransform;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Camera(uint32_t hsize, uint32_t vsize, double fov);
|
||||||
|
void setTransform(Matrix transform);
|
||||||
|
Ray rayForPixel(uint32_t pixelX, uint32_t pixelY);
|
||||||
|
Canvas render(World w);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DORAYME_CAMERA_H */
|
||||||
@@ -21,10 +21,12 @@ public:
|
|||||||
uint32_t width, height;
|
uint32_t width, height;
|
||||||
|
|
||||||
Canvas(uint32_t width, uint32_t height);
|
Canvas(uint32_t width, uint32_t height);
|
||||||
|
Canvas(const Canvas *c);
|
||||||
|
Canvas(const Canvas &c);
|
||||||
~Canvas();
|
~Canvas();
|
||||||
|
|
||||||
void put_pixel(uint32_t x, uint32_t y, Colour c);
|
void putPixel(uint32_t x, uint32_t y, Tuple c);
|
||||||
Colour get_pixel(uint32_t x, uint32_t y);
|
Colour getPixel(uint32_t x, uint32_t y);
|
||||||
|
|
||||||
bool SaveAsPNG(const char *filename);
|
bool SaveAsPNG(const char *filename);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,15 +15,16 @@
|
|||||||
class Intersect
|
class Intersect
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
Intersection *list;
|
Intersection **list;
|
||||||
uint32_t num;
|
uint32_t num;
|
||||||
uint32_t allocated;
|
uint32_t allocated;
|
||||||
public:
|
public:
|
||||||
Intersect();
|
Intersect();
|
||||||
|
~Intersect();
|
||||||
void add(Intersection i);
|
void add(Intersection i);
|
||||||
int count() { return this->num; };
|
int count() { return this->num; };
|
||||||
Intersection operator[](const int p) { return this->list[p]; }
|
Intersection operator[](const int p) { return *this->list[p]; }
|
||||||
Intersection hit();
|
Intersection hit();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //DORAYME_INTERSECT_H
|
#endif /* DORAYME_INTERSECT_H */
|
||||||
|
|||||||
@@ -10,20 +10,36 @@
|
|||||||
#define DORAYME_INTERSECTION_H
|
#define DORAYME_INTERSECTION_H
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <ray.h>
|
||||||
|
|
||||||
class Object;
|
class Shape;
|
||||||
|
|
||||||
|
struct Computation
|
||||||
|
{
|
||||||
|
Computation(Shape *object, double t, Tuple point, Tuple eyev, Tuple normalv, bool inside) :
|
||||||
|
object(object), t(t), hitPoint(point), eyeVector(eyev), normalVector(normalv), inside(inside) { };
|
||||||
|
Shape *object;
|
||||||
|
double t;
|
||||||
|
Tuple hitPoint;
|
||||||
|
Tuple eyeVector;
|
||||||
|
Tuple normalVector;
|
||||||
|
|
||||||
|
bool inside;
|
||||||
|
};
|
||||||
|
|
||||||
class Intersection
|
class Intersection
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
double t;
|
double t;
|
||||||
Object *object;
|
Shape *object;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Intersection(double t, Object *object) : t(t), object(object) { };
|
Intersection(double t, Shape *object) : t(t), object(object) { };
|
||||||
bool nothing() { return (this->object == nullptr); };
|
bool nothing() { return (this->object == nullptr); };
|
||||||
|
|
||||||
|
Computation prepareComputation(Ray r);
|
||||||
|
|
||||||
bool operator==(const Intersection &b) const { return ((this->t == b.t) && (this->object == b.object)); };
|
bool operator==(const Intersection &b) const { return ((this->t == b.t) && (this->object == b.object)); };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //DORAYME_INTERSECTION_H
|
#endif /* DORAYME_INTERSECTION_H */
|
||||||
|
|||||||
@@ -27,6 +27,10 @@ public:
|
|||||||
public:
|
public:
|
||||||
Light(LightType type = POINT_LIGHT, Tuple position=Point(0, 0, 0),
|
Light(LightType type = POINT_LIGHT, Tuple position=Point(0, 0, 0),
|
||||||
Colour intensity=Colour(1, 1, 1)) : type(type), position(position), intensity(intensity) { };
|
Colour intensity=Colour(1, 1, 1)) : type(type), position(position), intensity(intensity) { };
|
||||||
|
|
||||||
|
bool operator==(const Light &b) const { return this->intensity == b.intensity &&
|
||||||
|
this->position == b.position &&
|
||||||
|
this->type == b.type; };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //DORAYME_LIGHT_H
|
#endif /* DORAYME_LIGHT_H */
|
||||||
|
|||||||
@@ -34,4 +34,4 @@ public:
|
|||||||
(this->colour == b.colour); };
|
(this->colour == b.colour); };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //DORAYME_MATERIAL_H
|
#endif /* DORAYME_MATERIAL_H */
|
||||||
|
|||||||
@@ -17,4 +17,4 @@ bool double_equal(double a, double b);
|
|||||||
|
|
||||||
double deg_to_rad(double deg);
|
double deg_to_rad(double deg);
|
||||||
|
|
||||||
#endif //DORAYME_MATH_HELPER_H
|
#endif /* DORAYME_MATH_HELPER_H */
|
||||||
|
|||||||
@@ -11,6 +11,14 @@
|
|||||||
|
|
||||||
#include <tuple.h>
|
#include <tuple.h>
|
||||||
|
|
||||||
|
/* Some **** linux distro seems to define "minor" as a macro
|
||||||
|
* and wreak havoc.
|
||||||
|
* Let's make sure we are clean here
|
||||||
|
*/
|
||||||
|
#ifdef minor
|
||||||
|
#undef minor
|
||||||
|
#endif
|
||||||
|
|
||||||
class Matrix
|
class Matrix
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -22,4 +22,4 @@ public:
|
|||||||
Tuple position(double t) { return this->origin + this->direction * t; };
|
Tuple position(double t) { return this->origin + this->direction * t; };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //DORAYME_RAY_H
|
#endif /* DORAYME_RAY_H */
|
||||||
|
|||||||
@@ -6,10 +6,10 @@
|
|||||||
* Copyright (c) 2020 986-Studio.
|
* Copyright (c) 2020 986-Studio.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#ifndef DORAYME_OBJECT_H
|
#ifndef DORAYME_SHAPE_H
|
||||||
#define DORAYME_OBJECT_H
|
#define DORAYME_SHAPE_H
|
||||||
|
|
||||||
class Object;
|
class Shape;
|
||||||
|
|
||||||
#include <ray.h>
|
#include <ray.h>
|
||||||
#include <tuple.h>
|
#include <tuple.h>
|
||||||
@@ -17,16 +17,25 @@ class Object;
|
|||||||
#include <intersect.h>
|
#include <intersect.h>
|
||||||
#include <material.h>
|
#include <material.h>
|
||||||
|
|
||||||
/* Base class for all object that can be presented in the world */
|
enum ShapeType
|
||||||
class Object
|
|
||||||
{
|
{
|
||||||
|
SHAPE_NONE,
|
||||||
|
SHAPE_SPHERE,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Base class for all object that can be presented in the world */
|
||||||
|
class Shape
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
ShapeType type;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Matrix transformMatrix;
|
Matrix transformMatrix;
|
||||||
Matrix inverseTransform;
|
Matrix inverseTransform;
|
||||||
Material material;
|
Material material;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Object();
|
Shape(ShapeType = SHAPE_NONE);
|
||||||
|
|
||||||
virtual Intersect intersect(Ray r);
|
virtual Intersect intersect(Ray r);
|
||||||
virtual Tuple normalAt(Tuple point);
|
virtual Tuple normalAt(Tuple point);
|
||||||
@@ -35,6 +44,11 @@ public:
|
|||||||
void setMaterial(Material material) { this->material = material; };
|
void setMaterial(Material material) { this->material = material; };
|
||||||
Ray transform(Ray r) { return Ray(this->transformMatrix * r.origin, this->transformMatrix * r.direction); };
|
Ray transform(Ray r) { return Ray(this->transformMatrix * r.origin, this->transformMatrix * r.direction); };
|
||||||
Ray invTransform(Ray r) { return Ray(this->inverseTransform * r.origin, this->inverseTransform * r.direction); };
|
Ray invTransform(Ray r) { return Ray(this->inverseTransform * r.origin, this->inverseTransform * r.direction); };
|
||||||
|
|
||||||
|
bool operator==(const Shape &b) const { return this->material == b.material &&
|
||||||
|
this->type == b.type &&
|
||||||
|
this->transformMatrix == b.transformMatrix; };
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //DORAYME_OBJECT_H
|
#endif /* DORAYME_SHAPE_H */
|
||||||
@@ -9,16 +9,17 @@
|
|||||||
#ifndef DORAYME_SPHERE_H
|
#ifndef DORAYME_SPHERE_H
|
||||||
#define DORAYME_SPHERE_H
|
#define DORAYME_SPHERE_H
|
||||||
|
|
||||||
#include <object.h>
|
#include <shape.h>
|
||||||
#include <ray.h>
|
#include <ray.h>
|
||||||
#include <intersect.h>
|
#include <intersect.h>
|
||||||
|
|
||||||
class Sphere : public Object
|
class Sphere : public Shape
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
Sphere() : Shape(SHAPE_SPHERE) { };
|
||||||
/* All sphere are at (0, 0, 0) and radius 1 in the object space */
|
/* All sphere are at (0, 0, 0) and radius 1 in the object space */
|
||||||
virtual Intersect intersect(Ray r);
|
virtual Intersect intersect(Ray r);
|
||||||
virtual Tuple normalAt(Tuple point);
|
virtual Tuple normalAt(Tuple point);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //DORAYME_SPHERE_H
|
#endif /* DORAYME_SPHERE_H */
|
||||||
|
|||||||
@@ -15,10 +15,12 @@ Matrix translation(double x, double y, double z);
|
|||||||
|
|
||||||
Matrix scaling(double x, double y, double z);
|
Matrix scaling(double x, double y, double z);
|
||||||
|
|
||||||
Matrix rotation_x(double angle);
|
Matrix rotationX(double angle);
|
||||||
Matrix rotation_y(double angle);
|
Matrix rotationY(double angle);
|
||||||
Matrix rotation_z(double angle);
|
Matrix rotationZ(double angle);
|
||||||
|
|
||||||
Matrix shearing(double Xy, double Xx, double Yx, double Yz, double Zx, double Zy);
|
Matrix shearing(double Xy, double Xx, double Yx, double Yz, double Zx, double Zy);
|
||||||
|
|
||||||
|
Matrix viewTransform(Tuple from, Tuple to, Tuple up);
|
||||||
|
|
||||||
#endif /* DORAYME_TRANSFORMATION_H */
|
#endif /* DORAYME_TRANSFORMATION_H */
|
||||||
51
source/include/world.h
Normal file
51
source/include/world.h
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* World header
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef DORAYME_WORLD_H
|
||||||
|
#define DORAYME_WORLD_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <light.h>
|
||||||
|
#include <shape.h>
|
||||||
|
#include <intersect.h>
|
||||||
|
#include <ray.h>
|
||||||
|
|
||||||
|
class World
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
uint32_t objectCount;
|
||||||
|
uint32_t lightCount;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t allocatedObjectCount;
|
||||||
|
uint32_t allocatedLightCount;
|
||||||
|
|
||||||
|
Light* *lightList;
|
||||||
|
Shape* *objectList;
|
||||||
|
|
||||||
|
public:
|
||||||
|
World();
|
||||||
|
~World();
|
||||||
|
|
||||||
|
void addObject(Shape *s);
|
||||||
|
void addLight(Light *l);
|
||||||
|
|
||||||
|
/* Some debug things */
|
||||||
|
bool lightIsIn(Light &l);
|
||||||
|
bool objectIsIn(Shape &s);
|
||||||
|
|
||||||
|
Shape *getObject(int i) { return this->objectList[i]; };
|
||||||
|
|
||||||
|
Tuple shadeHit(Computation comps);;
|
||||||
|
Tuple colourAt(Ray r);
|
||||||
|
|
||||||
|
Intersect intersect(Ray r);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DORAYME_WORLD_H */
|
||||||
29
source/include/worldbuilder.h
Normal file
29
source/include/worldbuilder.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Worldbuilder header
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef DORAYME_WORLDBUILDER_H
|
||||||
|
#define DORAYME_WORLDBUILDER_H
|
||||||
|
|
||||||
|
#include <world.h>
|
||||||
|
|
||||||
|
/* Let's keep a single header for now, will see later */
|
||||||
|
|
||||||
|
class DefaultWorld : public World
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DefaultWorld();
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Not implemented yet */
|
||||||
|
class Hw3File : public World
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Hw3File(const char *filename);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DORAYME_WORLDBUILDER_H */
|
||||||
@@ -17,38 +17,50 @@
|
|||||||
Intersect::Intersect()
|
Intersect::Intersect()
|
||||||
{
|
{
|
||||||
this->allocated = MIN_ALLOC;
|
this->allocated = MIN_ALLOC;
|
||||||
this->list = (Intersection *)calloc(sizeof(Object *), MIN_ALLOC);
|
this->list = (Intersection **)calloc(sizeof(Intersection *), MIN_ALLOC);
|
||||||
this->num = 0;
|
this->num = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Intersect::~Intersect()
|
||||||
|
{
|
||||||
|
/* Free stuff */
|
||||||
|
}
|
||||||
|
|
||||||
void Intersect::add(Intersection i)
|
void Intersect::add(Intersection i)
|
||||||
{
|
{
|
||||||
if ((this->num + 1) < this->allocated)
|
Intersection *x;
|
||||||
|
int j, k;
|
||||||
|
|
||||||
|
if ((this->num + 1) > this->allocated)
|
||||||
{
|
{
|
||||||
this->allocated *= 2;
|
this->allocated *= 2;
|
||||||
this->list = (Intersection *)realloc(this->list, sizeof(Object *) * this->allocated);
|
this->list = (Intersection **)realloc(this->list, sizeof(Intersection *) * this->allocated);
|
||||||
|
}
|
||||||
|
this->list[this->num++] = new Intersection(i.t, i.object);
|
||||||
|
|
||||||
|
/* Now sort.. */
|
||||||
|
for(j = 1; j < (this->num); j++)
|
||||||
|
{
|
||||||
|
x = this->list[j];
|
||||||
|
k = j;
|
||||||
|
while( (k > 0) && (this->list[k - 1]->t) > x->t )
|
||||||
|
{
|
||||||
|
this->list[k] = this->list[k - 1];
|
||||||
|
k--;
|
||||||
|
}
|
||||||
|
this->list[k] = x;
|
||||||
}
|
}
|
||||||
this->list[this->num++] = i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Intersection Intersect::hit()
|
Intersection Intersect::hit()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
double minHit = DBL_MAX;
|
|
||||||
uint32_t curHit = -1;
|
|
||||||
for(i = 0; i < this->num; i++)
|
for(i = 0; i < this->num; i++)
|
||||||
{
|
{
|
||||||
if ((this->list[i].t >= 0) && (this->list[i].t < minHit))
|
if (this->list[i]->t >= 0)
|
||||||
{
|
return *this->list[i];
|
||||||
curHit = i;
|
|
||||||
minHit = this->list[i].t;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curHit == -1)
|
|
||||||
{
|
|
||||||
return Intersection(0, nullptr);
|
return Intersection(0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this->list[curHit];
|
|
||||||
}
|
|
||||||
32
source/intersection.cpp
Normal file
32
source/intersection.cpp
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Intersection implementation
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <intersection.h>
|
||||||
|
#include <shape.h>
|
||||||
|
|
||||||
|
Computation Intersection::prepareComputation(Ray r)
|
||||||
|
{
|
||||||
|
Tuple hitP = r.position(this->t);
|
||||||
|
Tuple normalV = this->object->normalAt(hitP);
|
||||||
|
Tuple eyeV = -r.direction;
|
||||||
|
bool inside = false;
|
||||||
|
|
||||||
|
if (normalV.dot(eyeV) < 0)
|
||||||
|
{
|
||||||
|
inside = true;
|
||||||
|
normalV = -normalV;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return Computation(this->object,
|
||||||
|
this->t,
|
||||||
|
hitP,
|
||||||
|
eyeV,
|
||||||
|
normalV,
|
||||||
|
inside);
|
||||||
|
}
|
||||||
@@ -8,28 +8,29 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <ray.h>
|
#include <ray.h>
|
||||||
#include <object.h>
|
#include <shape.h>
|
||||||
#include <matrix.h>
|
#include <matrix.h>
|
||||||
#include <tuple.h>
|
#include <tuple.h>
|
||||||
#include <intersect.h>
|
#include <intersect.h>
|
||||||
|
|
||||||
Object::Object()
|
Shape::Shape(ShapeType type)
|
||||||
{
|
{
|
||||||
|
this->type = type;
|
||||||
this->transformMatrix = Matrix4().identity();
|
this->transformMatrix = Matrix4().identity();
|
||||||
this->inverseTransform = this->transformMatrix.inverse();
|
this->inverseTransform = this->transformMatrix.inverse();
|
||||||
}
|
}
|
||||||
|
|
||||||
Intersect Object::intersect(Ray r)
|
Intersect Shape::intersect(Ray r)
|
||||||
{
|
{
|
||||||
return Intersect();
|
return Intersect();
|
||||||
};
|
};
|
||||||
|
|
||||||
Tuple Object::normalAt(Tuple point)
|
Tuple Shape::normalAt(Tuple point)
|
||||||
{
|
{
|
||||||
return Vector(0, 0, 0);
|
return Vector(0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::setTransform(Matrix transform)
|
void Shape::setTransform(Matrix transform)
|
||||||
{
|
{
|
||||||
this->transformMatrix = transform;
|
this->transformMatrix = transform;
|
||||||
this->inverseTransform = transform.inverse();
|
this->inverseTransform = transform.inverse();
|
||||||
@@ -33,7 +33,7 @@ Matrix scaling(double x, double y, double z)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix rotation_x(double angle)
|
Matrix rotationX(double angle)
|
||||||
{
|
{
|
||||||
Matrix ret = Matrix4().identity();
|
Matrix ret = Matrix4().identity();
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ Matrix rotation_x(double angle)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix rotation_y(double angle)
|
Matrix rotationY(double angle)
|
||||||
{
|
{
|
||||||
Matrix ret = Matrix4().identity();
|
Matrix ret = Matrix4().identity();
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ Matrix rotation_y(double angle)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix rotation_z(double angle)
|
Matrix rotationZ(double angle)
|
||||||
{
|
{
|
||||||
Matrix ret = Matrix4().identity();
|
Matrix ret = Matrix4().identity();
|
||||||
|
|
||||||
@@ -82,3 +82,18 @@ Matrix shearing(double Xy, double Xz, double Yx, double Yz, double Zx, double Zy
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Matrix viewTransform(Tuple from, Tuple to, Tuple up)
|
||||||
|
{
|
||||||
|
Tuple forward = (to - from).normalise();
|
||||||
|
Tuple left = forward.cross(up.normalise());
|
||||||
|
Tuple true_up = left.cross(forward);
|
||||||
|
|
||||||
|
double orientationValues[] = { left.x, left.y, left.z, 0,
|
||||||
|
true_up.x, true_up.y, true_up.z, 0,
|
||||||
|
-forward.x, -forward.y, -forward.z, 0,
|
||||||
|
0, 0, 0, 1 };
|
||||||
|
Matrix orientation = Matrix4(orientationValues);
|
||||||
|
|
||||||
|
return orientation * translation(-from.x, -from.y, -from.z);
|
||||||
|
}
|
||||||
112
source/world.cpp
Normal file
112
source/world.cpp
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* World implementation
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <world.h>
|
||||||
|
#include <light.h>
|
||||||
|
#include <shape.h>
|
||||||
|
|
||||||
|
#define MIN_ALLOC (2)
|
||||||
|
|
||||||
|
World::World() : objectCount(0), lightCount(0)
|
||||||
|
{
|
||||||
|
this->allocatedLightCount = MIN_ALLOC;
|
||||||
|
this->lightList = (Light **)calloc(sizeof(Light *), MIN_ALLOC);
|
||||||
|
this->lightCount = 0;
|
||||||
|
|
||||||
|
this->allocatedObjectCount = MIN_ALLOC;
|
||||||
|
this->objectList = (Shape **)calloc(sizeof(Shape *), MIN_ALLOC);
|
||||||
|
this->objectCount = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
World::~World()
|
||||||
|
{
|
||||||
|
/* We need to do some cleanup... */
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::addObject(Shape *s)
|
||||||
|
{
|
||||||
|
if ((this->objectCount + 1) > this->allocatedObjectCount)
|
||||||
|
{
|
||||||
|
this->allocatedObjectCount *= 2;
|
||||||
|
this->objectList = (Shape **)realloc(this->objectList, sizeof(Shape **) * this->allocatedObjectCount);
|
||||||
|
}
|
||||||
|
this->objectList[this->objectCount++] = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::addLight(Light *l)
|
||||||
|
{
|
||||||
|
if ((this->lightCount + 1) > this->allocatedLightCount)
|
||||||
|
{
|
||||||
|
this->allocatedLightCount *= 2;
|
||||||
|
this->lightList = (Light **)realloc(this->lightList, sizeof(Light **) * this->allocatedLightCount);
|
||||||
|
}
|
||||||
|
this->lightList[this->lightCount++] = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool World::lightIsIn(Light &l)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < this->lightCount; i++)
|
||||||
|
{
|
||||||
|
if (*this->lightList[i] == l)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool World::objectIsIn(Shape &s)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < this->objectCount; i++)
|
||||||
|
{
|
||||||
|
if (*this->objectList[i] == s)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Intersect World::intersect(Ray r)
|
||||||
|
{
|
||||||
|
Intersect ret;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for(i = 0; i < this->objectCount; i++)
|
||||||
|
{
|
||||||
|
Intersect xs = this->objectList[i]->intersect(r);
|
||||||
|
|
||||||
|
for(j = 0; j < xs.count(); j++)
|
||||||
|
{
|
||||||
|
ret.add(xs[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tuple World::shadeHit(Computation comps)
|
||||||
|
{
|
||||||
|
return comps.object->material.lighting(*this->lightList[0], comps.hitPoint, comps.eyeVector, comps.normalVector);
|
||||||
|
}
|
||||||
|
|
||||||
|
Tuple World::colourAt(Ray r)
|
||||||
|
{
|
||||||
|
Intersection hit = this->intersect(r).hit();
|
||||||
|
|
||||||
|
if (hit.nothing())
|
||||||
|
{
|
||||||
|
return Colour(0, 0, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return this->shadeHit(hit.prepareComputation(r));
|
||||||
|
}
|
||||||
|
}
|
||||||
34
source/worldbuilder/default_world.cpp
Normal file
34
source/worldbuilder/default_world.cpp
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Default World builder implementation
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <worldbuilder.h>
|
||||||
|
#include <world.h>
|
||||||
|
|
||||||
|
#include <sphere.h>
|
||||||
|
#include <light.h>
|
||||||
|
#include <material.h>
|
||||||
|
#include <transformation.h>
|
||||||
|
|
||||||
|
DefaultWorld::DefaultWorld()
|
||||||
|
{
|
||||||
|
Light *l = new Light(POINT_LIGHT, Point(-10, 10, -10), Colour(1, 1, 1));
|
||||||
|
Sphere *s1 = new Sphere();
|
||||||
|
Sphere *s2 = new Sphere();
|
||||||
|
Material s1Mat = Material();
|
||||||
|
s1Mat.colour = Colour(0.8, 1.0, 0.6);
|
||||||
|
s1Mat.diffuse = 0.7;
|
||||||
|
s1Mat.specular = 0.2;
|
||||||
|
s1->setMaterial(s1Mat);
|
||||||
|
|
||||||
|
s2->setTransform(scaling(0.5, 0.5,0.5));
|
||||||
|
|
||||||
|
this->addLight(l);
|
||||||
|
|
||||||
|
this->addObject(s1);
|
||||||
|
this->addObject(s2);
|
||||||
|
}
|
||||||
307
source/worldbuilder/hw3file.cpp
Normal file
307
source/worldbuilder/hw3file.cpp
Normal file
@@ -0,0 +1,307 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Hw3file implementation
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/* Don't build for now */
|
||||||
|
#if 0
|
||||||
|
/* This file is parsing a text format from another raytracer I made in the past. */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#define IS_CMD(_cmd) (strncmp(buffer, _cmd, sizeof(_cmd)) == 0)
|
||||||
|
|
||||||
|
typedef void (*cmdFunc)(scene *sc, uint32_t curLine, char *first, float argv[15]);
|
||||||
|
|
||||||
|
typedef struct cmd_def
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
int8_t numparam; /* -1 == one string, else >0 = number of argv */
|
||||||
|
cmdFunc f;
|
||||||
|
} cmd_def;
|
||||||
|
|
||||||
|
void cmdCamera (scene *sc, uint32_t curLine, char *first, float argv[15])
|
||||||
|
{
|
||||||
|
sc->cam.seteye(point(argv[0], argv[1], argv[2]));
|
||||||
|
sc->cam.setat(point(argv[3], argv[4], argv[5]));
|
||||||
|
sc->cam.setup(vector(argv[6], argv[7], argv[8]));
|
||||||
|
sc->cam.setfovy(argv[9]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmdSphere (scene *sc, uint32_t curLine, char *first, float argv[15])
|
||||||
|
{
|
||||||
|
/* Instanciate a sphere */
|
||||||
|
sphere *sp = new sphere(point(argv[0], argv[1], argv[2]), argv[3], sc->getMatrix());
|
||||||
|
sp->ambient = sc->ambient;
|
||||||
|
sp->diffuse = sc->diffuse;
|
||||||
|
sp->specular = sc->specular;
|
||||||
|
sp->emission = sc->emission;
|
||||||
|
sp->shininess = sc->shininess;
|
||||||
|
sp->sourceLine = curLine;
|
||||||
|
sc->o[sc->o_count] = sp;
|
||||||
|
sc->o_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmdCube (scene *sc, uint32_t curLine, char *first, float argv[15])
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void cmdMaxVerts (scene *sc, uint32_t curLine, char *first, float argv[15])
|
||||||
|
{
|
||||||
|
sc->vertexCount = (uint32_t) argv[0];
|
||||||
|
sc->vertex = new point[sc->vertexCount];
|
||||||
|
sc->curVertex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmdMaxVertN (scene *sc, uint32_t curLine, char *first, float argv[15])
|
||||||
|
{
|
||||||
|
/* ignore for now */
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmdVertex (scene *sc, uint32_t curLine, char *first, float argv[15])
|
||||||
|
{
|
||||||
|
sc->vertex[sc->curVertex].set(argv[0], argv[1], argv[2]);
|
||||||
|
sc->curVertex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmdVertexN (scene *sc, uint32_t curLine, char *first, float argv[15])
|
||||||
|
{
|
||||||
|
/* ignore for now */
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmdTri (scene *sc, uint32_t curLine, char *first, float argv[15])
|
||||||
|
{
|
||||||
|
/* arg are vertex numbers */
|
||||||
|
triangle *tr = new triangle(sc->vertex[(int)argv[0]], sc->vertex[(int)argv[1]], sc->vertex[(int)argv[2]], sc->getMatrix());
|
||||||
|
tr->ambient = sc->ambient;
|
||||||
|
tr->diffuse = sc->diffuse;
|
||||||
|
tr->specular = sc->specular;
|
||||||
|
tr->emission = sc->emission;
|
||||||
|
tr->shininess = sc->shininess;
|
||||||
|
tr->sourceLine = curLine;
|
||||||
|
sc->o[sc->o_count] = tr;
|
||||||
|
sc->o_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmdTriN (scene *sc, uint32_t curLine, char *first, float argv[15])
|
||||||
|
{
|
||||||
|
/* ignore for noz */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void cmdTrans (scene *sc, uint32_t curLine, char *first, float argv[15])
|
||||||
|
{
|
||||||
|
matrix m;
|
||||||
|
m.translation(argv[0], argv[1], argv[2]);
|
||||||
|
sc->applyTransform(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmdRotate (scene *sc, uint32_t curLine, char *first, float argv[15])
|
||||||
|
{
|
||||||
|
matrix m;
|
||||||
|
vector axis;
|
||||||
|
axis.set(argv[0], argv[1], argv[2]);
|
||||||
|
m.rotation(axis, argv[3]);
|
||||||
|
sc->applyTransform(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmdScale (scene *sc, uint32_t curLine, char *first, float argv[15])
|
||||||
|
{
|
||||||
|
matrix m;
|
||||||
|
m.scale(argv[0], argv[1], argv[2]);
|
||||||
|
sc->applyTransform(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmdPushT (scene *sc, uint32_t curLine, char *first, float argv[15])
|
||||||
|
{
|
||||||
|
sc->pushMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmdPopT (scene *sc, uint32_t curLine, char *first, float argv[15])
|
||||||
|
{
|
||||||
|
sc->popMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void cmdLDire (scene *sc, uint32_t curLine, char *first, float argv[15])
|
||||||
|
{
|
||||||
|
/* create directional light */
|
||||||
|
light *cur = new light();
|
||||||
|
|
||||||
|
cur->type = LIGHT_DIRECTIONAL;
|
||||||
|
cur->attenuation = sc->attenuation;
|
||||||
|
|
||||||
|
cur->position.set(argv[0], argv[1], argv[2]);
|
||||||
|
cur->lightcolor.set(argv[3], argv[4], argv[5]);
|
||||||
|
|
||||||
|
sc->l[sc->l_count] = cur;
|
||||||
|
sc->l_count++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void cmdLPoint (scene *sc, uint32_t curLine, char *first, float argv[15])
|
||||||
|
{
|
||||||
|
/* create point light */
|
||||||
|
light *cur = new light();
|
||||||
|
|
||||||
|
cur->type = LIGHT_POINT;
|
||||||
|
cur->attenuation = sc->attenuation;
|
||||||
|
|
||||||
|
cur->position.set(argv[0], argv[1], argv[2]);
|
||||||
|
cur->lightcolor.set(argv[3], argv[4], argv[5]);
|
||||||
|
sc->l[sc->l_count] = cur;
|
||||||
|
sc->l_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void cmdAtten (scene *sc, uint32_t curLine, char *first, float argv[15])
|
||||||
|
{
|
||||||
|
sc->attenuation = vector(argv[0], argv[1], argv[2]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void cmdAmbient (scene *sc, uint32_t curLine, char *first, float argv[15])
|
||||||
|
{
|
||||||
|
sc->ambient = color(argv[0], argv[1], argv[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmdDiffuse (scene *sc, uint32_t curLine, char *first, float argv[15])
|
||||||
|
{
|
||||||
|
sc->diffuse = color(argv[0], argv[1], argv[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmdSpecular (scene *sc, uint32_t curLine, char *first, float argv[15])
|
||||||
|
{
|
||||||
|
sc->specular = color(argv[0], argv[1], argv[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmdShine (scene *sc, uint32_t curLine, char *first, float argv[15])
|
||||||
|
{
|
||||||
|
sc->shininess = argv[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmdEmission (scene *sc, uint32_t curLine, char *first, float argv[15])
|
||||||
|
{
|
||||||
|
sc->emission = color(argv[0], argv[1], argv[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_def commandList[] =
|
||||||
|
{
|
||||||
|
/* Camera */
|
||||||
|
{ "camera", 10, cmdCamera },
|
||||||
|
/* Geometry */
|
||||||
|
{ "sphere", 4, cmdSphere },
|
||||||
|
//{ "maxverts", 1, cmdMaxVerts },
|
||||||
|
//{ "maxvertnorms", 1, cmdMaxVertN },
|
||||||
|
//{ "vertex", 3, cmdVertex },
|
||||||
|
//{ "vertexnormal", 6, cmdVertexN },
|
||||||
|
//{ "tri", 3, cmdTri },
|
||||||
|
//{ "trinormal", 3, cmdTriN },
|
||||||
|
//{ "cube", 1, cmdCube },
|
||||||
|
/* transformation */
|
||||||
|
{ "translate", 3, cmdTrans },
|
||||||
|
{ "rotate", 4, cmdRotate },
|
||||||
|
{ "scale", 3, cmdScale },
|
||||||
|
{ "pushTransform", 0, cmdPushT },
|
||||||
|
{ "popTransform", 0, cmdPopT },
|
||||||
|
/* Lights */
|
||||||
|
//{ "directional", 6, cmdLDire },
|
||||||
|
{ "point", 6, cmdLPoint },
|
||||||
|
//{ "attenuation", 3, cmdAtten },
|
||||||
|
/* Materials */
|
||||||
|
{ "ambient", 3, cmdAmbient },
|
||||||
|
{ "diffuse", 3, cmdDiffuse },
|
||||||
|
{ "specular", 3, cmdSpecular },
|
||||||
|
{ "shininess", 1, cmdShine },
|
||||||
|
{ "emission", 3, cmdEmission },
|
||||||
|
};
|
||||||
|
#define CMD_COUNT (sizeof(commandList) / sizeof(cmd_def))
|
||||||
|
|
||||||
|
|
||||||
|
scene *readfile::read(char *filename)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
scene *sc = new scene;
|
||||||
|
if (sc != NULL)
|
||||||
|
{
|
||||||
|
fp = fopen(filename, "rt");
|
||||||
|
if (fp == NULL)
|
||||||
|
{
|
||||||
|
delete sc;
|
||||||
|
sc = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char buffer[512];
|
||||||
|
int line = 0;
|
||||||
|
while(!feof(fp))
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
line++;
|
||||||
|
memset(buffer, 0, 512);
|
||||||
|
fgets(buffer, 512, fp);
|
||||||
|
if ((buffer[0] == '#') || (strlen(buffer) < 2))
|
||||||
|
continue; /* Ingore empty line or commented lines */
|
||||||
|
//printf("::%d:> %s", strlen(buffer), buffer);
|
||||||
|
for (i = 0; i < CMD_COUNT; i++)
|
||||||
|
{
|
||||||
|
if (strncmp(buffer, commandList[i].name, strlen(commandList[i].name)) == 0)
|
||||||
|
{
|
||||||
|
char first[512];
|
||||||
|
float value[15];
|
||||||
|
if (commandList[i].numparam != 0)
|
||||||
|
{
|
||||||
|
size_t j;
|
||||||
|
int k = 0, l = 0;
|
||||||
|
char buff[512];
|
||||||
|
for(j = strlen(commandList[i].name); j < strlen(buffer); j++)
|
||||||
|
{
|
||||||
|
if (!isspace(buffer[j]))
|
||||||
|
{
|
||||||
|
buff[l++] = buffer[j];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buff[l] = 0;
|
||||||
|
l = 0;
|
||||||
|
if (k == 0)
|
||||||
|
{
|
||||||
|
strcpy(first, buff);
|
||||||
|
}
|
||||||
|
if (strlen(buff) > 0)
|
||||||
|
{
|
||||||
|
value[k++] = atof(buff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (k != abs(commandList[i].numparam))
|
||||||
|
{
|
||||||
|
printf("line %d malformed: given %d parameter, expected %d\n%s", line, k, abs(commandList[i].numparam), buffer);
|
||||||
|
sc = NULL;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
commandList[i].f(sc, line, first, value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef USE_OCTREE
|
||||||
|
sc->createOctree();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return sc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -4,7 +4,7 @@ set(THREADS_PREFER_PTHREAD_FLAG ON)
|
|||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
|
|
||||||
set(TESTS_SRC tuple_test.cpp colour_test.cpp canvas_test.cpp matrix_test.cpp transformation_test.cpp ray_test.cpp
|
set(TESTS_SRC tuple_test.cpp colour_test.cpp canvas_test.cpp matrix_test.cpp transformation_test.cpp ray_test.cpp
|
||||||
intersect_test.cpp sphere_test.cpp light_test.cpp material_test.cpp)
|
intersect_test.cpp sphere_test.cpp light_test.cpp material_test.cpp world_test.cpp camera_test.cpp)
|
||||||
|
|
||||||
add_executable(testMyRays)
|
add_executable(testMyRays)
|
||||||
target_include_directories(testMyRays PUBLIC ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
|
target_include_directories(testMyRays PUBLIC ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
|
||||||
@@ -22,3 +22,17 @@ add_executable(ch5_test)
|
|||||||
target_include_directories(ch5_test PUBLIC ../source/include)
|
target_include_directories(ch5_test PUBLIC ../source/include)
|
||||||
target_sources(ch5_test PRIVATE ch5_test.cpp)
|
target_sources(ch5_test PRIVATE ch5_test.cpp)
|
||||||
target_link_libraries(ch5_test rayonnement)
|
target_link_libraries(ch5_test rayonnement)
|
||||||
|
|
||||||
|
add_executable(ch6_test)
|
||||||
|
target_include_directories(ch6_test PUBLIC ../source/include)
|
||||||
|
target_sources(ch6_test PRIVATE ch6_test.cpp)
|
||||||
|
target_link_libraries(ch6_test rayonnement)
|
||||||
|
|
||||||
|
add_executable(ch7_test)
|
||||||
|
target_include_directories(ch6_test PUBLIC ../source/include)
|
||||||
|
target_sources(ch7_test PRIVATE ch7_test.cpp)
|
||||||
|
target_link_libraries(ch7_test rayonnement)
|
||||||
|
|
||||||
|
add_test(NAME Chapter05_Test COMMAND $<TARGET_FILE:ch5_test>)
|
||||||
|
add_test(NAME Chapter06_Test COMMAND $<TARGET_FILE:ch6_test>)
|
||||||
|
add_test(NAME Chapter07_Test COMMAND $<TARGET_FILE:ch7_test>)
|
||||||
111
tests/camera_test.cpp
Normal file
111
tests/camera_test.cpp
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Camera unit tests
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <camera.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <math_helper.h>
|
||||||
|
#include <matrix.h>
|
||||||
|
#include <tuple.h>
|
||||||
|
#include <ray.h>
|
||||||
|
#include <world.h>
|
||||||
|
#include <canvas.h>
|
||||||
|
#include <colour.h>
|
||||||
|
#include <worldbuilder.h>
|
||||||
|
#include <transformation.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
TEST(CameraTest, Constructing_a_camera)
|
||||||
|
{
|
||||||
|
uint32_t hsize = 160;
|
||||||
|
uint32_t vsize = 120;
|
||||||
|
double field_of_view = M_PI / 2;
|
||||||
|
|
||||||
|
Camera c = Camera(hsize, vsize, field_of_view);
|
||||||
|
|
||||||
|
ASSERT_EQ(c.horizontalSize, 160);
|
||||||
|
ASSERT_EQ(c.verticalSize, 120);
|
||||||
|
ASSERT_TRUE(double_equal(c.fieldOfView, M_PI / 2));
|
||||||
|
ASSERT_EQ(c.transformMatrix, Matrix4().identity());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CameraTest, Pixel_size_for_a_horizontal_canvas)
|
||||||
|
{
|
||||||
|
Camera c = Camera(200, 125, M_PI / 2);
|
||||||
|
|
||||||
|
ASSERT_TRUE(double_equal(c.pixelSize, 0.01));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CameraTest, Pixel_size_for_a_vertical_canvas)
|
||||||
|
{
|
||||||
|
Camera c = Camera(125, 200, M_PI / 2);
|
||||||
|
|
||||||
|
ASSERT_TRUE(double_equal(c.pixelSize, 0.01));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CameraTest, Constructing_a_ray_through_the_center_of_the_canvas)
|
||||||
|
{
|
||||||
|
Camera c = Camera(201, 101, M_PI / 2);
|
||||||
|
Ray r = c.rayForPixel(100, 50);
|
||||||
|
|
||||||
|
ASSERT_EQ(r.origin, Point(0, 0, 0));
|
||||||
|
ASSERT_EQ(r.direction, Vector(0, 0, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CameraTest, Constructing_a_ray_through_a_corner_of_the_canvas)
|
||||||
|
{
|
||||||
|
Camera c = Camera(201, 101, M_PI / 2);
|
||||||
|
Ray r = c.rayForPixel(0, 0);
|
||||||
|
|
||||||
|
ASSERT_EQ(r.origin, Point(0, 0, 0));
|
||||||
|
|
||||||
|
/* Temporary lower the precision */
|
||||||
|
set_equal_precision(0.00001);
|
||||||
|
|
||||||
|
ASSERT_EQ(r.direction, Vector(0.66519, 0.33259, -0.66851));
|
||||||
|
|
||||||
|
set_equal_precision(FLT_EPSILON);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CameraTest, Constructing_a_ray_when_the_camera_is_transformed)
|
||||||
|
{
|
||||||
|
Camera c = Camera(201, 101, M_PI / 2);
|
||||||
|
c.setTransform(rotationY(M_PI / 4) * translation(0, -2, 5));
|
||||||
|
Ray r = c.rayForPixel(100, 50);
|
||||||
|
|
||||||
|
ASSERT_EQ(r.origin, Point(0, 2, -5));
|
||||||
|
ASSERT_EQ(r.direction, Vector(sqrt(2)/2, 0, -sqrt(2)/2));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CameraTest, Rendering_a_world_with_a_camera)
|
||||||
|
{
|
||||||
|
World w = DefaultWorld();
|
||||||
|
Camera c = Camera(11, 11, M_PI / 2);
|
||||||
|
|
||||||
|
Tuple from = Point(0, 0, -5);
|
||||||
|
Tuple to = Point(0, 0, 0);
|
||||||
|
Tuple up = Vector(0, 1, 0);
|
||||||
|
|
||||||
|
c.setTransform(viewTransform(from, to, up));
|
||||||
|
|
||||||
|
Canvas image = c.render(w);
|
||||||
|
|
||||||
|
/* Temporary lower the precision */
|
||||||
|
/* We need to lower a lot as Canvas is not keeping the
|
||||||
|
* floating point value, but a value between 0 and 255 per channel,
|
||||||
|
* as it is storing the actual frame buffer, so there is a more big different
|
||||||
|
* between the value.
|
||||||
|
*/
|
||||||
|
set_equal_precision(0.005);
|
||||||
|
|
||||||
|
Colour col = image.getPixel(5, 5);
|
||||||
|
|
||||||
|
ASSERT_EQ(col, Colour(0.38066, 0.47583, 0.2855));
|
||||||
|
|
||||||
|
set_equal_precision(FLT_EPSILON);
|
||||||
|
}
|
||||||
@@ -21,7 +21,7 @@ TEST(CanvasTest, Creating_a_canvas)
|
|||||||
{
|
{
|
||||||
for(x = 0; x < 10; x++)
|
for(x = 0; x < 10; x++)
|
||||||
{
|
{
|
||||||
ASSERT_EQ(c.get_pixel(x, y), Colour(0, 0, 0));
|
ASSERT_EQ(c.getPixel(x, y), Colour(0, 0, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,9 +31,9 @@ TEST(CanvasTest, Test_Writing_pixels_to_a_canvas_Test)
|
|||||||
Canvas c = Canvas(10, 20);
|
Canvas c = Canvas(10, 20);
|
||||||
Colour red = Colour(1, 0, 0);
|
Colour red = Colour(1, 0, 0);
|
||||||
|
|
||||||
c.put_pixel(2, 3, red);
|
c.putPixel(2, 3, red);
|
||||||
|
|
||||||
ASSERT_EQ(c.get_pixel(2, 3), red);
|
ASSERT_EQ(c.getPixel(2, 3), red);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,9 +44,9 @@ TEST(CanvasTest, Save_a_PNG_file)
|
|||||||
Colour c2 = Colour(0, 0.5, 0);
|
Colour c2 = Colour(0, 0.5, 0);
|
||||||
Colour c3 = Colour(-0.5, 0, 1);
|
Colour c3 = Colour(-0.5, 0, 1);
|
||||||
|
|
||||||
c.put_pixel(0, 0, c1);
|
c.putPixel(0, 0, c1);
|
||||||
c.put_pixel(2, 1, c2);
|
c.putPixel(2, 1, c2);
|
||||||
c.put_pixel(4, 2, c3);
|
c.putPixel(4, 2, c3);
|
||||||
|
|
||||||
ASSERT_TRUE(c.SaveAsPNG("Save_a_PNG_file.png"));
|
ASSERT_TRUE(c.SaveAsPNG("Save_a_PNG_file.png"));
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ int main()
|
|||||||
|
|
||||||
if (!xs.hit().nothing())
|
if (!xs.hit().nothing())
|
||||||
{
|
{
|
||||||
c.put_pixel(x, y, red);
|
c.putPixel(x, y, red);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
57
tests/ch6_test.cpp
Normal file
57
tests/ch6_test.cpp
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Render test for chapter 5 "Put it together".
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <ray.h>
|
||||||
|
#include <sphere.h>
|
||||||
|
#include <colour.h>
|
||||||
|
#include <canvas.h>
|
||||||
|
#include <transformation.h>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
Canvas c = Canvas(100, 100);
|
||||||
|
|
||||||
|
Sphere s = Sphere();
|
||||||
|
|
||||||
|
s.material.colour = Colour(1, 0.2, 1);
|
||||||
|
|
||||||
|
|
||||||
|
Light light = Light(POINT_LIGHT, Point(-10, 10, -10), Colour(1, 1, 1));
|
||||||
|
|
||||||
|
Point cameraOrigin = Point(0, 0, -5);
|
||||||
|
double wallDistance = 10;
|
||||||
|
double wallSize = 7;
|
||||||
|
double pixelSize = wallSize / c.width;
|
||||||
|
for(y = 0; y < c.height; y++)
|
||||||
|
{
|
||||||
|
double worldY = (wallSize / 2) - pixelSize * y;
|
||||||
|
for(x = 0; x < c.width; x++)
|
||||||
|
{
|
||||||
|
double worldX = -(wallSize / 2) + pixelSize * x;
|
||||||
|
Point position = Point(worldX, worldY, wallDistance);
|
||||||
|
Ray r = Ray(cameraOrigin, (position - cameraOrigin).normalise());
|
||||||
|
Intersect xs = s.intersect(r);
|
||||||
|
|
||||||
|
Intersection hit = xs.hit();
|
||||||
|
|
||||||
|
if (!hit.nothing())
|
||||||
|
{
|
||||||
|
Tuple hitPoint = r.position(hit.t);
|
||||||
|
Tuple hitNormalVector = hit.object->normalAt(hitPoint);
|
||||||
|
Tuple eye = -r.direction;
|
||||||
|
Colour pixelColour = hit.object->material.lighting(light, hitPoint, eye, hitNormalVector);
|
||||||
|
|
||||||
|
c.putPixel(x, y, pixelColour);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.SaveAsPNG("ch6_test.png");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
83
tests/ch7_test.cpp
Normal file
83
tests/ch7_test.cpp
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Render test for chapter 5 "Put it together".
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <world.h>
|
||||||
|
#include <light.h>
|
||||||
|
#include <sphere.h>
|
||||||
|
#include <material.h>
|
||||||
|
#include <colour.h>
|
||||||
|
#include <canvas.h>
|
||||||
|
#include <camera.h>
|
||||||
|
#include <transformation.h>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
/* First we need to construct the world */
|
||||||
|
Sphere floor = Sphere();
|
||||||
|
floor.setTransform(scaling(10, 0.01, 10));
|
||||||
|
floor.material.colour = Colour(1, 0.9, 0.9);
|
||||||
|
floor.material.specular = 0;
|
||||||
|
|
||||||
|
Sphere left_wall = Sphere();
|
||||||
|
left_wall.setTransform(translation(0, 0, 5) *
|
||||||
|
rotationY(-M_PI / 4) * rotationX((M_PI / 2)) *
|
||||||
|
scaling(10, 0.01, 10));
|
||||||
|
left_wall.material = floor.material;
|
||||||
|
|
||||||
|
Sphere right_wall = Sphere();
|
||||||
|
right_wall.setTransform(translation(0, 0, 5) *
|
||||||
|
rotationY(M_PI / 4) * rotationX((M_PI / 2)) *
|
||||||
|
scaling(10, 0.01, 10));
|
||||||
|
right_wall.material = floor.material;
|
||||||
|
|
||||||
|
Sphere middle = Sphere();
|
||||||
|
middle.setTransform(translation(-0.5, 1, 0.5));
|
||||||
|
middle.material.colour = Colour(0.1, 1, 0.5);
|
||||||
|
middle.material.diffuse = 0.7;
|
||||||
|
middle.material.specular = 0.3;
|
||||||
|
|
||||||
|
Sphere right = Sphere();
|
||||||
|
right.setTransform(translation(1.5, 0.5, -0.5) * scaling(0.5, 0.5, 0.5));
|
||||||
|
right.material.colour = Colour(0.5, 1, 0.1);
|
||||||
|
right.material.diffuse = 0.7;
|
||||||
|
right.material.specular = 0.3;
|
||||||
|
|
||||||
|
Sphere left = Sphere();
|
||||||
|
left.setTransform(translation(-1.5, 0.33, -0.75) * scaling(0.33, 0.33, 0.33));
|
||||||
|
left.material.colour = Colour(1, 0.8, 0.1);
|
||||||
|
left.material.diffuse = 0.7;
|
||||||
|
left.material.specular = 0.3;
|
||||||
|
|
||||||
|
World w = World();
|
||||||
|
|
||||||
|
w.addObject(&floor);
|
||||||
|
w.addObject(&left_wall);
|
||||||
|
w.addObject(&right_wall);
|
||||||
|
w.addObject(&middle);
|
||||||
|
w.addObject(&left);
|
||||||
|
w.addObject(&right);
|
||||||
|
|
||||||
|
/* Add light */
|
||||||
|
Light light = Light(POINT_LIGHT, Point(-10, 10, -10), Colour(1, 1, 1));
|
||||||
|
|
||||||
|
w.addLight(&light);
|
||||||
|
|
||||||
|
/* Set the camera */
|
||||||
|
Camera camera = Camera(1000, 500, M_PI / 3);
|
||||||
|
camera.setTransform(viewTransform(Point(0, 1.5, -5),
|
||||||
|
Point(0, 1, 0),
|
||||||
|
Vector(0, 1, 0)));
|
||||||
|
|
||||||
|
/* Now render it */
|
||||||
|
Canvas image = camera.render(w);
|
||||||
|
|
||||||
|
image.SaveAsPNG("ch7_test.png");
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include <intersect.h>
|
#include <intersect.h>
|
||||||
|
#include <intersection.h>
|
||||||
#include <sphere.h>
|
#include <sphere.h>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
@@ -32,7 +33,7 @@ TEST(IntersectTest, An_intersection_encapsulate_t_and_object)
|
|||||||
Intersection i = Intersection(3.5, &s);
|
Intersection i = Intersection(3.5, &s);
|
||||||
|
|
||||||
ASSERT_EQ(i.t, 3.5);
|
ASSERT_EQ(i.t, 3.5);
|
||||||
ASSERT_EQ(i.object, (Object *)&s);
|
ASSERT_EQ(i.object, (Shape *)&s);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(IntersectTest, Aggregating_intersections)
|
TEST(IntersectTest, Aggregating_intersections)
|
||||||
@@ -57,8 +58,8 @@ TEST(IntersectTest, Intersect_sets_the_object_on_the_intersection)
|
|||||||
Intersect xs = s.intersect(r);
|
Intersect xs = s.intersect(r);
|
||||||
|
|
||||||
ASSERT_EQ(xs.count(), 2);
|
ASSERT_EQ(xs.count(), 2);
|
||||||
ASSERT_EQ(xs[0].object, (Object *)&s);
|
ASSERT_EQ(xs[0].object, (Shape *)&s);
|
||||||
ASSERT_EQ(xs[1].object, (Object *)&s);
|
ASSERT_EQ(xs[1].object, (Shape *)&s);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(IntersectTest, The_hit_when_all_intersection_have_positive_t)
|
TEST(IntersectTest, The_hit_when_all_intersection_have_positive_t)
|
||||||
@@ -130,3 +131,46 @@ TEST(IntersectTest, The_hit_is_always_the_lowest_nonnegative_intersection)
|
|||||||
|
|
||||||
ASSERT_EQ(i, i4);
|
ASSERT_EQ(i, i4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(IntersectTest, Precomputing_the_state_of_an_intersection)
|
||||||
|
{
|
||||||
|
Ray r = Ray(Point(0, 0, -5), Vector(0, 0, 1));
|
||||||
|
Sphere shape = Sphere();
|
||||||
|
Intersection i = Intersection(4, &shape);
|
||||||
|
|
||||||
|
Computation comps = i.prepareComputation(r);
|
||||||
|
|
||||||
|
ASSERT_EQ(comps.t, i.t);
|
||||||
|
ASSERT_EQ(comps.object, i.object);
|
||||||
|
ASSERT_EQ(comps.hitPoint, Point(0, 0, -1));
|
||||||
|
ASSERT_EQ(comps.eyeVector, Vector(0, 0, -1));
|
||||||
|
ASSERT_EQ(comps.normalVector, Vector(0, 0, -1));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(IntersectTest, The_hit_when_an_intersection_occurs_on_the_outside)
|
||||||
|
{
|
||||||
|
Ray r = Ray(Point(0, 0, -5), Vector(0, 0, 1));
|
||||||
|
Sphere shape = Sphere();
|
||||||
|
Intersection i = Intersection(4, &shape);
|
||||||
|
|
||||||
|
Computation comps = i.prepareComputation(r);
|
||||||
|
|
||||||
|
ASSERT_EQ(comps.inside, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(IntersectTest, The_hit_when_an_intersection_occurs_on_the_inside)
|
||||||
|
{
|
||||||
|
Ray r = Ray(Point(0, 0, 0), Vector(0, 0, 1));
|
||||||
|
Sphere shape = Sphere();
|
||||||
|
Intersection i = Intersection(1, &shape);
|
||||||
|
|
||||||
|
Computation comps = i.prepareComputation(r);
|
||||||
|
ASSERT_EQ(comps.hitPoint, Point(0, 0, 1));
|
||||||
|
ASSERT_EQ(comps.eyeVector, Vector(0, 0, -1));
|
||||||
|
ASSERT_EQ(comps.inside, true);
|
||||||
|
|
||||||
|
/* Normal vector would have been (0, 0, 1); but is inverted ! */
|
||||||
|
|
||||||
|
ASSERT_EQ(comps.normalVector, Vector(0, 0, -1));
|
||||||
|
}
|
||||||
@@ -30,7 +30,7 @@ TEST(MatrixTest, Constructing_and_inspecting_a_4x4_Matrix)
|
|||||||
ASSERT_EQ(m.get(3, 2), 15.5);
|
ASSERT_EQ(m.get(3, 2), 15.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(MatrixTest, A_2x2_matric_ought_to_be_representable)
|
TEST(MatrixTest, Change_a_single_value_and_check_it)
|
||||||
{
|
{
|
||||||
double values[] = {-3, 5,
|
double values[] = {-3, 5,
|
||||||
1, -2};
|
1, -2};
|
||||||
@@ -41,9 +41,13 @@ TEST(MatrixTest, A_2x2_matric_ought_to_be_representable)
|
|||||||
ASSERT_EQ(m.get(0, 1), 5);
|
ASSERT_EQ(m.get(0, 1), 5);
|
||||||
ASSERT_EQ(m.get(1, 0), 1);
|
ASSERT_EQ(m.get(1, 0), 1);
|
||||||
ASSERT_EQ(m.get(1, 1), -2);
|
ASSERT_EQ(m.get(1, 1), -2);
|
||||||
|
|
||||||
|
m.set(0, 0, 12);
|
||||||
|
|
||||||
|
ASSERT_EQ(m.get(0, 0), 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(MatrixTest, A_3x3_matric_ought_to_be_representable)
|
TEST(MatrixTest, A_3x3_matrix_ought_to_be_representable)
|
||||||
{
|
{
|
||||||
double values[] = {-3, 5, 0,
|
double values[] = {-3, 5, 0,
|
||||||
1, -2, -7,
|
1, -2, -7,
|
||||||
@@ -56,6 +60,19 @@ TEST(MatrixTest, A_3x3_matric_ought_to_be_representable)
|
|||||||
ASSERT_EQ(m.get(2, 2), 1);
|
ASSERT_EQ(m.get(2, 2), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(MatrixTest, A_2x2_matrix_ought_to_be_representable)
|
||||||
|
{
|
||||||
|
double values[] = {-3, 5,
|
||||||
|
1, -2};
|
||||||
|
|
||||||
|
Matrix2 m = Matrix2(values);
|
||||||
|
|
||||||
|
ASSERT_EQ(m.get(0, 0), -3);
|
||||||
|
ASSERT_EQ(m.get(0, 1), 5);
|
||||||
|
ASSERT_EQ(m.get(1, 0), 1);
|
||||||
|
ASSERT_EQ(m.get(1, 1), -2);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(MatrixTest, Matrix_equality_with_identical_matrix)
|
TEST(MatrixTest, Matrix_equality_with_identical_matrix)
|
||||||
{
|
{
|
||||||
double values1[] = {1, 2, 3, 4,
|
double values1[] = {1, 2, 3, 4,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
#include <ray.h>
|
#include <ray.h>
|
||||||
#include <transformation.h>
|
#include <transformation.h>
|
||||||
#include <object.h>
|
#include <shape.h>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ TEST(RayTest, Translating_a_ray)
|
|||||||
Ray r = Ray(Point(1, 2, 3), Vector(0, 1, 0));
|
Ray r = Ray(Point(1, 2, 3), Vector(0, 1, 0));
|
||||||
|
|
||||||
Matrix m = translation(3, 4, 5);
|
Matrix m = translation(3, 4, 5);
|
||||||
Object o = Object();
|
Shape o = Shape();
|
||||||
|
|
||||||
o.setTransform(m);
|
o.setTransform(m);
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ TEST(RayTest, Scaling_a_ray)
|
|||||||
Ray r = Ray(Point(1, 2, 3), Vector(0, 1, 0));
|
Ray r = Ray(Point(1, 2, 3), Vector(0, 1, 0));
|
||||||
|
|
||||||
Matrix m = scaling(2, 3, 4);
|
Matrix m = scaling(2, 3, 4);
|
||||||
Object o = Object();
|
Shape o = Shape();
|
||||||
|
|
||||||
o.setTransform(m);
|
o.setTransform(m);
|
||||||
|
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ TEST(SphereTest, Computing_the_normal_on_a_tranformed_sphere)
|
|||||||
{
|
{
|
||||||
Sphere s = Sphere();
|
Sphere s = Sphere();
|
||||||
|
|
||||||
s.setTransform(scaling(1, 0.5, 1) * rotation_z(M_PI / 5));
|
s.setTransform(scaling(1, 0.5, 1) * rotationZ(M_PI / 5));
|
||||||
|
|
||||||
Tuple n = s.normalAt(Point(0, sqrt(2)/2, -sqrt(2)/2));
|
Tuple n = s.normalAt(Point(0, sqrt(2)/2, -sqrt(2)/2));
|
||||||
|
|
||||||
|
|||||||
@@ -78,8 +78,8 @@ TEST(TransformationTest, Reflexion_is_scaling_by_a_negative_value)
|
|||||||
TEST(TransformationTest, Rotating_a_point_around_the_X_axis)
|
TEST(TransformationTest, Rotating_a_point_around_the_X_axis)
|
||||||
{
|
{
|
||||||
Point p = Point(0, 1, 0);
|
Point p = Point(0, 1, 0);
|
||||||
Matrix half_quarter = rotation_x(M_PI / 4.);
|
Matrix half_quarter = rotationX(M_PI / 4.);
|
||||||
Matrix full_quarter = rotation_x(M_PI / 2.);
|
Matrix full_quarter = rotationX(M_PI / 2.);
|
||||||
|
|
||||||
ASSERT_EQ(half_quarter * p, Point(0, sqrt(2)/2, sqrt(2)/2));
|
ASSERT_EQ(half_quarter * p, Point(0, sqrt(2)/2, sqrt(2)/2));
|
||||||
ASSERT_EQ(full_quarter * p, Point(0, 0, 1));
|
ASSERT_EQ(full_quarter * p, Point(0, 0, 1));
|
||||||
@@ -88,7 +88,7 @@ TEST(TransformationTest, Rotating_a_point_around_the_X_axis)
|
|||||||
TEST(TransformationTest, The_inverse_of_an_x_rotation_rotates_in_the_opposite_direction)
|
TEST(TransformationTest, The_inverse_of_an_x_rotation_rotates_in_the_opposite_direction)
|
||||||
{
|
{
|
||||||
Point p = Point(0, 1, 0);
|
Point p = Point(0, 1, 0);
|
||||||
Matrix half_quarter = rotation_x(M_PI / 4.);
|
Matrix half_quarter = rotationX(M_PI / 4.);
|
||||||
Matrix inv = half_quarter.inverse();
|
Matrix inv = half_quarter.inverse();
|
||||||
|
|
||||||
ASSERT_EQ(inv * p, Point(0, sqrt(2)/2, -sqrt(2)/2));
|
ASSERT_EQ(inv * p, Point(0, sqrt(2)/2, -sqrt(2)/2));
|
||||||
@@ -97,8 +97,8 @@ TEST(TransformationTest, The_inverse_of_an_x_rotation_rotates_in_the_opposite_di
|
|||||||
TEST(TransformationTest, Rotating_a_point_around_the_Y_axis)
|
TEST(TransformationTest, Rotating_a_point_around_the_Y_axis)
|
||||||
{
|
{
|
||||||
Point p = Point(0, 0, 1);
|
Point p = Point(0, 0, 1);
|
||||||
Matrix half_quarter = rotation_y(M_PI / 4.);
|
Matrix half_quarter = rotationY(M_PI / 4.);
|
||||||
Matrix full_quarter = rotation_y(M_PI / 2.);
|
Matrix full_quarter = rotationY(M_PI / 2.);
|
||||||
|
|
||||||
ASSERT_EQ(half_quarter * p, Point(sqrt(2)/2, 0, sqrt(2)/2));
|
ASSERT_EQ(half_quarter * p, Point(sqrt(2)/2, 0, sqrt(2)/2));
|
||||||
ASSERT_EQ(full_quarter * p, Point(1, 0, 0));
|
ASSERT_EQ(full_quarter * p, Point(1, 0, 0));
|
||||||
@@ -107,8 +107,8 @@ TEST(TransformationTest, Rotating_a_point_around_the_Y_axis)
|
|||||||
TEST(TransformationTest, Rotating_a_point_around_the_Z_axis)
|
TEST(TransformationTest, Rotating_a_point_around_the_Z_axis)
|
||||||
{
|
{
|
||||||
Point p = Point(0, 1, 0);
|
Point p = Point(0, 1, 0);
|
||||||
Matrix half_quarter = rotation_z(M_PI / 4.);
|
Matrix half_quarter = rotationZ(M_PI / 4.);
|
||||||
Matrix full_quarter = rotation_z(M_PI / 2.);
|
Matrix full_quarter = rotationZ(M_PI / 2.);
|
||||||
|
|
||||||
ASSERT_EQ(half_quarter * p, Point(-sqrt(2)/2, sqrt(2)/2, 0));
|
ASSERT_EQ(half_quarter * p, Point(-sqrt(2)/2, sqrt(2)/2, 0));
|
||||||
ASSERT_EQ(full_quarter * p, Point(-1, 0, 0));
|
ASSERT_EQ(full_quarter * p, Point(-1, 0, 0));
|
||||||
@@ -165,7 +165,7 @@ TEST(TransformationTest, A_shearing_transformation_moves_z_in_proportion_to_y)
|
|||||||
TEST(TransformationTest, Individual_trnasformations_are_applied_in_sequence)
|
TEST(TransformationTest, Individual_trnasformations_are_applied_in_sequence)
|
||||||
{
|
{
|
||||||
Point p = Point(1, 0, 1);
|
Point p = Point(1, 0, 1);
|
||||||
Matrix A = rotation_x(M_PI / 2.);
|
Matrix A = rotationX(M_PI / 2.);
|
||||||
Matrix B = scaling(5, 5, 5);
|
Matrix B = scaling(5, 5, 5);
|
||||||
Matrix C = translation(10, 5, 7);
|
Matrix C = translation(10, 5, 7);
|
||||||
|
|
||||||
@@ -182,10 +182,77 @@ TEST(TransformationTest, Individual_trnasformations_are_applied_in_sequence)
|
|||||||
TEST(TransformationTest, Chained_transformation_must_be_applied_in_reverse_order)
|
TEST(TransformationTest, Chained_transformation_must_be_applied_in_reverse_order)
|
||||||
{
|
{
|
||||||
Point p = Point(1, 0, 1);
|
Point p = Point(1, 0, 1);
|
||||||
Matrix A = rotation_x(M_PI / 2.);
|
Matrix A = rotationX(M_PI / 2.);
|
||||||
Matrix B = scaling(5, 5, 5);
|
Matrix B = scaling(5, 5, 5);
|
||||||
Matrix C = translation(10, 5, 7);
|
Matrix C = translation(10, 5, 7);
|
||||||
|
|
||||||
Matrix T = C * B * A;
|
Matrix T = C * B * A;
|
||||||
ASSERT_EQ(T * p, Point(15, 0, 7));
|
ASSERT_EQ(T * p, Point(15, 0, 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(TransformationTest, The_transformation_matrix_for_the_default_orientation)
|
||||||
|
{
|
||||||
|
Tuple from = Point(0, 0, 0);
|
||||||
|
Tuple to = Point(0, 0, -1);
|
||||||
|
Tuple up = Vector(0, 1, 0);
|
||||||
|
|
||||||
|
Matrix t = viewTransform(from, to, up);
|
||||||
|
|
||||||
|
ASSERT_EQ(t, Matrix4().identity());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(TransformationTest, A_view_transformation_matrix_looking_in_positive_z_direction)
|
||||||
|
{
|
||||||
|
Tuple from = Point(0, 0, 0);
|
||||||
|
Tuple to = Point(0, 0, 1);
|
||||||
|
Tuple up = Vector(0, 1, 0);
|
||||||
|
|
||||||
|
Matrix t = viewTransform(from, to, up);
|
||||||
|
|
||||||
|
ASSERT_EQ(t, scaling(-1, 1, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TransformationTest, The_view_transformation_move_the_world)
|
||||||
|
{
|
||||||
|
Tuple from = Point(0, 0, 8);
|
||||||
|
Tuple to = Point(0, 0, 0);
|
||||||
|
Tuple up = Vector(0, 1, 0);
|
||||||
|
|
||||||
|
Matrix t = viewTransform(from, to, up);
|
||||||
|
|
||||||
|
ASSERT_EQ(t, translation(0, 0, -8));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TransformationTest, An_arbitrary_view_transformation)
|
||||||
|
{
|
||||||
|
Tuple from = Point(1, 3, 2);
|
||||||
|
Tuple to = Point(4, -2, 8);
|
||||||
|
Tuple up = Vector(1, 1, 0);
|
||||||
|
|
||||||
|
Matrix t = viewTransform(from, to, up);
|
||||||
|
|
||||||
|
double values[] = {-0.50709, 0.50709, 0.67612, -2.36643,
|
||||||
|
0.76772, 0.60609, 0.12122, -2.82843,
|
||||||
|
-0.35857, 0.59761, -0.71714, 0.00000,
|
||||||
|
0.00000, 0.00000, 0.00000, 1.00000};
|
||||||
|
|
||||||
|
/* Temporary lower the precision */
|
||||||
|
set_equal_precision(0.00001);
|
||||||
|
|
||||||
|
ASSERT_EQ(t, Matrix4(values));
|
||||||
|
|
||||||
|
set_equal_precision(FLT_EPSILON);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TransformationTest, Check_that_deg_to_rad_is_working)
|
||||||
|
{
|
||||||
|
double angle180 = deg_to_rad(180);
|
||||||
|
double angle90 = deg_to_rad(90);
|
||||||
|
double angle270 = deg_to_rad(270);
|
||||||
|
|
||||||
|
ASSERT_EQ(angle180, M_PI);
|
||||||
|
ASSERT_EQ(angle90, M_PI / 2.);
|
||||||
|
ASSERT_EQ(angle270, M_PI * 1.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
114
tests/world_test.cpp
Normal file
114
tests/world_test.cpp
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* World unit tests
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <world.h>
|
||||||
|
#include <light.h>
|
||||||
|
#include <sphere.h>
|
||||||
|
#include <material.h>
|
||||||
|
#include <transformation.h>
|
||||||
|
#include <worldbuilder.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
|
||||||
|
TEST(WorldTest, Creating_a_world)
|
||||||
|
{
|
||||||
|
World w;
|
||||||
|
|
||||||
|
ASSERT_EQ(w.lightCount, 0);
|
||||||
|
ASSERT_EQ(w.objectCount, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(WorldTest, The_default_world)
|
||||||
|
{
|
||||||
|
World w = DefaultWorld();
|
||||||
|
|
||||||
|
Light l = Light(POINT_LIGHT, Point(-10, 10, -10), Colour(1, 1, 1));
|
||||||
|
Sphere s1 = Sphere();
|
||||||
|
Sphere s2 = Sphere();
|
||||||
|
Material s1Mat = Material();
|
||||||
|
s1Mat.colour = Colour(0.8, 1.0, 0.6);
|
||||||
|
s1Mat.diffuse = 0.7;
|
||||||
|
s1Mat.specular = 0.2;
|
||||||
|
s1.setMaterial(s1Mat);
|
||||||
|
|
||||||
|
s2.setTransform(scaling(0.5, 0.5,0.5));
|
||||||
|
|
||||||
|
ASSERT_TRUE(w.lightIsIn(l));
|
||||||
|
ASSERT_TRUE(w.objectIsIn(s1));
|
||||||
|
ASSERT_TRUE(w.objectIsIn(s2));
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(WorldTest, Intersect_a_world_with_a_ray)
|
||||||
|
{
|
||||||
|
World w = DefaultWorld();
|
||||||
|
Ray r = Ray(Point(0, 0, -5), Vector(0, 0, 1));
|
||||||
|
|
||||||
|
Intersect xs = w.intersect(r);
|
||||||
|
|
||||||
|
ASSERT_EQ(xs.count(), 4);
|
||||||
|
ASSERT_EQ(xs[0].t, 4);
|
||||||
|
ASSERT_EQ(xs[1].t, 4.5);
|
||||||
|
ASSERT_EQ(xs[2].t, 5.5);
|
||||||
|
ASSERT_EQ(xs[3].t, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(WorldTest, Shading_an_intersection)
|
||||||
|
{
|
||||||
|
World w = DefaultWorld();
|
||||||
|
Ray r = Ray(Point(0, 0, -5), Vector(0, 0, 1));
|
||||||
|
Shape *s = w.getObject(0);
|
||||||
|
Intersection i = Intersection(4, s);
|
||||||
|
Computation comps = i.prepareComputation(r);
|
||||||
|
Tuple c = w.shadeHit(comps);
|
||||||
|
|
||||||
|
/* Temporary lower the precision */
|
||||||
|
set_equal_precision(0.00001);
|
||||||
|
|
||||||
|
ASSERT_EQ(c, Colour(0.38066, 0.47583, 0.2855));
|
||||||
|
|
||||||
|
set_equal_precision(FLT_EPSILON);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(WorldTest, The_when_ray_miss)
|
||||||
|
{
|
||||||
|
World w = DefaultWorld();
|
||||||
|
Ray r = Ray(Point(0, 0, -5), Vector(0, 1, 0));
|
||||||
|
Tuple c = w.colourAt(r);
|
||||||
|
|
||||||
|
ASSERT_EQ(c, Colour(0, 0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(WorldTest, The_when_ray_hit)
|
||||||
|
{
|
||||||
|
World w = DefaultWorld();
|
||||||
|
Ray r = Ray(Point(0, 0, -5), Vector(0, 0, 1));
|
||||||
|
Tuple c = w.colourAt(r);
|
||||||
|
|
||||||
|
/* Temporary lower the precision */
|
||||||
|
set_equal_precision(0.00001);
|
||||||
|
|
||||||
|
ASSERT_EQ(c, Colour(0.38066, 0.47583, 0.2855));
|
||||||
|
|
||||||
|
set_equal_precision(FLT_EPSILON);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(WorldTest, The_colour_with_an_intersection_behind_the_ray)
|
||||||
|
{
|
||||||
|
World w = DefaultWorld();
|
||||||
|
Shape *outer = w.getObject(0);
|
||||||
|
outer->material.ambient = 1;
|
||||||
|
Shape *inner = w.getObject(1);
|
||||||
|
inner->material.ambient = 1;
|
||||||
|
|
||||||
|
Ray r = Ray(Point(0, 0, 0.75), Vector(0, 0, -1));
|
||||||
|
|
||||||
|
Tuple c = w.colourAt(r);
|
||||||
|
|
||||||
|
ASSERT_EQ(c, inner->material.colour);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user