| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| // Don't edit this file! It is auto-generated by frameworks/rs/api/generate.sh. |
| |
| /* |
| * rs_matrix.rsh: Matrix Functions |
| * |
| * These functions let you manipulate square matrices of rank 2x2, 3x3, and 4x4. |
| * They are particularly useful for graphical transformations and are compatible |
| * with OpenGL. |
| * |
| * We use a zero-based index for rows and columns. E.g. the last element of a |
| * rs_matrix4x4 is found at (3, 3). |
| * |
| * RenderScript uses column-major matrices and column-based vectors. Transforming |
| * a vector is done by postmultiplying the vector, e.g. (matrix * vector), |
| * as provided by rsMatrixMultiply(). |
| * |
| * To create a transformation matrix that performs two transformations at once, |
| * multiply the two source matrices, with the first transformation as the right |
| * argument. E.g. to create a transformation matrix that applies the |
| * transformation s1 followed by s2, call rsMatrixLoadMultiply(&combined, &s2, &s1). |
| * This derives from s2 * (s1 * v), which is (s2 * s1) * v. |
| * |
| * We have two style of functions to create transformation matrices: |
| * rsMatrixLoadTransformation and rsMatrixTransformation. The former |
| * style simply stores the transformation matrix in the first argument. The latter |
| * modifies a pre-existing transformation matrix so that the new transformation |
| * happens first. E.g. if you call rsMatrixTranslate() on a matrix that already |
| * does a scaling, the resulting matrix when applied to a vector will first do the |
| * translation then the scaling. |
| */ |
| |
| #ifndef RENDERSCRIPT_RS_MATRIX_RSH |
| #define RENDERSCRIPT_RS_MATRIX_RSH |
| |
| #include "rs_vector_math.rsh" |
| |
| /* |
| * rsExtractFrustumPlanes: Compute frustum planes |
| * |
| * Computes 6 frustum planes from the view projection matrix |
| * |
| * Parameters: |
| * viewProj: Matrix to extract planes from. |
| * left: Left plane. |
| * right: Right plane. |
| * top: Top plane. |
| * bottom: Bottom plane. |
| * near: Near plane. |
| * far: Far plane. |
| */ |
| #if !defined(RS_VERSION) || (RS_VERSION <= 23) |
| static inline void __attribute__((overloadable)) |
| rsExtractFrustumPlanes(const rs_matrix4x4* viewProj, float4* left, float4* right, float4* top, |
| float4* bottom, float4* near, float4* far) { |
| // x y z w = a b c d in the plane equation |
| left->x = viewProj->m[3] + viewProj->m[0]; |
| left->y = viewProj->m[7] + viewProj->m[4]; |
| left->z = viewProj->m[11] + viewProj->m[8]; |
| left->w = viewProj->m[15] + viewProj->m[12]; |
| |
| right->x = viewProj->m[3] - viewProj->m[0]; |
| right->y = viewProj->m[7] - viewProj->m[4]; |
| right->z = viewProj->m[11] - viewProj->m[8]; |
| right->w = viewProj->m[15] - viewProj->m[12]; |
| |
| top->x = viewProj->m[3] - viewProj->m[1]; |
| top->y = viewProj->m[7] - viewProj->m[5]; |
| top->z = viewProj->m[11] - viewProj->m[9]; |
| top->w = viewProj->m[15] - viewProj->m[13]; |
| |
| bottom->x = viewProj->m[3] + viewProj->m[1]; |
| bottom->y = viewProj->m[7] + viewProj->m[5]; |
| bottom->z = viewProj->m[11] + viewProj->m[9]; |
| bottom->w = viewProj->m[15] + viewProj->m[13]; |
| |
| near->x = viewProj->m[3] + viewProj->m[2]; |
| near->y = viewProj->m[7] + viewProj->m[6]; |
| near->z = viewProj->m[11] + viewProj->m[10]; |
| near->w = viewProj->m[15] + viewProj->m[14]; |
| |
| far->x = viewProj->m[3] - viewProj->m[2]; |
| far->y = viewProj->m[7] - viewProj->m[6]; |
| far->z = viewProj->m[11] - viewProj->m[10]; |
| far->w = viewProj->m[15] - viewProj->m[14]; |
| |
| float len = length(left->xyz); |
| *left /= len; |
| len = length(right->xyz); |
| *right /= len; |
| len = length(top->xyz); |
| *top /= len; |
| len = length(bottom->xyz); |
| *bottom /= len; |
| len = length(near->xyz); |
| *near /= len; |
| len = length(far->xyz); |
| *far /= len; |
| } |
| #endif |
| |
| #if (defined(RS_VERSION) && (RS_VERSION >= 24)) |
| extern void __attribute__((overloadable)) |
| rsExtractFrustumPlanes(const rs_matrix4x4* viewProj, float4* left, float4* righ, float4* top, |
| float4* bottom, float4* near, float4* far); |
| #endif |
| |
| /* |
| * rsIsSphereInFrustum: Checks if a sphere is within the frustum planes |
| * |
| * Returns true if the sphere is within the 6 frustum planes. |
| * |
| * Parameters: |
| * sphere: float4 representing the sphere. |
| * left: Left plane. |
| * right: Right plane. |
| * top: Top plane. |
| * bottom: Bottom plane. |
| * near: Near plane. |
| * far: Far plane. |
| */ |
| #if !defined(RS_VERSION) || (RS_VERSION <= 23) |
| static inline bool __attribute__((always_inline, overloadable)) |
| rsIsSphereInFrustum(float4* sphere, float4* left, float4* right, float4* top, float4* bottom, |
| float4* near, float4* far) { |
| float distToCenter = dot(left->xyz, sphere->xyz) + left->w; |
| if (distToCenter < -sphere->w) { |
| return false; |
| } |
| distToCenter = dot(right->xyz, sphere->xyz) + right->w; |
| if (distToCenter < -sphere->w) { |
| return false; |
| } |
| distToCenter = dot(top->xyz, sphere->xyz) + top->w; |
| if (distToCenter < -sphere->w) { |
| return false; |
| } |
| distToCenter = dot(bottom->xyz, sphere->xyz) + bottom->w; |
| if (distToCenter < -sphere->w) { |
| return false; |
| } |
| distToCenter = dot(near->xyz, sphere->xyz) + near->w; |
| if (distToCenter < -sphere->w) { |
| return false; |
| } |
| distToCenter = dot(far->xyz, sphere->xyz) + far->w; |
| if (distToCenter < -sphere->w) { |
| return false; |
| } |
| return true; |
| } |
| #endif |
| |
| #if (defined(RS_VERSION) && (RS_VERSION >= 24)) |
| extern bool __attribute__((overloadable)) |
| rsIsSphereInFrustum(float4* sphere, float4* left, float4* right, float4* top, float4* bottom, |
| float4* near, float4* far); |
| #endif |
| |
| /* |
| * rsMatrixGet: Get one element |
| * |
| * Returns one element of a matrix. |
| * |
| * Warning: The order of the column and row parameters may be unexpected. |
| * |
| * Parameters: |
| * m: Matrix to extract the element from. |
| * col: Zero-based column of the element to be extracted. |
| * row: Zero-based row of the element to extracted. |
| */ |
| extern float __attribute__((overloadable)) |
| rsMatrixGet(const rs_matrix4x4* m, uint32_t col, uint32_t row); |
| |
| extern float __attribute__((overloadable)) |
| rsMatrixGet(const rs_matrix3x3* m, uint32_t col, uint32_t row); |
| |
| extern float __attribute__((overloadable)) |
| rsMatrixGet(const rs_matrix2x2* m, uint32_t col, uint32_t row); |
| |
| /* |
| * rsMatrixInverse: Inverts a matrix in place |
| * |
| * Returns true if the matrix was successfully inverted. |
| * |
| * Parameters: |
| * m: Matrix to invert. |
| */ |
| extern bool __attribute__((overloadable)) |
| rsMatrixInverse(rs_matrix4x4* m); |
| |
| /* |
| * rsMatrixInverseTranspose: Inverts and transpose a matrix in place |
| * |
| * The matrix is first inverted then transposed. Returns true if the matrix was |
| * successfully inverted. |
| * |
| * Parameters: |
| * m: Matrix to modify. |
| */ |
| extern bool __attribute__((overloadable)) |
| rsMatrixInverseTranspose(rs_matrix4x4* m); |
| |
| /* |
| * rsMatrixLoad: Load or copy a matrix |
| * |
| * Set the elements of a matrix from an array of floats or from another matrix. |
| * |
| * If loading from an array, the floats should be in row-major order, i.e. the element a |
| * row 0, column 0 should be first, followed by the element at |
| * row 0, column 1, etc. |
| * |
| * If loading from a matrix and the source is smaller than the destination, the rest |
| * of the destination is filled with elements of the identity matrix. E.g. |
| * loading a rs_matrix2x2 into a rs_matrix4x4 will give: |
| * |
| * m00 m01 0.0 0.0 |
| * m10 m11 0.0 0.0 |
| * 0.0 0.0 1.0 0.0 |
| * 0.0 0.0 0.0 1.0 |
| * |
| * |
| * Parameters: |
| * destination: Matrix to set. |
| * array: Array of values to set the matrix to. These arrays should be 4, 9, or 16 floats long, depending on the matrix size. |
| * source: Source matrix. |
| */ |
| extern void __attribute__((overloadable)) |
| rsMatrixLoad(rs_matrix4x4* destination, const float* array); |
| |
| extern void __attribute__((overloadable)) |
| rsMatrixLoad(rs_matrix3x3* destination, const float* array); |
| |
| extern void __attribute__((overloadable)) |
| rsMatrixLoad(rs_matrix2x2* destination, const float* array); |
| |
| extern void __attribute__((overloadable)) |
| rsMatrixLoad(rs_matrix4x4* destination, const rs_matrix4x4* source); |
| |
| extern void __attribute__((overloadable)) |
| rsMatrixLoad(rs_matrix3x3* destination, const rs_matrix3x3* source); |
| |
| extern void __attribute__((overloadable)) |
| rsMatrixLoad(rs_matrix2x2* destination, const rs_matrix2x2* source); |
| |
| extern void __attribute__((overloadable)) |
| rsMatrixLoad(rs_matrix4x4* destination, const rs_matrix3x3* source); |
| |
| extern void __attribute__((overloadable)) |
| rsMatrixLoad(rs_matrix4x4* destination, const rs_matrix2x2* source); |
| |
| /* |
| * rsMatrixLoadFrustum: Load a frustum projection matrix |
| * |
| * Constructs a frustum projection matrix, transforming the box identified by |
| * the six clipping planes left, right, bottom, top, near, far. |
| * |
| * To apply this projection to a vector, multiply the vector by the created |
| * matrix using rsMatrixMultiply(). |
| * |
| * Parameters: |
| * m: Matrix to set. |
| */ |
| extern void __attribute__((overloadable)) |
| rsMatrixLoadFrustum(rs_matrix4x4* m, float left, float right, float bottom, float top, |
| float near, float far); |
| |
| /* |
| * rsMatrixLoadIdentity: Load identity matrix |
| * |
| * Set the elements of a matrix to the identity matrix. |
| * |
| * Parameters: |
| * m: Matrix to set. |
| */ |
| extern void __attribute__((overloadable)) |
| rsMatrixLoadIdentity(rs_matrix4x4* m); |
| |
| extern void __attribute__((overloadable)) |
| rsMatrixLoadIdentity(rs_matrix3x3* m); |
| |
| extern void __attribute__((overloadable)) |
| rsMatrixLoadIdentity(rs_matrix2x2* m); |
| |
| /* |
| * rsMatrixLoadMultiply: Multiply two matrices |
| * |
| * Sets m to the matrix product of lhs * rhs. |
| * |
| * To combine two 4x4 transformaton matrices, multiply the second transformation matrix |
| * by the first transformation matrix. E.g. to create a transformation matrix that applies |
| * the transformation s1 followed by s2, call rsMatrixLoadMultiply(&combined, &s2, &s1). |
| * |
| * Warning: Prior to version 21, storing the result back into right matrix is not supported and |
| * will result in undefined behavior. Use rsMatrixMulitply instead. E.g. instead of doing |
| * rsMatrixLoadMultiply (&m2r, &m2r, &m2l), use rsMatrixMultiply (&m2r, &m2l). |
| * rsMatrixLoadMultiply (&m2l, &m2r, &m2l) works as expected. |
| * |
| * Parameters: |
| * m: Matrix to set. |
| * lhs: Left matrix of the product. |
| * rhs: Right matrix of the product. |
| */ |
| extern void __attribute__((overloadable)) |
| rsMatrixLoadMultiply(rs_matrix4x4* m, const rs_matrix4x4* lhs, const rs_matrix4x4* rhs); |
| |
| extern void __attribute__((overloadable)) |
| rsMatrixLoadMultiply(rs_matrix3x3* m, const rs_matrix3x3* lhs, const rs_matrix3x3* rhs); |
| |
| extern void __attribute__((overloadable)) |
| rsMatrixLoadMultiply(rs_matrix2x2* m, const rs_matrix2x2* lhs, const rs_matrix2x2* rhs); |
| |
| /* |
| * rsMatrixLoadOrtho: Load an orthographic projection matrix |
| * |
| * Constructs an orthographic projection matrix, transforming the box identified by the |
| * six clipping planes left, right, bottom, top, near, far into a unit cube |
| * with a corner at (-1, -1, -1) and the opposite at (1, 1, 1). |
| * |
| * To apply this projection to a vector, multiply the vector by the created matrix |
| * using rsMatrixMultiply(). |
| * |
| * See https://en.wikipedia.org/wiki/Orthographic_projection . |
| * |
| * Parameters: |
| * m: Matrix to set. |
| */ |
| extern void __attribute__((overloadable)) |
| rsMatrixLoadOrtho(rs_matrix4x4* m, float left, float right, float bottom, float top, float near, |
| float far); |
| |
| /* |
| * rsMatrixLoadPerspective: Load a perspective projection matrix |
| * |
| * Constructs a perspective projection matrix, assuming a symmetrical field of view. |
| * |
| * To apply this projection to a vector, multiply the vector by the created matrix |
| * using rsMatrixMultiply(). |
| * |
| * Parameters: |
| * m: Matrix to set. |
| * fovy: Field of view, in degrees along the Y axis. |
| * aspect: Ratio of x / y. |
| * near: Near clipping plane. |
| * far: Far clipping plane. |
| */ |
| extern void __attribute__((overloadable)) |
| rsMatrixLoadPerspective(rs_matrix4x4* m, float fovy, float aspect, float near, float far); |
| |
| /* |
| * rsMatrixLoadRotate: Load a rotation matrix |
| * |
| * This function creates a rotation matrix. The axis of rotation is the (x, y, z) vector. |
| * |
| * To rotate a vector, multiply the vector by the created matrix using rsMatrixMultiply(). |
| * |
| * See http://en.wikipedia.org/wiki/Rotation_matrix . |
| * |
| * Parameters: |
| * m: Matrix to set. |
| * rot: How much rotation to do, in degrees. |
| * x: X component of the vector that is the axis of rotation. |
| * y: Y component of the vector that is the axis of rotation. |
| * z: Z component of the vector that is the axis of rotation. |
| */ |
| extern void __attribute__((overloadable)) |
| rsMatrixLoadRotate(rs_matrix4x4* m, float rot, float x, float y, float z); |
| |
| /* |
| * rsMatrixLoadScale: Load a scaling matrix |
| * |
| * This function creates a scaling matrix, where each component of a vector is multiplied |
| * by a number. This number can be negative. |
| * |
| * To scale a vector, multiply the vector by the created matrix using rsMatrixMultiply(). |
| * |
| * Parameters: |
| * m: Matrix to set. |
| * x: Multiple to scale the x components by. |
| * y: Multiple to scale the y components by. |
| * z: Multiple to scale the z components by. |
| */ |
| extern void __attribute__((overloadable)) |
| rsMatrixLoadScale(rs_matrix4x4* m, float x, float y, float z); |
| |
| /* |
| * rsMatrixLoadTranslate: Load a translation matrix |
| * |
| * This function creates a translation matrix, where a number is added to each element of |
| * a vector. |
| * |
| * To translate a vector, multiply the vector by the created matrix using |
| * rsMatrixMultiply(). |
| * |
| * Parameters: |
| * m: Matrix to set. |
| * x: Number to add to each x component. |
| * y: Number to add to each y component. |
| * z: Number to add to each z component. |
| */ |
| extern void __attribute__((overloadable)) |
| rsMatrixLoadTranslate(rs_matrix4x4* m, float x, float y, float z); |
| |
| /* |
| * rsMatrixMultiply: Multiply a matrix by a vector or another matrix |
| * |
| * For the matrix by matrix variant, sets m to the matrix product m * rhs. |
| * |
| * When combining two 4x4 transformation matrices using this function, the resulting |
| * matrix will correspond to performing the rhs transformation first followed by |
| * the original m transformation. |
| * |
| * For the matrix by vector variant, returns the post-multiplication of the vector |
| * by the matrix, ie. m * in. |
| * |
| * When multiplying a float3 to a rs_matrix4x4, the vector is expanded with (1). |
| * |
| * When multiplying a float2 to a rs_matrix4x4, the vector is expanded with (0, 1). |
| * |
| * When multiplying a float2 to a rs_matrix3x3, the vector is expanded with (0). |
| * |
| * Starting with API 14, this function takes a const matrix as the first argument. |
| * |
| * Parameters: |
| * m: Left matrix of the product and the matrix to be set. |
| * rhs: Right matrix of the product. |
| */ |
| extern void __attribute__((overloadable)) |
| rsMatrixMultiply(rs_matrix4x4* m, const rs_matrix4x4* rhs); |
| |
| extern void __attribute__((overloadable)) |
| rsMatrixMultiply(rs_matrix3x3* m, const rs_matrix3x3* rhs); |
| |
| extern void __attribute__((overloadable)) |
| rsMatrixMultiply(rs_matrix2x2* m, const rs_matrix2x2* rhs); |
| |
| #if !defined(RS_VERSION) || (RS_VERSION <= 13) |
| extern float4 __attribute__((overloadable)) |
| rsMatrixMultiply(rs_matrix4x4* m, float4 in); |
| #endif |
| |
| #if !defined(RS_VERSION) || (RS_VERSION <= 13) |
| extern float4 __attribute__((overloadable)) |
| rsMatrixMultiply(rs_matrix4x4* m, float3 in); |
| #endif |
| |
| #if !defined(RS_VERSION) || (RS_VERSION <= 13) |
| extern float4 __attribute__((overloadable)) |
| rsMatrixMultiply(rs_matrix4x4* m, float2 in); |
| #endif |
| |
| #if !defined(RS_VERSION) || (RS_VERSION <= 13) |
| extern float3 __attribute__((overloadable)) |
| rsMatrixMultiply(rs_matrix3x3* m, float3 in); |
| #endif |
| |
| #if !defined(RS_VERSION) || (RS_VERSION <= 13) |
| extern float3 __attribute__((overloadable)) |
| rsMatrixMultiply(rs_matrix3x3* m, float2 in); |
| #endif |
| |
| #if !defined(RS_VERSION) || (RS_VERSION <= 13) |
| extern float2 __attribute__((overloadable)) |
| rsMatrixMultiply(rs_matrix2x2* m, float2 in); |
| #endif |
| |
| #if (defined(RS_VERSION) && (RS_VERSION >= 14)) |
| extern float4 __attribute__((overloadable)) |
| rsMatrixMultiply(const rs_matrix4x4* m, float4 in); |
| #endif |
| |
| #if (defined(RS_VERSION) && (RS_VERSION >= 14)) |
| extern float4 __attribute__((overloadable)) |
| rsMatrixMultiply(const rs_matrix4x4* m, float3 in); |
| #endif |
| |
| #if (defined(RS_VERSION) && (RS_VERSION >= 14)) |
| extern float4 __attribute__((overloadable)) |
| rsMatrixMultiply(const rs_matrix4x4* m, float2 in); |
| #endif |
| |
| #if (defined(RS_VERSION) && (RS_VERSION >= 14)) |
| extern float3 __attribute__((overloadable)) |
| rsMatrixMultiply(const rs_matrix3x3* m, float3 in); |
| #endif |
| |
| #if (defined(RS_VERSION) && (RS_VERSION >= 14)) |
| extern float3 __attribute__((overloadable)) |
| rsMatrixMultiply(const rs_matrix3x3* m, float2 in); |
| #endif |
| |
| #if (defined(RS_VERSION) && (RS_VERSION >= 14)) |
| extern float2 __attribute__((overloadable)) |
| rsMatrixMultiply(const rs_matrix2x2* m, float2 in); |
| #endif |
| |
| /* |
| * rsMatrixRotate: Apply a rotation to a transformation matrix |
| * |
| * Multiply the matrix m with a rotation matrix. |
| * |
| * This function modifies a transformation matrix to first do a rotation. The axis of |
| * rotation is the (x, y, z) vector. |
| * |
| * To apply this combined transformation to a vector, multiply the vector by the created |
| * matrix using rsMatrixMultiply(). |
| * |
| * Parameters: |
| * m: Matrix to modify. |
| * rot: How much rotation to do, in degrees. |
| * x: X component of the vector that is the axis of rotation. |
| * y: Y component of the vector that is the axis of rotation. |
| * z: Z component of the vector that is the axis of rotation. |
| */ |
| extern void __attribute__((overloadable)) |
| rsMatrixRotate(rs_matrix4x4* m, float rot, float x, float y, float z); |
| |
| /* |
| * rsMatrixScale: Apply a scaling to a transformation matrix |
| * |
| * Multiply the matrix m with a scaling matrix. |
| * |
| * This function modifies a transformation matrix to first do a scaling. When scaling, |
| * each component of a vector is multiplied by a number. This number can be negative. |
| * |
| * To apply this combined transformation to a vector, multiply the vector by the created |
| * matrix using rsMatrixMultiply(). |
| * |
| * Parameters: |
| * m: Matrix to modify. |
| * x: Multiple to scale the x components by. |
| * y: Multiple to scale the y components by. |
| * z: Multiple to scale the z components by. |
| */ |
| extern void __attribute__((overloadable)) |
| rsMatrixScale(rs_matrix4x4* m, float x, float y, float z); |
| |
| /* |
| * rsMatrixSet: Set one element |
| * |
| * Set an element of a matrix. |
| * |
| * Warning: The order of the column and row parameters may be unexpected. |
| * |
| * Parameters: |
| * m: Matrix that will be modified. |
| * col: Zero-based column of the element to be set. |
| * row: Zero-based row of the element to be set. |
| * v: Value to set. |
| */ |
| extern void __attribute__((overloadable)) |
| rsMatrixSet(rs_matrix4x4* m, uint32_t col, uint32_t row, float v); |
| |
| extern void __attribute__((overloadable)) |
| rsMatrixSet(rs_matrix3x3* m, uint32_t col, uint32_t row, float v); |
| |
| extern void __attribute__((overloadable)) |
| rsMatrixSet(rs_matrix2x2* m, uint32_t col, uint32_t row, float v); |
| |
| /* |
| * rsMatrixTranslate: Apply a translation to a transformation matrix |
| * |
| * Multiply the matrix m with a translation matrix. |
| * |
| * This function modifies a transformation matrix to first do a translation. When |
| * translating, a number is added to each component of a vector. |
| * |
| * To apply this combined transformation to a vector, multiply the vector by the |
| * created matrix using rsMatrixMultiply(). |
| * |
| * Parameters: |
| * m: Matrix to modify. |
| * x: Number to add to each x component. |
| * y: Number to add to each y component. |
| * z: Number to add to each z component. |
| */ |
| extern void __attribute__((overloadable)) |
| rsMatrixTranslate(rs_matrix4x4* m, float x, float y, float z); |
| |
| /* |
| * rsMatrixTranspose: Transpose a matrix place |
| * |
| * Transpose the matrix m in place. |
| * |
| * Parameters: |
| * m: Matrix to transpose. |
| */ |
| extern void __attribute__((overloadable)) |
| rsMatrixTranspose(rs_matrix4x4* m); |
| |
| extern void __attribute__((overloadable)) |
| rsMatrixTranspose(rs_matrix3x3* m); |
| |
| extern void __attribute__((overloadable)) |
| rsMatrixTranspose(rs_matrix2x2* m); |
| |
| #endif // RENDERSCRIPT_RS_MATRIX_RSH |