/** * * RenderPipeline * * Copyright (c) 2014-2016 tobspr * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * */ /** * @brief Returns the amount of shadow sources * @details This returns the amount of shadow sources attached to this light. * In case the light has no shadows enabled, or the light was not attached * yet, this returns 0. * * @return Amount of shadow sources */ inline int RPLight::get_num_shadow_sources() const { return _shadow_sources.size(); } /** * @brief Returns the n-th shadow source * @details This returns the n-th attached shadow source. This ranges from * 0 .. RPLight::get_num_shadow_sources(). If an invalid index is passed, * an assertion is thrown. * * @param index Index of the source * @return Handle to the shadow source */ inline ShadowSource* RPLight::get_shadow_source(size_t index) const { nassertr(index < _shadow_sources.size(), NULL); // Invalid shadow source index return _shadow_sources[index]; } /** * @brief Clears all shadow source * @details This removes and destructs all shadow sources attached to this light. * This usually gets called when the light gets detached or destructed. * All shadows sources are freed, and then removed from the shadow source list. */ inline void RPLight::clear_shadow_sources() { for (size_t i = 0; i < _shadow_sources.size(); ++i) { delete _shadow_sources[i]; } _shadow_sources.clear(); } /** * @brief Sets whether the light needs an update * @details This controls whether the light needs to get an update. This is the * case when a property of the light changed, e.g. position or color. It does * not affect the shadows (For that use RPLight::invalidate_shadows()). * When this flag is set to true, the light will get resubmitted to the GPU * in the next update cycle. * * You should usually never set the flag to false manually. The * InternalLightManager will do this when the data got sucessfully updated. * * @param flag Update-Flag */ inline void RPLight::set_needs_update(bool flag) { _needs_update = flag; } /** * @brief Returns whether the light needs an update * @details This returns whether the light needs an update. This might be the * case when a property of the light was changed, e.g. position or color. * It does not affect the shadows, you have to query the update flag of each * individual source for that. * The return value is the value previously set with RPLight::set_needs_update. * * @return Update-flag */ inline bool RPLight::get_needs_update() const { return _needs_update; } /** * @brief Returns whether the light has a slot * @details This returns wheter the light currently is attached, and thus has * a slot in the InternalLightManagers light list. When the light is attached, * this returns true, otherwise it will return false. * * @return true if the light has a slot, false otherwise */ inline bool RPLight::has_slot() const { return _slot >= 0; } /** * @brief Returns the slot of the light * @details This returns the slot of the light. This is the space on the GPU * where the light is stored. If the light is not attached yet, this will * return -1, otherwise the index of the light. * * @return Light-Slot */ inline int RPLight::get_slot() const { return _slot; } /** * @brief Removes the light slot * @details This is an internal method to remove the slot of the light. It gets * called by the InternalLightManager when a light gets detached. It internally * sets the slot to -1 to indicate the light is no longer attached. */ inline void RPLight::remove_slot() { _slot = -1; } /** * @brief Assigns a slot to the light * @details This assigns a slot to the light, marking it as attached. The slot * relates to the index in the GPU's storage of lights. This is an internal * method called by the InternalLightManager when the light got attached. * * @param slot Slot of the light */ inline void RPLight::assign_slot(int slot) { _slot = slot; } /** * @brief Invalidates the shadows * @details This invalidates all shadows of the light, causing them to get * regenerated. This might be the case when the lights position or similar * changed. This will cause all shadow sources to be updated, emitting a * shadow update. Be careful when calling this method if you don't want all * sources to get updated. If you only have to invalidate a single shadow source, * use get_shadow_source(n)->set_needs_update(true). */ inline void RPLight::invalidate_shadows() { for (size_t i = 0; i < _shadow_sources.size(); ++i) { _shadow_sources[i]->set_needs_update(true); } } /** * @brief Sets the position of the light * @details This sets the position of the light in world space. It will cause * the light to get invalidated, and resubmitted to the GPU. * * @param pos Position in world space */ inline void RPLight::set_pos(const LVecBase3f &pos) { set_pos(pos.get_x(), pos.get_y(), pos.get_z()); } /** * @brief Sets the position of the light * @details @copydetails RPLight::set_pos(const LVecBase3f &pos) * * @param x X-component of the position * @param y Y-component of the position * @param z Z-component of the position */ inline void RPLight::set_pos(float x, float y, float z) { _position.set(x, y, z); set_needs_update(true); invalidate_shadows(); } /** * @brief Returns the position of the light * @details This returns the position of the light previously set with * RPLight::set_pos(). The returned position is in world space. * @return Light-position */ inline const LVecBase3f& RPLight::get_pos() const { return _position; } /** * @brief Sets the lights color * @details This sets the lights color. The color should not include the brightness * of the light, you should control that with the energy. The color specifies * the lights "tint" and will get multiplied with its specular and diffuse * contribution. * * The color will be normalized by dividing by the colors luminance. Setting * higher values than 1.0 will have no effect. * * @param color Light color */ inline void RPLight::set_color(const LVecBase3f &color) { _color = color; _color /= 0.2126 * color.get_x() + 0.7152 * color.get_y() + 0.0722 * color.get_z(); set_needs_update(true); } /** * @brief Sets the lights color * @details @copydetails RPLight::set_color(const LVecBase3f &color) * * @param r Red-component of the color * @param g Green-component of the color * @param b Blue-component of the color */ inline void RPLight::set_color(float r, float g, float b) { set_color(LVecBase3f(r, g, b)); } /** * @brief Returns the lights color * @details This returns the light color, previously set with RPLight::set_color. * This does not include the energy of the light. It might differ from what * was set with set_color, because the color is normalized by dividing it * by its luminance. * @return Light-color */ inline const LVecBase3f& RPLight::get_color() const { return _color; } /** * @brief Sets the energy of the light * @details This sets the energy of the light, which can be seen as the brightness * of the light. It will get multiplied with the normalized color. * * @param energy energy of the light */ inline void RPLight::set_energy(float energy) { _energy = energy; set_needs_update(true); } /** * @brief Returns the energy of the light * @details This returns the energy of the light, previously set with * RPLight::set_energy. * * @return energy of the light */ inline float RPLight::get_energy() const { return _energy; } /** * @brief Returns the type of the light * @details This returns the internal type of the light, which was specified * in the lights constructor. This can be used to distinguish between light * types. * @return Type of the light */ inline RPLight::LightType RPLight::get_light_type() const { return _light_type; } /** * @brief Controls whether the light casts shadows * @details This sets whether the light casts shadows. You can not change this * while the light is attached. When flag is set to true, the light will be * setup to cast shadows, spawning shadow sources based on the lights type. * If the flag is set to false, the light will be inddicated to cast no shadows. * * @param flag Whether the light casts shadows */ inline void RPLight::set_casts_shadows(bool flag) { if (has_slot()) { cerr << "Light is already attached, can not call set_casts_shadows!" << endl; return; } _casts_shadows = flag; } /** * @brief Returns whether the light casts shadows * @details This returns whether the light casts shadows, the returned value * is the one previously set with RPLight::set_casts_shadows. * * @return true if the light casts shadows, false otherwise */ inline bool RPLight::get_casts_shadows() const { return _casts_shadows; } /** * @brief Sets the lights shadow map resolution * @details This sets the lights shadow map resolution. This has no effect * when the light is not told to cast shadows (Use RPLight::set_casts_shadows). * * When calling this on a light with multiple shadow sources (e.g. PointLight), * this controls the resolution of each source. If the light has 6 shadow sources, * and you use a resolution of 512x512, the lights shadow map will occur a * space of 6 * 512x512 maps in the shadow atlas. * * @param resolution Resolution of the shadow map in pixels */ inline void RPLight::set_shadow_map_resolution(size_t resolution) { nassertv(resolution >= 32 && resolution <= 16384); _source_resolution = resolution; invalidate_shadows(); } /** * @brief Returns the shadow map resolution * @details This returns the shadow map resolution of each source of the light. * If the light is not setup to cast shadows, this value is meaningless. * The returned value is the one previously set with RPLight::set_shadow_map_resolution. * * @return Shadow map resolution in pixels */ inline size_t RPLight::get_shadow_map_resolution() const { return _source_resolution; } /** * @brief Sets the ies profile * @details This sets the ies profile of the light. The parameter should be a * handle previously returned by RenderPipeline.load_ies_profile. Using a * value of -1 indicates no ies profile. * * Notice that for ies profiles which cover a whole range, you should use * PointLights, whereas for ies profiles which only cover the lower hemisphere * you should use SpotLights for the best performance. * * @param profile IES Profile handle */ inline void RPLight::set_ies_profile(int profile) { _ies_profile = profile; set_needs_update(true); } /** * @brief Returns the lights ies profile * @details This returns the ies profile of a light, previously set with * RPLight::set_ies_profile. In case no ies profile was set, returns -1. * * @return IES Profile handle */ inline int RPLight::get_ies_profile() const { return _ies_profile; } /** * @brief Returns whether the light has an ies profile assigned * @details This returns whether the light has an ies profile assigned, * previously done with RPLight::set_ies_profile. * * @return true if the light has an ies profile assigned, false otherwise */ inline bool RPLight::has_ies_profile() const { return _ies_profile >= 0; } /** * @brief Clears the ies profile * @details This clears the ies profile of the light, telling it to no longer * use an ies profile, and instead use the default attenuation. */ inline void RPLight::clear_ies_profile() { set_ies_profile(-1); } /** * @brief Sets the near plane of the light * @details This sets the near plane of all shadow sources of the light. It has * no effects if the light does not cast shadows. This prevents artifacts from * objects near to the light. It behaves like Lens::set_near_plane. * * It can also help increasing shadow map precision, low near planes will * cause the precision to suffer. Try setting the near plane as big as possible. * * If a negative or zero near plane is passed, an assertion is thrown. * * @param near_plane Near-plane */ inline void RPLight::set_near_plane(float near_plane) { nassertv(near_plane > 0.00001); _near_plane = near_plane; invalidate_shadows(); } /** * @brief Returns the near plane of the light * @details This returns the lights near plane, previously set with * RPLight::set_near_plane. If the light does not cast shadows, this value * is meaningless. * * @return Near-plane */ inline float RPLight::get_near_plane() const { return _near_plane; }