static int node_shader_gpu_tex_environment(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *out)
{
	Image *ima= (Image*)node->id;
	ImageUser *iuser= NULL;
	NodeTexImage *tex = node->storage;
	int isdata = tex->color_space == SHD_COLORSPACE_NONE;
	int ret;

	if (!ima)
		return GPU_stack_link(mat, "node_tex_environment_empty", in, out);

	if (!in[0].link)
		in[0].link = GPU_builtin(GPU_VIEW_POSITION);

	node_shader_gpu_tex_mapping(mat, node, in, out);

	ret = GPU_stack_link(mat, "node_tex_environment", in, out, GPU_image(ima, iuser, isdata));

	if (ret) {
		ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
		if (ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 &&
		    GPU_material_do_color_management(mat))
		{
			GPU_link(mat, "srgb_to_linearrgb", out[0].link, &out[0].link);
		}
		BKE_image_release_ibuf(ima, ibuf, NULL);
	}

	return ret;
}
static int node_shader_gpu_oct_tex_float_image(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) {
	int          ret;
    float        rgb[4];
    int          isdata;
	Image        *ima   = (Image*)node->id;
	ImageUser    *iuser = NULL;
	NodeTexImage *tex   = node->storage;
    if(!tex) {
        node_oct_float_image_tex_init(0, node);
        tex   = node->storage;
    }
	isdata = tex->color_space == SHD_COLORSPACE_NONE;

    in[0].type = GPU_VEC3;
	in[0].link = GPU_attribute(CD_MTFACE, "");
    in[1].type = GPU_NONE;

	if(!ima) return GPU_stack_link(mat, "node_tex_image_empty", in, out, GPU_uniform(rgb));
	
	node_shader_gpu_tex_mapping(mat, node, in, out);

	ret = GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata), GPU_uniform(rgb));
	if(ret) {
		ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
		if (ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 && GPU_material_do_color_management(mat)) {
			GPU_link(mat, "srgb_to_linearrgb", out[0].link, &out[0].link);
		}
		BKE_image_release_ibuf(ima, ibuf, NULL);
	}
	return ret;
}
static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
	Image *ima = (Image *)node->id;
	ImageUser *iuser = NULL;
	NodeTexImage *tex = node->storage;

	GPUNodeLink *norm;

	int isdata = tex->color_space == SHD_COLORSPACE_NONE;
	float blend = tex->projection_blend;

	if (!ima)
		return GPU_stack_link(mat, "node_tex_image_empty", in, out);

	if (!in[0].link)
		in[0].link = GPU_attribute(CD_MTFACE, "");

	node_shader_gpu_tex_mapping(mat, node, in, out);

	switch (tex->projection) {
		case SHD_PROJ_FLAT:
			GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata));
			break;
		case SHD_PROJ_BOX:
			GPU_link(mat, "direction_transform_m4v3", GPU_builtin(GPU_VIEW_NORMAL),
			                                          GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
			                                          &norm);
			GPU_link(mat, "direction_transform_m4v3", norm,
			                                          GPU_builtin(GPU_INVERSE_OBJECT_MATRIX),
			                                          &norm);
			GPU_link(mat, "node_tex_image_box", in[0].link,
			                                    norm,
			                                    GPU_image(ima, iuser, isdata),
			                                    GPU_uniform(&blend),
			                                    &out[0].link,
			                                    &out[1].link);
			break;
		case SHD_PROJ_SPHERE:
			GPU_link(mat, "point_texco_remap_square", in[0].link, &in[0].link);
			GPU_link(mat, "point_map_to_sphere", in[0].link, &in[0].link);
			GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata));
			break;
		case SHD_PROJ_TUBE:
			GPU_link(mat, "point_texco_remap_square", in[0].link, &in[0].link);
			GPU_link(mat, "point_map_to_tube", in[0].link, &in[0].link);
			GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata));
			break;
	}

	ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
	if ((tex->color_space == SHD_COLORSPACE_COLOR) &&
	    ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 &&
	    GPU_material_do_color_management(mat))
	{
		GPU_link(mat, "srgb_to_linearrgb", out[0].link, &out[0].link);
	}
	BKE_image_release_ibuf(ima, ibuf, NULL);

	return true;
}
static int gpu_shader_texture(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
	Tex *tex = (Tex *)node->id;

	if (tex && tex->type == TEX_IMAGE && tex->ima) {
		GPUNodeLink *texlink = GPU_image(tex->ima, &tex->iuser, false);
		int ret = GPU_stack_link(mat, "texture_image", in, out, texlink);

		if (ret) {
			ImBuf *ibuf = BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL);
			if (ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 &&
			    GPU_material_do_color_management(mat))
			{
				GPU_link(mat, "srgb_to_linearrgb", out[1].link, &out[1].link);
			}
			BKE_image_release_ibuf(tex->ima, ibuf, NULL);
		}

		return ret;
	}
	else
		return 0;
}
static int node_shader_gpu_tex_environment(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
	Image *ima = (Image *)node->id;
	ImageUser *iuser = NULL;
	NodeTexImage *tex = node->storage;
	int isdata = tex->color_space == SHD_COLORSPACE_NONE;

	if (!ima)
		return GPU_stack_link(mat, "node_tex_environment_empty", in, out);

	if (!in[0].link) {
		GPUMatType type = GPU_Material_get_type(mat);
		
		if (type == GPU_MATERIAL_TYPE_MESH)
			in[0].link = GPU_builtin(GPU_VIEW_POSITION);
		else
			GPU_link(mat, "background_transform_to_world", GPU_builtin(GPU_VIEW_POSITION), &in[0].link);
	}
	
	node_shader_gpu_tex_mapping(mat, node, in, out);

	if (tex->projection == SHD_PROJ_EQUIRECTANGULAR)
		GPU_stack_link(mat, "node_tex_environment_equirectangular", in, out, GPU_image(ima, iuser, isdata));
	else
		GPU_stack_link(mat, "node_tex_environment_mirror_ball", in, out, GPU_image(ima, iuser, isdata));
		
	ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
	if (ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 &&
	    GPU_material_do_color_management(mat))
	{
		GPU_link(mat, "srgb_to_linearrgb", out[0].link, &out[0].link);
	}
	BKE_image_release_ibuf(ima, ibuf, NULL);

	return true;
}