| 230 | } |
| 231 | |
| 232 | void Camera::scale_at(const vec4& center_ndc, const float delta) { |
| 233 | // Check if lowest zoom value has been reached. |
| 234 | auto new_delta{delta}; |
| 235 | if (new_delta < 0) { |
| 236 | |
| 237 | // Ratio which defines farthest zoom limit. (0; 1]. |
| 238 | // 1 forbids to zoom farther than window size. |
| 239 | // 0 allows unlimited zoom-out. |
| 240 | static constexpr auto ratio_lowest{0.75f}; |
| 241 | |
| 242 | // Get initial dimensions of buffer (without zoom). |
| 243 | const auto [buffer_width, buffer_height] = |
| 244 | get_buffer_initial_dimensions(); |
| 245 | |
| 246 | // Find the lowest allowed zoom ratio. |
| 247 | const auto zoom_lowest_x = |
| 248 | ratio_lowest * static_cast<float>(canvas_width_) / buffer_width; |
| 249 | const auto zoom_lowest_y = |
| 250 | ratio_lowest * static_cast<float>(canvas_height_) / buffer_height; |
| 251 | const auto zoom_lowest = (std::min)(zoom_lowest_x, zoom_lowest_y); |
| 252 | |
| 253 | // Find the lowest allowed zoom power. |
| 254 | const auto zoom_power_lowest = |
| 255 | std::log(zoom_lowest) / std::log(zoom_factor); |
| 256 | |
| 257 | // Find the lowest allowed delta. |
| 258 | const auto delta_lowest = zoom_power_lowest - zoom_power_; |
| 259 | if (delta_lowest >= 0) { |
| 260 | return; |
| 261 | } |
| 262 | |
| 263 | // Update delta if view matrix is near its lowest zoom. |
| 264 | new_delta = (std::max)(new_delta, delta_lowest); |
| 265 | } |
| 266 | |
| 267 | // Check if greatest zoom value has been reached. |
| 268 | if (new_delta > 0) { |
| 269 | |
| 270 | // Closest zoom power. It may be any positive value. |
| 271 | // 1 forbids to zoom closer than original matrix scale. |
| 272 | // infinity allows unlimited zoom-in. |
| 273 | static constexpr auto zoom_power_greatest{50.0f}; |
| 274 | |
| 275 | // Find the greatest allowed delta. |
| 276 | const auto delta_greatest{zoom_power_greatest - zoom_power_}; |
| 277 | if (delta_greatest <= 0) { |
| 278 | return; |
| 279 | } |
| 280 | |
| 281 | // Update delta if view matrix is near its greatest zoom. |
| 282 | new_delta = (std::min)(new_delta, delta_greatest); |
| 283 | } |
| 284 | |
| 285 | const auto vp_inv = game_object_ref().get_pose() * projection_.inv(); |
| 286 | |
| 287 | const auto delta_zoom = std::pow(zoom_factor, -new_delta); |
| 288 | |
| 289 | const auto center_pos = scale_.inv() * vp_inv * center_ndc; |