| @@ -35,7 +35,7 @@ public: | |||||
| for (int i = 0; i < SPRITE_COUNT; ++i) | for (int i = 0; i < SPRITE_COUNT; ++i) | ||||
| { | { | ||||
| m_sprites.Push(ivec3(rand(-96, 640), rand(-96, 480), 0), | |||||
| m_sprites.Push(vec3(rand(-96, 640), rand(-96, 480), 0), | |||||
| rand(0.f, 1.f)); | rand(0.f, 1.f)); | ||||
| } | } | ||||
| @@ -78,7 +78,7 @@ public: | |||||
| int frame = (int)(m_sprites[i].m2 * FRAME_COUNT); | int frame = (int)(m_sprites[i].m2 * FRAME_COUNT); | ||||
| // m_sprites[i].m1.z = frame; | // m_sprites[i].m1.z = frame; | ||||
| scene.AddTile(m_tileset, frame, | scene.AddTile(m_tileset, frame, | ||||
| (ivec3)m_sprites[i].m1, 0, vec2(2.f), 0.f); | |||||
| m_sprites[i].m1, 0, vec2(2.f), 0.f); | |||||
| } | } | ||||
| } | } | ||||
| @@ -73,7 +73,7 @@ public: | |||||
| m_lines_indices << 0 << 4 << 1 << 5 << 2 << 6 << 3 << 7; | m_lines_indices << 0 << 4 << 1 << 5 << 2 << 6 << 3 << 7; | ||||
| m_text = new Text("", "data/font/ascii.png"); | m_text = new Text("", "data/font/ascii.png"); | ||||
| m_text->SetPos(ivec3(5, 5, 1)); | |||||
| m_text->SetPos(vec3(5, 5, 1)); | |||||
| Ticker::Ref(m_text); | Ticker::Ref(m_text); | ||||
| m_ready = false; | m_ready = false; | ||||
| @@ -33,8 +33,8 @@ public: | |||||
| m_size = size; | m_size = size; | ||||
| m_size.x = (m_size.x + 15) & ~15; | m_size.x = (m_size.x + 15) & ~15; | ||||
| m_size.y = (m_size.y + 15) & ~15; | m_size.y = (m_size.y + 15) & ~15; | ||||
| m_texel_settings = vec4(1.0, 1.0, 2.0, 2.0) / m_size.xyxy; | |||||
| m_screen_settings = vec4(1.0, 1.0, 0.5, 0.5) * m_size.xyxy; | |||||
| m_texel_settings = vec4(1.0, 1.0, 2.0, 2.0) / (vec4)m_size.xyxy; | |||||
| m_screen_settings = vec4(1.0, 1.0, 0.5, 0.5) * (vec4)m_size.xyxy; | |||||
| /* Window size decides the world aspect ratio. For instance, 640×480 | /* Window size decides the world aspect ratio. For instance, 640×480 | ||||
| * will be mapped to (-0.66,-0.5) - (0.66,0.5). */ | * will be mapped to (-0.66,-0.5) - (0.66,0.5). */ | ||||
| @@ -105,21 +105,21 @@ public: | |||||
| #if !defined __native_client__ | #if !defined __native_client__ | ||||
| m_centertext = new Text(NULL, "data/font/ascii.png"); | m_centertext = new Text(NULL, "data/font/ascii.png"); | ||||
| m_centertext->SetPos(ivec3(5, m_window_size.y - 15, 1)); | |||||
| m_centertext->SetPos(vec3(5, m_window_size.y - 15, 1)); | |||||
| Ticker::Ref(m_centertext); | Ticker::Ref(m_centertext); | ||||
| m_mousetext = new Text(NULL, "data/font/ascii.png"); | m_mousetext = new Text(NULL, "data/font/ascii.png"); | ||||
| m_mousetext->SetPos(ivec3(5, m_window_size.y - 29, 1)); | |||||
| m_mousetext->SetPos(vec3(5, m_window_size.y - 29, 1)); | |||||
| Ticker::Ref(m_mousetext); | Ticker::Ref(m_mousetext); | ||||
| m_zoomtext = new Text(NULL, "data/font/ascii.png"); | m_zoomtext = new Text(NULL, "data/font/ascii.png"); | ||||
| m_zoomtext->SetPos(ivec3(5, m_window_size.y - 43, 1)); | |||||
| m_zoomtext->SetPos(vec3(5, m_window_size.y - 43, 1)); | |||||
| Ticker::Ref(m_zoomtext); | Ticker::Ref(m_zoomtext); | ||||
| #endif | #endif | ||||
| m_position = ivec3(0, 0, 0); | |||||
| m_position = vec3::zero; | |||||
| m_bbox[0] = m_position; | m_bbox[0] = m_position; | ||||
| m_bbox[1] = ivec3(m_window_size, 0); | |||||
| m_bbox[1] = vec3((vec2)m_window_size, 0); | |||||
| //Input::TrackMouse(this); | //Input::TrackMouse(this); | ||||
| #if LOL_FEATURE_THREADS | #if LOL_FEATURE_THREADS | ||||
| @@ -175,7 +175,8 @@ public: | |||||
| int prev_frame = (m_frame + 4) % 4; | int prev_frame = (m_frame + 4) % 4; | ||||
| m_frame = (m_frame + 1) % 4; | m_frame = (m_frame + 1) % 4; | ||||
| rcmplx worldmouse = m_center + rcmplx(ScreenToWorldOffset(mousepos)); | |||||
| rcmplx worldmouse = m_center | |||||
| + rcmplx(ScreenToWorldOffset((vec2)mousepos)); | |||||
| uint32_t buttons = 0; | uint32_t buttons = 0; | ||||
| //uint32_t buttons = Input::GetMouseButtons(); | //uint32_t buttons = Input::GetMouseButtons(); | ||||
| @@ -187,13 +188,13 @@ public: | |||||
| m_oldmouse = mousepos; | m_oldmouse = mousepos; | ||||
| m_drag = true; | m_drag = true; | ||||
| } | } | ||||
| m_translate = ScreenToWorldOffset(m_oldmouse) | |||||
| - ScreenToWorldOffset(mousepos); | |||||
| m_translate = rcmplx(ScreenToWorldOffset((vec2)m_oldmouse) | |||||
| - ScreenToWorldOffset((vec2)mousepos)); | |||||
| /* XXX: the purpose of this hack is to avoid translating by | /* XXX: the purpose of this hack is to avoid translating by | ||||
| * an exact number of pixels. If this were to happen, the step() | * an exact number of pixels. If this were to happen, the step() | ||||
| * optimisation for i915 cards in our shader would behave | * optimisation for i915 cards in our shader would behave | ||||
| * incorrectly because a quarter of the pixels in the image | * incorrectly because a quarter of the pixels in the image | ||||
| * would have tie rankings in the distance calculation. */ | |||||
| * would have tied rankings in the distance calculation. */ | |||||
| m_translate *= real(1023.0 / 1024.0); | m_translate *= real(1023.0 / 1024.0); | ||||
| m_oldmouse = mousepos; | m_oldmouse = mousepos; | ||||
| } | } | ||||
| @@ -203,7 +204,7 @@ public: | |||||
| if (m_translate != rcmplx(0.0, 0.0)) | if (m_translate != rcmplx(0.0, 0.0)) | ||||
| { | { | ||||
| m_translate *= real(std::pow(2.0, -seconds * 5.0)); | m_translate *= real(std::pow(2.0, -seconds * 5.0)); | ||||
| if ((double)m_translate.norm() < m_radius * 1e-4) | |||||
| if ((double)norm(m_translate) < m_radius * 1e-4) | |||||
| m_translate = rcmplx(0.0, 0.0); | m_translate = rcmplx(0.0, 0.0); | ||||
| } | } | ||||
| } | } | ||||
| @@ -242,7 +243,8 @@ public: | |||||
| #if !defined __CELLOS_LV2__ && !defined _XBOX | #if !defined __CELLOS_LV2__ && !defined _XBOX | ||||
| m_center += m_translate; | m_center += m_translate; | ||||
| m_center = (m_center - worldmouse) * real(zoom) + worldmouse; | m_center = (m_center - worldmouse) * real(zoom) + worldmouse; | ||||
| worldmouse = m_center + rcmplx(ScreenToWorldOffset(mousepos)); | |||||
| worldmouse = m_center | |||||
| + rcmplx(ScreenToWorldOffset((vec2)mousepos)); | |||||
| #endif | #endif | ||||
| /* Store the transformation properties to go from m_frame - 1 | /* Store the transformation properties to go from m_frame - 1 | ||||
| @@ -352,7 +354,7 @@ public: | |||||
| for (int i = m_frame % 2; i < m_size.x; i += 2) | for (int i = m_frame % 2; i < m_size.x; i += 2) | ||||
| { | { | ||||
| double xr, yr, x0, y0, x1, y1, x2, y2, x3, y3; | double xr, yr, x0, y0, x1, y1, x2, y2, x3, y3; | ||||
| dcmplx z0 = c + TexelToWorldOffset(ivec2(i, j)); | |||||
| dcmplx z0 = c + TexelToWorldOffset(vec2(i, j)); | |||||
| //dcmplx r0(0.28693186889504513, 0.014286693904085048); | //dcmplx r0(0.28693186889504513, 0.014286693904085048); | ||||
| //dcmplx r0(0.001643721971153, 0.822467633298876); | //dcmplx r0(0.001643721971153, 0.822467633298876); | ||||
| //dcmplx r0(-1.207205434596, 0.315432814901); | //dcmplx r0(-1.207205434596, 0.315432814901); | ||||
| @@ -50,7 +50,7 @@ DebugFps::DebugFps(int x, int y) | |||||
| } | } | ||||
| #else | #else | ||||
| data->lines[0] = new Text("", "data/font/ascii.png"); | data->lines[0] = new Text("", "data/font/ascii.png"); | ||||
| data->lines[0]->SetPos(ivec3(x, y, 100)); | |||||
| data->lines[0]->SetPos(vec3(x, y, 100)); | |||||
| Ticker::Ref(data->lines[0]); | Ticker::Ref(data->lines[0]); | ||||
| #endif | #endif | ||||
| } | } | ||||
| @@ -247,7 +247,7 @@ EglApp::EglApp(char const *title, ivec2 res, float fps) : | |||||
| # if !defined HAVE_BCM_HOST_H | # if !defined HAVE_BCM_HOST_H | ||||
| XWindowAttributes gwa; | XWindowAttributes gwa; | ||||
| XGetWindowAttributes(data->dpy, data->win, &gwa); | XGetWindowAttributes(data->dpy, data->win, &gwa); | ||||
| data->screen_size = ivec2(gwa.width, gwa.height); | |||||
| data->screen_size = uvec2(gwa.width, gwa.height); | |||||
| # endif | # endif | ||||
| # if defined USE_SDL | # if defined USE_SDL | ||||
| @@ -139,7 +139,7 @@ Renderer::Renderer(ivec2 size) | |||||
| /* Initialise rendering states */ | /* Initialise rendering states */ | ||||
| m_data->m_viewport = ibox2(0, 0, 0, 0); | m_data->m_viewport = ibox2(0, 0, 0, 0); | ||||
| SetViewport(ibox2(vec2::zero, size)); | |||||
| SetViewport(ibox2(ivec2::zero, size)); | |||||
| m_data->m_clear_color = vec4(-1.f); | m_data->m_clear_color = vec4(-1.f); | ||||
| SetClearColor(vec4(0.1f, 0.2f, 0.3f, 1.0f)); | SetClearColor(vec4(0.1f, 0.2f, 0.3f, 1.0f)); | ||||
| @@ -257,17 +257,17 @@ ibox2 Renderer::GetViewport() const | |||||
| float Renderer::GetXYRatio() const | float Renderer::GetXYRatio() const | ||||
| { | { | ||||
| ibox2 a = GetViewport(); | ibox2 a = GetViewport(); | ||||
| box2 b(a.A, a.B); | |||||
| vec2 s = b.B - b.A; | |||||
| return s.x / s.y; | |||||
| ibox2 b(a.A, a.B); | |||||
| ivec2 s = b.B - b.A; | |||||
| return (float)s.x / s.y; | |||||
| } | } | ||||
| float Renderer::GetYXRatio() const | float Renderer::GetYXRatio() const | ||||
| { | { | ||||
| ibox2 a = GetViewport(); | ibox2 a = GetViewport(); | ||||
| box2 b(a.A, a.B); | |||||
| vec2 s = b.B - b.A; | |||||
| return s.y / s.x; | |||||
| ibox2 b(a.A, a.B); | |||||
| ivec2 s = b.B - b.A; | |||||
| return (float)s.y / s.x; | |||||
| } | } | ||||
| /* | /* | ||||
| @@ -500,7 +500,7 @@ void OricImageCodec::WriteScreen(Image &image, array<uint8_t> &result) | |||||
| /* Recursively compute and apply best command */ | /* Recursively compute and apply best command */ | ||||
| int dummy; | int dummy; | ||||
| uint8_t command = bestmove(srcl, bgfg, vec3(0), depth, | |||||
| uint8_t command = bestmove(srcl, bgfg, ivec3(0), depth, | |||||
| 0x7fffff, &dummy, dstl); | 0x7fffff, &dummy, dstl); | ||||
| /* Propagate error */ | /* Propagate error */ | ||||
| for (int i = 0; i < 6; i++) | for (int i = 0; i < 6; i++) | ||||
| @@ -49,7 +49,7 @@ template <typename T> struct Box2 | |||||
| B(T(0)) | B(T(0)) | ||||
| {} | {} | ||||
| inline Box2(Vec2<T> const &a, Vec2<T> const &b) | |||||
| inline Box2(vec<2,T> const &a, vec<2,T> const &b) | |||||
| : A(a), | : A(a), | ||||
| B(b) | B(b) | ||||
| {} | {} | ||||
| @@ -59,32 +59,32 @@ template <typename T> struct Box2 | |||||
| B(bx, by) | B(bx, by) | ||||
| {} | {} | ||||
| Box2<T> operator +(Vec2<T> const &v) const | |||||
| Box2<T> operator +(vec<2,T> const &v) const | |||||
| { | { | ||||
| return Box2<T>(A + v, B + v); | return Box2<T>(A + v, B + v); | ||||
| } | } | ||||
| Box2<T> &operator +=(Vec2<T> const &v) | |||||
| Box2<T> &operator +=(vec<2,T> const &v) | |||||
| { | { | ||||
| return *this = *this + v; | return *this = *this + v; | ||||
| } | } | ||||
| Box2<T> operator -(Vec2<T> const &v) const | |||||
| Box2<T> operator -(vec<2,T> const &v) const | |||||
| { | { | ||||
| return Box2<T>(A - v, B - v); | return Box2<T>(A - v, B - v); | ||||
| } | } | ||||
| Box2<T> &operator -=(Vec2<T> const &v) | |||||
| Box2<T> &operator -=(vec<2,T> const &v) | |||||
| { | { | ||||
| return *this = *this - v; | return *this = *this - v; | ||||
| } | } | ||||
| Box2<T> operator *(Vec2<T> const &v) const | |||||
| Box2<T> operator *(vec<2,T> const &v) const | |||||
| { | { | ||||
| return Box2<T>(A * v, B * v); | return Box2<T>(A * v, B * v); | ||||
| } | } | ||||
| Box2<T> &operator *=(Vec2<T> const &v) | |||||
| Box2<T> &operator *=(vec<2,T> const &v) | |||||
| { | { | ||||
| return *this = *this * v; | return *this = *this * v; | ||||
| } | } | ||||
| @@ -99,7 +99,7 @@ template <typename T> struct Box2 | |||||
| return A != box.A || B != box.B; | return A != box.A || B != box.B; | ||||
| } | } | ||||
| Vec2<T> A, B; | |||||
| vec<2,T> A, B; | |||||
| }; | }; | ||||
| /* | /* | ||||
| @@ -113,7 +113,7 @@ template <typename T> struct Box3 | |||||
| B(T(0)) | B(T(0)) | ||||
| {} | {} | ||||
| inline Box3(Vec3<T> const &a, Vec3<T> const &b) | |||||
| inline Box3(vec<3,T> const &a, vec<3,T> const &b) | |||||
| : A(a), | : A(a), | ||||
| B(b) | B(b) | ||||
| {} | {} | ||||
| @@ -124,32 +124,32 @@ template <typename T> struct Box3 | |||||
| B(bx, by, bz) | B(bx, by, bz) | ||||
| {} | {} | ||||
| Box3<T> operator +(Vec3<T> const &v) const | |||||
| Box3<T> operator +(vec<3,T> const &v) const | |||||
| { | { | ||||
| return Box3<T>(A + v, B + v); | return Box3<T>(A + v, B + v); | ||||
| } | } | ||||
| Box3<T> &operator +=(Vec3<T> const &v) | |||||
| Box3<T> &operator +=(vec<3,T> const &v) | |||||
| { | { | ||||
| return *this = *this + v; | return *this = *this + v; | ||||
| } | } | ||||
| Box3<T> operator -(Vec3<T> const &v) const | |||||
| Box3<T> operator -(vec<3,T> const &v) const | |||||
| { | { | ||||
| return Box3<T>(A - v, B - v); | return Box3<T>(A - v, B - v); | ||||
| } | } | ||||
| Box3<T> &operator -=(Vec3<T> const &v) | |||||
| Box3<T> &operator -=(vec<3,T> const &v) | |||||
| { | { | ||||
| return *this = *this - v; | return *this = *this - v; | ||||
| } | } | ||||
| Box3<T> operator *(Vec3<T> const &v) const | |||||
| Box3<T> operator *(vec<3,T> const &v) const | |||||
| { | { | ||||
| return Box3<T>(A * v, B * v); | return Box3<T>(A * v, B * v); | ||||
| } | } | ||||
| Box3<T> &operator *=(Vec3<T> const &v) | |||||
| Box3<T> &operator *=(vec<3,T> const &v) | |||||
| { | { | ||||
| return *this = *this * v; | return *this = *this * v; | ||||
| } | } | ||||
| @@ -164,7 +164,7 @@ template <typename T> struct Box3 | |||||
| return A != box.A || B != box.B; | return A != box.A || B != box.B; | ||||
| } | } | ||||
| Vec3<T> A, B; | |||||
| vec<3,T> A, B; | |||||
| }; | }; | ||||
| /* | /* | ||||
| @@ -18,25 +18,25 @@ namespace lol { | |||||
| #define LOL_VEC_2_CONST(type, name, a, b) \ | #define LOL_VEC_2_CONST(type, name, a, b) \ | ||||
| template<> \ | template<> \ | ||||
| Vec2<type> const Vec2<type>::name = Vec2<type>((type)a, (type)b); | |||||
| vec<2,type> const vec<2,type>::name = vec<2,type>((type)a, (type)b); | |||||
| #define LOL_VEC_3_CONST(type, name, a, b, c) \ | #define LOL_VEC_3_CONST(type, name, a, b, c) \ | ||||
| template<> \ | template<> \ | ||||
| Vec3<type> const Vec3<type>::name = Vec3<type>((type)a, (type)b, (type)c); | |||||
| vec<3,type> const vec<3,type>::name = vec<3,type>((type)a, (type)b, (type)c); | |||||
| #define LOL_VEC_4_CONST(type, name, a, b, c, d) \ | #define LOL_VEC_4_CONST(type, name, a, b, c, d) \ | ||||
| template<> \ | template<> \ | ||||
| Vec4<type> const Vec4<type>::name = Vec4<type>((type)a, (type)b, (type)c, (type)d); | |||||
| vec<4,type> const vec<4,type>::name = vec<4,type>((type)a, (type)b, (type)c, (type)d); | |||||
| #define LOL_MAT_CONST(type, name, a) \ | #define LOL_MAT_CONST(type, name, a) \ | ||||
| template<> \ | template<> \ | ||||
| Mat2<type> const Mat2<type>::name = Mat2<type>((type)a); \ | |||||
| matrix<2,2,type> const matrix<2,2,type>::name = matrix<2,2,type>((type)a); \ | |||||
| \ | \ | ||||
| template<> \ | template<> \ | ||||
| Mat3<type> const Mat3<type>::name = Mat3<type>((type)a); \ | |||||
| matrix<3,3,type> const matrix<3,3,type>::name = matrix<3,3,type>((type)a); \ | |||||
| \ | \ | ||||
| template<> \ | template<> \ | ||||
| Mat4<type> const Mat4<type>::name = Mat4<type>((type)a); | |||||
| matrix<4,4,type> const matrix<4,4,type>::name = matrix<4,4,type>((type)a); | |||||
| #define LOL_ALL_CONST_INNER(type) \ | #define LOL_ALL_CONST_INNER(type) \ | ||||
| LOL_VEC_2_CONST(type, zero, 0, 0) \ | LOL_VEC_2_CONST(type, zero, 0, 0) \ | ||||
| @@ -407,7 +407,7 @@ template<> mat3 mat3::rotate(float degrees, vec3 v) | |||||
| return rotate(degrees, v.x, v.y, v.z); | return rotate(degrees, v.x, v.y, v.z); | ||||
| } | } | ||||
| template<> mat3::Mat3(quat const &q) | |||||
| template<> mat3::matrix(quat const &q) | |||||
| { | { | ||||
| float n = norm(q); | float n = norm(q); | ||||
| @@ -434,7 +434,7 @@ template<> mat3::Mat3(quat const &q) | |||||
| v2[2] = 1.0f - s * (q.x * q.x + q.y * q.y); | v2[2] = 1.0f - s * (q.x * q.x + q.y * q.y); | ||||
| } | } | ||||
| template<> mat4::Mat4(quat const &q) | |||||
| template<> mat4::matrix(quat const &q) | |||||
| { | { | ||||
| *this = mat4(mat3(q), 1.f); | *this = mat4(mat3(q), 1.f); | ||||
| } | } | ||||
| @@ -19,7 +19,6 @@ | |||||
| #include <lol/main.h> | #include <lol/main.h> | ||||
| #include "scenesetup.h" | #include "scenesetup.h" | ||||
| using namespace std; | |||||
| using namespace lol; | using namespace lol; | ||||
| static int const TEXTURE_WIDTH = 256; | static int const TEXTURE_WIDTH = 256; | ||||
| @@ -61,17 +61,17 @@ LOLUNIT_FIXTURE(ComplexTest) | |||||
| { | { | ||||
| cmplx a(3.0f, -4.0f); | cmplx a(3.0f, -4.0f); | ||||
| LOLUNIT_ASSERT_EQUAL(a.norm(), 5.0f); | |||||
| LOLUNIT_ASSERT_EQUAL(norm(a), 5.0f); | |||||
| cmplx b = a * ~a; | cmplx b = a * ~a; | ||||
| cmplx c = a.norm() * a.norm(); | |||||
| cmplx c = norm(a) * norm(a); | |||||
| LOLUNIT_ASSERT_EQUAL(b, c); | LOLUNIT_ASSERT_EQUAL(b, c); | ||||
| cmplx d(5.0f, 12.0f); | cmplx d(5.0f, 12.0f); | ||||
| LOLUNIT_ASSERT_EQUAL(d.norm(), 13.0f); | |||||
| LOLUNIT_ASSERT_EQUAL((a * d).norm(), a.norm() * d.norm()); | |||||
| LOLUNIT_ASSERT_EQUAL(norm(d), 13.0f); | |||||
| LOLUNIT_ASSERT_EQUAL(norm(a * d), norm(a) * norm(d)); | |||||
| } | } | ||||
| LOLUNIT_TEST(Base) | LOLUNIT_TEST(Base) | ||||
| @@ -79,8 +79,8 @@ LOLUNIT_FIXTURE(ComplexTest) | |||||
| cmplx one(1.0f, 0.0f); | cmplx one(1.0f, 0.0f); | ||||
| cmplx i(0.0f, 1.0f); | cmplx i(0.0f, 1.0f); | ||||
| LOLUNIT_ASSERT_EQUAL(one.norm(), 1.0f); | |||||
| LOLUNIT_ASSERT_EQUAL(i.norm(), 1.0f); | |||||
| LOLUNIT_ASSERT_EQUAL(norm(one), 1.0f); | |||||
| LOLUNIT_ASSERT_EQUAL(norm(i), 1.0f); | |||||
| LOLUNIT_ASSERT_EQUAL(i * i, -one); | LOLUNIT_ASSERT_EQUAL(i * i, -one); | ||||
| } | } | ||||
| @@ -90,7 +90,7 @@ LOLUNIT_FIXTURE(ComplexTest) | |||||
| cmplx a(3.0f, -4.0f); | cmplx a(3.0f, -4.0f); | ||||
| cmplx b = normalize(a); | cmplx b = normalize(a); | ||||
| LOLUNIT_ASSERT_DOUBLES_EQUAL(b.norm(), 1.0, 1e-8); | |||||
| LOLUNIT_ASSERT_DOUBLES_EQUAL(norm(b), 1.0, 1e-8); | |||||
| } | } | ||||
| LOLUNIT_TEST(Reciprocal) | LOLUNIT_TEST(Reciprocal) | ||||