This example shows how to use a custom implementation of the state module. It enables you to adapt the generated code to your renderer, thus avoiding costly copies of your renderer state to the MDL SDK API state.
In case of errors reported by the MDL SDK code generator, it may be useful to look at the LLVM IR code of your module. You can create an LLVM IR assembly text file "state.ll"
with this command line:
#include "mdl_user_modules.h"
struct User_state_environment {
float3 direction;
};
struct User_state_material
{
float3 normal;
float3 geom_normal;
float3 position;
float animation_time;
const float3 *text_coords;
const float3 *tangent_u;
const float3 *tangent_v;
const float4 *text_results;
const char *ro_data_segment;
const float4 *world_to_object;
const float4 *object_to_world;
int object_id;
};
static vfloat4x4 make_matrix_rm2cm(float4 const *v)
{
return vfloat4x4{
v[0].x, v[1].x, v[2].x, 0,
v[0].y, v[1].y, v[2].y, 0,
v[0].z, v[1].z, v[2].z, 0,
v[0].w, v[1].w, v[2].w, 1
};
}
namespace state {
vfloat3 direction(State_environment const *state_context)
{
User_state_environment const *state =
reinterpret_cast<User_state_environment const *>(state_context);
return make_vector(state->direction);
}
vfloat3 position(State_core const *state_context)
{
User_state_material const *state = reinterpret_cast<User_state_material const *>(state_context);
return make_vector(state->position);
}
vfloat3 normal(State_core const *state_context)
{
User_state_material const *state = reinterpret_cast<User_state_material const *>(state_context);
return make_vector(state->normal);
}
void set_normal(State_core *state_context, vfloat3 new_normal)
{
User_state_material *state = reinterpret_cast<User_state_material *>(state_context);
state->normal.x = new_normal.x;
state->normal.y = new_normal.y;
state->normal.z = new_normal.z;
}
vfloat3 geometry_normal(State_core const *state_context)
{
User_state_material const *state = reinterpret_cast<User_state_material const *>(state_context);
return make_vector(state->geom_normal);
}
vfloat3 motion(State_core const *state_context)
{
return vfloat3{ 0, 0, 0 };
}
vfloat3 texture_coordinate(
State_core const *state_context,
Exception_state const *exc_state,
int index)
{
User_state_material const *state = reinterpret_cast<User_state_material const *>(state_context);
return make_vector(state->text_coords[index]);
}
vfloat3 texture_tangent_u(
State_core const *state_context,
Exception_state const *exc_state,
int index)
{
User_state_material const *state = reinterpret_cast<User_state_material const *>(state_context);
return make_vector(state->tangent_u[index]);
}
vfloat3 texture_tangent_v(
State_core const *state_context,
Exception_state const *exc_state,
int index)
{
User_state_material const *state = reinterpret_cast<User_state_material const *>(state_context);
return make_vector(state->tangent_v[index]);
}
vfloat3x3 tangent_space(
State_core const *state_context,
Exception_state const *exc_state,
int index)
{
return vfloat3x3(0);
}
vfloat3 geometry_tangent_u(
State_core const *state_context,
Exception_state const *exc_state,
int index)
{
return vfloat3{ 0, 0, 0 };
}
vfloat3 geometry_tangent_v(
State_core const *state_context,
Exception_state const *exc_state,
int index)
{
return vfloat3{ 0, 0, 0 };
}
float animation_time(State_core const *state_context)
{
User_state_material const *state = reinterpret_cast<User_state_material const *>(state_context);
return state->animation_time;
}
float *wavelength_base(State_core const *state_context)
{
return nullptr;
}
vfloat4x4
transform(State_core
const *state_context, coordinate_space from, coordinate_space to)
{
if (from == coordinate_internal) from = INTERNAL_SPACE;
if (to == coordinate_internal) to = INTERNAL_SPACE;
if (from == to) {
return vfloat4x4{
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
};
}
User_state_material const *state = reinterpret_cast<User_state_material const *>(state_context);
float4 const *transform_matrix =
(from == coordinate_world) ? state->world_to_object : state->object_to_world;
return make_matrix_rm2cm(transform_matrix);
}
State_core const *state_context,
coordinate_space from,
coordinate_space to,
vfloat3 point)
{
if (from == coordinate_internal) from = INTERNAL_SPACE;
if (to == coordinate_internal) to = INTERNAL_SPACE;
if (from == to) return point;
User_state_material const *state = reinterpret_cast<User_state_material const *>(state_context);
float4 const *mat =
(from == coordinate_world) ? state->world_to_object : state->object_to_world;
return vfloat3{
point.x * mat[0].x + point.y * mat[0].y + point.z * mat[0].z + mat[0].w,
point.x * mat[1].x + point.y * mat[1].y + point.z * mat[1].z + mat[1].w,
point.x * mat[2].x + point.y * mat[2].y + point.z * mat[2].z + mat[2].w
};
}
State_core const *state_context,
coordinate_space from,
coordinate_space to,
vfloat3 vector)
{
if (from == coordinate_internal) from = INTERNAL_SPACE;
if (to == coordinate_internal) to = INTERNAL_SPACE;
if (from == to) return vector;
User_state_material const *state = reinterpret_cast<User_state_material const *>(state_context);
float4 const *mat =
(from == coordinate_world) ? state->world_to_object : state->object_to_world;
return vfloat3{
vector.x * mat[0].x + vector.y * mat[0].y + vector.z * mat[0].z,
vector.x * mat[1].x + vector.y * mat[1].y + vector.z * mat[1].z,
vector.x * mat[2].x + vector.y * mat[2].y + vector.z * mat[2].z
};
}
State_core const *state_context,
coordinate_space from,
coordinate_space to,
vfloat3 normal)
{
if (from == coordinate_internal) from = INTERNAL_SPACE;
if (to == coordinate_internal) to = INTERNAL_SPACE;
if (from == to) return normal;
User_state_material const *state = reinterpret_cast<User_state_material const *>(state_context);
float4 const *inv_mat =
(from == coordinate_world) ? state->object_to_world : state->world_to_object;
return vfloat3{
normal.x * inv_mat[0].x + normal.y * inv_mat[1].x + normal.z * inv_mat[2].x,
normal.x * inv_mat[0].y + normal.y * inv_mat[1].y + normal.z * inv_mat[2].y,
normal.x * inv_mat[0].z + normal.y * inv_mat[1].z + normal.z * inv_mat[2].z
};
}
float transform_scale(
State_core const *state_context,
coordinate_space from,
coordinate_space to,
float scale)
{
if (from == coordinate_internal) from = INTERNAL_SPACE;
if (to == coordinate_internal) to = INTERNAL_SPACE;
if (from == to) return scale;
User_state_material const *state = reinterpret_cast<User_state_material const *>(state_context);
float4 const *mat =
(from == coordinate_world) ? state->world_to_object : state->object_to_world;
float t_0 =
math::length(make_vector(*reinterpret_cast<const float3 *>(&mat[0])));
float t_1 =
math::length(make_vector(*reinterpret_cast<const float3 *>(&mat[1])));
float t_2 =
math::length(make_vector(*reinterpret_cast<const float3 *>(&mat[2])));
return scale * ((t_0 + t_1 + t_2) / 3.0f);
}
int object_id(State_core const *state_context)
{
User_state_material const *state = reinterpret_cast<User_state_material const *>(state_context);
return state->object_id;
}
float4 *get_texture_results(State_core *state_context)
{
User_state_material *state = reinterpret_cast<User_state_material *>(state_context);
return const_cast<float4 *>(state->text_results);
}
const char *get_ro_data_segment(State_core const *state_context)
{
User_state_material const *state = reinterpret_cast<User_state_material const *>(state_context);
return state->ro_data_segment;
}
}
#ifndef MDL_USER_MODULES_H
#define MDL_USER_MODULES_H
#include <vector_types.h>
struct __align__(2) bool2
{
bool x, y;
};
struct bool3
{
bool x, y, z;
};
struct __align__(4) bool4
{
bool x, y, z, w;
};
typedef char const *string;
typedef bool vbool2 __attribute((ext_vector_type(2)));
typedef bool vbool3 __attribute((ext_vector_type(3)));
typedef bool vbool4 __attribute((ext_vector_type(4)));
typedef int vint2 __attribute((ext_vector_type(2)));
typedef int vint3 __attribute((ext_vector_type(3)));
typedef int vint4 __attribute((ext_vector_type(4)));
typedef float vfloat2 __attribute((ext_vector_type(2)));
typedef float vfloat3 __attribute((ext_vector_type(3)));
typedef float vfloat4 __attribute((ext_vector_type(4)));
typedef float vfloat3x3 __attribute((ext_vector_type(9)));
typedef float vfloat4x4 __attribute((ext_vector_type(16)));
typedef double vdouble2 __attribute((ext_vector_type(2)));
typedef double vdouble3 __attribute((ext_vector_type(3)));
typedef double vdouble4 __attribute((ext_vector_type(4)));
typedef double vdouble3x3 __attribute((ext_vector_type(9)));
typedef double vdouble4x4 __attribute((ext_vector_type(16)));
#include "mdl_runtime.h"
struct State_core;
struct State_environment;
struct Exception_state;
static vbool2 make_vector(bool2 const &v)
{
return vbool2{ v.x, v.y };
}
static vbool3 make_vector(bool3 const &v)
{
return vbool3{ v.x, v.y, v.z };
}
static vbool4 make_vector(bool4 const &v)
{
return vbool4{ v.x, v.y, v.z, v.w };
}
static vint2 make_vector(int2 const &v)
{
return vint2{ v.x, v.y };
}
static vint3 make_vector(int3 const &v)
{
return vint3{ v.x, v.y, v.z };
}
static vint4 make_vector(int4 const &v)
{
return vint4{ v.x, v.y, v.z, v.w };
}
static vfloat2 make_vector(float2 const &v)
{
return vfloat2{ v.x, v.y };
}
static vfloat3 make_vector(float3 const &v)
{
return vfloat3{ v.x, v.y, v.z };
}
static vfloat4 make_vector(float4 const &v)
{
return vfloat4{ v.x, v.y, v.z, v.w };
}
static vdouble2 make_vector(double2 const &v)
{
return vdouble2{ v.x, v.y };
}
static vdouble3 make_vector(double3 const &v)
{
return vdouble3{ v.x, v.y, v.z };
}
static vdouble4 make_vector(double4 const &v)
{
return vdouble4{ v.x, v.y, v.z, v.w };
}
namespace state {
enum coordinate_space {
coordinate_internal,
coordinate_object,
coordinate_world
};
}
extern state::coordinate_space INTERNAL_SPACE;
#endif // MDL_USER_MODULES_H
#ifndef MDL_USER_MODULES_MDL_RUNTIME_H
#define MDL_USER_MODULES_MDL_RUNTIME_H
namespace math
{
vdouble2
abs(vdouble2 a);
vdouble3
abs(vdouble3 a);
vdouble4
abs(vdouble4 a);
vdouble2
acos(vdouble2 a);
vdouble3
acos(vdouble3 a);
vdouble4
acos(vdouble4 a);
vdouble2
asin(vdouble2 a);
vdouble3
asin(vdouble3 a);
vdouble4
asin(vdouble4 a);
vdouble2
atan(vdouble2 a);
vdouble3
atan(vdouble3 a);
vdouble4
atan(vdouble4 a);
float atan2(
float y,
float x);
vfloat2
atan2(vfloat2 y, vfloat2 x);
vfloat3
atan2(vfloat3 y, vfloat3 x);
vfloat4
atan2(vfloat4 y, vfloat4 x);
double atan2(
double y,
double x);
vdouble2
atan2(vdouble2 y, vdouble2 x);
vdouble3
atan2(vdouble3 y, vdouble3 x);
vdouble4
atan2(vdouble4 y, vdouble4 x);
float average(float a);
float average(vfloat2 a);
float average(vfloat3 a);
float average(vfloat4 a);
double average(double a);
double average(vdouble2 a);
double average(vdouble3 a);
double average(vdouble4 a);
vdouble2
ceil(vdouble2 a);
vdouble3
ceil(vdouble3 a);
vdouble4
ceil(vdouble4 a);
int clamp(
int a,
int min,
int max);
vint2
clamp(vint2 a, vint2 min, vint2 max);
vint3
clamp(vint3 a, vint3 min, vint3 max);
vint4
clamp(vint4 a, vint4 min, vint4 max);
float clamp(
float a,
float min,
float max);
vfloat2
clamp(vfloat2 a, vfloat2 min, vfloat2 max);
vfloat3
clamp(vfloat3 a, vfloat3 min, vfloat3 max);
vfloat4
clamp(vfloat4 a, vfloat4 min, vfloat4 max);
double clamp(
double a,
double min,
double max);
vdouble2
clamp(vdouble2 a, vdouble2 min, vdouble2 max);
vdouble3
clamp(vdouble3 a, vdouble3 min, vdouble3 max);
vdouble4
clamp(vdouble4 a, vdouble4 min, vdouble4 max);
vint2
clamp(vint2 a, vint2 min,
int max);
vint2
clamp(vint2 a,
int min, vint2 max);
vint2
clamp(vint2 a,
int min,
int max);
vint3
clamp(vint3 a, vint3 min,
int max);
vint3
clamp(vint3 a,
int min, vint3 max);
vint3
clamp(vint3 a,
int min,
int max);
vint4
clamp(vint4 a, vint4 min,
int max);
vint4
clamp(vint4 a,
int min, vint4 max);
vint4
clamp(vint4 a,
int min,
int max);
vfloat2
clamp(vfloat2 a, vfloat2 min,
float max);
vfloat2
clamp(vfloat2 a,
float min, vfloat2 max);
vfloat2
clamp(vfloat2 a,
float min,
float max);
vfloat3
clamp(vfloat3 a, vfloat3 min,
float max);
vfloat3
clamp(vfloat3 a,
float min, vfloat3 max);
vfloat3
clamp(vfloat3 a,
float min,
float max);
vfloat4
clamp(vfloat4 a, vfloat4 min,
float max);
vfloat4
clamp(vfloat4 a,
float min, vfloat4 max);
vfloat4
clamp(vfloat4 a,
float min,
float max);
vdouble2
clamp(vdouble2 a, vdouble2 min,
double max);
vdouble2
clamp(vdouble2 a,
double min, vdouble2 max);
vdouble2
clamp(vdouble2 a,
double min,
double max);
vdouble3
clamp(vdouble3 a, vdouble3 min,
double max);
vdouble3
clamp(vdouble3 a,
double min, vdouble3 max);
vdouble3
clamp(vdouble3 a,
double min,
double max);
vdouble4
clamp(vdouble4 a, vdouble4 min,
double max);
vdouble4
clamp(vdouble4 a,
double min, vdouble4 max);
vdouble4
clamp(vdouble4 a,
double min,
double max);
vdouble2
cos(vdouble2 a);
vdouble3
cos(vdouble3 a);
vdouble4
cos(vdouble4 a);
vfloat3
cross(vfloat3 a, vfloat3 b);
vdouble3
cross(vdouble3 a, vdouble3 b);
double distance(vdouble2 a, vdouble2 b);
double distance(vdouble3 a, vdouble3 b);
double distance(vdouble4 a, vdouble4 b);
float dot(
float a,
float b);
float dot(vfloat2 a, vfloat2 b);
float dot(vfloat3 a, vfloat3 b);
float dot(vfloat4 a, vfloat4 b);
double dot(
double a,
double b);
double dot(vdouble2 a, vdouble2 b);
double dot(vdouble3 a, vdouble3 b);
double dot(vdouble4 a, vdouble4 b);
vdouble2
exp(vdouble2 a);
vdouble3
exp(vdouble3 a);
vdouble4
exp(vdouble4 a);
vdouble2
exp2(vdouble2 a);
vdouble3
exp2(vdouble3 a);
vdouble4
exp2(vdouble4 a);
vfloat2
floor(vfloat2 a);
vfloat3
floor(vfloat3 a);
vfloat4
floor(vfloat4 a);
vdouble2
floor(vdouble2 a);
vdouble3
floor(vdouble3 a);
vdouble4
floor(vdouble4 a);
float fmod(
float a,
float b);
vfloat2
fmod(vfloat2 a, vfloat2 b);
vfloat3
fmod(vfloat3 a, vfloat3 b);
vfloat4
fmod(vfloat4 a, vfloat4 b);
double fmod(
double a,
double b);
vdouble2
fmod(vdouble2 a, vdouble2 b);
vdouble3
fmod(vdouble3 a, vdouble3 b);
vdouble4
fmod(vdouble4 a, vdouble4 b);
vfloat2
fmod(vfloat2 a,
float b);
vfloat3
fmod(vfloat3 a,
float b);
vfloat4
fmod(vfloat4 a,
float b);
vdouble2
fmod(vdouble2 a,
double b);
vdouble3
fmod(vdouble3 a,
double b);
vdouble4
fmod(vdouble4 a,
double b);
vdouble2
frac(vdouble2 a);
vdouble3
frac(vdouble3 a);
vdouble4
frac(vdouble4 a);
vbool2
isnan(vdouble2 a);
vbool3
isnan(vdouble3 a);
vbool4
isnan(vdouble4 a);
float lerp(
float a,
float b,
float l);
vfloat2
lerp(vfloat2 a, vfloat2 b, vfloat2 l);
vfloat3
lerp(vfloat3 a, vfloat3 b, vfloat3 l);
vfloat4
lerp(vfloat4 a, vfloat4 b, vfloat4 l);
double lerp(
double a,
double b,
double l);
vdouble2
lerp(vdouble2 a, vdouble2 b, vdouble2 l);
vdouble3
lerp(vdouble3 a, vdouble3 b, vdouble3 l);
vdouble4
lerp(vdouble4 a, vdouble4 b, vdouble4 l);
vfloat2
lerp(vfloat2 a, vfloat2 b,
float l);
vfloat3
lerp(vfloat3 a, vfloat3 b,
float l);
vfloat4
lerp(vfloat4 a, vfloat4 b,
float l);
vdouble2
lerp(vdouble2 a, vdouble2 b,
double l);
vdouble3
lerp(vdouble3 a, vdouble3 b,
double l);
vdouble4
lerp(vdouble4 a, vdouble4 b,
double l);
vdouble2
log(vdouble2 a);
vdouble3
log(vdouble3 a);
vdouble4
log(vdouble4 a);
vdouble2
log2(vdouble2 a);
vdouble3
log2(vdouble3 a);
vdouble4
log2(vdouble4 a);
vfloat2
log10(vfloat2 a);
vfloat3
log10(vfloat3 a);
vfloat4
log10(vfloat4 a);
vdouble2
log10(vdouble2 a);
vdouble3
log10(vdouble3 a);
vdouble4
log10(vdouble4 a);
float luminance(vfloat3 a);
vint2
max(vint2 a, vint2 b);
vint3
max(vint3 a, vint3 b);
vint4
max(vint4 a, vint4 b);
float max(
float a,
float b);
vfloat2
max(vfloat2 a, vfloat2 b);
vfloat3
max(vfloat3 a, vfloat3 b);
vfloat4
max(vfloat4 a, vfloat4 b);
double max(
double a,
double b);
vdouble2
max(vdouble2 a, vdouble2 b);
vdouble3
max(vdouble3 a, vdouble3 b);
vdouble4
max(vdouble4 a, vdouble4 b);
float max_value(float a);
float max_value(vfloat2 a);
float max_value(vfloat3 a);
float max_value(vfloat4 a);
double max_value(double a);
double max_value(vdouble2 a);
double max_value(vdouble3 a);
double max_value(vdouble4 a);
vint2
min(vint2 a, vint2 b);
vint3
min(vint3 a, vint3 b);
vint4
min(vint4 a, vint4 b);
float min(
float a,
float b);
vfloat2
min(vfloat2 a, vfloat2 b);
vfloat3
min(vfloat3 a, vfloat3 b);
vfloat4
min(vfloat4 a, vfloat4 b);
double min(
double a,
double b);
vdouble2
min(vdouble2 a, vdouble2 b);
vdouble3
min(vdouble3 a, vdouble3 b);
vdouble4
min(vdouble4 a, vdouble4 b);
float min_value(float a);
float min_value(vfloat2 a);
float min_value(vfloat3 a);
float min_value(vfloat4 a);
double min_value(double a);
double min_value(vdouble2 a);
double min_value(vdouble3 a);
double min_value(vdouble4 a);
float normalize(float a);
vfloat2 normalize(vfloat2 a);
vfloat3 normalize(vfloat3 a);
vfloat4 normalize(vfloat4 a);
double normalize(double a);
vdouble2 normalize(vdouble2 a);
vdouble3 normalize(vdouble3 a);
vdouble4 normalize(vdouble4 a);
vint2
pow(vint2 a, vint2 b);
vint3
pow(vint3 a, vint3 b);
vint4
pow(vint4 a, vint4 b);
float pow(
float a,
float b);
vfloat2
pow(vfloat2 a, vfloat2 b);
vfloat3
pow(vfloat3 a, vfloat3 b);
vfloat4
pow(vfloat4 a, vfloat4 b);
double pow(
double a,
double b);
vdouble2
pow(vdouble2 a, vdouble2 b);
vdouble3
pow(vdouble3 a, vdouble3 b);
vdouble4
pow(vdouble4 a, vdouble4 b);
vint2
pow(vint2 a,
int b);
vint3
pow(vint3 a,
int b);
vint4
pow(vint4 a,
int b);
vfloat2
pow(vfloat2 a,
float b);
vfloat3
pow(vfloat3 a,
float b);
vfloat4
pow(vfloat4 a,
float b);
vdouble2
pow(vdouble2 a,
double b);
vdouble3
pow(vdouble3 a,
double b);
vdouble4
pow(vdouble4 a,
double b);
vfloat2
round(vfloat2 a);
vfloat3
round(vfloat3 a);
vfloat4
round(vfloat4 a);
vdouble2
round(vdouble2 a);
vdouble3
round(vdouble3 a);
vdouble4
round(vdouble4 a);
vfloat2
rsqrt(vfloat2 a);
vfloat3
rsqrt(vfloat3 a);
vfloat4
rsqrt(vfloat4 a);
vdouble2
rsqrt(vdouble2 a);
vdouble3
rsqrt(vdouble3 a);
vdouble4
rsqrt(vdouble4 a);
vdouble2
sign(vdouble2 a);
vdouble3
sign(vdouble3 a);
vdouble4
sign(vdouble4 a);
vdouble2
sin(vdouble2 a);
vdouble3
sin(vdouble3 a);
vdouble4
sin(vdouble4 a);
vfloat2
smoothstep(vfloat2 a, vfloat2 b, vfloat2 l);
vfloat3
smoothstep(vfloat3 a, vfloat3 b, vfloat3 l);
vfloat4
smoothstep(vfloat4 a, vfloat4 b, vfloat4 l);
vdouble2
smoothstep(vdouble2 a, vdouble2 b, vdouble2 l);
vdouble3
smoothstep(vdouble3 a, vdouble3 b, vdouble3 l);
vdouble4
smoothstep(vdouble4 a, vdouble4 b, vdouble4 l);
vfloat2
smoothstep(vfloat2 a, vfloat2 b,
float l);
vfloat3
smoothstep(vfloat3 a, vfloat3 b,
float l);
vfloat4
smoothstep(vfloat4 a, vfloat4 b,
float l);
vdouble2
smoothstep(vdouble2 a, vdouble2 b,
double l);
vdouble3
smoothstep(vdouble3 a, vdouble3 b,
double l);
vdouble4
smoothstep(vdouble4 a, vdouble4 b,
double l);
vdouble2
sqrt(vdouble2 a);
vdouble3
sqrt(vdouble3 a);
vdouble4
sqrt(vdouble4 a);
float step(
float a,
float b);
vfloat2
step(vfloat2 a, vfloat2 b);
vfloat3
step(vfloat3 a, vfloat3 b);
vfloat4
step(vfloat4 a, vfloat4 b);
double step(
double a,
double b);
vdouble2
step(vdouble2 a, vdouble2 b);
vdouble3
step(vdouble3 a, vdouble3 b);
vdouble4
step(vdouble4 a, vdouble4 b);
vdouble2
tan(vdouble2 a);
vdouble3
tan(vdouble3 a);
vdouble4
tan(vdouble4 a);
}
{
bool breakpoint();
bool assert(bool condition, string reason, string funcname = "", string filename = "",
int line = 0);
bool print(bool v);
bool print(vbool2 v);
bool print(vbool3 v);
bool print(vbool4 v);
bool print(int v);
bool print(vint2 v);
bool print(vint3 v);
bool print(vint4 v);
bool print(float v);
bool print(vfloat2 v);
bool print(vfloat3 v);
bool print(vfloat4 v);
bool print(double v);
bool print(vdouble2 v);
bool print(vdouble3 v);
bool print(vdouble4 v);
bool print(string v);
}
#endif // MDL_USER_MODULES_MDL_RUNTIME_H