Updated ozz-animation to version 0.14.1 @35b2efd4

This commit is contained in:
Martin Felis
2023-03-26 13:28:12 +02:00
parent bf3189ff49
commit 15871f349c
194 changed files with 3495 additions and 1957 deletions
@@ -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);
@@ -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() {}