Initial commit

This commit is contained in:
Martin Felis
2021-11-11 21:22:24 +01:00
commit b78045ffe7
812 changed files with 421882 additions and 0 deletions
@@ -0,0 +1,279 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// 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. //
// //
//----------------------------------------------------------------------------//
#define OZZ_INCLUDE_PRIVATE_HEADER // Allows to include private headers.
#include "camera.h"
#include "ozz/base/log.h"
#include "ozz/base/maths/box.h"
#include "ozz/base/maths/math_constant.h"
#include "ozz/base/maths/math_ex.h"
#include "ozz/base/platform.h"
#include "framework/application.h"
#include "framework/imgui.h"
#include "renderer_impl.h"
using ozz::math::Float2;
using ozz::math::Float3;
using ozz::math::Float4x4;
namespace ozz {
namespace sample {
namespace internal {
// Declares camera navigation constants.
const float kDefaultDistance = 8.f;
const Float3 kDefaultCenter = Float3(0.f, .5f, 0.f);
const Float2 kDefaultAngle =
Float2(-ozz::math::kPi * 1.f / 12.f, ozz::math::kPi * 1.f / 5.f);
const float kAngleFactor = .01f;
const float kDistanceFactor = .1f;
const float kScrollFactor = .03f;
const float kPanFactor = .05f;
const float kKeyboardFactor = 100.f;
const float kNear = .01f;
const float kFar = 1000.f;
const float kFovY = ozz::math::kPi / 3.f;
const float kFrameAllZoomOut = 1.3f; // 30% bigger than the scene.
// Setups initial values.
Camera::Camera()
: projection_(Float4x4::identity()),
projection_2d_(Float4x4::identity()),
view_(Float4x4::identity()),
view_proj_(Float4x4::identity()),
angles_(kDefaultAngle),
center_(kDefaultCenter),
distance_(kDefaultDistance),
mouse_last_x_(0),
mouse_last_y_(0),
mouse_last_wheel_(0),
auto_framing_(true) {}
Camera::~Camera() {}
void Camera::Update(const math::Box& _box, float _delta_time,
bool _first_frame) {
// Frame the scene according to the provided box.
if (_box.is_valid()) {
if (auto_framing_ || _first_frame) {
center_ = (_box.max + _box.min) * .5f;
if (_first_frame) {
const float radius = Length(_box.max - _box.min) * .5f;
distance_ = radius * kFrameAllZoomOut / tanf(kFovY * .5f);
}
}
}
// Update manual controls.
const Controls controls = UpdateControls(_delta_time);
// Disable autoframing according to inputs.
auto_framing_ &=
!controls.panning && !controls.zooming && !controls.zooming_wheel;
}
void Camera::Update(const math::Float4x4& _transform, const math::Box& _box,
float _delta_time, bool _first_frame) {
// Extract distance and angles such that theu are coherent when switching out
// of auto_framing_.
if (_box.is_valid()) {
if (auto_framing_ || _first_frame) {
// Extract components from the view martrix.
ozz::math::Float3 camera_dir;
ozz::math::Store3PtrU(-ozz::math::Normalize3(_transform.cols[2]),
&camera_dir.x);
ozz::math::Float3 camera_pos;
ozz::math::Store3PtrU(_transform.cols[3], &camera_pos.x);
// Arbitrary decides that distance (focus point) is from camera to scene
// center.
const ozz::math::Float3 box_center_ = (_box.max + _box.min) * .5f;
distance_ = Length(box_center_ - camera_pos);
center_ = camera_pos + camera_dir * distance_;
angles_.x = asinf(camera_dir.y);
angles_.y = atan2(-camera_dir.x, -camera_dir.z);
}
}
// Update manual controls.
const Controls controls = UpdateControls(_delta_time);
// Disable autoframing according to inputs.
auto_framing_ &= !controls.panning && !controls.rotating &&
!controls.zooming && !controls.zooming_wheel;
if (auto_framing_) {
view_ = Invert(_transform);
}
}
Camera::Controls Camera::UpdateControls(float _delta_time) {
Controls controls;
controls.zooming = false;
controls.zooming_wheel = false;
controls.rotating = false;
controls.panning = false;
// Mouse wheel + SHIFT activates Zoom.
if (glfwGetKey(GLFW_KEY_LSHIFT) == GLFW_PRESS) {
const int w = glfwGetMouseWheel();
const int dw = w - mouse_last_wheel_;
mouse_last_wheel_ = w;
if (dw != 0) {
controls.zooming_wheel = true;
distance_ *= 1.f + -dw * kScrollFactor;
}
} else {
mouse_last_wheel_ = glfwGetMouseWheel();
}
// Fetches current mouse position and compute its movement since last frame.
int x, y;
glfwGetMousePos(&x, &y);
const int mdx = x - mouse_last_x_;
const int mdy = y - mouse_last_y_;
mouse_last_x_ = x;
mouse_last_y_ = y;
// Finds keyboard relative dx and dy commmands.
const int timed_factor =
ozz::math::Max(1, static_cast<int>(kKeyboardFactor * _delta_time));
const int kdx =
timed_factor * (glfwGetKey(GLFW_KEY_LEFT) - glfwGetKey(GLFW_KEY_RIGHT));
const int kdy =
timed_factor * (glfwGetKey(GLFW_KEY_DOWN) - glfwGetKey(GLFW_KEY_UP));
const bool keyboard_interact = kdx || kdy;
// Computes composed keyboard and mouse dx and dy.
const int dx = mdx + kdx;
const int dy = mdy + kdy;
// Mouse right button activates Zoom, Pan and Orbit modes.
if (keyboard_interact ||
glfwGetMouseButton(GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS) {
if (glfwGetKey(GLFW_KEY_LSHIFT) == GLFW_PRESS) { // Zoom mode.
controls.zooming = true;
distance_ += dy * kDistanceFactor;
} else if (glfwGetKey(GLFW_KEY_LALT) == GLFW_PRESS) { // Pan mode.
controls.panning = true;
const float dx_pan = -dx * kPanFactor;
const float dy_pan = -dy * kPanFactor;
// Moves along camera axes.
math::Float4x4 transpose = Transpose(view_);
math::Float3 right_transpose, up_transpose;
math::Store3PtrU(transpose.cols[0], &right_transpose.x);
math::Store3PtrU(transpose.cols[1], &up_transpose.x);
center_ = center_ + right_transpose * dx_pan + up_transpose * dy_pan;
} else { // Orbit mode.
controls.rotating = true;
angles_.x = fmodf(angles_.x - dy * kAngleFactor, ozz::math::k2Pi);
angles_.y = fmodf(angles_.y - dx * kAngleFactor, ozz::math::k2Pi);
}
}
// Build the model view matrix components.
const Float4x4 center = Float4x4::Translation(
math::simd_float4::Load(center_.x, center_.y, center_.z, 1.f));
const Float4x4 y_rotation = Float4x4::FromAxisAngle(
math::simd_float4::y_axis(), math::simd_float4::Load1(angles_.y));
const Float4x4 x_rotation = Float4x4::FromAxisAngle(
math::simd_float4::x_axis(), math::simd_float4::Load1(angles_.x));
const Float4x4 distance =
Float4x4::Translation(math::simd_float4::Load(0.f, 0.f, distance_, 1.f));
// Concatenate view matrix components.
view_ = Invert(center * y_rotation * x_rotation * distance);
return controls;
}
void Camera::Reset(const math::Float3& _center, const math::Float2& _angles,
float _distance) {
center_ = _center;
angles_ = _angles;
distance_ = _distance;
}
void Camera::OnGui(ImGui* _im_gui) {
const char* controls_label =
"-RMB: Rotate\n"
"-Shift + Wheel: Zoom\n"
"-Shift + RMB: Zoom\n"
"-Alt + RMB: Pan\n";
_im_gui->DoLabel(controls_label, ImGui::kLeft, false);
_im_gui->DoCheckBox("Automatic", &auto_framing_);
}
void Camera::Bind3D() {
// Updates internal vp matrix.
view_proj_ = projection_ * view_;
}
void Camera::Bind2D() {
// Updates internal vp matrix. View matrix is identity.
view_proj_ = projection_2d_;
}
void Camera::Resize(int _width, int _height) {
// Handle empty windows.
if (_width <= 0 || _height <= 0) {
projection_ = ozz::math::Float4x4::identity();
projection_2d_ = ozz::math::Float4x4::identity();
return;
}
// Compute the 3D projection matrix.
const float ratio = 1.f * _width / _height;
const float h = tan(kFovY * .5f) * kNear;
const float w = h * ratio;
projection_.cols[0] = math::simd_float4::Load(kNear / w, 0.f, 0.f, 0.f);
projection_.cols[1] = math::simd_float4::Load(0.f, kNear / h, 0.f, 0.f);
projection_.cols[2] =
math::simd_float4::Load(0.f, 0.f, -(kFar + kNear) / (kFar - kNear), -1.f);
projection_.cols[3] = math::simd_float4::Load(
0.f, 0.f, -(2.f * kFar * kNear) / (kFar - kNear), 0.f);
// Computes the 2D projection matrix.
projection_2d_.cols[0] = math::simd_float4::Load(2.f / _width, 0.f, 0.f, 0.f);
projection_2d_.cols[1] =
math::simd_float4::Load(0.f, 2.f / _height, 0.f, 0.f);
projection_2d_.cols[2] = math::simd_float4::Load(0.f, 0.f, -2.0f, 0.f);
projection_2d_.cols[3] = math::simd_float4::Load(-1.f, -1.f, 0.f, 1.f);
}
} // namespace internal
} // namespace sample
} // namespace ozz
@@ -0,0 +1,136 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// 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. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_SAMPLES_FRAMEWORK_INTERNAL_CAMERA_H_
#define OZZ_SAMPLES_FRAMEWORK_INTERNAL_CAMERA_H_
#ifndef OZZ_INCLUDE_PRIVATE_HEADER
#error "This header is private, it cannot be included from public headers."
#endif // OZZ_INCLUDE_PRIVATE_HEADER
#include "ozz/base/maths/simd_math.h"
#include "ozz/base/maths/vec_float.h"
namespace ozz {
namespace math {
struct Box;
}
namespace sample {
class ImGui;
namespace internal {
// Framework internal implementation of an OpenGL/glfw camera system that can be
// manipulated with the mouse and some shortcuts.
class Camera {
public:
// Initializes camera to its default framing.
Camera();
// Destructor.
~Camera();
// Updates camera framing: mouse manipulation, timed transitions...
// Returns actions that the user applied to the camera during the frame.
void Update(const math::Box& _box, float _delta_time, bool _first_frame);
// Updates camera location, overriding user inputs.
// Returns actions that the user applied to the camera during the frame.
void Update(const math::Float4x4& _transform, const math::Box& _box,
float _delta_time, bool _first_frame);
// Resets camera center, angles and distance.
void Reset(const math::Float3& _center, const math::Float2& _angles,
float _distance);
// Provides immediate mode gui display event.
void OnGui(ImGui* _im_gui);
// Binds 3d projection and view matrices to the current matrix.
void Bind3D();
// Binds 2d projection and view matrices to the current matrix.
void Bind2D();
// Resize notification, used to rebuild projection matrix.
void Resize(int _width, int _height);
// Get the current projection matrix.
const math::Float4x4& projection() { return projection_; }
// Get the current model-view matrix.
const math::Float4x4& view() { return view_; }
// Get the current model-view-projection matrix.
const math::Float4x4& view_proj() { return view_proj_; }
// Set to true to automatically frame the camera on the whole scene.
void set_auto_framing(bool _auto) { auto_framing_ = _auto; }
// Get auto framing state.
bool auto_framing() const { return auto_framing_; }
private:
struct Controls {
bool zooming;
bool zooming_wheel;
bool rotating;
bool panning;
};
Controls UpdateControls(float _delta_time);
// The current projection matrix.
math::Float4x4 projection_;
// The current projection matrix.
math::Float4x4 projection_2d_;
// The current model-view matrix.
math::Float4x4 view_;
// The current model-view-projection matrix.
math::Float4x4 view_proj_;
// The angles in degree of the camera rotation around x and y axes.
math::Float2 angles_;
// The center of the rotation.
math::Float3 center_;
// The view distance, from the center of rotation.
float distance_;
// The position of the mouse, the last time it has been seen.
int mouse_last_x_;
int mouse_last_y_;
int mouse_last_wheel_;
// Set to true to automatically frame the camera on the whole scene.
bool auto_framing_;
};
} // namespace internal
} // namespace sample
} // namespace ozz
#endif // OZZ_SAMPLES_FRAMEWORK_INTERNAL_CAMERA_H_
@@ -0,0 +1,171 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// 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. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_SAMPLES_FRAMEWORK_INTERNAL_ICOSPHERE_H_
#define OZZ_SAMPLES_FRAMEWORK_INTERNAL_ICOSPHERE_H_
#include "ozz/base/platform.h"
// Precomputed normalized icosphere with 2 levels of subdivisions.
// Note that kVertices can also be used as normals.
namespace icosphere {
static const float kVertices[] = {
-0.682f, 0.717f, 0.148f, -0.588f, 0.688f, 0.425f, -0.443f, 0.864f,
0.239f, -0.526f, 0.851f, 0.000f, -0.809f, 0.500f, 0.309f, -0.309f,
0.809f, 0.500f, -0.717f, 0.148f, 0.682f, -0.688f, 0.425f, 0.588f,
-0.864f, 0.239f, 0.443f, -0.851f, 0.000f, 0.526f, -0.500f, 0.309f,
0.809f, -0.148f, 0.682f, 0.717f, -0.425f, 0.588f, 0.688f, -0.239f,
0.443f, 0.864f, 0.000f, 0.526f, 0.851f, -0.162f, 0.951f, 0.263f,
-0.295f, 0.955f, 0.000f, 0.000f, 1.000f, 0.000f, 0.148f, 0.682f,
0.717f, 0.000f, 0.851f, 0.526f, 0.309f, 0.809f, 0.500f, 0.295f,
0.955f, 0.000f, 0.162f, 0.951f, 0.263f, 0.443f, 0.864f, 0.239f,
0.526f, 0.851f, 0.000f, -0.162f, 0.951f, -0.263f, -0.443f, 0.864f,
-0.239f, -0.309f, 0.809f, -0.500f, 0.443f, 0.864f, -0.239f, 0.162f,
0.951f, -0.263f, 0.309f, 0.809f, -0.500f, -0.148f, 0.682f, -0.717f,
0.000f, 0.851f, -0.526f, 0.148f, 0.682f, -0.717f, 0.000f, 0.526f,
-0.851f, -0.588f, 0.688f, -0.425f, -0.682f, 0.717f, -0.148f, -0.809f,
0.500f, -0.309f, -0.239f, 0.443f, -0.864f, -0.425f, 0.588f, -0.688f,
-0.500f, 0.309f, -0.809f, -0.864f, 0.239f, -0.443f, -0.688f, 0.425f,
-0.588f, -0.717f, 0.148f, -0.682f, -0.851f, 0.000f, -0.526f, -0.851f,
0.526f, 0.000f, -0.955f, 0.000f, -0.295f, -0.951f, 0.263f, -0.162f,
-1.000f, 0.000f, 0.000f, -0.951f, 0.263f, 0.162f, -0.955f, 0.000f,
0.295f, 0.588f, 0.688f, 0.425f, 0.682f, 0.717f, 0.148f, 0.809f,
0.500f, 0.309f, 0.239f, 0.443f, 0.864f, 0.425f, 0.588f, 0.688f,
0.500f, 0.309f, 0.809f, 0.864f, 0.239f, 0.443f, 0.688f, 0.425f,
0.588f, 0.717f, 0.148f, 0.682f, 0.851f, 0.000f, 0.526f, -0.263f,
0.162f, 0.951f, 0.000f, 0.295f, 0.955f, 0.000f, 0.000f, 1.000f,
-0.717f, -0.148f, 0.682f, -0.526f, 0.000f, 0.851f, -0.500f, -0.309f,
0.809f, 0.000f, -0.295f, 0.955f, -0.263f, -0.162f, 0.951f, -0.239f,
-0.443f, 0.864f, 0.000f, -0.526f, 0.851f, -0.951f, -0.263f, 0.162f,
-0.864f, -0.239f, 0.443f, -0.809f, -0.500f, 0.309f, -0.864f, -0.239f,
-0.443f, -0.951f, -0.263f, -0.162f, -0.809f, -0.500f, -0.309f, -0.682f,
-0.717f, 0.148f, -0.851f, -0.526f, 0.000f, -0.682f, -0.717f, -0.148f,
-0.526f, -0.851f, 0.000f, -0.526f, 0.000f, -0.851f, -0.717f, -0.148f,
-0.682f, -0.500f, -0.309f, -0.809f, 0.000f, 0.295f, -0.955f, -0.263f,
0.162f, -0.951f, 0.000f, 0.000f, -1.000f, -0.239f, -0.443f, -0.864f,
-0.263f, -0.162f, -0.951f, 0.000f, -0.295f, -0.955f, 0.000f, -0.526f,
-0.851f, 0.425f, 0.588f, -0.688f, 0.239f, 0.443f, -0.864f, 0.500f,
0.309f, -0.809f, 0.682f, 0.717f, -0.148f, 0.588f, 0.688f, -0.425f,
0.809f, 0.500f, -0.309f, 0.717f, 0.148f, -0.682f, 0.688f, 0.425f,
-0.588f, 0.864f, 0.239f, -0.443f, 0.851f, 0.000f, -0.526f, 0.682f,
-0.717f, 0.148f, 0.588f, -0.688f, 0.425f, 0.443f, -0.864f, 0.239f,
0.526f, -0.851f, 0.000f, 0.809f, -0.500f, 0.309f, 0.309f, -0.809f,
0.500f, 0.717f, -0.148f, 0.682f, 0.688f, -0.425f, 0.588f, 0.864f,
-0.239f, 0.443f, 0.500f, -0.309f, 0.809f, 0.148f, -0.682f, 0.717f,
0.425f, -0.588f, 0.688f, 0.239f, -0.443f, 0.864f, 0.162f, -0.951f,
0.263f, 0.295f, -0.955f, 0.000f, 0.000f, -1.000f, 0.000f, -0.148f,
-0.682f, 0.717f, 0.000f, -0.851f, 0.526f, -0.309f, -0.809f, 0.500f,
-0.295f, -0.955f, 0.000f, -0.162f, -0.951f, 0.263f, -0.443f, -0.864f,
0.239f, 0.162f, -0.951f, -0.263f, 0.443f, -0.864f, -0.239f, 0.309f,
-0.809f, -0.500f, -0.443f, -0.864f, -0.239f, -0.162f, -0.951f, -0.263f,
-0.309f, -0.809f, -0.500f, 0.148f, -0.682f, -0.717f, 0.000f, -0.851f,
-0.526f, -0.148f, -0.682f, -0.717f, 0.588f, -0.688f, -0.425f, 0.682f,
-0.717f, -0.148f, 0.809f, -0.500f, -0.309f, 0.239f, -0.443f, -0.864f,
0.425f, -0.588f, -0.688f, 0.500f, -0.309f, -0.809f, 0.864f, -0.239f,
-0.443f, 0.688f, -0.425f, -0.588f, 0.717f, -0.148f, -0.682f, 0.851f,
-0.526f, 0.000f, 0.955f, 0.000f, -0.295f, 0.951f, -0.263f, -0.162f,
1.000f, 0.000f, 0.000f, 0.951f, -0.263f, 0.162f, 0.955f, 0.000f,
0.295f, 0.263f, -0.162f, 0.951f, 0.526f, 0.000f, 0.851f, 0.263f,
0.162f, 0.951f, -0.588f, -0.688f, 0.425f, -0.425f, -0.588f, 0.688f,
-0.688f, -0.425f, 0.588f, -0.425f, -0.588f, -0.688f, -0.588f, -0.688f,
-0.425f, -0.688f, -0.425f, -0.588f, 0.526f, 0.000f, -0.851f, 0.263f,
-0.162f, -0.951f, 0.263f, 0.162f, -0.951f, 0.951f, 0.263f, 0.162f,
0.951f, 0.263f, -0.162f, 0.851f, 0.526f, 0.000f};
static const int kNumVertices = OZZ_ARRAY_SIZE(kVertices);
static const uint16_t kIndices[] = {
3, 0, 2, 4, 1, 0, 5, 2, 1, 0, 1, 2, 9, 6, 8,
10, 7, 6, 4, 8, 7, 6, 7, 8, 14, 11, 13, 5, 12, 11,
10, 13, 12, 11, 12, 13, 4, 7, 1, 10, 12, 7, 5, 1, 12,
7, 12, 1, 3, 2, 16, 5, 15, 2, 17, 16, 15, 2, 15, 16,
14, 18, 11, 20, 19, 18, 5, 11, 19, 18, 19, 11, 24, 21, 23,
17, 22, 21, 20, 23, 22, 21, 22, 23, 5, 19, 15, 20, 22, 19,
17, 15, 22, 19, 22, 15, 3, 16, 26, 17, 25, 16, 27, 26, 25,
16, 25, 26, 24, 28, 21, 30, 29, 28, 17, 21, 29, 28, 29, 21,
34, 31, 33, 27, 32, 31, 30, 33, 32, 31, 32, 33, 17, 29, 25,
30, 32, 29, 27, 25, 32, 29, 32, 25, 3, 26, 36, 27, 35, 26,
37, 36, 35, 26, 35, 36, 34, 38, 31, 40, 39, 38, 27, 31, 39,
38, 39, 31, 44, 41, 43, 37, 42, 41, 40, 43, 42, 41, 42, 43,
27, 39, 35, 40, 42, 39, 37, 35, 42, 39, 42, 35, 3, 36, 0,
37, 45, 36, 4, 0, 45, 36, 45, 0, 44, 46, 41, 48, 47, 46,
37, 41, 47, 46, 47, 41, 9, 8, 50, 4, 49, 8, 48, 50, 49,
8, 49, 50, 37, 47, 45, 48, 49, 47, 4, 45, 49, 47, 49, 45,
24, 23, 52, 20, 51, 23, 53, 52, 51, 23, 51, 52, 14, 54, 18,
56, 55, 54, 20, 18, 55, 54, 55, 18, 60, 57, 59, 53, 58, 57,
56, 59, 58, 57, 58, 59, 20, 55, 51, 56, 58, 55, 53, 51, 58,
55, 58, 51, 14, 13, 62, 10, 61, 13, 63, 62, 61, 13, 61, 62,
9, 64, 6, 66, 65, 64, 10, 6, 65, 64, 65, 6, 70, 67, 69,
63, 68, 67, 66, 69, 68, 67, 68, 69, 10, 65, 61, 66, 68, 65,
63, 61, 68, 65, 68, 61, 9, 50, 72, 48, 71, 50, 73, 72, 71,
50, 71, 72, 44, 74, 46, 76, 75, 74, 48, 46, 75, 74, 75, 46,
80, 77, 79, 73, 78, 77, 76, 79, 78, 77, 78, 79, 48, 75, 71,
76, 78, 75, 73, 71, 78, 75, 78, 71, 44, 43, 82, 40, 81, 43,
83, 82, 81, 43, 81, 82, 34, 84, 38, 86, 85, 84, 40, 38, 85,
84, 85, 38, 90, 87, 89, 83, 88, 87, 86, 89, 88, 87, 88, 89,
40, 85, 81, 86, 88, 85, 83, 81, 88, 85, 88, 81, 34, 33, 92,
30, 91, 33, 93, 92, 91, 33, 91, 92, 24, 94, 28, 96, 95, 94,
30, 28, 95, 94, 95, 28, 100, 97, 99, 93, 98, 97, 96, 99, 98,
97, 98, 99, 30, 95, 91, 96, 98, 95, 93, 91, 98, 95, 98, 91,
104, 101, 103, 105, 102, 101, 106, 103, 102, 101, 102, 103, 60, 107, 109,
110, 108, 107, 105, 109, 108, 107, 108, 109, 70, 111, 113, 106, 112, 111,
110, 113, 112, 111, 112, 113, 105, 108, 102, 110, 112, 108, 106, 102, 112,
108, 112, 102, 104, 103, 115, 106, 114, 103, 116, 115, 114, 103, 114, 115,
70, 117, 111, 119, 118, 117, 106, 111, 118, 117, 118, 111, 80, 120, 122,
116, 121, 120, 119, 122, 121, 120, 121, 122, 106, 118, 114, 119, 121, 118,
116, 114, 121, 118, 121, 114, 104, 115, 124, 116, 123, 115, 125, 124, 123,
115, 123, 124, 80, 126, 120, 128, 127, 126, 116, 120, 127, 126, 127, 120,
90, 129, 131, 125, 130, 129, 128, 131, 130, 129, 130, 131, 116, 127, 123,
128, 130, 127, 125, 123, 130, 127, 130, 123, 104, 124, 133, 125, 132, 124,
134, 133, 132, 124, 132, 133, 90, 135, 129, 137, 136, 135, 125, 129, 136,
135, 136, 129, 100, 138, 140, 134, 139, 138, 137, 140, 139, 138, 139, 140,
125, 136, 132, 137, 139, 136, 134, 132, 139, 136, 139, 132, 104, 133, 101,
134, 141, 133, 105, 101, 141, 133, 141, 101, 100, 142, 138, 144, 143, 142,
134, 138, 143, 142, 143, 138, 60, 109, 146, 105, 145, 109, 144, 146, 145,
109, 145, 146, 134, 143, 141, 144, 145, 143, 105, 141, 145, 143, 145, 141,
70, 113, 67, 110, 147, 113, 63, 67, 147, 113, 147, 67, 60, 59, 107,
56, 148, 59, 110, 107, 148, 59, 148, 107, 14, 62, 54, 63, 149, 62,
56, 54, 149, 62, 149, 54, 110, 148, 147, 56, 149, 148, 63, 147, 149,
148, 149, 147, 80, 122, 77, 119, 150, 122, 73, 77, 150, 122, 150, 77,
70, 69, 117, 66, 151, 69, 119, 117, 151, 69, 151, 117, 9, 72, 64,
73, 152, 72, 66, 64, 152, 72, 152, 64, 119, 151, 150, 66, 152, 151,
73, 150, 152, 151, 152, 150, 90, 131, 87, 128, 153, 131, 83, 87, 153,
131, 153, 87, 80, 79, 126, 76, 154, 79, 128, 126, 154, 79, 154, 126,
44, 82, 74, 83, 155, 82, 76, 74, 155, 82, 155, 74, 128, 154, 153,
76, 155, 154, 83, 153, 155, 154, 155, 153, 100, 140, 97, 137, 156, 140,
93, 97, 156, 140, 156, 97, 90, 89, 135, 86, 157, 89, 137, 135, 157,
89, 157, 135, 34, 92, 84, 93, 158, 92, 86, 84, 158, 92, 158, 84,
137, 157, 156, 86, 158, 157, 93, 156, 158, 157, 158, 156, 60, 146, 57,
144, 159, 146, 53, 57, 159, 146, 159, 57, 100, 99, 142, 96, 160, 99,
144, 142, 160, 99, 160, 142, 24, 52, 94, 53, 161, 52, 96, 94, 161,
52, 161, 94, 144, 160, 159, 96, 161, 160, 53, 159, 161, 160, 161, 159};
static const int kNumIndices = OZZ_ARRAY_SIZE(kIndices);
} // namespace icosphere
#endif // OZZ_SAMPLES_FRAMEWORK_INTERNAL_ICOSPHERE_H_
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,233 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// 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. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_SAMPLES_FRAMEWORK_INTERNAL_IMGUI_IMPL_H_
#define OZZ_SAMPLES_FRAMEWORK_INTERNAL_IMGUI_IMPL_H_
#ifndef OZZ_INCLUDE_PRIVATE_HEADER
#error "This header is private, it cannot be included from public headers."
#endif // OZZ_INCLUDE_PRIVATE_HEADER
// Implements immediate mode gui.
// See imgui.h for details about function specifications.
#include "framework/imgui.h"
#include "ozz/base/containers/vector.h"
#include "ozz/base/maths/rect.h"
#include "renderer_impl.h"
namespace ozz {
namespace sample {
namespace internal {
class RendererImpl;
// Immediate mode gui implementation.
class ImGuiImpl : public ImGui {
public:
ImGuiImpl();
virtual ~ImGuiImpl();
// Input state.
struct Inputs {
// Default input values.
Inputs() : mouse_x(0), mouse_y(0), lmb_pressed(false) {}
// Cursor x position. 0 indicates the screen left border.
int mouse_x;
// Cursor y position. 0 indicates the screen bottom border.
int mouse_y;
// Left mouse button state. true when the left mouse button is pressed.
bool lmb_pressed;
};
// Starts an imgui frame.
// _inputs describes next frame inputs. It is internally copied.
// _rect is the windows size.
void BeginFrame(const Inputs& _inputs, const math::RectInt& _rect,
RendererImpl* _renderer);
// Ends the current imgui frame.
void EndFrame();
protected:
// Starts ImGui interface implementation.
// See imgui.h for virtual function specifications.
virtual void BeginContainer(const char* _title, const math::RectFloat* _rect,
bool* _open, bool _constrain);
virtual void EndContainer();
virtual bool DoButton(const char* _label, bool _enabled, bool* _state);
virtual bool DoSlider(const char* _label, float _min, float _max,
float* _value, float _pow, bool _enabled);
virtual bool DoSlider(const char* _label, int _min, int _max, int* _value,
float _pow, bool _enabled);
virtual bool DoCheckBox(const char* _label, bool* _state, bool _enabled);
virtual bool DoRadioButton(int _ref, const char* _label, int* _value,
bool _enabled);
virtual void DoLabel(const char* _label, Justification _justification,
bool _single_line);
virtual void DoGraph(const char* _label, float _min, float _max, float _mean,
const float* _value_cursor, const float* _value_begin,
const float* _value_end);
private:
// Computes the rect of a new widget to add.
// Returns true if there is enough space for a new widget.
bool AddWidget(float _height, math::RectFloat* _rect);
// Implements button logic.
// Returns true if the button was clicked.
bool ButtonLogic(const math::RectFloat& _rect, int _id, bool* _hot,
bool* _active);
// Fills a rectangle with _rect coordinates. Draws rounded angles if _radius
// is greater than 0.
// If _texture id is not 0, then texture with id _texture is mapped using a
// planar projection to the rect.
void FillRect(const math::RectFloat& _rect, float _radius,
const GLubyte _rgba[4]) const;
void FillRect(const math::RectFloat& _rect, float _radius,
const GLubyte _rgba[4],
const ozz::math::Float4x4& _transform) const;
// Strokes a rectangle with _rect coordinates. Draws rounded angles if _radius
// is greater than 0.
void StrokeRect(const math::RectFloat& _rect, float _radius,
const GLubyte _rgba[4]) const;
void StrokeRect(const math::RectFloat& _rect, float _radius,
const GLubyte _rgba[4],
const ozz::math::Float4x4& _transform) const;
enum PrintLayout {
kNorthWest,
kNorth,
kNorthEst,
kWest,
kMiddle,
kEst,
kSouthWest,
kSouth,
kSouthEst,
};
// Print _text in _rect.
float Print(const char* _text, const math::RectFloat& _rect,
PrintLayout _layout, const GLubyte _rgba[4]) const;
// Initialize circle vertices.
void InitializeCircle();
// Initializes and destroys the internal font rendering system.
void InitalizeFont();
void DestroyFont();
// ImGui state.
// Current frame inputs.
Inputs inputs_;
// Internal states.
// The hot item is the one that's below the mouse cursor.
int hot_item_;
// The active item is the one being currently interacted with.
int active_item_;
// The automatically generated widget identifier.
int auto_gen_id_;
struct Container {
// The current rect.
math::RectFloat rect;
// The y offset of the top of the next widget in the current container.
float offset_y;
// Constrains container height to the size used by controls in the
// container.
bool constrain;
};
// Container stack.
ozz::vector<Container> containers_;
// Round rendering.
// Defines the number of segments used by the precomputed circle.
// Must be multiple of 4.
static const int kCircleSegments = 8;
// Circle vertices coordinates (cosine/sinus)
float circle_[kCircleSegments][2];
// Font rendering.
// Declares font's structure.
struct Font {
int texture_width; // width of the pow2 texture.
int texture_height; // height of the pow2 texture.
int image_width; // width of the image area in the texture.
int image_height; // height of the image area in the texture.
int glyph_height;
int glyph_width;
int glyph_count;
unsigned char glyph_start; // ascii code of the first character.
const unsigned char* pixels;
size_t pixels_size;
};
// Declares the font instance.
static const Font font_;
// Pre-cooked glyphes uv and vertex coordinates.
struct Glyph {
float uv[4][2];
float pos[4][2];
};
Glyph glyphes_[256];
// Glyph GL texture
unsigned int glyph_texture_;
// Renderer, available between Begin/EndFrame
RendererImpl* renderer_;
};
} // namespace internal
} // namespace sample
} // namespace ozz
#endif // OZZ_SAMPLES_FRAMEWORK_INTERNAL_IMGUI_IMPL_H_
@@ -0,0 +1,116 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// 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. //
// //
//----------------------------------------------------------------------------//
#define OZZ_INCLUDE_PRIVATE_HEADER // Allows to include private headers.
#include "immediate.h"
#include <cassert>
#include "camera.h"
#include "ozz/base/memory/allocator.h"
#include "renderer_impl.h"
#include "shader.h"
namespace ozz {
namespace sample {
namespace internal {
GlImmediateRenderer::GlImmediateRenderer(RendererImpl* _renderer)
: vbo_(0), size_(0), renderer_(_renderer) {}
GlImmediateRenderer::~GlImmediateRenderer() {
assert(size_ == 0 && "Immediate rendering still in use.");
if (vbo_) {
GL(DeleteBuffers(1, &vbo_));
vbo_ = 0;
}
}
bool GlImmediateRenderer::Initialize() {
GL(GenBuffers(1, &vbo_));
immediate_pc_shader = ImmediatePCShader::Build();
if (!immediate_pc_shader) {
return false;
}
immediate_ptc_shader = ImmediatePTCShader::Build();
if (!immediate_ptc_shader) {
return false;
}
return true;
}
void GlImmediateRenderer::Begin() {
assert(size_ == 0 && "Immediate rendering already in use.");
}
template <>
void GlImmediateRenderer::End<VertexPC>(GLenum _mode,
const ozz::math::Float4x4& _transform) {
GL(BindBuffer(GL_ARRAY_BUFFER, vbo_));
GL(BufferData(GL_ARRAY_BUFFER, size_, buffer_.data(), GL_STREAM_DRAW));
immediate_pc_shader->Bind(_transform, renderer_->camera()->view_proj(),
sizeof(VertexPC), 0, sizeof(VertexPC), 12);
const int count = static_cast<int>(size_ / sizeof(VertexPC));
GL(DrawArrays(_mode, 0, count));
immediate_pc_shader->Unbind();
GL(BindBuffer(GL_ARRAY_BUFFER, 0));
// Reset vertex count for the next call
size_ = 0;
}
template <>
void GlImmediateRenderer::End<VertexPTC>(
GLenum _mode, const ozz::math::Float4x4& _transform) {
GL(BindBuffer(GL_ARRAY_BUFFER, vbo_));
GL(BufferData(GL_ARRAY_BUFFER, size_, buffer_.data(), GL_STREAM_DRAW));
immediate_ptc_shader->Bind(_transform, renderer_->camera()->view_proj(),
sizeof(VertexPTC), 0, sizeof(VertexPTC), 12,
sizeof(VertexPTC), 20);
const int count = static_cast<int>(size_ / sizeof(VertexPTC));
GL(DrawArrays(_mode, 0, count));
immediate_ptc_shader->Unbind();
GL(BindBuffer(GL_ARRAY_BUFFER, 0));
// Reset vertex count for the next call
size_ = 0;
}
} // namespace internal
} // namespace sample
} // namespace ozz
@@ -0,0 +1,173 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// 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. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_SAMPLES_FRAMEWORK_INTERNAL_IMMEDIATE_H_
#define OZZ_SAMPLES_FRAMEWORK_INTERNAL_IMMEDIATE_H_
#ifndef OZZ_INCLUDE_PRIVATE_HEADER
#error "This header is private, it cannot be included from public headers."
#endif // OZZ_INCLUDE_PRIVATE_HEADER
#include <cstring>
#include "ozz/base/containers/vector.h"
#include "ozz/base/maths/math_ex.h"
#include "ozz/base/maths/simd_math.h"
#include "ozz/base/memory/unique_ptr.h"
#include "ozz/base/platform.h"
#include "renderer_impl.h"
namespace ozz {
namespace sample {
namespace internal {
class RendererImpl;
class ImmediatePCShader;
class ImmediatePNShader;
class ImmediatePTCShader;
// Declares supported vertex formats.
// Position + Color.
struct VertexPC {
float pos[3];
GLubyte rgba[4];
};
// Declares supported vertex formats.
// Position + Normal.
struct VertexPN {
float pos[3];
float normal[3];
};
// Position + Texture coordinate + Color.
struct VertexPTC {
float pos[3];
float uv[2];
GLubyte rgba[4];
};
// Declares Immediate mode types.
template <typename _Ty>
class GlImmediate;
typedef GlImmediate<VertexPC> GlImmediatePC;
typedef GlImmediate<VertexPN> GlImmediatePN;
typedef GlImmediate<VertexPTC> GlImmediatePTC;
// GL immedialte mode renderer.
// Should be used with a GlImmediate object to push vertices to the renderer.
class GlImmediateRenderer {
public:
GlImmediateRenderer(RendererImpl* _renderer);
~GlImmediateRenderer();
// Initializes immediate mode renderer. Can fail.
bool Initialize();
private:
// GlImmediate is used to work with the renderer.
template <typename _Ty>
friend class GlImmediate;
// Begin stacking vertices.
void Begin();
// End stacking vertices. Call GL rendering.
template <typename _Ty>
void End(GLenum _mode, const ozz::math::Float4x4& _transform);
// Push a new vertex to the buffer.
template <typename _Ty>
OZZ_INLINE void PushVertex(const _Ty& _vertex) {
// Resize buffer if needed.
const size_t new_size = size_ + sizeof(_Ty);
if (new_size > buffer_.size()) {
buffer_.resize(new_size);
}
// Copy this last vertex.
std::memcpy(buffer_.data() + size_, &_vertex, sizeof(_Ty));
size_ = new_size;
}
// The vertex object used by the renderer.
GLuint vbo_;
// Buffer of vertices.
ozz::vector<char> buffer_;
// Number of vertices.
size_t size_;
// Immediate mode shaders;
ozz::unique_ptr<ImmediatePCShader> immediate_pc_shader;
ozz::unique_ptr<ImmediatePTCShader> immediate_ptc_shader;
// The renderer object.
RendererImpl* renderer_;
};
// RAII object that allows to push vertices to the imrender stack.
template <typename _Ty>
class GlImmediate {
public:
// Immediate object vertex format.
typedef _Ty Vertex;
// Start a new immediate stack.
GlImmediate(GlImmediateRenderer* _renderer, GLenum _mode,
const ozz::math::Float4x4& _transform)
: transform_(_transform), renderer_(_renderer), mode_(_mode) {
renderer_->Begin();
}
// End immediate vertex stacking, and renders all vertices.
~GlImmediate() { renderer_->End<_Ty>(mode_, transform_); }
// Pushes a new vertex to the stack.
OZZ_INLINE void PushVertex(const _Ty& _vertex) {
renderer_->PushVertex(_vertex);
}
private:
// Non copyable.
GlImmediate(const GlImmediate&);
void operator=(const GlImmediate&);
// Transformation matrix.
const ozz::math::Float4x4 transform_;
// Shared renderer.
GlImmediateRenderer* renderer_;
// Draw array mode GL_POINTS, GL_LINE_STRIP, ...
GLenum mode_;
};
} // namespace internal
} // namespace sample
} // namespace ozz
#endif // OZZ_SAMPLES_FRAMEWORK_INTERNAL_IMMEDIATE_H_
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,332 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// 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. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_SAMPLES_FRAMEWORK_INTERNAL_RENDERER_IMPL_H_
#define OZZ_SAMPLES_FRAMEWORK_INTERNAL_RENDERER_IMPL_H_
#ifndef OZZ_INCLUDE_PRIVATE_HEADER
#error "This header is private, it cannot be included from public headers."
#endif // OZZ_INCLUDE_PRIVATE_HEADER
// GL and GL ext requires that ptrdif_t is defined on APPLE platforms.
#include <cstddef>
// Don't allow gl.h to automatically include glext.h
#define GL_GLEXT_LEGACY
// Including glfw includes gl.h
#include "GL/glfw.h"
#ifdef EMSCRIPTEN
// include features as core functions.
#include <GLES2/gl2.h>
#else // EMSCRIPTEN
// Detects already defined GL_VERSION and deduces required extensions.
#ifndef GL_VERSION_1_5
#define OZZ_GL_VERSION_1_5_EXT
#endif // GL_VERSION_1_5
#ifndef GL_VERSION_2_0
#define OZZ_GL_VERSION_2_0_EXT
#endif // GL_VERSION_2_0
#endif // EMSCRIPTEN
// Include features as extentions
#include "GL/glext.h"
#include "framework/renderer.h"
#include "ozz/base/containers/vector.h"
#include "ozz/base/memory/unique_ptr.h"
// Provides helper macro to test for glGetError on a gl call.
#ifndef NDEBUG
#define GL(_f) \
do { \
gl##_f; \
GLenum error = glGetError(); \
assert(error == GL_NO_ERROR); \
\
} while (void(0), 0)
#else // NDEBUG
#define GL(_f) gl##_f
#endif // NDEBUG
// Convenient macro definition for specifying buffer offsets.
#define GL_PTR_OFFSET(i) reinterpret_cast<void*>(static_cast<intptr_t>(i))
namespace ozz {
namespace animation {
class Skeleton;
}
namespace math {
struct Float4x4;
}
namespace sample {
namespace internal {
class Camera;
class Shader;
class SkeletonShader;
class AmbientShader;
class AmbientTexturedShader;
class AmbientShaderInstanced;
class GlImmediateRenderer;
// Implements Renderer interface.
class RendererImpl : public Renderer {
public:
RendererImpl(Camera* _camera);
virtual ~RendererImpl();
// See Renderer for all the details about the API.
virtual bool Initialize();
virtual bool DrawAxes(const ozz::math::Float4x4& _transform);
virtual bool DrawGrid(int _cell_count, float _cell_size);
virtual bool DrawSkeleton(const animation::Skeleton& _skeleton,
const ozz::math::Float4x4& _transform,
bool _draw_joints);
virtual bool DrawPosture(const animation::Skeleton& _skeleton,
ozz::span<const ozz::math::Float4x4> _matrices,
const ozz::math::Float4x4& _transform,
bool _draw_joints);
virtual bool DrawBoxIm(const ozz::math::Box& _box,
const ozz::math::Float4x4& _transform,
const Color _colors[2]);
virtual bool DrawBoxShaded(const ozz::math::Box& _box,
ozz::span<const ozz::math::Float4x4> _transforms,
Color _color);
virtual bool DrawSphereIm(float _radius,
const ozz::math::Float4x4& _transform,
const Color _color);
virtual bool DrawSphereShaded(
float _radius, ozz::span<const ozz::math::Float4x4> _transforms,
Color _color);
virtual bool DrawSkinnedMesh(const Mesh& _mesh,
const span<math::Float4x4> _skinning_matrices,
const ozz::math::Float4x4& _transform,
const Options& _options = Options());
virtual bool DrawMesh(const Mesh& _mesh,
const ozz::math::Float4x4& _transform,
const Options& _options = Options());
virtual bool DrawSegment(const math::Float3& _begin, const math::Float3& _end,
Color _color, const ozz::math::Float4x4& _transform);
virtual bool DrawVectors(ozz::span<const float> _positions,
size_t _positions_stride,
ozz::span<const float> _directions,
size_t _directions_stride, int _num_vectors,
float _vector_length, Color _color,
const ozz::math::Float4x4& _transform);
virtual bool DrawBinormals(
ozz::span<const float> _positions, size_t _positions_stride,
ozz::span<const float> _normals, size_t _normals_stride,
ozz::span<const float> _tangents, size_t _tangents_stride,
ozz::span<const float> _handenesses, size_t _handenesses_stride,
int _num_vectors, float _vector_length, Color _color,
const ozz::math::Float4x4& _transform);
// Get GL immediate renderer implementation;
GlImmediateRenderer* immediate_renderer() const { return immediate_.get(); }
// Get application camera that provides rendering matrices.
Camera* camera() const { return camera_; }
private:
// Defines the internal structure used to define a model.
struct Model {
Model();
~Model();
GLuint vbo;
GLenum mode;
GLsizei count;
ozz::unique_ptr<SkeletonShader> shader;
};
// Detects and initializes all OpenGL extension.
// Return true if all mandatory extensions were found.
bool InitOpenGLExtensions();
// Initializes posture rendering.
// Return true if initialization succeeded.
bool InitPostureRendering();
// Initializes the checkered texture.
// Return true if initialization succeeded.
bool InitCheckeredTexture();
// Draw posture internal non-instanced rendering fall back implementation.
void DrawPosture_Impl(const ozz::math::Float4x4& _transform,
const float* _uniforms, int _instance_count,
bool _draw_joints);
// Draw posture internal instanced rendering implementation.
void DrawPosture_InstancedImpl(const ozz::math::Float4x4& _transform,
const float* _uniforms, int _instance_count,
bool _draw_joints);
// Array of matrices used to store model space matrices during DrawSkeleton
// execution.
ozz::vector<ozz::math::Float4x4> prealloc_models_;
// Application camera that provides rendering matrices.
Camera* camera_;
// Bone and joint model objects.
Model models_[2];
// Dynamic vbo used for arrays.
GLuint dynamic_array_bo_;
// Dynamic vbo used for indices.
GLuint dynamic_index_bo_;
// Volatile memory buffer that can be used within function scope.
// Minimum alignment is 16 bytes.
class ScratchBuffer {
public:
ScratchBuffer();
~ScratchBuffer();
// Resizes the buffer to the new size and return the memory address.
void* Resize(size_t _size);
private:
void* buffer_;
size_t size_;
};
ScratchBuffer scratch_buffer_;
// Immediate renderer implementation.
ozz::unique_ptr<GlImmediateRenderer> immediate_;
// Ambient rendering shader.
ozz::unique_ptr<AmbientShader> ambient_shader;
ozz::unique_ptr<AmbientTexturedShader> ambient_textured_shader;
ozz::unique_ptr<AmbientShaderInstanced> ambient_shader_instanced;
// Checkered texture
unsigned int checkered_texture_;
};
} // namespace internal
} // namespace sample
} // namespace ozz
// OpenGL 1.5 buffer object management functions, mandatory.
#ifdef OZZ_GL_VERSION_1_5_EXT
extern PFNGLBINDBUFFERPROC glBindBuffer;
extern PFNGLDELETEBUFFERSPROC glDeleteBuffers;
extern PFNGLGENBUFFERSPROC glGenBuffers;
extern PFNGLISBUFFERPROC glIsBuffer;
extern PFNGLBUFFERDATAPROC glBufferData;
extern PFNGLBUFFERSUBDATAPROC glBufferSubData;
extern PFNGLGETBUFFERSUBDATAPROC glGetBufferSubData;
extern PFNGLMAPBUFFERPROC glMapBuffer;
extern PFNGLUNMAPBUFFERPROC glUnmapBuffer;
extern PFNGLGETBUFFERPARAMETERIVPROC glGetBufferParameteriv;
extern PFNGLGETBUFFERPOINTERVPROC glGetBufferPointerv;
#endif // OZZ_GL_VERSION_1_5_EXT
// OpenGL 2.0 shader management functions, mandatory.
#ifdef OZZ_GL_VERSION_2_0_EXT
extern PFNGLATTACHSHADERPROC glAttachShader;
extern PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation;
extern PFNGLCOMPILESHADERPROC glCompileShader;
extern PFNGLCREATEPROGRAMPROC glCreateProgram;
extern PFNGLCREATESHADERPROC glCreateShader;
extern PFNGLDELETEPROGRAMPROC glDeleteProgram;
extern PFNGLDELETESHADERPROC glDeleteShader;
extern PFNGLDETACHSHADERPROC glDetachShader;
extern PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray;
extern PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
extern PFNGLGETACTIVEATTRIBPROC glGetActiveAttrib;
extern PFNGLGETACTIVEUNIFORMPROC glGetActiveUniform;
extern PFNGLGETATTACHEDSHADERSPROC glGetAttachedShaders;
extern PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation;
extern PFNGLGETPROGRAMIVPROC glGetProgramiv;
extern PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
extern PFNGLGETSHADERIVPROC glGetShaderiv;
extern PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
extern PFNGLGETSHADERSOURCEPROC glGetShaderSource;
extern PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
extern PFNGLGETUNIFORMFVPROC glGetUniformfv;
extern PFNGLGETUNIFORMIVPROC glGetUniformiv;
extern PFNGLGETVERTEXATTRIBDVPROC glGetVertexAttribdv;
extern PFNGLGETVERTEXATTRIBFVPROC glGetVertexAttribfv;
extern PFNGLGETVERTEXATTRIBIVPROC glGetVertexAttribiv;
extern PFNGLGETVERTEXATTRIBPOINTERVPROC glGetVertexAttribPointerv;
extern PFNGLISPROGRAMPROC glIsProgram;
extern PFNGLISSHADERPROC glIsShader;
extern PFNGLLINKPROGRAMPROC glLinkProgram;
extern PFNGLSHADERSOURCEPROC glShaderSource;
extern PFNGLUSEPROGRAMPROC glUseProgram;
extern PFNGLUNIFORM1FPROC glUniform1f;
extern PFNGLUNIFORM2FPROC glUniform2f;
extern PFNGLUNIFORM3FPROC glUniform3f;
extern PFNGLUNIFORM4FPROC glUniform4f;
extern PFNGLUNIFORM1IPROC glUniform1i;
extern PFNGLUNIFORM2IPROC glUniform2i;
extern PFNGLUNIFORM3IPROC glUniform3i;
extern PFNGLUNIFORM4IPROC glUniform4i;
extern PFNGLUNIFORM1FVPROC glUniform1fv;
extern PFNGLUNIFORM2FVPROC glUniform2fv;
extern PFNGLUNIFORM3FVPROC glUniform3fv;
extern PFNGLUNIFORM4FVPROC glUniform4fv;
extern PFNGLUNIFORMMATRIX2FVPROC glUniformMatrix2fv;
extern PFNGLUNIFORMMATRIX3FVPROC glUniformMatrix3fv;
extern PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv;
extern PFNGLVALIDATEPROGRAMPROC glValidateProgram;
extern PFNGLVERTEXATTRIB1FPROC glVertexAttrib1f;
extern PFNGLVERTEXATTRIB1FVPROC glVertexAttrib1fv;
extern PFNGLVERTEXATTRIB2FPROC glVertexAttrib2f;
extern PFNGLVERTEXATTRIB2FVPROC glVertexAttrib2fv;
extern PFNGLVERTEXATTRIB3FPROC glVertexAttrib3f;
extern PFNGLVERTEXATTRIB3FVPROC glVertexAttrib3fv;
extern PFNGLVERTEXATTRIB4FPROC glVertexAttrib4f;
extern PFNGLVERTEXATTRIB4FVPROC glVertexAttrib4fv;
extern PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;
#endif // OZZ_GL_VERSION_2_0_EXT
// OpenGL ARB_instanced_arrays extension, optional.
extern bool GL_ARB_instanced_arrays_supported;
extern PFNGLVERTEXATTRIBDIVISORARBPROC glVertexAttribDivisor_;
extern PFNGLDRAWARRAYSINSTANCEDARBPROC glDrawArraysInstanced_;
extern PFNGLDRAWELEMENTSINSTANCEDARBPROC glDrawElementsInstanced_;
#endif // OZZ_SAMPLES_FRAMEWORK_INTERNAL_RENDERER_IMPL_H_
@@ -0,0 +1,766 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// 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. //
// //
//----------------------------------------------------------------------------//
#define OZZ_INCLUDE_PRIVATE_HEADER // Allows to include private headers.
#include "shader.h"
#include <cassert>
#include <cstdio>
#include <limits>
#include "ozz/base/log.h"
#include "ozz/base/maths/simd_math.h"
namespace ozz {
namespace sample {
namespace internal {
#ifdef EMSCRIPTEN
// WebGL requires to specify floating point precision
static const char* kPlatformSpecivicVSHeader = "precision mediump float;\n";
static const char* kPlatformSpecivicFSHeader = "precision mediump float;\n";
#else // EMSCRIPTEN
static const char* kPlatformSpecivicVSHeader = "";
static const char* kPlatformSpecivicFSHeader = "";
#endif // EMSCRIPTEN
Shader::Shader() : program_(0), vertex_(0), fragment_(0) {}
Shader::~Shader() {
if (vertex_) {
GL(DetachShader(program_, vertex_));
GL(DeleteShader(vertex_));
}
if (fragment_) {
GL(DetachShader(program_, fragment_));
GL(DeleteShader(fragment_));
}
if (program_) {
GL(DeleteProgram(program_));
}
}
namespace {
GLuint CompileShader(GLenum _type, int _count, const char** _src) {
GLuint shader = glCreateShader(_type);
GL(ShaderSource(shader, _count, _src, nullptr));
GL(CompileShader(shader));
int infolog_length = 0;
GL(GetShaderiv(shader, GL_INFO_LOG_LENGTH, &infolog_length));
if (infolog_length > 1) {
char* info_log = reinterpret_cast<char*>(
memory::default_allocator()->Allocate(infolog_length, alignof(char)));
int chars_written = 0;
glGetShaderInfoLog(shader, infolog_length, &chars_written, info_log);
log::Err() << info_log << std::endl;
memory::default_allocator()->Deallocate(info_log);
}
int status;
GL(GetShaderiv(shader, GL_COMPILE_STATUS, &status));
if (status) {
return shader;
}
GL(DeleteShader(shader));
return 0;
}
} // namespace
bool Shader::BuildFromSource(int _vertex_count, const char** _vertex,
int _fragment_count, const char** _fragment) {
// Tries to compile shaders.
GLuint vertex_shader = 0;
if (_vertex) {
vertex_shader = CompileShader(GL_VERTEX_SHADER, _vertex_count, _vertex);
if (!vertex_shader) {
return false;
}
}
GLuint fragment_shader = 0;
if (_fragment) {
fragment_shader =
CompileShader(GL_FRAGMENT_SHADER, _fragment_count, _fragment);
if (!fragment_shader) {
if (vertex_shader) {
GL(DeleteShader(vertex_shader));
}
return false;
}
}
// Shaders are compiled, builds program.
program_ = glCreateProgram();
vertex_ = vertex_shader;
fragment_ = fragment_shader;
GL(AttachShader(program_, vertex_shader));
GL(AttachShader(program_, fragment_shader));
GL(LinkProgram(program_));
int infolog_length = 0;
GL(GetProgramiv(program_, GL_INFO_LOG_LENGTH, &infolog_length));
if (infolog_length > 1) {
char* info_log = reinterpret_cast<char*>(
memory::default_allocator()->Allocate(infolog_length, alignof(char)));
int chars_written = 0;
glGetProgramInfoLog(program_, infolog_length, &chars_written, info_log);
log::Err() << info_log << std::endl;
memory::default_allocator()->Deallocate(info_log);
}
return true;
}
bool Shader::BindUniform(const char* _semantic) {
if (!program_) {
return false;
}
GLint location = glGetUniformLocation(program_, _semantic);
if (glGetError() != GL_NO_ERROR || location == -1) { // _semantic not found.
return false;
}
uniforms_.push_back(location);
return true;
}
bool Shader::FindAttrib(const char* _semantic) {
if (!program_) {
return false;
}
GLint location = glGetAttribLocation(program_, _semantic);
if (glGetError() != GL_NO_ERROR || location == -1) { // _semantic not found.
return false;
}
attribs_.push_back(location);
return true;
}
void Shader::UnbindAttribs() {
for (size_t i = 0; i < attribs_.size(); ++i) {
GL(DisableVertexAttribArray(attribs_[i]));
}
}
void Shader::Unbind() {
UnbindAttribs();
GL(UseProgram(0));
}
ozz::unique_ptr<ImmediatePCShader> ImmediatePCShader::Build() {
bool success = true;
const char* kSimplePCVS =
"uniform mat4 u_mvp;\n"
"attribute vec3 a_position;\n"
"attribute vec4 a_color;\n"
"varying vec4 v_vertex_color;\n"
"void main() {\n"
" vec4 vertex = vec4(a_position.xyz, 1.);\n"
" gl_Position = u_mvp * vertex;\n"
" v_vertex_color = a_color;\n"
"}\n";
const char* kSimplePCPS =
"varying vec4 v_vertex_color;\n"
"void main() {\n"
" gl_FragColor = v_vertex_color;\n"
"}\n";
const char* vs[] = {kPlatformSpecivicVSHeader, kSimplePCVS};
const char* fs[] = {kPlatformSpecivicFSHeader, kSimplePCPS};
ozz::unique_ptr<ImmediatePCShader> shader = make_unique<ImmediatePCShader>();
success &=
shader->BuildFromSource(OZZ_ARRAY_SIZE(vs), vs, OZZ_ARRAY_SIZE(fs), fs);
// Binds default attributes
success &= shader->FindAttrib("a_position");
success &= shader->FindAttrib("a_color");
// Binds default uniforms
success &= shader->BindUniform("u_mvp");
if (!success) {
shader.reset();
}
return shader;
}
void ImmediatePCShader::Bind(const math::Float4x4& _model,
const math::Float4x4& _view_proj,
GLsizei _pos_stride, GLsizei _pos_offset,
GLsizei _color_stride, GLsizei _color_offset) {
GL(UseProgram(program()));
const GLint position_attrib = attrib(0);
GL(EnableVertexAttribArray(position_attrib));
GL(VertexAttribPointer(position_attrib, 3, GL_FLOAT, GL_FALSE, _pos_stride,
GL_PTR_OFFSET(_pos_offset)));
const GLint color_attrib = attrib(1);
GL(EnableVertexAttribArray(color_attrib));
GL(VertexAttribPointer(color_attrib, 4, GL_UNSIGNED_BYTE, GL_TRUE,
_color_stride, GL_PTR_OFFSET(_color_offset)));
// Binds mvp uniform
const GLint mvp_uniform = uniform(0);
const ozz::math::Float4x4 mvp = _view_proj * _model;
float values[16];
math::StorePtrU(mvp.cols[0], values + 0);
math::StorePtrU(mvp.cols[1], values + 4);
math::StorePtrU(mvp.cols[2], values + 8);
math::StorePtrU(mvp.cols[3], values + 12);
GL(UniformMatrix4fv(mvp_uniform, 1, false, values));
}
ozz::unique_ptr<ImmediatePTCShader> ImmediatePTCShader::Build() {
bool success = true;
const char* kSimplePCVS =
"uniform mat4 u_mvp;\n"
"attribute vec3 a_position;\n"
"attribute vec2 a_tex_coord;\n"
"attribute vec4 a_color;\n"
"varying vec4 v_vertex_color;\n"
"varying vec2 v_texture_coord;\n"
"void main() {\n"
" vec4 vertex = vec4(a_position.xyz, 1.);\n"
" gl_Position = u_mvp * vertex;\n"
" v_vertex_color = a_color;\n"
" v_texture_coord = a_tex_coord;\n"
"}\n";
const char* kSimplePCPS =
"uniform sampler2D u_texture;\n"
"varying vec4 v_vertex_color;\n"
"varying vec2 v_texture_coord;\n"
"void main() {\n"
" vec4 tex_color = texture2D(u_texture, v_texture_coord);\n"
" gl_FragColor = v_vertex_color * tex_color;\n"
" if(gl_FragColor.a < .01) discard;\n" // Implements alpha testing.
"}\n";
const char* vs[] = {kPlatformSpecivicVSHeader, kSimplePCVS};
const char* fs[] = {kPlatformSpecivicFSHeader, kSimplePCPS};
ozz::unique_ptr<ImmediatePTCShader> shader =
make_unique<ImmediatePTCShader>();
success &=
shader->BuildFromSource(OZZ_ARRAY_SIZE(vs), vs, OZZ_ARRAY_SIZE(fs), fs);
// Binds default attributes
success &= shader->FindAttrib("a_position");
success &= shader->FindAttrib("a_tex_coord");
success &= shader->FindAttrib("a_color");
// Binds default uniforms
success &= shader->BindUniform("u_mvp");
success &= shader->BindUniform("u_texture");
if (!success) {
shader.reset();
}
return shader;
}
void ImmediatePTCShader::Bind(const math::Float4x4& _model,
const math::Float4x4& _view_proj,
GLsizei _pos_stride, GLsizei _pos_offset,
GLsizei _tex_stride, GLsizei _tex_offset,
GLsizei _color_stride, GLsizei _color_offset) {
GL(UseProgram(program()));
const GLint position_attrib = attrib(0);
GL(EnableVertexAttribArray(position_attrib));
GL(VertexAttribPointer(position_attrib, 3, GL_FLOAT, GL_FALSE, _pos_stride,
GL_PTR_OFFSET(_pos_offset)));
const GLint tex_attrib = attrib(1);
GL(EnableVertexAttribArray(tex_attrib));
GL(VertexAttribPointer(tex_attrib, 2, GL_FLOAT, GL_FALSE, _tex_stride,
GL_PTR_OFFSET(_tex_offset)));
const GLint color_attrib = attrib(2);
GL(EnableVertexAttribArray(color_attrib));
GL(VertexAttribPointer(color_attrib, 4, GL_UNSIGNED_BYTE, GL_TRUE,
_color_stride, GL_PTR_OFFSET(_color_offset)));
// Binds mvp uniform
const GLint mvp_uniform = uniform(0);
const ozz::math::Float4x4 mvp = _view_proj * _model;
float values[16];
math::StorePtrU(mvp.cols[0], values + 0);
math::StorePtrU(mvp.cols[1], values + 4);
math::StorePtrU(mvp.cols[2], values + 8);
math::StorePtrU(mvp.cols[3], values + 12);
GL(UniformMatrix4fv(mvp_uniform, 1, false, values));
// Binds texture
const GLint texture = uniform(1);
GL(Uniform1i(texture, 0));
}
namespace {
const char* kPassUv =
"attribute vec2 a_uv;\n"
"varying vec2 v_vertex_uv;\n"
"void PassUv() {\n"
" v_vertex_uv = a_uv;\n"
"}\n";
const char* kPassNoUv =
"void PassUv() {\n"
"}\n";
const char* kShaderUberVS =
"uniform mat4 u_mvp;\n"
"attribute vec3 a_position;\n"
"attribute vec3 a_normal;\n"
"attribute vec4 a_color;\n"
"varying vec3 v_world_normal;\n"
"varying vec4 v_vertex_color;\n"
"void main() {\n"
" mat4 world_matrix = GetWorldMatrix();\n"
" vec4 vertex = vec4(a_position.xyz, 1.);\n"
" gl_Position = u_mvp * world_matrix * vertex;\n"
" mat3 cross_matrix = mat3(\n"
" cross(world_matrix[1].xyz, world_matrix[2].xyz),\n"
" cross(world_matrix[2].xyz, world_matrix[0].xyz),\n"
" cross(world_matrix[0].xyz, world_matrix[1].xyz));\n"
" float invdet = 1.0 / dot(cross_matrix[2], world_matrix[2].xyz);\n"
" mat3 normal_matrix = cross_matrix * invdet;\n"
" v_world_normal = normal_matrix * a_normal;\n"
" v_vertex_color = a_color;\n"
" PassUv();\n"
"}\n";
const char* kShaderAmbientFct =
"vec4 GetAmbient(vec3 _world_normal) {\n"
" vec3 normal = normalize(_world_normal);\n"
" vec3 alpha = (normal + 1.) * .5;\n"
" vec2 bt = mix(vec2(.3, .7), vec2(.4, .8), alpha.xz);\n"
" vec3 ambient = mix(vec3(bt.x, .3, bt.x), vec3(bt.y, .8, bt.y), "
"alpha.y);\n"
" return vec4(ambient, 1.);\n"
"}\n";
const char* kShaderAmbientFS =
"varying vec3 v_world_normal;\n"
"varying vec4 v_vertex_color;\n"
"void main() {\n"
" vec4 ambient = GetAmbient(v_world_normal);\n"
" gl_FragColor = ambient *\n"
" v_vertex_color;\n"
"}\n";
const char* kShaderAmbientTexturedFS =
"uniform sampler2D u_texture;\n"
"varying vec3 v_world_normal;\n"
"varying vec4 v_vertex_color;\n"
"varying vec2 v_vertex_uv;\n"
"void main() {\n"
" vec4 ambient = GetAmbient(v_world_normal);\n"
" gl_FragColor = ambient *\n"
" v_vertex_color *\n"
" texture2D(u_texture, v_vertex_uv);\n"
"}\n";
} // namespace
void SkeletonShader::Bind(const math::Float4x4& _model,
const math::Float4x4& _view_proj, GLsizei _pos_stride,
GLsizei _pos_offset, GLsizei _normal_stride,
GLsizei _normal_offset, GLsizei _color_stride,
GLsizei _color_offset) {
GL(UseProgram(program()));
const GLint position_attrib = attrib(0);
GL(EnableVertexAttribArray(position_attrib));
GL(VertexAttribPointer(position_attrib, 3, GL_FLOAT, GL_FALSE, _pos_stride,
GL_PTR_OFFSET(_pos_offset)));
const GLint normal_attrib = attrib(1);
GL(EnableVertexAttribArray(normal_attrib));
GL(VertexAttribPointer(normal_attrib, 3, GL_FLOAT, GL_FALSE, _normal_stride,
GL_PTR_OFFSET(_normal_offset)));
const GLint color_attrib = attrib(2);
GL(EnableVertexAttribArray(color_attrib));
GL(VertexAttribPointer(color_attrib, 4, GL_UNSIGNED_BYTE, GL_TRUE,
_color_stride, GL_PTR_OFFSET(_color_offset)));
// Binds mvp uniform
const GLint mvp_uniform = uniform(0);
const ozz::math::Float4x4 mvp = _view_proj * _model;
float values[16];
math::StorePtrU(mvp.cols[0], values + 0);
math::StorePtrU(mvp.cols[1], values + 4);
math::StorePtrU(mvp.cols[2], values + 8);
math::StorePtrU(mvp.cols[3], values + 12);
GL(UniformMatrix4fv(mvp_uniform, 1, false, values));
}
ozz::unique_ptr<JointShader> JointShader::Build() {
bool success = true;
const char* vs_joint_to_world_matrix =
"mat4 GetWorldMatrix() {\n"
" // Rebuilds joint matrix.\n"
" mat4 joint_matrix;\n"
" joint_matrix[0] = vec4(normalize(joint[0].xyz), 0.);\n"
" joint_matrix[1] = vec4(normalize(joint[1].xyz), 0.);\n"
" joint_matrix[2] = vec4(normalize(joint[2].xyz), 0.);\n"
" joint_matrix[3] = vec4(joint[3].xyz, 1.);\n"
" // Rebuilds bone properties.\n"
" vec3 bone_dir = vec3(joint[0].w, joint[1].w, joint[2].w);\n"
" float bone_len = length(bone_dir);\n"
" // Setup rendering world matrix.\n"
" mat4 world_matrix;\n"
" world_matrix[0] = joint_matrix[0] * bone_len;\n"
" world_matrix[1] = joint_matrix[1] * bone_len;\n"
" world_matrix[2] = joint_matrix[2] * bone_len;\n"
" world_matrix[3] = joint_matrix[3];\n"
" return world_matrix;\n"
"}\n";
const char* vs[] = {kPlatformSpecivicVSHeader, kPassNoUv,
GL_ARB_instanced_arrays_supported
? "attribute mat4 joint;\n"
: "uniform mat4 joint;\n",
vs_joint_to_world_matrix, kShaderUberVS};
const char* fs[] = {kPlatformSpecivicFSHeader, kShaderAmbientFct,
kShaderAmbientFS};
ozz::unique_ptr<JointShader> shader = make_unique<JointShader>();
success &=
shader->BuildFromSource(OZZ_ARRAY_SIZE(vs), vs, OZZ_ARRAY_SIZE(fs), fs);
// Binds default attributes
success &= shader->FindAttrib("a_position");
success &= shader->FindAttrib("a_normal");
success &= shader->FindAttrib("a_color");
// Binds default uniforms
success &= shader->BindUniform("u_mvp");
if (GL_ARB_instanced_arrays_supported) {
success &= shader->FindAttrib("joint");
} else {
success &= shader->BindUniform("joint");
}
if (!success) {
shader.reset();
}
return shader;
}
ozz::unique_ptr<BoneShader>
BoneShader::Build() { // Builds a world matrix from joint uniforms,
// sticking bone model between
bool success = true;
// parent and child joints.
const char* vs_joint_to_world_matrix =
"mat4 GetWorldMatrix() {\n"
" // Rebuilds bone properties.\n"
" // Bone length is set to zero to disable leaf rendering.\n"
" float is_bone = joint[3].w;\n"
" vec3 bone_dir = vec3(joint[0].w, joint[1].w, joint[2].w) * is_bone;\n"
" float bone_len = length(bone_dir);\n"
" // Setup rendering world matrix.\n"
" float dot1 = dot(joint[2].xyz, bone_dir);\n"
" float dot2 = dot(joint[0].xyz, bone_dir);\n"
" vec3 binormal = abs(dot1) < abs(dot2) ? joint[2].xyz : joint[0].xyz;\n"
" mat4 world_matrix;\n"
" world_matrix[0] = vec4(bone_dir, 0.);\n"
" world_matrix[1] = \n"
" vec4(bone_len * normalize(cross(binormal, bone_dir)), 0.);\n"
" world_matrix[2] =\n"
" vec4(bone_len * normalize(cross(bone_dir, world_matrix[1].xyz)), "
"0.);\n"
" world_matrix[3] = vec4(joint[3].xyz, 1.);\n"
" return world_matrix;\n"
"}\n";
const char* vs[] = {kPlatformSpecivicVSHeader, kPassNoUv,
GL_ARB_instanced_arrays_supported
? "attribute mat4 joint;\n"
: "uniform mat4 joint;\n",
vs_joint_to_world_matrix, kShaderUberVS};
const char* fs[] = {kPlatformSpecivicFSHeader, kShaderAmbientFct,
kShaderAmbientFS};
ozz::unique_ptr<BoneShader> shader = make_unique<BoneShader>();
success &=
shader->BuildFromSource(OZZ_ARRAY_SIZE(vs), vs, OZZ_ARRAY_SIZE(fs), fs);
// Binds default attributes
success &= shader->FindAttrib("a_position");
success &= shader->FindAttrib("a_normal");
success &= shader->FindAttrib("a_color");
// Binds default uniforms
success &= shader->BindUniform("u_mvp");
if (GL_ARB_instanced_arrays_supported) {
success &= shader->FindAttrib("joint");
} else {
success &= shader->BindUniform("joint");
}
if (!success) {
shader.reset();
}
return shader;
}
ozz::unique_ptr<AmbientShader> AmbientShader::Build() {
const char* vs[] = {
kPlatformSpecivicVSHeader, kPassNoUv,
"uniform mat4 u_mw;\n mat4 GetWorldMatrix() {return u_mw;}\n",
kShaderUberVS};
const char* fs[] = {kPlatformSpecivicFSHeader, kShaderAmbientFct,
kShaderAmbientFS};
ozz::unique_ptr<AmbientShader> shader = make_unique<AmbientShader>();
bool success =
shader->InternalBuild(OZZ_ARRAY_SIZE(vs), vs, OZZ_ARRAY_SIZE(fs), fs);
if (!success) {
shader.reset();
}
return shader;
}
bool AmbientShader::InternalBuild(int _vertex_count, const char** _vertex,
int _fragment_count, const char** _fragment) {
bool success = true;
success &=
BuildFromSource(_vertex_count, _vertex, _fragment_count, _fragment);
// Binds default attributes
success &= FindAttrib("a_position");
success &= FindAttrib("a_normal");
success &= FindAttrib("a_color");
// Binds default uniforms
success &= BindUniform("u_mw");
success &= BindUniform("u_mvp");
return success;
}
void AmbientShader::Bind(const math::Float4x4& _model,
const math::Float4x4& _view_proj, GLsizei _pos_stride,
GLsizei _pos_offset, GLsizei _normal_stride,
GLsizei _normal_offset, GLsizei _color_stride,
GLsizei _color_offset) {
GL(UseProgram(program()));
const GLint position_attrib = attrib(0);
GL(EnableVertexAttribArray(position_attrib));
GL(VertexAttribPointer(position_attrib, 3, GL_FLOAT, GL_FALSE, _pos_stride,
GL_PTR_OFFSET(_pos_offset)));
const GLint normal_attrib = attrib(1);
GL(EnableVertexAttribArray(normal_attrib));
GL(VertexAttribPointer(normal_attrib, 3, GL_FLOAT, GL_TRUE, _normal_stride,
GL_PTR_OFFSET(_normal_offset)));
const GLint color_attrib = attrib(2);
GL(EnableVertexAttribArray(color_attrib));
GL(VertexAttribPointer(color_attrib, 4, GL_UNSIGNED_BYTE, GL_TRUE,
_color_stride, GL_PTR_OFFSET(_color_offset)));
// Binds mw uniform
float values[16];
const GLint mw_uniform = uniform(0);
math::StorePtrU(_model.cols[0], values + 0);
math::StorePtrU(_model.cols[1], values + 4);
math::StorePtrU(_model.cols[2], values + 8);
math::StorePtrU(_model.cols[3], values + 12);
GL(UniformMatrix4fv(mw_uniform, 1, false, values));
// Binds mvp uniform
const GLint mvp_uniform = uniform(1);
math::StorePtrU(_view_proj.cols[0], values + 0);
math::StorePtrU(_view_proj.cols[1], values + 4);
math::StorePtrU(_view_proj.cols[2], values + 8);
math::StorePtrU(_view_proj.cols[3], values + 12);
GL(UniformMatrix4fv(mvp_uniform, 1, false, values));
}
ozz::unique_ptr<AmbientShaderInstanced> AmbientShaderInstanced::Build() {
bool success = true;
const char* vs[] = {
kPlatformSpecivicVSHeader, kPassNoUv,
"attribute mat4 a_mw;\n mat4 GetWorldMatrix() {return a_mw;}\n",
kShaderUberVS};
const char* fs[] = {kPlatformSpecivicFSHeader, kShaderAmbientFct,
kShaderAmbientFS};
ozz::unique_ptr<AmbientShaderInstanced> shader =
make_unique<AmbientShaderInstanced>();
success &=
shader->BuildFromSource(OZZ_ARRAY_SIZE(vs), vs, OZZ_ARRAY_SIZE(fs), fs);
// Binds default attributes
success &= shader->FindAttrib("a_position");
success &= shader->FindAttrib("a_normal");
success &= shader->FindAttrib("a_color");
success &= shader->FindAttrib("a_mw");
// Binds default uniforms
success &= shader->BindUniform("u_mvp");
if (!success) {
shader.reset();
}
return shader;
}
void AmbientShaderInstanced::Bind(GLsizei _models_offset,
const math::Float4x4& _view_proj,
GLsizei _pos_stride, GLsizei _pos_offset,
GLsizei _normal_stride,
GLsizei _normal_offset, GLsizei _color_stride,
GLsizei _color_offset) {
GL(UseProgram(program()));
const GLint position_attrib = attrib(0);
GL(EnableVertexAttribArray(position_attrib));
GL(VertexAttribPointer(position_attrib, 3, GL_FLOAT, GL_FALSE, _pos_stride,
GL_PTR_OFFSET(_pos_offset)));
const GLint normal_attrib = attrib(1);
GL(EnableVertexAttribArray(normal_attrib));
GL(VertexAttribPointer(normal_attrib, 3, GL_FLOAT, GL_TRUE, _normal_stride,
GL_PTR_OFFSET(_normal_offset)));
const GLint color_attrib = attrib(2);
GL(EnableVertexAttribArray(color_attrib));
GL(VertexAttribPointer(color_attrib, 4, GL_UNSIGNED_BYTE, GL_TRUE,
_color_stride, GL_PTR_OFFSET(_color_offset)));
if (_color_stride == 0) {
GL(VertexAttribDivisor_(color_attrib,
std::numeric_limits<unsigned int>::max()));
}
// Binds mw uniform
const GLint models_attrib = attrib(3);
GL(EnableVertexAttribArray(models_attrib + 0));
GL(EnableVertexAttribArray(models_attrib + 1));
GL(EnableVertexAttribArray(models_attrib + 2));
GL(EnableVertexAttribArray(models_attrib + 3));
GL(VertexAttribDivisor_(models_attrib + 0, 1));
GL(VertexAttribDivisor_(models_attrib + 1, 1));
GL(VertexAttribDivisor_(models_attrib + 2, 1));
GL(VertexAttribDivisor_(models_attrib + 3, 1));
GL(VertexAttribPointer(models_attrib + 0, 4, GL_FLOAT, GL_FALSE,
sizeof(math::Float4x4),
GL_PTR_OFFSET(0 + _models_offset)));
GL(VertexAttribPointer(models_attrib + 1, 4, GL_FLOAT, GL_FALSE,
sizeof(math::Float4x4),
GL_PTR_OFFSET(16 + _models_offset)));
GL(VertexAttribPointer(models_attrib + 2, 4, GL_FLOAT, GL_FALSE,
sizeof(math::Float4x4),
GL_PTR_OFFSET(32 + _models_offset)));
GL(VertexAttribPointer(models_attrib + 3, 4, GL_FLOAT, GL_FALSE,
sizeof(math::Float4x4),
GL_PTR_OFFSET(48 + _models_offset)));
// Binds mvp uniform
const GLint mvp_uniform = uniform(0);
float values[16];
math::StorePtrU(_view_proj.cols[0], values + 0);
math::StorePtrU(_view_proj.cols[1], values + 4);
math::StorePtrU(_view_proj.cols[2], values + 8);
math::StorePtrU(_view_proj.cols[3], values + 12);
GL(UniformMatrix4fv(mvp_uniform, 1, false, values));
}
void AmbientShaderInstanced::Unbind() {
const GLint color_attrib = attrib(2);
GL(VertexAttribDivisor_(color_attrib, 0));
const GLint models_attrib = attrib(3);
GL(DisableVertexAttribArray(models_attrib + 0));
GL(DisableVertexAttribArray(models_attrib + 1));
GL(DisableVertexAttribArray(models_attrib + 2));
GL(DisableVertexAttribArray(models_attrib + 3));
GL(VertexAttribDivisor_(models_attrib + 0, 0));
GL(VertexAttribDivisor_(models_attrib + 1, 0));
GL(VertexAttribDivisor_(models_attrib + 2, 0));
GL(VertexAttribDivisor_(models_attrib + 3, 0));
Shader::Unbind();
}
ozz::unique_ptr<AmbientTexturedShader> AmbientTexturedShader::Build() {
const char* vs[] = {
kPlatformSpecivicVSHeader, kPassUv,
"uniform mat4 u_mw;\n mat4 GetWorldMatrix() {return u_mw;}\n",
kShaderUberVS};
const char* fs[] = {kPlatformSpecivicFSHeader, kShaderAmbientFct,
kShaderAmbientTexturedFS};
ozz::unique_ptr<AmbientTexturedShader> shader =
make_unique<AmbientTexturedShader>();
bool success =
shader->InternalBuild(OZZ_ARRAY_SIZE(vs), vs, OZZ_ARRAY_SIZE(fs), fs);
success &= shader->FindAttrib("a_uv");
if (!success) {
shader.reset();
}
return shader;
}
void AmbientTexturedShader::Bind(const math::Float4x4& _model,
const math::Float4x4& _view_proj,
GLsizei _pos_stride, GLsizei _pos_offset,
GLsizei _normal_stride, GLsizei _normal_offset,
GLsizei _color_stride, GLsizei _color_offset,
GLsizei _uv_stride, GLsizei _uv_offset) {
AmbientShader::Bind(_model, _view_proj, _pos_stride, _pos_offset,
_normal_stride, _normal_offset, _color_stride,
_color_offset);
const GLint uv_attrib = attrib(3);
GL(EnableVertexAttribArray(uv_attrib));
GL(VertexAttribPointer(uv_attrib, 2, GL_FLOAT, GL_FALSE, _uv_stride,
GL_PTR_OFFSET(_uv_offset)));
}
} // namespace internal
} // namespace sample
} // namespace ozz
@@ -0,0 +1,249 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// 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. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_SAMPLES_FRAMEWORK_INTERNAL_SHADER_H_
#define OZZ_SAMPLES_FRAMEWORK_INTERNAL_SHADER_H_
#include "ozz/base/memory/unique_ptr.h"
#include "renderer_impl.h"
namespace ozz {
namespace math {
struct Float4x4;
}
namespace sample {
namespace internal {
// Declares a shader program.
class Shader {
public:
// Construct a fixed function pipeline shader. Use Shader::Build to specify
// shader sources.
Shader();
// Destruct a shader.
virtual ~Shader();
// Returns the shader program that can be bound to the OpenGL context.
GLuint program() const { return program_; }
// Request an uniform location and pushes it to the uniform stack.
// The uniform location is then accessible thought uniform().
bool BindUniform(const char* _semantic);
// Get an uniform location from the stack at index _index.
GLint uniform(int _index) const { return uniforms_[_index]; }
// Request an attribute location and pushes it to the uniform stack.
// The varying location is then accessible thought attrib().
bool FindAttrib(const char* _semantic);
// Get an varying location from the stack at index _index.
GLint attrib(int _index) const { return attribs_[_index]; }
// Unblind shader.
virtual void Unbind();
protected:
// Constructs a shader from _vertex and _fragment glsl sources.
// Mutliple source files can be specified using the *count argument.
bool BuildFromSource(int _vertex_count, const char** _vertex,
int _fragment_count, const char** _fragment);
private:
// Unbind all attribs from GL.
void UnbindAttribs();
// Shader program
GLuint program_;
// Vertex and fragment shaders
GLuint vertex_;
GLuint fragment_;
// Uniform locations, in the order they were requested.
ozz::vector<GLint> uniforms_;
// Varying locations, in the order they were requested.
ozz::vector<GLint> attribs_;
};
class ImmediatePCShader : public Shader {
public:
ImmediatePCShader() {}
virtual ~ImmediatePCShader() {}
// Constructs the shader.
// Returns nullptr if shader compilation failed or a valid Shader pointer on
// success. The shader must then be deleted using default allocator Delete
// function.
static ozz::unique_ptr<ImmediatePCShader> Build();
// Binds the shader.
void Bind(const math::Float4x4& _model, const math::Float4x4& _view_proj,
GLsizei _pos_stride, GLsizei _pos_offset, GLsizei _color_stride,
GLsizei _color_offset);
};
class ImmediatePTCShader : public Shader {
public:
ImmediatePTCShader() {}
virtual ~ImmediatePTCShader() {}
// Constructs the shader.
// Returns nullptr if shader compilation failed or a valid Shader pointer on
// success. The shader must then be deleted using default allocator Delete
// function.
static ozz::unique_ptr<ImmediatePTCShader> Build();
// Binds the shader.
void Bind(const math::Float4x4& _model, const math::Float4x4& _view_proj,
GLsizei _pos_stride, GLsizei _pos_offset, GLsizei _tex_stride,
GLsizei _tex_offset, GLsizei _color_stride, GLsizei _color_offset);
};
class SkeletonShader : public Shader {
public:
SkeletonShader() {}
virtual ~SkeletonShader() {}
// Binds the shader.
void Bind(const math::Float4x4& _model, const math::Float4x4& _view_proj,
GLsizei _pos_stride, GLsizei _pos_offset, GLsizei _normal_stride,
GLsizei _normal_offset, GLsizei _color_stride,
GLsizei _color_offset);
// Get an attribute location for the join, in cased of instanced rendering.
GLint joint_instanced_attrib() const { return attrib(3); }
// Get an uniform location for the join, in cased of non-instanced rendering.
GLint joint_uniform() const { return uniform(1); }
};
class JointShader : public SkeletonShader {
public:
JointShader() {}
virtual ~JointShader() {}
// Constructs the shader.
// Returns nullptr if shader compilation failed or a valid Shader pointer on
// success. The shader must then be deleted using default allocator Delete
// function.
static ozz::unique_ptr<JointShader> Build();
};
class BoneShader : public SkeletonShader {
public:
BoneShader() {}
virtual ~BoneShader() {}
// Constructs the shader.
// Returns nullptr if shader compilation failed or a valid Shader pointer on
// success. The shader must then be deleted using default allocator Delete
// function.
static ozz::unique_ptr<BoneShader> Build();
};
class AmbientShader : public Shader {
public:
AmbientShader() {}
virtual ~AmbientShader() {}
// Constructs the shader.
// Returns nullptr if shader compilation failed or a valid Shader pointer on
// success. The shader must then be deleted using default allocator Delete
// function.
static ozz::unique_ptr<AmbientShader> Build();
// Binds the shader.
void Bind(const math::Float4x4& _model, const math::Float4x4& _view_proj,
GLsizei _pos_stride, GLsizei _pos_offset, GLsizei _normal_stride,
GLsizei _normal_offset, GLsizei _color_stride,
GLsizei _color_offset);
protected:
bool InternalBuild(int _vertex_count, const char** _vertex,
int _fragment_count, const char** _fragment);
};
class AmbientShaderInstanced : public Shader {
public:
AmbientShaderInstanced() {}
virtual ~AmbientShaderInstanced() {}
// Constructs the shader.
// Returns nullptr if shader compilation failed or a valid Shader pointer on
// success. The shader must then be deleted using default allocator Delete
// function.
static ozz::unique_ptr<AmbientShaderInstanced> Build();
// Binds the shader.
void Bind(GLsizei _models_offset, const math::Float4x4& _view_proj,
GLsizei _pos_stride, GLsizei _pos_offset, GLsizei _normal_stride,
GLsizei _normal_offset, GLsizei _color_stride,
GLsizei _color_offset);
virtual void Unbind();
};
class AmbientTexturedShader : public AmbientShader {
public:
// Constructs the shader.
// Returns nullptr if shader compilation failed or a valid Shader pointer on
// success. The shader must then be deleted using default allocator Delete
// function.
static ozz::unique_ptr<AmbientTexturedShader> Build();
// Binds the shader.
void Bind(const math::Float4x4& _model, const math::Float4x4& _view_proj,
GLsizei _pos_stride, GLsizei _pos_offset, GLsizei _normal_stride,
GLsizei _normal_offset, GLsizei _color_stride,
GLsizei _color_offset, GLsizei _uv_stride, GLsizei _uv_offset);
};
/*
class AmbientTexturedShaderInstanced : public AmbientShaderInstanced {
public:
// Constructs the shader.
// Returns nullptr if shader compilation failed or a valid Shader pointer on
// success. The shader must then be deleted using default allocator Delete
// function.
static AmbientTexturedShaderInstanced* Build();
// Binds the shader.
void Bind(GLsizei _models_offset,
const math::Float4x4& _view_proj,
GLsizei _pos_stride, GLsizei _pos_offset,
GLsizei _normal_stride, GLsizei _normal_offset,
GLsizei _color_stride, GLsizei _color_offset,
GLsizei _uv_stride, GLsizei _uv_offset);
};
*/
} // namespace internal
} // namespace sample
} // namespace ozz
#endif // OZZ_SAMPLES_FRAMEWORK_INTERNAL_SHADER_H_
@@ -0,0 +1,220 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// 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. //
// //
//----------------------------------------------------------------------------//
#define OZZ_INCLUDE_PRIVATE_HEADER // Allows to include private headers.
#include "shooter.h"
#include <cassert>
#include <cstdio>
#include "renderer_impl.h"
namespace ozz {
namespace sample {
namespace internal {
Shooter::Shooter()
: gl_shot_format_(GL_RGBA), // Default fail safe format and types.
image_format_(image::Format::kRGBA),
shot_number_(0) {
// Test required extension (optional for the framework).
// If GL_VERSION_1_5 is defined (aka OZZ_GL_VERSION_1_5_EXT not defined), then
// these functions are part of the library (don't need extensions).
supported_ = true;
#ifdef OZZ_GL_VERSION_1_5_EXT
supported_ &= glMapBuffer != nullptr && glUnmapBuffer != nullptr;
#endif // OZZ_GL_VERSION_1_5_EXT
// Initializes shots
GLuint pbos[kNumShots];
GL(GenBuffers(kNumShots, pbos));
for (int i = 0; i < kNumShots; ++i) {
Shot& shot = shots_[i];
shot.pbo = pbos[i];
}
// OpenGL ES2 compatibility extension allows to query for implementation best
// format and type.
if (glfwExtensionSupported("GL_ARB_ES2_compatibility") != 0) {
GLint format;
GL(GetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES, &format));
GLint type;
GL(GetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES, &type));
// Only support GL_UNSIGNED_BYTE.
if (type == GL_UNSIGNED_BYTE) {
switch (format) {
case GL_RGBA:
gl_shot_format_ = format;
image_format_ = image::Format::kRGBA;
break;
case GL_BGRA:
gl_shot_format_ = format;
image_format_ = image::Format::kBGRA;
break;
case GL_RGB:
gl_shot_format_ = format;
image_format_ = image::Format::kRGB;
break;
case GL_BGR:
gl_shot_format_ = format;
image_format_ = image::Format::kBGR;
break;
}
}
} else {
// Default fail safe format and types.
gl_shot_format_ = GL_RGBA;
image_format_ = image::Format::kRGBA;
}
}
Shooter::~Shooter() {
// Process all remaining shots.
ProcessAll();
// Clean shot pbos.
for (int i = 0; i < kNumShots; ++i) {
Shot& shot = shots_[i];
GL(DeleteBuffers(1, &shot.pbo));
assert(shot.cooldown == 0); // Must have been processed.
}
}
void Shooter::Resize(int _width, int _height) {
// Early out if not supported.
if (!supported_) {
return;
}
// Process all remaining shots.
ProcessAll();
// Resizes all pbos.
#ifndef EMSCRIPTEN
for (int i = 0; i < kNumShots; ++i) {
Shot& shot = shots_[i];
GL(BindBuffer(GL_PIXEL_PACK_BUFFER, shot.pbo));
GL(BufferData(GL_PIXEL_PACK_BUFFER, _width * _height * 4, 0,
GL_STREAM_READ));
shot.width = _width;
shot.height = _height;
assert(shot.cooldown == 0); // Must have been processed.
}
GL(BindBuffer(GL_PIXEL_PACK_BUFFER, 0));
#endif // EMSCRIPTEN
}
bool Shooter::Update() { return Process(); }
bool Shooter::Process() {
// Early out if not supported.
if (!supported_) {
return true;
}
// Early out if process stack is empty.
for (int i = 0; i < kNumShots; ++i) {
Shot& shot = shots_[i];
// Early out for already processed, or empty shots.
if (shot.cooldown == 0) {
continue;
}
// Skip shots that didn't reached the cooldown.
if (--shot.cooldown != 0) {
continue;
}
// Processes this shot.
#ifdef EMSCRIPTEN
(void)shot_number_;
#else // EMSCRIPTEN
GL(BindBuffer(GL_PIXEL_PACK_BUFFER, shot.pbo));
const void* pixels = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
if (pixels) {
char name[16];
sprintf(name, "%06d.tga", shot_number_++);
ozz::sample::image::WriteTGA(name, shot.width, shot.height, image_format_,
reinterpret_cast<const uint8_t*>(pixels),
false);
GL(UnmapBuffer(GL_PIXEL_PACK_BUFFER));
}
GL(BindBuffer(GL_PIXEL_PACK_BUFFER, 0));
#endif // EMSCRIPTEN
}
return true;
}
bool Shooter::ProcessAll() {
// Reset cooldown to 1 for all "unprocessed" shots, so they will be
// "processed".
for (int i = 0; i < kNumShots; ++i) {
Shot& shot = shots_[i];
shot.cooldown = shot.cooldown > 0 ? 1 : 0;
}
return Process();
}
bool Shooter::Capture(int _buffer) {
assert(_buffer == GL_FRONT || _buffer == GL_BACK);
// Early out if not supported.
if (!supported_) {
return true;
}
// Finds the shot to use for this capture.
Shot* shot;
for (shot = shots_; shot < shots_ + kNumShots && shot->cooldown != 0;
++shot) {
}
assert(shot != shots_ + kNumShots);
// Initializes cooldown.
shot->cooldown = kInitialCountDown;
#ifndef EMSCRIPTEN
// Copy pixels to shot's pbo.
GL(ReadBuffer(_buffer));
GL(BindBuffer(GL_PIXEL_PACK_BUFFER, shot->pbo));
GL(PixelStorei(GL_PACK_ALIGNMENT, 4));
GL(ReadPixels(0, 0, shot->width, shot->height, gl_shot_format_,
GL_UNSIGNED_BYTE, 0));
GL(BindBuffer(GL_PIXEL_PACK_BUFFER, 0));
#endif // EMSCRIPTEN
return true;
}
} // namespace internal
} // namespace sample
} // namespace ozz
@@ -0,0 +1,95 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// 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. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_SAMPLES_FRAMEWORK_INTERNAL_SHOOTER_H_
#define OZZ_SAMPLES_FRAMEWORK_INTERNAL_SHOOTER_H_
#include "ozz/base/containers/vector.h"
#include "framework/image.h"
namespace ozz {
namespace sample {
namespace internal {
// Implements GL screen shot and video shooter
class Shooter {
public:
Shooter();
virtual ~Shooter();
// Resize notification, used to resize memory buffers.
void Resize(int _width, int _height);
// Updates shooter (output captured buffers to memory).
bool Update();
// Captures current (GL_FRONT or GL_BACK) _buffer to memory.
bool Capture(int _buffer);
private:
// Updates all cooldowns and process terminated shots. Returns false if it
// fails, true on success or empty stack.
bool Process();
// Processes all shots from the stack. Returns false if it fails, true on
// success or empty stack.
bool ProcessAll();
// Defines shot buffer (pbo) and data.
struct Shot {
unsigned int pbo;
int width;
int height;
int cooldown; // Shot is processed when cooldown falls to 0.
Shot() : pbo(0), width(0), height(0), cooldown(0) {}
};
// Array of pre-allocated shots, used to allow asynchronous dma transfers of
// pbos.
enum {
kInitialCountDown = 2, // Allows to delay pbo mapping 2 rendering frames.
kNumShots = kInitialCountDown,
};
Shot shots_[kNumShots];
// Format of pixels to use to glReadPixels calls.
int gl_shot_format_;
// Image format that matches GL format.
image::Format::Value image_format_;
// Shot number, used to name images.
int shot_number_;
// Is the shooter functionality supported.
bool supported_;
};
} // namespace internal
} // namespace sample
} // namespace ozz
#endif // OZZ_SAMPLES_FRAMEWORK_INTERNAL_SHOOTER_H_