// Copyright (C) 2023 RozK // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef RK_ENGINE_VERTEX_FORMAT_H #define RK_ENGINE_VERTEX_FORMAT_H #include "render_opengles.hpp" #include namespace rk_vertex { #pragma pack(push, 1) template struct alignas(alignof(_type)) rk_input { _type input; }; template struct alignas(alignof(_type)) rk_output { _type output; [[RK_FAST]] inline void convert( rk_input<_input> const & __restrict src) { output = static_cast<_type>(src.input); } }; template struct alignas(alignof(_type)) rk_output<_type, rk_float, _signed, true> { _type output; [[RK_FAST]] inline void convert( rk_input const & __restrict src) { enum : _type { max = std::numeric_limits<_type>::max() }; output = static_cast<_type>(src.input * static_cast(max)); } }; #pragma pack(4) template struct alignas(4) rk_input_row { rk_input<_input> input_col[_cols]; }; template struct alignas(4) rk_output_row { rk_output<_output, _input, _signed, _normalized> output_col[_cols]; [[RK_FAST, RK_FLATTEN, RK_UNROLLED]] inline void convert( rk_input_row<_input, _cols> const & __restrict src) { for (unsigned col = 0; col < _cols; ++col) { output_col[col].convert(src.input_col[col]); } } }; template struct alignas(4) rk_output_row<_output, _output, _cols, _signed, _normalized> { rk_output<_output, _output, _signed, _normalized> output_col[_cols]; [[RK_FAST]] inline void convert( rk_input_row<_output, _cols> const & __restrict src) { static_assert(sizeof(output_col) == sizeof(src.input_col)); rk_output<_output, _output, _signed, _normalized> const * const input_col = reinterpret_cast const *>(src.input_col); *output_col = *input_col; } }; template struct alignas(4) rk_output_row, _input, _cols, _signed, _normalized> { rk_output, _input, _signed, _normalized> output_cols; [[RK_FAST, RK_FLATTEN]] inline void convert( rk_input_row<_input, _cols> const & __restrict src) { output_cols.convert(src); } }; template struct alignas(4) rk_input_format { rk_input_row<_input, _cols> input_row[_rows]; }; template struct alignas(4) rk_output_format { rk_output_row<_output, _input, _cols, _signed, _normalized> output_row[_rows]; [[RK_FAST, RK_FLATTEN, RK_UNROLLED]] inline void convert( rk_input_format<_input, _cols, _rows> const & __restrict src) { for (unsigned row = 0; row < _rows; ++row) { output_row[row].convert(src.input_row[row]); } } }; template struct alignas(4) rk_output_format<_output, _output, _cols, _rows, _signed, _normalized> { rk_output_row<_output, _output, _cols, _signed, _normalized> output_row[_rows]; [[RK_FAST]] inline void convert( rk_input_format<_output, _cols, _rows> const & __restrict src) { static_assert(sizeof(output_row) == sizeof(src.input_row)); rk_output_row<_output, _output, _cols, _signed, _normalized> const * const input_row = reinterpret_cast const *>(src.input_row); *output_row = *input_row; } }; template struct alignas(alignof(rk_packed<_signed, 3>)) rk_output, _input, _signed, _normalized> { rk_packed<_signed, 3> output; [[RK_FAST]] inline void convert( rk_input_row<_input, 3> const & __restrict src) { typedef typename rk_packed<_signed, 3>::type packed_type; output.packed = ((static_cast(src.input_col[0].input) & 1023)) | ((static_cast(src.input_col[1].input) & 1023) << 10) | ((static_cast(src.input_col[2].input) & 1023) << 20); } }; template struct alignas(alignof(rk_packed<_signed, 4>)) rk_output, _input, _signed, _normalized> { rk_packed<_signed, 4> output; [[RK_FAST]] inline void convert( rk_input_row<_input, 4> const & __restrict src) { typedef typename rk_packed<_signed, 4>::type packed_type; output.packed = ((static_cast(src.input_col[0].input) & 1023)) | ((static_cast(src.input_col[1].input) & 1023) << 10) | ((static_cast(src.input_col[2].input) & 1023) << 20) | ((static_cast(src.input_col[3].input) & 3) << 30); } }; template<> struct alignas(alignof(rk_packed)) rk_output, rk_float, true, true> { rk_packed output; [[RK_FAST]] inline void convert( rk_input_row const & __restrict src) { output.packed = ((static_cast(src.input_col[0].input * 511.f) & 1023)) | ((static_cast(src.input_col[1].input * 511.f) & 1023) << 10) | ((static_cast(src.input_col[2].input * 511.f) & 1023) << 20); } }; template<> struct alignas(alignof(rk_packed)) rk_output, rk_float, true, true> { rk_packed output; [[RK_FAST]] inline void convert( rk_input_row const & __restrict src) { output.packed = ((static_cast(src.input_col[0].input * 511.f) & 1023)) | ((static_cast(src.input_col[1].input * 511.f) & 1023) << 10) | ((static_cast(src.input_col[2].input * 511.f) & 1023) << 20) | ((static_cast(src.input_col[3].input) & 3) << 30); } }; #pragma pack(pop) template struct rk_format { typedef rk_input<_input> input; typedef rk_output<_output, input, _signed, _normalized> output; typedef rk_input_row<_input, _cols> input_row; typedef rk_output_row<_output, _input, _cols, _signed, _normalized> output_row; typedef rk_input_format<_input, _cols, _rows> input_format; typedef rk_output_format<_output, _input, _cols, _rows, _signed, _normalized> output_format; static_assert(sizeof(input) == sizeof(_input)); static_assert(sizeof(output) == sizeof(_output)); static_assert((sizeof(input_row) % sizeof(rk_vertex_input)) == 0); static_assert((sizeof(output_row) % sizeof(rk_vertex_output)) == 0); static_assert((sizeof(input_format) % sizeof(rk_vertex_input)) == 0); static_assert((sizeof(output_format) % sizeof(rk_vertex_output)) == 0); static unsigned get_input_size() { return sizeof(input_format); } static unsigned get_output_size() { return sizeof(output_format); } static unsigned get_output_offset(unsigned const index) { return index * sizeof(output_row); } [[RK_FAST, RK_FLATTEN]] inline static void convert( output_format & __restrict dst, input_format const & __restrict src) { dst.convert(src); } [[RK_HOT, RK_FAST, RK_FLATTEN]] static void param_packer( unsigned const count, rk_instance_index const * const __restrict indices, rk_vertex_output * __restrict _dst, rk_vertex_input const * const __restrict _src) { rk_instance_index const * const last_index = indices + count; output_format * __restrict dst = reinterpret_cast(_dst); input_format const * const __restrict src = reinterpret_cast(_src); for (rk_instance_index const * __restrict index = indices; index < last_index; ++index, ++dst) { dst->convert(src[*index]); } } }; } // namepace rk_vertex typedef rk_vertex::rk_format rk_vec3_float; typedef rk_vertex::rk_format rk_vec3_short; typedef rk_vertex::rk_format rk_vec3_short_norm; typedef rk_vertex::rk_format, rk_float, 3, 1, true, false> rk_vec3_int10; typedef rk_vertex::rk_format, rk_float, 3, 1, true, true> rk_vec3_int10_norm; typedef rk_vertex::rk_format, rk_float, 3, 1, false, false> rk_vec3_uint10; typedef rk_vertex::rk_format, rk_float, 3, 1, false, true> rk_vec3_uint10_norm; typedef rk_vertex::rk_format rk_mat3_float; typedef rk_vertex::rk_format, rk_float, 3, 3, true, false> rk_mat3_int10; typedef rk_vertex::rk_format, rk_float, 3, 3, true, true> rk_mat3_int10_norm; #endif // RK_ENGINE_VERTEX_FORMAT_H