Updated ozz-animation to version 0.14.1 @35b2efd4
This commit is contained in:
+144
-23
@@ -34,11 +34,11 @@
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include "immediate.h"
|
||||
#include "ozz/base/maths/math_constant.h"
|
||||
#include "ozz/base/maths/math_ex.h"
|
||||
#include "ozz/base/maths/vec_float.h"
|
||||
#include "ozz/base/memory/allocator.h"
|
||||
|
||||
#include "immediate.h"
|
||||
#include "renderer_impl.h"
|
||||
|
||||
namespace ozz {
|
||||
@@ -211,6 +211,11 @@ bool ImGuiImpl::AddWidget(float _height, math::RectFloat* _rect) {
|
||||
// Get current container.
|
||||
Container& container = containers_.back();
|
||||
|
||||
// Make it a square if height is negative.
|
||||
if (_height < 0) {
|
||||
_height = container.rect.width - kWidgetMarginX * 2.f;
|
||||
}
|
||||
|
||||
// Early out if outside of the container.
|
||||
// But don't modify current container's state.
|
||||
if (container.offset_y < kWidgetMarginY + _height) {
|
||||
@@ -740,6 +745,33 @@ void ImGuiImpl::DoGraph(const char* _label, float _min, float _max, float _mean,
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
float SliderControl(float _value, float _min, float _max, float _pow,
|
||||
int _mouse, int _mouse_max, bool _enabled, bool _active,
|
||||
float* _cursor) {
|
||||
const float pow_min = powf(_min, _pow);
|
||||
const float pow_max = powf(_max, _pow);
|
||||
const float clamped_value = ozz::math::Clamp(_min, _value, _max);
|
||||
float pow_value = powf(clamped_value, _pow);
|
||||
|
||||
// Finds cursor position and rect.
|
||||
*_cursor = floorf((_mouse_max * (pow_value - pow_min)) / (pow_max - pow_min));
|
||||
|
||||
if (_enabled) {
|
||||
if (_active) {
|
||||
_mouse = ozz::math::Clamp(0, _mouse, _mouse_max);
|
||||
pow_value = (_mouse * (pow_max - pow_min)) / _mouse_max + pow_min;
|
||||
return ozz::math::Clamp(_min, powf(pow_value, 1.f / _pow), _max);
|
||||
} else {
|
||||
// Clamping is only applied if the widget is enabled.
|
||||
return clamped_value;
|
||||
}
|
||||
}
|
||||
return _value;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool ImGuiImpl::DoSlider(const char* _label, float _min, float _max,
|
||||
float* _value, float _pow, bool _enabled) {
|
||||
math::RectFloat rect;
|
||||
@@ -751,7 +783,6 @@ bool ImGuiImpl::DoSlider(const char* _label, float _min, float _max,
|
||||
|
||||
// Calculate mouse cursor's relative y offset.
|
||||
const float initial_value = *_value;
|
||||
const float clamped_value = ozz::math::Clamp(_min, initial_value, _max);
|
||||
|
||||
// Check for hotness.
|
||||
bool hot = false, active = false;
|
||||
@@ -795,24 +826,100 @@ bool ImGuiImpl::DoSlider(const char* _label, float _min, float _max,
|
||||
}
|
||||
|
||||
// Update widget value.
|
||||
const float pow_min = powf(_min, _pow);
|
||||
const float pow_max = powf(_max, _pow);
|
||||
float pow_value = powf(clamped_value, _pow);
|
||||
float cursor;
|
||||
*_value =
|
||||
SliderControl(initial_value, _min, _max, _pow,
|
||||
inputs_.mouse_x - static_cast<int>(rect.left),
|
||||
static_cast<int>(rect.width), _enabled, active, &cursor);
|
||||
|
||||
// Renders slider's rail.
|
||||
const math::RectFloat rail_rect(rect.left, rect.bottom, rect.width,
|
||||
rect.height);
|
||||
FillRect(rail_rect, kSliderRoundRectRadius, background_color);
|
||||
StrokeRect(rail_rect, kSliderRoundRectRadius, border_color);
|
||||
|
||||
const math::RectFloat cursor_rect(
|
||||
rect.left + cursor - kWidgetCursorWidth / 2.f, rect.bottom - 1.f,
|
||||
kWidgetCursorWidth, rect.height + 2.f);
|
||||
FillRect(cursor_rect, kSliderRoundRectRadius, slider_color);
|
||||
StrokeRect(cursor_rect, kSliderRoundRectRadius, slider_border_color);
|
||||
|
||||
const math::RectFloat text_rect(
|
||||
rail_rect.left + kSliderRoundRectRadius, rail_rect.bottom,
|
||||
rail_rect.width - kSliderRoundRectRadius * 2.f, rail_rect.height);
|
||||
Print(_label, text_rect, kMiddle, text_color);
|
||||
|
||||
// Returns true if the value has changed or if it was clamped in _min / _max
|
||||
// bounds.
|
||||
return initial_value != *_value;
|
||||
}
|
||||
|
||||
bool ImGuiImpl::DoSlider2D(const char* _label, ozz::array<float, 2> _min,
|
||||
ozz::array<float, 2> _max,
|
||||
ozz::array<float, 2>* _value, bool _enabled) {
|
||||
math::RectFloat rect;
|
||||
if (!AddWidget(-1.f, &rect)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto_gen_id_++;
|
||||
|
||||
// Calculate mouse cursor's relative y offset.
|
||||
const ozz::array<float, 2> initial_value = *_value;
|
||||
|
||||
// Check for hotness.
|
||||
bool hot = false, active = false;
|
||||
if (_enabled) {
|
||||
// Includes the cursor size in the pick region.
|
||||
math::RectFloat pick_rect = rect;
|
||||
pick_rect.left -= kWidgetHeight / 2.f;
|
||||
pick_rect.width += kWidgetHeight;
|
||||
pick_rect.bottom -= kWidgetHeight / 2.f;
|
||||
pick_rect.height += kWidgetHeight;
|
||||
ButtonLogic(pick_rect, auto_gen_id_, &hot, &active);
|
||||
|
||||
// A slider is active on lmb pressed, not released. It's different to the
|
||||
// usual button behavior.
|
||||
active &= inputs_.lmb_pressed;
|
||||
}
|
||||
|
||||
// Render the scrollbar
|
||||
const GLubyte* background_color = kSliderBackgroundColor;
|
||||
const GLubyte* border_color = kWidgetBorderColor;
|
||||
const GLubyte* slider_color = kSliderCursorColor;
|
||||
const GLubyte* slider_border_color = kWidgetBorderColor;
|
||||
const GLubyte* text_color = kWidgetTextColor;
|
||||
|
||||
if (!_enabled) {
|
||||
background_color = kWidgetDisabledBackgroundColor;
|
||||
border_color = kWidgetDisabledBorderColor;
|
||||
slider_color = kSliderDisabledCursorColor;
|
||||
slider_border_color = kWidgetDisabledBorderColor;
|
||||
text_color = kWidgetDisabledTextColor;
|
||||
} else if (hot) {
|
||||
if (active) {
|
||||
int mousepos = inputs_.mouse_x - static_cast<int>(rect.left);
|
||||
if (mousepos < 0) {
|
||||
mousepos = 0;
|
||||
}
|
||||
if (mousepos > rect.width) {
|
||||
mousepos = static_cast<int>(rect.width);
|
||||
}
|
||||
pow_value = (mousepos * (pow_max - pow_min)) / rect.width + pow_min;
|
||||
*_value = ozz::math::Clamp(_min, powf(pow_value, 1.f / _pow), _max);
|
||||
// Button is both 'hot' and 'active'.
|
||||
slider_color = kWidgetActiveBackgroundColor;
|
||||
slider_border_color = kWidgetActiveBorderColor;
|
||||
} else {
|
||||
// Clamping is only applied if the widget is enabled.
|
||||
*_value = clamped_value;
|
||||
// Button is merely 'hot'.
|
||||
slider_color = kSliderCursorHotColor;
|
||||
slider_border_color = kWidgetHotBorderColor;
|
||||
}
|
||||
} else {
|
||||
// button is not hot, but it may be active. Use default colors.
|
||||
}
|
||||
|
||||
// Update widget value.
|
||||
ozz::array<float, 2> cursor;
|
||||
const int mouse[2] = {inputs_.mouse_x - static_cast<int>(rect.left),
|
||||
inputs_.mouse_y - static_cast<int>(rect.bottom)};
|
||||
const int mouse_max[2] = {static_cast<int>(rect.width),
|
||||
static_cast<int>(rect.height)};
|
||||
for (size_t i = 0; i < 2; ++i) {
|
||||
_value->at(i) =
|
||||
SliderControl(initial_value[i], _min[i], _max[i], 1.f, mouse[i],
|
||||
mouse_max[i], _enabled, active, &cursor[i]);
|
||||
}
|
||||
|
||||
// Renders slider's rail.
|
||||
@@ -822,14 +929,24 @@ bool ImGuiImpl::DoSlider(const char* _label, float _min, float _max,
|
||||
StrokeRect(rail_rect, kSliderRoundRectRadius, border_color);
|
||||
|
||||
// Finds cursor position and rect.
|
||||
const float cursor =
|
||||
floorf((rect.width * (pow_value - pow_min)) / (pow_max - pow_min));
|
||||
const math::RectFloat cursor_rect(
|
||||
rect.left + cursor - kWidgetCursorWidth / 2.f, rect.bottom - 1.f,
|
||||
kWidgetCursorWidth, rect.height + 2.f);
|
||||
rect.left + cursor[0] - kWidgetHeight / 2.f,
|
||||
rect.bottom + cursor[1] - kWidgetHeight / 2.f, kWidgetHeight,
|
||||
kWidgetHeight);
|
||||
|
||||
// Cursor cross
|
||||
const math::RectFloat cross_hrect(rect.left, rect.bottom + cursor[1],
|
||||
rect.width, 1);
|
||||
StrokeRect(cross_hrect, 0.f, slider_color);
|
||||
const math::RectFloat cross_vrect(rect.left + cursor[0], rect.bottom, 1,
|
||||
rect.height);
|
||||
StrokeRect(cross_vrect, 0.f, slider_color);
|
||||
|
||||
// Draw slider
|
||||
FillRect(cursor_rect, kSliderRoundRectRadius, slider_color);
|
||||
StrokeRect(cursor_rect, kSliderRoundRectRadius, slider_border_color);
|
||||
|
||||
// Text
|
||||
const math::RectFloat text_rect(
|
||||
rail_rect.left + kSliderRoundRectRadius, rail_rect.bottom,
|
||||
rail_rect.width - kSliderRoundRectRadius * 2.f, rail_rect.height);
|
||||
@@ -1361,7 +1478,9 @@ float ImGuiImpl::Print(const char* _text, const math::RectFloat& _rect,
|
||||
ly = _rect.bottom + (line_count - 1) * (font_.glyph_height + interlign);
|
||||
break;
|
||||
}
|
||||
default: { break; }
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GL(BindTexture(GL_TEXTURE_2D, glyph_texture_));
|
||||
@@ -1385,7 +1504,9 @@ float ImGuiImpl::Print(const char* _text, const math::RectFloat& _rect,
|
||||
lx = _rect.right() - (line_char_count * font_.glyph_width);
|
||||
break;
|
||||
}
|
||||
default: { break; }
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Loops through all characters of the current line, and renders them using
|
||||
|
||||
@@ -36,10 +36,8 @@
|
||||
// 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 {
|
||||
@@ -90,6 +88,10 @@ class ImGuiImpl : public ImGui {
|
||||
virtual bool DoSlider(const char* _label, float _min, float _max,
|
||||
float* _value, float _pow, bool _enabled);
|
||||
|
||||
virtual bool DoSlider2D(const char* _label, ozz::array<float, 2> _min,
|
||||
ozz::array<float, 2> _max,
|
||||
ozz::array<float, 2>* _value, bool _enabled);
|
||||
|
||||
virtual bool DoSlider(const char* _label, int _min, int _max, int* _value,
|
||||
float _pow, bool _enabled);
|
||||
|
||||
|
||||
+214
-91
@@ -132,6 +132,12 @@ bool RendererImpl::Initialize() {
|
||||
}
|
||||
}
|
||||
|
||||
// Instantiate instanced ambient rendering shader.
|
||||
points_shader = PointsShader::Build();
|
||||
if (!points_shader) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -239,7 +245,7 @@ bool RendererImpl::DrawGrid(int _cell_count, float _cell_size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Computes the model space bind pose and renders it.
|
||||
// Computes the model space rest pose and renders it.
|
||||
bool RendererImpl::DrawSkeleton(const ozz::animation::Skeleton& _skeleton,
|
||||
const ozz::math::Float4x4& _transform,
|
||||
bool _draw_joints) {
|
||||
@@ -253,9 +259,9 @@ bool RendererImpl::DrawSkeleton(const ozz::animation::Skeleton& _skeleton,
|
||||
// Reallocate matrix array if necessary.
|
||||
prealloc_models_.resize(num_joints);
|
||||
|
||||
// Compute model space bind pose.
|
||||
// Compute model space rest pose.
|
||||
ozz::animation::LocalToModelJob job;
|
||||
job.input = _skeleton.joint_bind_poses();
|
||||
job.input = _skeleton.joint_rest_poses();
|
||||
job.output = make_span(prealloc_models_);
|
||||
job.skeleton = &_skeleton;
|
||||
if (!job.Run()) {
|
||||
@@ -460,10 +466,7 @@ int DrawPosture_FillUniforms(const ozz::animation::Skeleton& _skeleton,
|
||||
// Copy parent joint's raw matrix, to render a bone between the parent
|
||||
// and current matrix.
|
||||
float* uniform = _uniforms + instances * 16;
|
||||
math::StorePtr(parent.cols[0], uniform + 0);
|
||||
math::StorePtr(parent.cols[1], uniform + 4);
|
||||
math::StorePtr(parent.cols[2], uniform + 8);
|
||||
math::StorePtr(parent.cols[3], uniform + 12);
|
||||
std::memcpy(uniform, parent.cols, 16 * sizeof(float));
|
||||
|
||||
// Set bone direction (bone_dir). The shader expects to find it at index
|
||||
// [3,7,11] of the matrix.
|
||||
@@ -483,11 +486,7 @@ int DrawPosture_FillUniforms(const ozz::animation::Skeleton& _skeleton,
|
||||
// Only the joint is rendered for leaves, the bone model isn't.
|
||||
if (IsLeaf(_skeleton, i)) {
|
||||
// Copy current joint's raw matrix.
|
||||
uniform = _uniforms + instances * 16;
|
||||
math::StorePtr(current.cols[0], uniform + 0);
|
||||
math::StorePtr(current.cols[1], uniform + 4);
|
||||
math::StorePtr(current.cols[2], uniform + 8);
|
||||
math::StorePtr(current.cols[3], uniform + 12);
|
||||
std::memcpy(uniform, current.cols, 16 * sizeof(float));
|
||||
|
||||
// Re-use bone_dir to fix the size of the leaf (same as previous bone).
|
||||
// The shader expects to find it at index [3,7,11] of the matrix.
|
||||
@@ -621,6 +620,84 @@ bool RendererImpl::DrawPosture(const ozz::animation::Skeleton& _skeleton,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RendererImpl::DrawPoints(const ozz::span<const float>& _positions,
|
||||
const ozz::span<const float>& _sizes,
|
||||
const ozz::span<const Color>& _colors,
|
||||
const ozz::math::Float4x4& _transform,
|
||||
bool _round, bool _screen_space) {
|
||||
// Early out if no instance to render.
|
||||
if (_positions.size() == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Sizes and colors must be of size 1 or equal to _positions' size.
|
||||
if (_sizes.size() != 1 && _sizes.size() != _positions.size() / 3) {
|
||||
return false;
|
||||
}
|
||||
if (_colors.size() != 1 && _colors.size() != _positions.size() / 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const GLsizei positions_size = static_cast<GLsizei>(_positions.size_bytes());
|
||||
const GLsizei colors_size =
|
||||
static_cast<GLsizei>(_colors.size() == 1 ? 0 : _colors.size_bytes());
|
||||
const GLsizei sizes_size =
|
||||
static_cast<GLsizei>(_sizes.size() == 1 ? 0 : _sizes.size_bytes());
|
||||
const GLsizei buffer_size = positions_size + colors_size + sizes_size;
|
||||
const GLsizei positions_offset = 0;
|
||||
const GLsizei colors_offset = positions_offset + positions_size;
|
||||
const GLsizei sizes_offset = colors_offset + colors_size;
|
||||
|
||||
// Reallocate vertex buffer.
|
||||
GL(BindBuffer(GL_ARRAY_BUFFER, dynamic_array_bo_));
|
||||
GL(BufferData(GL_ARRAY_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW));
|
||||
|
||||
GL(BufferSubData(GL_ARRAY_BUFFER, positions_offset, positions_size,
|
||||
_positions.data()));
|
||||
GL(BufferSubData(GL_ARRAY_BUFFER, colors_offset, colors_size,
|
||||
_colors.data()));
|
||||
GL(BufferSubData(GL_ARRAY_BUFFER, sizes_offset, sizes_size, _sizes.data()));
|
||||
|
||||
// Square or round sprites. Beware msaa makes sprites round if GL_POINT_SPRITE
|
||||
// isn't enabled
|
||||
if (_round) {
|
||||
GL(Enable(GL_POINT_SMOOTH));
|
||||
GL(Disable(GL_POINT_SPRITE));
|
||||
} else {
|
||||
GL(Disable(GL_POINT_SMOOTH));
|
||||
GL(Enable(GL_POINT_SPRITE));
|
||||
}
|
||||
|
||||
// Size is managed in vertex shader side.
|
||||
GL(Enable(GL_PROGRAM_POINT_SIZE));
|
||||
|
||||
const PointsShader::GenericAttrib attrib =
|
||||
points_shader->Bind(_transform, camera()->view_proj(), 12,
|
||||
positions_offset, colors_size ? 4 : 0, colors_offset,
|
||||
sizes_size ? 4 : 0, sizes_offset, _screen_space);
|
||||
|
||||
GL(BindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
|
||||
// Apply remaining general attributes
|
||||
if (_colors.size() <= 1) {
|
||||
const Color color = _colors.empty() ? kWhite : _colors[0];
|
||||
GL(VertexAttrib4f(attrib.color, color.r / 255.f, color.g / 255.f,
|
||||
color.b / 255.f, color.a / 255.f));
|
||||
}
|
||||
if (_sizes.size() <= 1) {
|
||||
const float size = _sizes.empty() ? 1.f : _sizes[0];
|
||||
GL(VertexAttrib1f(attrib.size, size));
|
||||
}
|
||||
|
||||
// Draws the mesh.
|
||||
GL(DrawArrays(GL_POINTS, 0, static_cast<GLsizei>(_positions.size() / 3)));
|
||||
|
||||
// Unbinds.
|
||||
points_shader->Unbind();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RendererImpl::DrawBoxIm(const ozz::math::Box& _box,
|
||||
const ozz::math::Float4x4& _transform,
|
||||
const Color _colors[2]) {
|
||||
@@ -1218,49 +1295,70 @@ bool RendererImpl::DrawMesh(const Mesh& _mesh,
|
||||
vertex_offset += part_vertex_count;
|
||||
}
|
||||
|
||||
// Binds shader with this array buffer, depending on rendering options.
|
||||
Shader* shader = nullptr;
|
||||
if (_options.texture) {
|
||||
ambient_textured_shader->Bind(_transform, camera()->view_proj(),
|
||||
positions_stride, positions_offset,
|
||||
normals_stride, normals_offset, colors_stride,
|
||||
colors_offset, uvs_stride, uvs_offset);
|
||||
shader = ambient_textured_shader.get();
|
||||
if (_options.triangles) {
|
||||
// Binds shader with this array buffer, depending on rendering options.
|
||||
Shader* shader = nullptr;
|
||||
if (_options.texture) {
|
||||
ambient_textured_shader->Bind(
|
||||
_transform, camera()->view_proj(), positions_stride, positions_offset,
|
||||
normals_stride, normals_offset, colors_stride, colors_offset,
|
||||
uvs_stride, uvs_offset);
|
||||
shader = ambient_textured_shader.get();
|
||||
|
||||
// Binds default texture
|
||||
GL(BindTexture(GL_TEXTURE_2D, checkered_texture_));
|
||||
} else {
|
||||
ambient_shader->Bind(_transform, camera()->view_proj(), positions_stride,
|
||||
positions_offset, normals_stride, normals_offset,
|
||||
colors_stride, colors_offset);
|
||||
shader = ambient_shader.get();
|
||||
// Binds default texture
|
||||
GL(BindTexture(GL_TEXTURE_2D, checkered_texture_));
|
||||
} else {
|
||||
ambient_shader->Bind(_transform, camera()->view_proj(), positions_stride,
|
||||
positions_offset, normals_stride, normals_offset,
|
||||
colors_stride, colors_offset);
|
||||
shader = ambient_shader.get();
|
||||
}
|
||||
|
||||
// Maps the index dynamic buffer and update it.
|
||||
GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, dynamic_index_bo_));
|
||||
const Mesh::TriangleIndices& indices = _mesh.triangle_indices;
|
||||
GL(BufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||
indices.size() * sizeof(Mesh::TriangleIndices::value_type),
|
||||
array_begin(indices), GL_STREAM_DRAW));
|
||||
|
||||
// Draws the mesh.
|
||||
static_assert(sizeof(Mesh::TriangleIndices::value_type) == 2,
|
||||
"Expects 2 bytes indices.");
|
||||
GL(DrawElements(GL_TRIANGLES, static_cast<GLsizei>(indices.size()),
|
||||
GL_UNSIGNED_SHORT, 0));
|
||||
|
||||
// Unbinds.
|
||||
GL(BindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
GL(BindTexture(GL_TEXTURE_2D, 0));
|
||||
GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
|
||||
shader->Unbind();
|
||||
}
|
||||
|
||||
// Maps the index dynamic buffer and update it.
|
||||
GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, dynamic_index_bo_));
|
||||
const Mesh::TriangleIndices& indices = _mesh.triangle_indices;
|
||||
GL(BufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||
indices.size() * sizeof(Mesh::TriangleIndices::value_type),
|
||||
array_begin(indices), GL_STREAM_DRAW));
|
||||
|
||||
// Draws the mesh.
|
||||
static_assert(sizeof(Mesh::TriangleIndices::value_type) == 2,
|
||||
"Expects 2 bytes indices.");
|
||||
GL(DrawElements(GL_TRIANGLES, static_cast<GLsizei>(indices.size()),
|
||||
GL_UNSIGNED_SHORT, 0));
|
||||
|
||||
// Unbinds.
|
||||
GL(BindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
GL(BindTexture(GL_TEXTURE_2D, 0));
|
||||
GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
|
||||
shader->Unbind();
|
||||
|
||||
if (_options.wireframe) {
|
||||
#ifndef EMSCRIPTEN
|
||||
GL(PolygonMode(GL_FRONT_AND_BACK, GL_FILL));
|
||||
#endif // EMSCRIPTEN
|
||||
}
|
||||
|
||||
// Renders debug vertices.
|
||||
if (_options.vertices) {
|
||||
for (size_t i = 0; i < _mesh.parts.size(); ++i) {
|
||||
const Mesh::Part& part = _mesh.parts[i];
|
||||
ozz::sample::Color color = ozz::sample::kWhite;
|
||||
span<const ozz::sample::Color> colors;
|
||||
if (_options.colors && part.colors.size() == part.positions.size() / 3) {
|
||||
colors = {
|
||||
reinterpret_cast<const ozz::sample::Color*>(part.colors.data()),
|
||||
part.positions.size() / 3};
|
||||
} else {
|
||||
colors = {&color, 1};
|
||||
}
|
||||
const float size = 2.f;
|
||||
DrawPoints({part.positions.data(), part.positions.size()}, {&size, 1},
|
||||
{&color, 1}, _transform, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Renders debug normals.
|
||||
if (_options.normals) {
|
||||
for (size_t i = 0; i < _mesh.parts.size(); ++i) {
|
||||
@@ -1313,7 +1411,7 @@ bool RendererImpl::DrawSkinnedMesh(
|
||||
const Mesh& _mesh, const span<math::Float4x4> _skinning_matrices,
|
||||
const ozz::math::Float4x4& _transform, const Options& _options) {
|
||||
// Forward to DrawMesh function is skinning is disabled.
|
||||
if (_options.skip_skinning) {
|
||||
if (_options.skip_skinning || !_mesh.skinned()) {
|
||||
return DrawMesh(_mesh, _transform, _options);
|
||||
}
|
||||
|
||||
@@ -1327,13 +1425,16 @@ bool RendererImpl::DrawSkinnedMesh(
|
||||
|
||||
// Positions and normals are interleaved to improve caching while executing
|
||||
// skinning job.
|
||||
|
||||
const GLsizei positions_offset = 0;
|
||||
const GLsizei normals_offset = sizeof(float) * 3;
|
||||
const GLsizei tangents_offset = sizeof(float) * 6;
|
||||
const GLsizei positions_stride = sizeof(float) * 9;
|
||||
const GLsizei normals_stride = positions_stride;
|
||||
const GLsizei tangents_stride = positions_stride;
|
||||
const GLsizei skinned_data_size = vertex_count * positions_stride;
|
||||
const GLsizei positions_stride = sizeof(float) * 3;
|
||||
const GLsizei normals_offset = vertex_count * positions_stride;
|
||||
const GLsizei normals_stride = sizeof(float) * 3;
|
||||
const GLsizei tangents_offset =
|
||||
normals_offset + vertex_count * normals_stride;
|
||||
const GLsizei tangents_stride = sizeof(float) * 3;
|
||||
const GLsizei skinned_data_size =
|
||||
tangents_offset + vertex_count * tangents_stride;
|
||||
|
||||
// Colors and uvs are contiguous. They aren't transformed, so they can be
|
||||
// directly copied from source mesh which is non-interleaved as-well.
|
||||
@@ -1542,54 +1643,76 @@ bool RendererImpl::DrawSkinnedMesh(
|
||||
processed_vertex_count += part_vertex_count;
|
||||
}
|
||||
|
||||
// Updates dynamic vertex buffer with skinned data.
|
||||
GL(BindBuffer(GL_ARRAY_BUFFER, dynamic_array_bo_));
|
||||
GL(BufferData(GL_ARRAY_BUFFER, vbo_size, nullptr, GL_STREAM_DRAW));
|
||||
GL(BufferSubData(GL_ARRAY_BUFFER, 0, vbo_size, vbo_map));
|
||||
if (_options.triangles) {
|
||||
// Updates dynamic vertex buffer with skinned data.
|
||||
GL(BindBuffer(GL_ARRAY_BUFFER, dynamic_array_bo_));
|
||||
GL(BufferData(GL_ARRAY_BUFFER, vbo_size, nullptr, GL_STREAM_DRAW));
|
||||
GL(BufferSubData(GL_ARRAY_BUFFER, 0, vbo_size, vbo_map));
|
||||
|
||||
// Binds shader with this array buffer, depending on rendering options.
|
||||
Shader* shader = nullptr;
|
||||
if (_options.texture) {
|
||||
ambient_textured_shader->Bind(_transform, camera()->view_proj(),
|
||||
positions_stride, positions_offset,
|
||||
normals_stride, normals_offset, colors_stride,
|
||||
colors_offset, uvs_stride, uvs_offset);
|
||||
shader = ambient_textured_shader.get();
|
||||
// Binds shader with this array buffer, depending on rendering options.
|
||||
Shader* shader = nullptr;
|
||||
if (_options.texture) {
|
||||
ambient_textured_shader->Bind(
|
||||
_transform, camera()->view_proj(), positions_stride, positions_offset,
|
||||
normals_stride, normals_offset, colors_stride, colors_offset,
|
||||
uvs_stride, uvs_offset);
|
||||
shader = ambient_textured_shader.get();
|
||||
|
||||
// Binds default texture
|
||||
GL(BindTexture(GL_TEXTURE_2D, checkered_texture_));
|
||||
} else {
|
||||
ambient_shader->Bind(_transform, camera()->view_proj(), positions_stride,
|
||||
positions_offset, normals_stride, normals_offset,
|
||||
colors_stride, colors_offset);
|
||||
shader = ambient_shader.get();
|
||||
// Binds default texture
|
||||
GL(BindTexture(GL_TEXTURE_2D, checkered_texture_));
|
||||
} else {
|
||||
ambient_shader->Bind(_transform, camera()->view_proj(), positions_stride,
|
||||
positions_offset, normals_stride, normals_offset,
|
||||
colors_stride, colors_offset);
|
||||
shader = ambient_shader.get();
|
||||
}
|
||||
|
||||
// Maps the index dynamic buffer and update it.
|
||||
GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, dynamic_index_bo_));
|
||||
const Mesh::TriangleIndices& indices = _mesh.triangle_indices;
|
||||
GL(BufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||
indices.size() * sizeof(Mesh::TriangleIndices::value_type),
|
||||
array_begin(indices), GL_STREAM_DRAW));
|
||||
|
||||
// Draws the mesh.
|
||||
static_assert(sizeof(Mesh::TriangleIndices::value_type) == 2,
|
||||
"Expects 2 bytes indices.");
|
||||
GL(DrawElements(GL_TRIANGLES, static_cast<GLsizei>(indices.size()),
|
||||
GL_UNSIGNED_SHORT, 0));
|
||||
|
||||
// Unbinds.
|
||||
GL(BindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
GL(BindTexture(GL_TEXTURE_2D, 0));
|
||||
GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
|
||||
shader->Unbind();
|
||||
}
|
||||
|
||||
// Maps the index dynamic buffer and update it.
|
||||
GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, dynamic_index_bo_));
|
||||
const Mesh::TriangleIndices& indices = _mesh.triangle_indices;
|
||||
GL(BufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||
indices.size() * sizeof(Mesh::TriangleIndices::value_type),
|
||||
array_begin(indices), GL_STREAM_DRAW));
|
||||
|
||||
// Draws the mesh.
|
||||
static_assert(sizeof(Mesh::TriangleIndices::value_type) == 2,
|
||||
"Expects 2 bytes indices.");
|
||||
GL(DrawElements(GL_TRIANGLES, static_cast<GLsizei>(indices.size()),
|
||||
GL_UNSIGNED_SHORT, 0));
|
||||
|
||||
// Unbinds.
|
||||
GL(BindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
GL(BindTexture(GL_TEXTURE_2D, 0));
|
||||
GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
|
||||
shader->Unbind();
|
||||
|
||||
if (_options.wireframe) {
|
||||
#ifndef EMSCRIPTEN
|
||||
GL(PolygonMode(GL_FRONT_AND_BACK, GL_FILL));
|
||||
#endif // EMSCRIPTEN
|
||||
}
|
||||
|
||||
// Renders debug vertices.
|
||||
if (_options.vertices) {
|
||||
ozz::sample::Color color = ozz::sample::kWhite;
|
||||
span<const ozz::sample::Color> colors;
|
||||
if (_options.colors) {
|
||||
colors = {reinterpret_cast<const ozz::sample::Color*>(
|
||||
ozz::PointerStride(vbo_map, colors_offset)),
|
||||
static_cast<size_t>(vertex_count)};
|
||||
} else {
|
||||
colors = {&color, 1};
|
||||
}
|
||||
|
||||
const span<const float> vertices{
|
||||
reinterpret_cast<const float*>(
|
||||
ozz::PointerStride(vbo_map, positions_offset)),
|
||||
static_cast<size_t>(vertex_count * 3)};
|
||||
const float size = 2.f;
|
||||
DrawPoints(vertices, {&size, 1}, colors, _transform, true, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,6 @@
|
||||
|
||||
// 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"
|
||||
@@ -91,6 +90,7 @@ namespace sample {
|
||||
namespace internal {
|
||||
class Camera;
|
||||
class Shader;
|
||||
class PointsShader;
|
||||
class SkeletonShader;
|
||||
class AmbientShader;
|
||||
class AmbientTexturedShader;
|
||||
@@ -119,6 +119,12 @@ class RendererImpl : public Renderer {
|
||||
const ozz::math::Float4x4& _transform,
|
||||
bool _draw_joints);
|
||||
|
||||
virtual bool DrawPoints(
|
||||
const ozz::span<const float>& _positions,
|
||||
const ozz::span<const float>& _sizes,
|
||||
const ozz::span<const Color>& _colors,
|
||||
const ozz::math::Float4x4& _transform, bool _round, bool _screen_space);
|
||||
|
||||
virtual bool DrawBoxIm(const ozz::math::Box& _box,
|
||||
const ozz::math::Float4x4& _transform,
|
||||
const Color _colors[2]);
|
||||
@@ -241,6 +247,7 @@ class RendererImpl : public Renderer {
|
||||
ozz::unique_ptr<AmbientShader> ambient_shader;
|
||||
ozz::unique_ptr<AmbientTexturedShader> ambient_textured_shader;
|
||||
ozz::unique_ptr<AmbientShaderInstanced> ambient_shader_instanced;
|
||||
ozz::unique_ptr<PointsShader> points_shader;
|
||||
|
||||
// Checkered texture
|
||||
unsigned int checkered_texture_;
|
||||
|
||||
@@ -326,6 +326,91 @@ void ImmediatePTCShader::Bind(const math::Float4x4& _model,
|
||||
GL(Uniform1i(texture, 0));
|
||||
}
|
||||
|
||||
ozz::unique_ptr<PointsShader> PointsShader::Build() {
|
||||
bool success = true;
|
||||
|
||||
const char* kSimplePointsVS =
|
||||
"uniform mat4 u_mvp;\n"
|
||||
"attribute vec3 a_position;\n"
|
||||
"attribute vec4 a_color;\n"
|
||||
"attribute float a_size;\n"
|
||||
"attribute float a_screen_space;\n"
|
||||
"varying vec4 v_vertex_color;\n"
|
||||
"void main() {\n"
|
||||
" vec4 vertex = vec4(a_position.xyz, 1.);\n"
|
||||
" gl_Position = u_mvp * vertex;\n"
|
||||
" gl_PointSize = a_screen_space == 0. ? a_size / gl_Position.w : a_size;\n"
|
||||
" v_vertex_color = a_color;\n"
|
||||
"}\n";
|
||||
const char* kSimplePointsPS =
|
||||
"varying vec4 v_vertex_color;\n"
|
||||
"void main() {\n"
|
||||
" gl_FragColor = v_vertex_color;\n"
|
||||
"}\n";
|
||||
|
||||
const char* vs[] = {kPlatformSpecivicVSHeader, kSimplePointsVS};
|
||||
const char* fs[] = {kPlatformSpecivicFSHeader, kSimplePointsPS};
|
||||
|
||||
ozz::unique_ptr<PointsShader> shader = make_unique<PointsShader>();
|
||||
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");
|
||||
success &= shader->FindAttrib("a_size");
|
||||
success &= shader->FindAttrib("a_screen_space");
|
||||
|
||||
// Binds default uniforms
|
||||
success &= shader->BindUniform("u_mvp");
|
||||
|
||||
if (!success) {
|
||||
shader.reset();
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
PointsShader::GenericAttrib PointsShader::Bind(
|
||||
const math::Float4x4& _model, const math::Float4x4& _view_proj,
|
||||
GLsizei _pos_stride, GLsizei _pos_offset, GLsizei _color_stride,
|
||||
GLsizei _color_offset, GLsizei _size_stride, GLsizei _size_offset,
|
||||
bool _screen_space) {
|
||||
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);
|
||||
if (_color_stride) {
|
||||
GL(EnableVertexAttribArray(color_attrib));
|
||||
GL(VertexAttribPointer(color_attrib, 4, GL_UNSIGNED_BYTE, GL_TRUE,
|
||||
_color_stride, GL_PTR_OFFSET(_color_offset)));
|
||||
}
|
||||
const GLint size_attrib = attrib(2);
|
||||
if (_size_stride) {
|
||||
GL(EnableVertexAttribArray(size_attrib));
|
||||
GL(VertexAttribPointer(size_attrib, 1, GL_FLOAT, GL_TRUE, _size_stride,
|
||||
GL_PTR_OFFSET(_size_offset)));
|
||||
}
|
||||
const GLint screen_space_attrib = attrib(3);
|
||||
GL(VertexAttrib1f(screen_space_attrib, 1.f * _screen_space));
|
||||
|
||||
// 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));
|
||||
|
||||
return {_color_stride ? -1 : color_attrib, _size_stride ? -1 : size_attrib};
|
||||
}
|
||||
|
||||
namespace {
|
||||
const char* kPassUv =
|
||||
"attribute vec2 a_uv;\n"
|
||||
|
||||
@@ -126,6 +126,29 @@ class ImmediatePTCShader : public Shader {
|
||||
GLsizei _tex_offset, GLsizei _color_stride, GLsizei _color_offset);
|
||||
};
|
||||
|
||||
class PointsShader : public Shader {
|
||||
public:
|
||||
PointsShader() {}
|
||||
virtual ~PointsShader() {}
|
||||
|
||||
// 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<PointsShader> Build();
|
||||
|
||||
// Binds the shader.
|
||||
struct GenericAttrib {
|
||||
GLint color;
|
||||
GLint size;
|
||||
};
|
||||
GenericAttrib Bind(const math::Float4x4& _model,
|
||||
const math::Float4x4& _view_proj, GLsizei _pos_stride,
|
||||
GLsizei _pos_offset, GLsizei _color_stride,
|
||||
GLsizei _color_offset, GLsizei _size_stride,
|
||||
GLsizei _size_offset, bool _screen_space);
|
||||
};
|
||||
|
||||
class SkeletonShader : public Shader {
|
||||
public:
|
||||
SkeletonShader() {}
|
||||
|
||||
Reference in New Issue
Block a user