text:
#include "la_includes.h"

#include "st_matrix_operations.h"
#include "la_geometry_undo.h"
#include "la_projection.h"
#include "la_draw_overlay.h"
#include "la_tool.h"
#include "la_particle_fx.h"

#define PI  3.141592653

#define ROTATE_GRID_SPLITS  32
#define ROTATE_GRID_DEGREES  36

typedef enum{
	TMM_IDLE,
	TMM_PLACE,
	TMM_TRANSFORM,
	TMM_ROTATE,
	TMM_SCALE,
	TMM_NORMAL,
	TMM_TANGENT,
	TMM_SMOOTH
}TManipMode;

struct{
	float		*manipulator_array;
	float		*manipulator_normal;
	float		*manipulator_color;
	float		*manipulator_circle;
	float		*manipulator_grid;
	float		*manipulator_normal_array;
	uint		manipulator_normal_array_length;
	float		*manipulator_rings;
	float		*manipulator_rings_normals;
	float		*manipulator_rings_color;
	float		*manipulator_rings_shadow;
	double		manipulator_pos[3];
	double		manipulator_start[3];
	double		manipulator_size;
	double		manipulator_scale[3];
	double		manipulator_rotate_scale;
	TManipMode	mode;
	double		grab_pos;
	double		grab_manip_pos;
	uint		grab_axis;
	double		*data;
	double		*normal;
	uint		data_length;
	double		*tags;
	uint		tag_length;
	boolean		hide;
	double		min_scale[3];
	double		max_scale[3];
	uint		update_rotate;
}GlobalTransformManipulator;

void la_t_tm_init(void)
{
	uint i, j, k;
	float square[8];
	GlobalTransformManipulator.manipulator_normal_array = NULL;
	GlobalTransformManipulator.manipulator_normal_array_length = 0;
	GlobalTransformManipulator.manipulator_circle = malloc((sizeof *GlobalTransformManipulator.manipulator_circle) * (ROTATE_GRID_DEGREES * 6 + 24) * 3);
	GlobalTransformManipulator.manipulator_grid = malloc((sizeof *GlobalTransformManipulator.manipulator_grid) * (ROTATE_GRID_DEGREES * 4 + ROTATE_GRID_SPLITS * 4) * 3);
	k = 0;
	for(i = 0; i < ROTATE_GRID_DEGREES; i++)
	{
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_grid, k++, 0.96 * sin(2 * PI * (float)i / ROTATE_GRID_DEGREES + 0.01), 0.96 * cos(2 * PI * (float)i / ROTATE_GRID_DEGREES + 0.01), -0.002);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_grid, k++, 0.99 * sin(2 * PI * (float)i / ROTATE_GRID_DEGREES + 0.006), 0.99 * cos(2 * PI * (float)i / ROTATE_GRID_DEGREES + 0.006), -0.018);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_grid, k++, 0.99 * sin(2 * PI * (float)i / ROTATE_GRID_DEGREES - 0.006), 0.99 * cos(2 * PI * (float)i / ROTATE_GRID_DEGREES - 0.006), -0.018);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_grid, k++, 0.96 * sin(2 * PI * (float)i / ROTATE_GRID_DEGREES - 0.01), 0.96 * cos(2 * PI * (float)i / ROTATE_GRID_DEGREES - 0.01), -0.002);

		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_circle, i * 6 + 0, 1 * sin(2 * PI * (float)i / ROTATE_GRID_DEGREES), 1 * cos(2 * PI * (float)i / ROTATE_GRID_DEGREES), -0.01);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_circle, i * 6 + 1, 1 * sin(2 * PI * (float)(i + 1) / ROTATE_GRID_DEGREES), 1 * cos(2 * PI * (float)(i + 1) / ROTATE_GRID_DEGREES), -0.01);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_circle, i * 6 + 2, 0.95 * sin(2 * PI * (float)i / ROTATE_GRID_DEGREES), 0.95 * cos(2 * PI * (float)i / ROTATE_GRID_DEGREES), -0.0);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_circle, i * 6 + 3, 0.95 * sin(2 * PI * (float)(i + 1) / ROTATE_GRID_DEGREES), 0.95 * cos(2 * PI * (float)(i + 1) / ROTATE_GRID_DEGREES), -0.0);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_circle, i * 6 + 4, 0.9 * sin(2 * PI * (float)i / ROTATE_GRID_DEGREES), 0.9 * cos(2 * PI * (float)i / ROTATE_GRID_DEGREES), -0.015);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_circle, i * 6 + 5, 0.9 * sin(2 * PI * (float)(i + 1) / ROTATE_GRID_DEGREES), 0.9 * cos(2 * PI * (float)(i + 1) / ROTATE_GRID_DEGREES), -0.015);
	}

	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_circle, i * 6 + 0, 0, 0, 1);
	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_circle, i * 6 + 1, 0, 0, 0.01);
	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_circle, i * 6 + 2, 0, 0, -0.01);
	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_circle, i * 6 + 3, 0, 0, -1);

	for(i = 0; i < ROTATE_GRID_SPLITS; i++)
	{
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_grid, k++, 0.94 * sin(2 * PI * (float)i / ROTATE_GRID_SPLITS + 0.02), 0.94 * cos(2 * PI * (float)i / ROTATE_GRID_SPLITS + 0.02), -0.002);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_grid, k++, 0.94 * sin(2 * PI * (float)i / ROTATE_GRID_SPLITS - 0.02), 0.94 * cos(2 * PI * (float)i / ROTATE_GRID_SPLITS - 0.02), -0.002);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_grid, k++, 0.91 * sin(2 * PI * (float)i / ROTATE_GRID_SPLITS - 0.01), 0.91 * cos(2 * PI * (float)i / ROTATE_GRID_SPLITS - 0.01), -0.028);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_grid, k++, 0.91 * sin(2 * PI * (float)i / ROTATE_GRID_SPLITS + 0.01), 0.91 * cos(2 * PI * (float)i / ROTATE_GRID_SPLITS + 0.01), -0.028);
	}
	k = 0;
	GlobalTransformManipulator.manipulator_array = malloc((sizeof *GlobalTransformManipulator.manipulator_array) * (12 + 24 * 6) * 3);
	GlobalTransformManipulator.manipulator_normal = malloc((sizeof *GlobalTransformManipulator.manipulator_normal) * (12 + 24 * 6) * 3);

	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_normal, k, 0, 1, 1);
	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_array, k++, 0.3, 0, 0.01);
	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_normal, k, 0, 1, 1);
	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_array, k++, 0.1, 0, 0.014);
	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_normal, k, 0, 1, 1);
	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_array, k++, 0.1, 0.014, 0);
	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_normal, k, 0, 1, 1);
	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_array, k++, 0.3, 0.01, 0);

	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_normal, k, 1, 0, 1);
	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_array, k++, 0, 0.1, 0.014);
	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_normal, k, 1, 0, 1);
	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_array, k++, 0, 0.3, 0.01);
	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_normal, k, 1, 0, 1);
	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_array, k++, 0.01, 0.3, 0);
	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_normal, k, 1, 0, 1);
	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_array, k++, 0.014, 0.1, 0);

	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_normal, k, 1, 12, 0);
	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_array, k++, 0.014, 0, 0.1);
	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_normal, k, 1, 1, 0);
	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_array, k++, 0.01, 0, 0.3);
	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_normal, k, 1, 1, 0);
	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_array, k++, 0, 0.01, 0.3);
	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_normal, k, 1, 1, 0);
	sui_draw_set_vec3(GlobalTransformManipulator.manipulator_array, k++, 0, 0.014, 0.1);

	for(i = 1; i < 13; i++)
	{
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_normal, k, 1, 0, 0);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_array, k++, 0, 0.3 * sin(0.5 * PI * (float)i / 14), 0.3 * cos(0.5 * PI * (float)i / 14));
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_normal, k, 1, 0, 0);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_array, k++, 0, 0.3 * sin(0.5 * PI * (float)(i + 1) / 14), 0.3 * cos(0.5 * PI * (float)(i + 1) / 14));
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_normal, k, 1, 0, 0);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_array, k++, 0, 0.29 * sin(0.5 * PI * (float)(i + 1) / 14), 0.29 * cos(0.5 * PI * (float)(i + 1) / 14));
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_normal, k, 1, 0, 0);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_array, k++, 0, 0.29 * sin(0.5 * PI * (float)i / 14), 0.29 * cos(0.5 * PI * (float)i / 14));

		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_normal, k, 0, 1, 0);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_array, k++, 0.3 * sin(0.5 * PI * (float)i / 14), 0, 0.3 * cos(0.5 * PI * (float)i / 14));
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_normal, k, 0, 1, 0);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_array, k++, 0.3 * sin(0.5 * PI * (float)(i + 1) / 14), 0, 0.3 * cos(0.5 * PI * (float)(i + 1) / 14));
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_normal, k, 0, 1, 0);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_array, k++, 0.29 * sin(0.5 * PI * (float)(i + 1) / 14), 0, 0.29 * cos(0.5 * PI * (float)(i + 1) / 14));
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_normal, k, 0, 1, 0);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_array, k++, 0.29 * sin(0.5 * PI * (float)i / 14), 0, 0.29 * cos(0.5 * PI * (float)i / 14));

		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_normal, k, 0, 0, 1);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_array, k++, 0.3 * sin(0.5 * PI * (float)i / 14), 0.3 * cos(0.5 * PI * (float)i / 14), 0);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_normal, k, 0, 0, 1);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_array, k++, 0.3 * sin(0.5 * PI * (float)(i + 1) / 14), 0.3 * cos(0.5 * PI * (float)(i + 1) / 14), 0);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_normal, k, 0, 0, 1);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_array, k++, 0.29 * sin(0.5 * PI * (float)(i + 1) / 14), 0.29 * cos(0.5 * PI * (float)(i + 1) / 14), 0);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_normal, k, 0, 0, 1);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_array, k++, 0.29 * sin(0.5 * PI * (float)i / 14), 0.29 * cos(0.5 * PI * (float)i / 14), 0);
	}

	GlobalTransformManipulator.manipulator_rings = malloc((sizeof *GlobalTransformManipulator.manipulator_array) * 4 * (ROTATE_GRID_DEGREES + 6) * 2);
	GlobalTransformManipulator.manipulator_rings_normals =  malloc((sizeof *GlobalTransformManipulator.manipulator_array) * 4 * (ROTATE_GRID_DEGREES + 6) * 3);
	GlobalTransformManipulator.manipulator_rings_shadow = malloc((sizeof *GlobalTransformManipulator.manipulator_array) *  16 * (ROTATE_GRID_DEGREES + 6) * 2);
	GlobalTransformManipulator.manipulator_rings_color = malloc((sizeof *GlobalTransformManipulator.manipulator_array) * 16 * (ROTATE_GRID_DEGREES + 6) * 4);
	for(i = 0; i < ROTATE_GRID_DEGREES; i++)
	{
		square[0] =  0.35 * sin(2 * PI * (float)i / ROTATE_GRID_DEGREES);
		square[1] = 0.35 * cos(2 * PI * (float)i / ROTATE_GRID_DEGREES);
		square[2] = 0.33 * sin(2 * PI * (float)i / ROTATE_GRID_DEGREES);
		square[3] = 0.33 * cos(2 * PI * (float)i / ROTATE_GRID_DEGREES);
		square[4] = 0.33 * sin(2 * PI * ((float)i + 0.5) / ROTATE_GRID_DEGREES);
		square[5] = 0.33 * cos(2 * PI * ((float)i + 0.5) / ROTATE_GRID_DEGREES);
		square[6] = 0.35 * sin(2 * PI * ((float)i + 0.5) / ROTATE_GRID_DEGREES);
		square[7] = 0.35 * cos(2 * PI * ((float)i + 0.5) / ROTATE_GRID_DEGREES);

		sui_draw_set_vec2(GlobalTransformManipulator.manipulator_rings, i * 4 + 0, square[0], square[1]);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_rings_normals, i * 4 + 0, square[0], square[1], -5);
		sui_draw_set_vec2(GlobalTransformManipulator.manipulator_rings, i * 4 + 1, square[2], square[3]);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_rings_normals, i * 4 + 1, square[2], square[3], -5);
		sui_draw_set_vec2(GlobalTransformManipulator.manipulator_rings, i * 4 + 2, square[4], square[5]);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_rings_normals, i * 4 + 2, square[4], square[5], -5);
		sui_draw_set_vec2(GlobalTransformManipulator.manipulator_rings, i * 4 + 3, square[6], square[7]);
		sui_draw_set_vec3(GlobalTransformManipulator.manipulator_rings_normals, i * 4 + 3, square[6], square[7], -5);
		sui_create_shadow_edge(-0.02, 4, &GlobalTransformManipulator.manipulator_rings_shadow[16 * i * 2], &GlobalTransformManipulator.manipulator_rings_color[16 * i * 4], square);
	}

	for(; i < ROTATE_GRID_DEGREES + 6; i++)
	{
		for(j = 0; j < 2; j++)
		{
			square[0] = -0.4 * cos(2 * PI * ((float)i - 2.4 + (float)j * 0.8) / 18);
			square[1] = 0.4 * sin(2 * PI * ((float)i - 2.4 + (float)j * 0.8) / 18);
			square[2] = -0.5 * cos(2 * PI * ((float)i - 2.2 + (float)j * 0.4) / 18);
			square[3] = 0.5 * sin(2 * PI * ((float)i - 2.2 + (float)j * 0.4) / 18);
			square[4] = -0.5 * cos(2 * PI * ((float)i - 2.1 + (float)j * 0.2) / 18);
			square[5] = 0.5 * sin(2 * PI * ((float)i - 2.1 + (float)j * 0.2) / 18);
			square[6] = -0.4 * cos(2 * PI * ((float)i - 2.2 + (float)j * 0.4) / 18);
			square[7] = 0.4 * sin(2 * PI * ((float)i - 2.2 + (float)j * 0.4) / 18);
			i += j;
			sui_draw_set_vec2(GlobalTransformManipulator.manipulator_rings, i * 4 + 0, square[0], square[1]);
			sui_draw_set_vec3(GlobalTransformManipulator.manipulator_rings_normals, i * 4 + 0, square[0], square[1], -5);
			sui_draw_set_vec2(GlobalTransformManipulator.manipulator_rings, i * 4 + 1, square[2], square[3]);
			sui_draw_set_vec3(GlobalTransformManipulator.manipulator_rings_normals, i * 4 + 1, square[2], square[3], -5);
			sui_draw_set_vec2(GlobalTransformManipulator.manipulator_rings, i * 4 + 2, square[4], square[5]);
			sui_draw_set_vec3(GlobalTransformManipulator.manipulator_rings_normals, i * 4 + 2, square[4], square[5], -5);
			sui_draw_set_vec2(GlobalTransformManipulator.manipulator_rings, i * 4 + 3, square[6], square[7]);
			sui_draw_set_vec3(GlobalTransformManipulator.manipulator_rings_normals, i * 4 + 3, square[6], square[7], -5);
			sui_create_shadow_edge(0.02 - (float)j * 0.04, 4, &GlobalTransformManipulator.manipulator_rings_shadow[16 * i * 2], &GlobalTransformManipulator.manipulator_rings_color[16 * i * 4], square);
		}
	}

	GlobalTransformManipulator.manipulator_pos[0] = 0;
	GlobalTransformManipulator.manipulator_pos[1] = 0;
	GlobalTransformManipulator.manipulator_pos[2] = 0;
	GlobalTransformManipulator.manipulator_size = 1;
	GlobalTransformManipulator.manipulator_rotate_scale = 1;
	GlobalTransformManipulator.mode = TMM_IDLE;
	GlobalTransformManipulator.data = NULL;
	GlobalTransformManipulator.hide = TRUE;
	GlobalTransformManipulator.tags = NULL;
	GlobalTransformManipulator.tag_length = 0;
}

void la_t_tm_place(double x, double y, double z)
{
	GlobalTransformManipulator.manipulator_pos[0] = x;
	GlobalTransformManipulator.manipulator_pos[1] = y;
	GlobalTransformManipulator.manipulator_pos[2] = z;
}
void la_t_tm_get_pos(double *pos)
{
	pos[0] = GlobalTransformManipulator.manipulator_pos[0];
	pos[1] = GlobalTransformManipulator.manipulator_pos[1];
	pos[2] = GlobalTransformManipulator.manipulator_pos[2];
}
void la_t_tm_get_vector(double *vector)
{
	double r;
	uint i;
	p_get_view_camera(vector);
	dv3_sub(vector, GlobalTransformManipulator.manipulator_pos);
	r = sqrt(vector[0] * vector[0] + vector[1] * vector[1] + vector[2] * vector[2]);
	vector[0] = (double)((uint)(vector[0] * 1.6 / r));
	vector[1] = (double)((uint)(vector[1] * 1.6 / r));
	vector[2] = (double)((uint)(vector[2] * 1.6 / r));
	dv3_normalize(vector);
}

void la_t_tm_hide(boolean hide)
{
	GlobalTransformManipulator.hide = hide;
}

void la_t_tm_draw(BInputState *input, boolean active)
{
	uint i;
	if(GlobalTransformManipulator.hide)
		return;
	if(active != TRUE)
	{
		double camera[3];
		p_get_projection_screen(camera, GlobalTransformManipulator.manipulator_pos[0], GlobalTransformManipulator.manipulator_pos[1], GlobalTransformManipulator.manipulator_pos[2]);
		GlobalTransformManipulator.manipulator_size = 0.5 * camera[2]; /*sqrt(camera[0] * camera[0] + camera[1] * camera[1] + camera[2] * camera[2]);*/
		p_get_view_camera(camera);
		camera[0] =	camera[0] - GlobalTransformManipulator.manipulator_pos[0];
		camera[1] = camera[1] - GlobalTransformManipulator.manipulator_pos[1];
		camera[2] = camera[2] - GlobalTransformManipulator.manipulator_pos[2];
		for(i = 0; i < 3; i++)
		{
			if(0 > camera[i])
				GlobalTransformManipulator.manipulator_scale[i] = GlobalTransformManipulator.manipulator_size;
			else
				GlobalTransformManipulator.manipulator_scale[i] = -GlobalTransformManipulator.manipulator_size;
		}
		for(i = 0; i < 3; i++)
		{
			double dist[3];
			p_get_projection_plane(dist, i, input->pointer_x, input->pointer_y, GlobalTransformManipulator.manipulator_pos[i]);
		}
	}
	glDisable(GL_DEPTH_TEST);
	if(GlobalTransformManipulator.mode == TMM_SCALE)
		la_do_xyz_lines(GlobalTransformManipulator.manipulator_pos, input->mouse_button[1]);
	glPushMatrix();
	glTranslated(GlobalTransformManipulator.manipulator_pos[0], GlobalTransformManipulator.manipulator_pos[1], GlobalTransformManipulator.manipulator_pos[2]);
	glScaled(GlobalTransformManipulator.manipulator_scale[0], GlobalTransformManipulator.manipulator_scale[1], GlobalTransformManipulator.manipulator_scale[2]);

	if(GlobalTransformManipulator.mode == TMM_ROTATE)
	{
		if(GlobalTransformManipulator.grab_axis == 0)
			glRotated(90, 0, 1, 0);
		if(GlobalTransformManipulator.grab_axis == 1)
			glRotated(90, 1, 0, 0);
		sui_draw_gl(GL_LINES, GlobalTransformManipulator.manipulator_circle, (ROTATE_GRID_DEGREES * 6 + 24), 3, 1, 1, 1, 0.0);
		glScaled(1, 1, GlobalTransformManipulator.manipulator_rotate_scale);
		sui_draw_gl(GL_QUADS, GlobalTransformManipulator.manipulator_grid, (ROTATE_GRID_DEGREES * 4 + ROTATE_GRID_SPLITS * 4), 3, 1, 1, 1, 0.0);
		glScaled(-8 * GlobalTransformManipulator.manipulator_size / GlobalTransformManipulator.manipulator_scale[0], -8 * GlobalTransformManipulator.manipulator_size / GlobalTransformManipulator.manipulator_scale[1], -8 * GlobalTransformManipulator.manipulator_size / GlobalTransformManipulator.manipulator_scale[2]);
	}

	if(GlobalTransformManipulator.mode == TMM_IDLE || GlobalTransformManipulator.mode == TMM_PLACE)
	{
		double matrix[16];
//		sui_set_normal_array_gl(GlobalTransformManipulator.manipulator_normal, 12 + 24 * 6);
		sui_draw_gl(GL_QUADS, GlobalTransformManipulator.manipulator_array, 12 + 24 * 6, 3, 1, 1, 1, 0.0);
		p_get_model_matrix(matrix);
		matrix[3] = 0;
		matrix[7] = 0;
		matrix[11] = 0;
		matrix[12] = 0;
		matrix[13] = 0;
		matrix[14] = 0;
		glPopMatrix();
		glPushMatrix();
		reverse_matrix(matrix);
		glTranslated(GlobalTransformManipulator.manipulator_pos[0], GlobalTransformManipulator.manipulator_pos[1], GlobalTransformManipulator.manipulator_pos[2]);
		glMultMatrixd(matrix);
		glScaled(GlobalTransformManipulator.manipulator_size, GlobalTransformManipulator.manipulator_size, GlobalTransformManipulator.manipulator_size);
//		sui_set_normal_array_gl(GlobalTransformManipulator.manipulator_normal, 12 + 24 * 6);
		sui_draw_gl(GL_QUADS, GlobalTransformManipulator.manipulator_rings, 4 * (ROTATE_GRID_DEGREES + 6), 2, 1, 1, 1, 0.0);
		sui_set_blend_gl(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		sui_set_color_array_gl(GlobalTransformManipulator.manipulator_rings_color, 16 * (ROTATE_GRID_DEGREES + 6), 4);
		sui_draw_gl(GL_QUADS, GlobalTransformManipulator.manipulator_rings_shadow, 16 * (ROTATE_GRID_DEGREES + 6), 2, 1, 1, 1, 0.0);
		glPopMatrix();
		glPushMatrix();
	}

	{
		double vector[3], origo[3] = {0, 0, 0}, point[3] = {0.1, 0.1, 1}, matrix[16];
		la_t_tm_get_vector(vector);
		create_matrix_normalized(matrix, origo, vector, point);
		glPopMatrix();
		glPushMatrix();
		glTranslated(GlobalTransformManipulator.manipulator_pos[0], GlobalTransformManipulator.manipulator_pos[1], GlobalTransformManipulator.manipulator_pos[2]);
		glMultMatrixd(matrix);
		glScaled(GlobalTransformManipulator.manipulator_size, GlobalTransformManipulator.manipulator_size, GlobalTransformManipulator.manipulator_size);
		la_pfx_video_flare();
//		sui_draw_gl(GL_QUADS, GlobalTransformManipulator.manipulator_rings, (ROTATE_GRID_DEGREES * 4 + 8), 3, 1, 1, 1);
		glPopMatrix();
		glPushMatrix();
	}
	glPopMatrix();
	if(GlobalTransformManipulator.mode == TMM_NORMAL || GlobalTransformManipulator.mode == TMM_TANGENT || GlobalTransformManipulator.mode == TMM_SMOOTH)
	{
		sui_draw_gl(GL_LINES, GlobalTransformManipulator.manipulator_normal_array, GlobalTransformManipulator.manipulator_normal_array_length * 2, 3, 1, 1, 1, 0.0);
	}
	glEnable(GL_DEPTH_TEST);
}

void compute_tangent(double *vertex, uint edge_a, uint edge_b, uint other)
{
	float r;
	double normal[3], temp[3];
	edge_a *= 3;
	edge_b *= 3;
	other *= 3;
	dv3o_sub(normal, &vertex[edge_a], &vertex[other]);
	dv3o_sub(temp, &vertex[edge_a], &vertex[edge_b]);
	dv3_normalize(temp);
	r = dv3_dot(normal, temp);
	normal[0] -= temp[0] * r;
	normal[1] -= temp[1] * r;
	normal[2] -= temp[2] * r;
	dv3_normalize(normal);
	dv3_add(&GlobalTransformManipulator.normal[edge_a], normal);
	r = dv3_dot(&GlobalTransformManipulator.normal[edge_a], normal);
	dv3_division(&GlobalTransformManipulator.normal[edge_a], r);
	dv3_add(&GlobalTransformManipulator.normal[edge_b], normal);
	r = dv3_dot(&GlobalTransformManipulator.normal[edge_b], normal);
	dv3_division(&GlobalTransformManipulator.normal[edge_b], r);
}

void lock_transform_vertexes(BInputState *input, boolean normal, boolean tangent, boolean smooth)
{
	ENode *node;
	UNDOTag *tag;
	uint i, j, *ref, ref_count, vertex_count, count;
	double select, *vertex;
	boolean computed;
	udg_get_geometry(&vertex_count, &ref_count, &vertex, &ref, NULL);

	GlobalTransformManipulator.data_length = vertex_count;
	GlobalTransformManipulator.data = malloc((sizeof *GlobalTransformManipulator.data) * GlobalTransformManipulator.data_length * 3);

	for(i = 0; i < 3; i++)
	{
		GlobalTransformManipulator.min_scale[i] = GlobalTransformManipulator.manipulator_pos[i];
		GlobalTransformManipulator.max_scale[i] = GlobalTransformManipulator.manipulator_pos[i];
	}
	for(i = 0; i < GlobalTransformManipulator.data_length; i++)
	{
		GlobalTransformManipulator.data[i * 3] = vertex[i * 3];
		GlobalTransformManipulator.data[i * 3 + 1] = vertex[i * 3 + 1];
		GlobalTransformManipulator.data[i * 3 + 2] = vertex[i * 3 + 2];
		select = udg_get_select(i);
		if(select > 0.0001)
		{
			if(vertex[i * 3] > GlobalTransformManipulator.max_scale[0])
				GlobalTransformManipulator.max_scale[0] = vertex[i * 3];
			if(vertex[i * 3] < GlobalTransformManipulator.min_scale[0])
				GlobalTransformManipulator.min_scale[0] = vertex[i * 3];

			if(vertex[i * 3 + 1] > GlobalTransformManipulator.max_scale[1])
				GlobalTransformManipulator.max_scale[1] = vertex[i * 3 + 1];
			if(vertex[i * 3 + 1] < GlobalTransformManipulator.min_scale[1])
				GlobalTransformManipulator.min_scale[1] = vertex[i * 3 + 1];

			if(vertex[i * 3 + 2] > GlobalTransformManipulator.max_scale[2])
				GlobalTransformManipulator.max_scale[2] = vertex[i * 3 + 2];
			if(vertex[i * 3 + 2] < GlobalTransformManipulator.min_scale[2])
				GlobalTransformManipulator.min_scale[2] = vertex[i * 3 + 2];
		}
	}
	GlobalTransformManipulator.normal = NULL;
	if(normal)
	{
		double x, y, z, x2, y2, z2, r;
		uint *pos, poly, j2;
		GlobalTransformManipulator.normal = malloc((sizeof *GlobalTransformManipulator.normal) * vertex_count * 3);
		for(i = 0; i < vertex_count; i++)
		{
			GlobalTransformManipulator.normal[i * 3] = 0;
			GlobalTransformManipulator.normal[i * 3 + 1] = 0;
			GlobalTransformManipulator.normal[i * 3 + 2] = 0;
		}
		pos = ref;
		for(i = 0; i < ref_count; pos += 4)
		{
			i++;
			if(pos[0] < vertex_count &&
			   pos[1] < vertex_count &&
			   pos[2] < vertex_count &&
			   vertex[pos[0] * 3] != V_REAL64_MAX &&
			   vertex[pos[1] * 3] != V_REAL64_MAX &&
			   vertex[pos[2] * 3] != V_REAL64_MAX)
			{
				if(pos[3] < vertex_count && vertex[pos[3] * 3] != V_REAL64_MAX)
					poly = 4;
				else
					poly = 3;
				if(udg_get_select(pos[0]) > 0.01 && udg_get_select(pos[1]) > 0.01 && udg_get_select(pos[2]) > 0.01 && (poly == 3 || udg_get_select(pos[3]) > 0.01))
				{
					x = ((vertex[pos[0] * 3 + 1] - vertex[pos[1] * 3 + 1]) * (vertex[pos[2] * 3 + 2] - vertex[pos[1] * 3 + 2]) - (vertex[pos[0] * 3 + 2] - vertex[pos[1] * 3 + 2]) * (vertex[pos[2] * 3 + 1] - vertex[pos[1] * 3 + 1]));
					y = ((vertex[pos[0] * 3 + 2] - vertex[pos[1] * 3 + 2]) * (vertex[pos[2] * 3 + 0] - vertex[pos[1] * 3 + 0]) - (vertex[pos[0] * 3 + 0] - vertex[pos[1] * 3 + 0]) * (vertex[pos[2] * 3 + 2] - vertex[pos[1] * 3 + 2]));
					z = ((vertex[pos[0] * 3 + 0] - vertex[pos[1] * 3 + 0]) * (vertex[pos[2] * 3 + 1] - vertex[pos[1] * 3 + 1]) - (vertex[pos[0] * 3 + 1] - vertex[pos[1] * 3 + 1]) * (vertex[pos[2] * 3 + 0] - vertex[pos[1] * 3 + 0]));
					r = sqrt(x * x + y * y + z * z);
					x = x / r;
					y = y / r;
					z = z / r;
					for(j = 0; j < poly; j++)
					{
						GlobalTransformManipulator.normal[pos[j] * 3] += x;
						GlobalTransformManipulator.normal[pos[j] * 3 + 1] += y;
						GlobalTransformManipulator.normal[pos[j] * 3 + 2] += z;
					}
				}
			}
		}
		pos = ref;
		for(i = 0; i < vertex_count; i++)
		{
			x = GlobalTransformManipulator.normal[i * 3];
			y = GlobalTransformManipulator.normal[i * 3 + 1];
			z = GlobalTransformManipulator.normal[i * 3 + 2];
			r = x * x + y * y + z * z;
			if(r > 0.001)
			{
				r = sqrt(r);
				GlobalTransformManipulator.normal[i * 3] = x / r;
				GlobalTransformManipulator.normal[i * 3 + 1] = y / r;
				GlobalTransformManipulator.normal[i * 3 + 2] = z / r;
			}
		}
	}
	if(tangent)
	{
		double x, y, z, x2, y2, z2, r;
		uint *pos, poly, j2;
		boolean *edge;
		GlobalTransformManipulator.normal = malloc((sizeof *GlobalTransformManipulator.normal) * vertex_count * 3);
		edge = malloc((sizeof *edge) * vertex_count);
		for(i = 0; i < vertex_count; i++)
		{
			GlobalTransformManipulator.normal[i * 3] = 0;
			GlobalTransformManipulator.normal[i * 3 + 1] = 0;
			GlobalTransformManipulator.normal[i * 3 + 2] = 0;
			edge[i] = FALSE;
		}
		pos = ref;
		for(i = 0; i < ref_count; i++)
		{
			if(pos[3] < vertex_count)
				if(udg_get_select(pos[0]) < 0.01 || udg_get_select(pos[1]) < 0.01 || udg_get_select(pos[2]) < 0.01 || (pos[3] < vertex_count && udg_get_select(pos[3]) < 0.01))
					for(j = 0; j < 4; j++)
						if(pos[j] < vertex_count && udg_get_select(pos[j]) > 0.01)
							edge[pos[j]] = TRUE;
			pos += 4;
		}
		pos = ref;
		for(i = 0; i < ref_count; i++)
		{
			if(pos[3] < vertex_count)
			{
				if(udg_get_select(pos[0]) > 0.01 && udg_get_select(pos[1]) > 0.01 && udg_get_select(pos[2]) > 0.01 && (pos[3] > vertex_count || udg_get_select(pos[3]) > 0.01))
				{
					if(edge[pos[0]] && edge[pos[1]])
						compute_tangent(vertex, pos[0], pos[1], pos[2]);
					if(edge[pos[1]] && edge[pos[2]])
						compute_tangent(vertex, pos[1], pos[2], pos[0]);
					if(pos[3] >= vertex_count && edge[pos[2]] && edge[pos[0]])
						compute_tangent(vertex, pos[2], pos[0], pos[1]);
					if(pos[3] < vertex_count && edge[pos[2]] && edge[pos[3]])
						compute_tangent(vertex, pos[2], pos[3], pos[0]);
					if(pos[3] < vertex_count && edge[pos[3]] && edge[pos[0]])
						compute_tangent(vertex, pos[3], pos[0], pos[1]);
				}
			}
			pos += 4;
		}
		j = 0;
		for(i = 0; i < vertex_count; i++)
			if(GlobalTransformManipulator.normal[i * 3] != 0 || GlobalTransformManipulator.normal[i * 3 + 1] != 0 || GlobalTransformManipulator.normal[i * 3 + 2] != 0)
				j++;
/*		for(i = 0; i < vertex_count; i++)
		{
			printf("tangent output %f %f %f edge %u\n",GlobalTransformManipulator.normal[i * 3],
			GlobalTransformManipulator.normal[i * 3 + 1],
			GlobalTransformManipulator.normal[i * 3 + 2],
			edge[i]);
		}
*/		free(edge);
	}
	if(smooth)
	{
		uint *count, poly;
		double vertex[3], sum[3];
		GlobalTransformManipulator.normal = malloc((sizeof *GlobalTransformManipulator.normal) * vertex_count * 3);
		count = malloc((sizeof *count) * vertex_count);
		for(i = 0; i < vertex_count; i++)
		{
			GlobalTransformManipulator.normal[i * 3] = 0;
			GlobalTransformManipulator.normal[i * 3 + 1] = 0;
			GlobalTransformManipulator.normal[i * 3 + 2] = 0;
			count[i] = 0;
		}
		for(i = 0; i < ref_count * 4; i += 4)
		{
			if(ref[i] < vertex_count && ref[i + 1] < vertex_count && ref[i + 2] < vertex_count && vertex[ref[i] * 3] != V_REAL64_MAX && vertex[ref[i + 1] * 3] != V_REAL64_MAX && vertex[ref[i + 2] * 3] != V_REAL64_MAX)
			{
				if(ref[i + 3] < vertex_count && vertex[ref[i + 3] * 3] != V_REAL64_MAX)
					poly = 4;
				else
					poly = 3;
				sum[0] = 0;
				sum[1] = 0;
				sum[2] = 0;
				for(j = 0; j < poly; j++)
				{
					udg_get_vertex_pos(vertex, ref[i + j]);
					dv3_add(sum, vertex);
				}
				for(j = 0; j < poly; j++)
				{
					udg_get_vertex_pos(vertex, ref[i + j]);
					GlobalTransformManipulator.normal[ref[i + j] * 3] += sum[0] - vertex[0];
					GlobalTransformManipulator.normal[ref[i + j] * 3 + 1] += sum[1] - vertex[1];
					GlobalTransformManipulator.normal[ref[i + j] * 3 + 2] += sum[2] - vertex[2];
					count[ref[i + j]] += poly - 1;
				}
			}
		}
		for(i = 0; i < vertex_count; i++)
		{
			if(count[i] != 0)
			{
				udg_get_vertex_pos(vertex, i);
				GlobalTransformManipulator.normal[i * 3] = (vertex[0] - (GlobalTransformManipulator.normal[i * 3] / count[i])) / (GlobalTransformManipulator.manipulator_size * 0.4);
				GlobalTransformManipulator.normal[i * 3 + 1] = (vertex[1] - (GlobalTransformManipulator.normal[i * 3 + 1] / count[i])) / (GlobalTransformManipulator.manipulator_size * 0.4);
				GlobalTransformManipulator.normal[i * 3 + 2] = (vertex[2] - (GlobalTransformManipulator.normal[i * 3 + 2] / count[i])) / (GlobalTransformManipulator.manipulator_size * 0.4);
			}
		}
		free(count);
	}
	if(tangent || normal || smooth)
	{
		j = 0;
		for(i = 0; i < vertex_count; i++)
			if(GlobalTransformManipulator.normal[i * 3] != 0 || GlobalTransformManipulator.normal[i * 3 + 1] != 0 || GlobalTransformManipulator.normal[i * 3 + 2] != 0)
				if(udg_get_select(i) > 0.01)
					j++;
		GlobalTransformManipulator.manipulator_normal_array_length = j;
		GlobalTransformManipulator.manipulator_normal_array = malloc((sizeof *GlobalTransformManipulator.manipulator_normal_array) * j * 2 * 3);
		j = 0;
		for(i = 0; i < vertex_count; i++)
		{
			if(GlobalTransformManipulator.normal[i * 3] != 0 || GlobalTransformManipulator.normal[i * 3 + 1] != 0 || GlobalTransformManipulator.normal[i * 3 + 2] != 0)
			{
				if(udg_get_select(i) > 0.01)
				{
					sui_draw_set_vec3(GlobalTransformManipulator.manipulator_normal_array, j * 2 + 0, vertex[i * 3] - GlobalTransformManipulator.normal[i * 3] * GlobalTransformManipulator.manipulator_size * 0.4, vertex[i * 3 + 1] - GlobalTransformManipulator.normal[i * 3 + 1] * GlobalTransformManipulator.manipulator_size * 0.4, vertex[i * 3 + 2] - GlobalTransformManipulator.normal[i * 3 + 2] * GlobalTransformManipulator.manipulator_size * 0.4);
					sui_draw_set_vec3(GlobalTransformManipulator.manipulator_normal_array, j * 2 + 1, vertex[i * 3] + GlobalTransformManipulator.normal[i * 3] * GlobalTransformManipulator.manipulator_size * 0.4, vertex[i * 3 + 1] + GlobalTransformManipulator.normal[i * 3 + 1] * GlobalTransformManipulator.manipulator_size * 0.4, vertex[i * 3 + 2] + GlobalTransformManipulator.normal[i * 3 + 2] * GlobalTransformManipulator.manipulator_size * 0.4);
					j++;
				}
			}
		}
	}else
	{
		tag = udg_get_tags(&GlobalTransformManipulator.tag_length);
		for(i = 0; i < GlobalTransformManipulator.tag_length && tag[i].select < 0.01; i++);
		if(i == GlobalTransformManipulator.tag_length)
			return;
		GlobalTransformManipulator.tags = malloc((sizeof *GlobalTransformManipulator.tags) * GlobalTransformManipulator.tag_length * 3);
		for(i = 0; i < GlobalTransformManipulator.tag_length; i++)
		{
			GlobalTransformManipulator.tags[i * 3] = tag[i].vec[0];
			GlobalTransformManipulator.tags[i * 3 + 1] = tag[i].vec[1];
			GlobalTransformManipulator.tags[i * 3 + 2] = tag[i].vec[2];
		}
	}
}

boolean la_t_tm_grab(BInputState *input)
{
	double dist[3], pos, distance;
	uint i;
	if(GlobalTransformManipulator.hide)
		return FALSE;
	for(i = 0; i < 3; i++)
	{
		pos = p_get_projection_line(&distance, i, input->pointer_x, input->pointer_y, GlobalTransformManipulator.manipulator_pos);
		if(pos / GlobalTransformManipulator.manipulator_scale[i] > 0.1 && pos / GlobalTransformManipulator.manipulator_scale[i] < 0.3 && distance < 0.02 * 0.02)
		{
			GlobalTransformManipulator.grab_axis = i;
			GlobalTransformManipulator.grab_pos = pos;
			GlobalTransformManipulator.grab_manip_pos = GlobalTransformManipulator.manipulator_pos[i];
			GlobalTransformManipulator.mode = TMM_TRANSFORM;
			lock_transform_vertexes(input, FALSE, FALSE, FALSE);
			la_pfx_create_bright(GlobalTransformManipulator.manipulator_pos);
			return TRUE;
		}
	}

	distance = p_get_projection_screen_distance(GlobalTransformManipulator.manipulator_pos[0], GlobalTransformManipulator.manipulator_pos[1], GlobalTransformManipulator.manipulator_pos[2], input->pointer_x, input->pointer_y);
	if(distance < 0.05 * 0.05)
	{
		GlobalTransformManipulator.mode = TMM_PLACE;
		la_pfx_create_bright(GlobalTransformManipulator.manipulator_pos);
		return TRUE;
	}

	for(i = 0; i < 3; i++)
	{
		double a, b,radius;
		p_get_projection_plane(dist, i, input->pointer_x, input->pointer_y, GlobalTransformManipulator.manipulator_pos[i]);
		if((dist[(i + 1) % 3] - GlobalTransformManipulator.manipulator_pos[(i + 1) % 3]) * GlobalTransformManipulator.manipulator_scale[(i + 1) % 3] > 0 &&
			(dist[(i + 2) % 3] - GlobalTransformManipulator.manipulator_pos[(i + 2) % 3]) * GlobalTransformManipulator.manipulator_scale[(i + 2) % 3] > 0)
		{
			a = (dist[(i + 1) % 3] - GlobalTransformManipulator.manipulator_pos[(i + 1) % 3]) / (GlobalTransformManipulator.manipulator_size * 0.3);
			b = (dist[(i + 2) % 3] - GlobalTransformManipulator.manipulator_pos[(i + 2) % 3]) / (GlobalTransformManipulator.manipulator_size * 0.3);
			radius = a * a + b * b;
			if(radius < 1)
			{
				GlobalTransformManipulator.grab_axis = i;
				GlobalTransformManipulator.mode = TMM_ROTATE;
				GlobalTransformManipulator.grab_pos = atan2(dist[(GlobalTransformManipulator.grab_axis + 1) % 3] - GlobalTransformManipulator.manipulator_pos[(GlobalTransformManipulator.grab_axis + 1) % 3], dist[(GlobalTransformManipulator.grab_axis + 2) % 3] - GlobalTransformManipulator.manipulator_pos[(GlobalTransformManipulator.grab_axis + 2) % 3]);
				GlobalTransformManipulator.grab_pos = 0.5 * PI * (double)((int)(GlobalTransformManipulator.grab_pos / (0.5 * PI) + 4.5));
				lock_transform_vertexes(input, FALSE, FALSE, FALSE);
				la_pfx_create_bright(GlobalTransformManipulator.manipulator_pos);
				return TRUE;
			}
		}
	}
	if(distance < 0.15 * 0.15)
	{
		GlobalTransformManipulator.mode = TMM_SCALE;
		lock_transform_vertexes(input, FALSE, FALSE, FALSE);
		la_pfx_create_bright(GlobalTransformManipulator.manipulator_pos);
		return TRUE;
	}

	p_get_projection_screen(dist, GlobalTransformManipulator.manipulator_pos[0], GlobalTransformManipulator.manipulator_pos[1], GlobalTransformManipulator.manipulator_pos[2]);
	pos = (-input->pointer_x - dist[0]) - (-input->pointer_y - dist[1]);
	if(pos > -0.35 && pos < 0)
	{
		pos = (-input->pointer_x - dist[0]) + (-input->pointer_y - dist[1]);
		if(pos > -0.07 && pos < 0.07)
		{
			GlobalTransformManipulator.mode = TMM_NORMAL;
			GlobalTransformManipulator.grab_manip_pos = ((input->pointer_x - dist[0]) - (input->pointer_y - dist[1])) * GlobalTransformManipulator.manipulator_size;
			lock_transform_vertexes(input, TRUE, FALSE, FALSE);
			return TRUE;
		}
	}
	pos = (-input->pointer_x - dist[0]) + (-input->pointer_y - dist[1]);
	if(pos > -0.35 && pos < 0)
	{
		pos = (-input->pointer_x - dist[0]) - (-input->pointer_y - dist[1]);
		if(pos > -0.07 && pos < 0.07)
		{
			GlobalTransformManipulator.mode = TMM_SMOOTH;
			GlobalTransformManipulator.grab_manip_pos = ((input->pointer_x - dist[0]) + (input->pointer_y - dist[1])) * GlobalTransformManipulator.manipulator_size;
			lock_transform_vertexes(input, FALSE, FALSE, TRUE);
			return TRUE;
		}
	}
	pos = (-input->pointer_x - dist[0]);
	if(pos > -0.25 && pos < 0)
	{
		pos = (-input->pointer_y - dist[1]);
		if(pos > -0.03 && pos < 0.03)
		{
			GlobalTransformManipulator.mode = TMM_TANGENT;
			GlobalTransformManipulator.grab_manip_pos = (input->pointer_x - dist[0]) * -GlobalTransformManipulator.manipulator_size;
			lock_transform_vertexes(input, FALSE, TRUE, FALSE);
			return TRUE;
		}
	}

	GlobalTransformManipulator.mode = TMM_IDLE;
	return FALSE;
}

void la_t_tm_view_center(void)
{
	p_set_view_center(GlobalTransformManipulator.manipulator_pos);
}

boolean la_t_tm_test_center(BInputState *input)
{
	double manip[3], pos;
	if(GlobalTransformManipulator.hide == TRUE)
		return FALSE;
	p_get_projection_screen(manip, GlobalTransformManipulator.manipulator_pos[0], GlobalTransformManipulator.manipulator_pos[1], GlobalTransformManipulator.manipulator_pos[2]);
	if((manip[0] + input->pointer_x) * (manip[0] + input->pointer_x) + (manip[1] + input->pointer_y) * (manip[1] + input->pointer_y) < 0.165 * 0.165)
		return TRUE;
	pos = (-input->pointer_x - manip[0]) - (-input->pointer_y - manip[1]);
	if(pos > 0 && pos < 0.4)
	{
		pos = (-input->pointer_x - manip[0]) + (-input->pointer_y - manip[1]);
		if(pos > -0.05 && pos < 0.05)
			return TRUE;
	}
	return FALSE;
}

void  matrix_func(double *output, uint vertex_id, void *data)
{
	double vertex[3], select;
	select = udg_get_select(vertex_id);
	vertex[0] = GlobalTransformManipulator.data[vertex_id * 3];
	vertex[1] = GlobalTransformManipulator.data[vertex_id * 3 + 1];
	vertex[2] = GlobalTransformManipulator.data[vertex_id * 3 + 2];
	point_threw_matrix3((double *)data, &vertex[0], &vertex[1], &vertex[2]);
	output[0] = vertex[0] * select + GlobalTransformManipulator.data[vertex_id * 3] * (1 - select);
	output[1] = vertex[1] * select + GlobalTransformManipulator.data[vertex_id * 3 + 1] * (1 - select);
	output[2] = vertex[2] * select + GlobalTransformManipulator.data[vertex_id * 3 + 2] * (1 - select);
}

void  normal_func(double *output, uint vertex_id, void *data)
{
	double select;
	select = udg_get_select(vertex_id);
	output[0] = GlobalTransformManipulator.data[vertex_id * 3] + (select * *(double *)data * GlobalTransformManipulator.normal[vertex_id * 3]);
	output[1] = GlobalTransformManipulator.data[vertex_id * 3 + 1] + (select * *(double *)data * GlobalTransformManipulator.normal[vertex_id * 3 + 1]);
	output[2] = GlobalTransformManipulator.data[vertex_id * 3 + 2] + (select * *(double *)data * GlobalTransformManipulator.normal[vertex_id * 3 + 2]);
}

void la_t_tm_manipulate(BInputState *input, double *snap, uint snap_type)
{
	ENode *node;
	double select, delta, vertex[3], state[3], matrix[16], normal_tangent;
	uint i, j, id, update_length = -1;
	void  (*func)(double *output, uint vertex_id, void *data) = NULL;
	void *data;
	node = e_ns_get_node_selected(0, V_NT_GEOMETRY);

	if(input->mouse_button[0] == TRUE)
		update_length = 50;
	else
		GlobalTransformManipulator.update_rotate = 0;

	if(GlobalTransformManipulator.mode == TMM_IDLE)
	{
		GlobalTransformManipulator.manipulator_start[0] = GlobalTransformManipulator.manipulator_pos[0];
		GlobalTransformManipulator.manipulator_start[1] = GlobalTransformManipulator.manipulator_pos[1];
		GlobalTransformManipulator.manipulator_start[2] = GlobalTransformManipulator.manipulator_pos[2];
		return;
	}
	if(GlobalTransformManipulator.mode == TMM_PLACE)
	{
		GlobalTransformManipulator.manipulator_pos[0] = snap[0];
		GlobalTransformManipulator.manipulator_pos[1] = snap[1];
		GlobalTransformManipulator.manipulator_pos[2] = snap[2];
		if(input->mouse_button[0] != TRUE)
			GlobalTransformManipulator.mode = TMM_IDLE;
		return;
	}
	if(GlobalTransformManipulator.mode == TMM_NORMAL)
	{
		double output[3];
		p_get_projection_screen(output, GlobalTransformManipulator.manipulator_pos[0], GlobalTransformManipulator.manipulator_pos[1], GlobalTransformManipulator.manipulator_pos[2]);
		normal_tangent = ((input->pointer_x - output[0]) - (input->pointer_y - output[1])) * GlobalTransformManipulator.manipulator_size - GlobalTransformManipulator.grab_manip_pos;
		func = normal_func;
		data = &normal_tangent;
	}
	if(GlobalTransformManipulator.mode == TMM_SMOOTH)
	{
		double output[3];
		p_get_projection_screen(output, GlobalTransformManipulator.manipulator_pos[0], GlobalTransformManipulator.manipulator_pos[1], GlobalTransformManipulator.manipulator_pos[2]);
		normal_tangent = ((input->pointer_x - output[0]) + (input->pointer_y - output[1])) * GlobalTransformManipulator.manipulator_size - GlobalTransformManipulator.grab_manip_pos;
		if(normal_tangent > GlobalTransformManipulator.manipulator_size * -0.4)
			normal_tangent = GlobalTransformManipulator.manipulator_size * -0.4;
		func = normal_func;
		data = &normal_tangent;
	}
	if(GlobalTransformManipulator.mode == TMM_TANGENT)
	{
		double output[3];
		p_get_projection_screen(output, GlobalTransformManipulator.manipulator_pos[0], GlobalTransformManipulator.manipulator_pos[1], GlobalTransformManipulator.manipulator_pos[2]);
		normal_tangent = (input->pointer_x - output[0]) * -GlobalTransformManipulator.manipulator_size - GlobalTransformManipulator.grab_manip_pos;
		func = normal_func;
		data = &normal_tangent;
	}

	clear_matrix(matrix);
	if(GlobalTransformManipulator.mode == TMM_TRANSFORM)
	{
		if(input->mouse_button[1])
		{
		//	GlobalTransformManipulator.manipulator_pos[GlobalTransformManipulator.grab_axis] = snap[GlobalTransformManipulator.grab_axis];
			p_get_projection_line_snap(GlobalTransformManipulator.manipulator_pos, GlobalTransformManipulator.grab_axis, GlobalTransformManipulator.manipulator_pos[GlobalTransformManipulator.grab_axis] - GlobalTransformManipulator.manipulator_start[GlobalTransformManipulator.grab_axis], GlobalTransformManipulator.manipulator_start, snap, snap_type);
		}
		else
			GlobalTransformManipulator.manipulator_pos[GlobalTransformManipulator.grab_axis] += p_get_projection_line(NULL, GlobalTransformManipulator.grab_axis, input->pointer_x, input->pointer_y, GlobalTransformManipulator.manipulator_pos) - GlobalTransformManipulator.grab_pos;

		delta = GlobalTransformManipulator.manipulator_pos[GlobalTransformManipulator.grab_axis] - GlobalTransformManipulator.grab_manip_pos;
		matrix[12 + GlobalTransformManipulator.grab_axis] += delta;
		func = matrix_func;
		data = matrix;
	}
	if(GlobalTransformManipulator.mode == TMM_ROTATE)
	{
		double r, dist[3], matrix2[16], matrix3[16];

		if(input->mouse_button[1])
		{
			dist[0] = snap[0];
			dist[1] = snap[1];
			dist[2] = snap[2];
		}
		else
		{
			p_get_projection_plane(dist, GlobalTransformManipulator.grab_axis, input->pointer_x, input->pointer_y, GlobalTransformManipulator.manipulator_pos[GlobalTransformManipulator.grab_axis]);
		}
		delta = atan2(dist[(GlobalTransformManipulator.grab_axis + 1) % 3] - GlobalTransformManipulator.manipulator_pos[(GlobalTransformManipulator.grab_axis + 1) % 3], dist[(GlobalTransformManipulator.grab_axis + 2) % 3] - GlobalTransformManipulator.manipulator_pos[(GlobalTransformManipulator.grab_axis + 2) % 3]) - GlobalTransformManipulator.grab_pos;
		r = (dist[(GlobalTransformManipulator.grab_axis + 1) % 3] - GlobalTransformManipulator.manipulator_pos[(GlobalTransformManipulator.grab_axis + 1) % 3]) * (dist[(GlobalTransformManipulator.grab_axis + 1) % 3] - GlobalTransformManipulator.manipulator_pos[(GlobalTransformManipulator.grab_axis + 1) % 3]) + (dist[(GlobalTransformManipulator.grab_axis + 2) % 3] - GlobalTransformManipulator.manipulator_pos[(GlobalTransformManipulator.grab_axis + 2) % 3]) * (dist[(GlobalTransformManipulator.grab_axis + 2) % 3] - GlobalTransformManipulator.manipulator_pos[(GlobalTransformManipulator.grab_axis + 2) % 3]);
		if(r < GlobalTransformManipulator.manipulator_size * GlobalTransformManipulator.manipulator_size * 1 * 1 && r > GlobalTransformManipulator.manipulator_size * GlobalTransformManipulator.manipulator_size * 0.9 * 0.9)
		{
			if(r < GlobalTransformManipulator.manipulator_size * GlobalTransformManipulator.manipulator_size * 0.96 * 0.96)
				delta = (double)((uint)(ROTATE_GRID_SPLITS * delta / (2 * PI))) * 2 * PI / ROTATE_GRID_SPLITS;
			else
				delta = (double)((uint)(ROTATE_GRID_DEGREES * delta / (2 * PI))) * 2 * PI / ROTATE_GRID_DEGREES;
			GlobalTransformManipulator.manipulator_rotate_scale *= 0.9;
		}else
			GlobalTransformManipulator.manipulator_rotate_scale = GlobalTransformManipulator.manipulator_rotate_scale * 0.9 + 0.1;

		clear_matrix(matrix2);
		clear_matrix(matrix3);
		transform_matrix(matrix2, GlobalTransformManipulator.manipulator_pos[0], GlobalTransformManipulator.manipulator_pos[1], GlobalTransformManipulator.manipulator_pos[2]);
		if(GlobalTransformManipulator.grab_axis == 0)
			matrix_rotate_x(matrix, -delta);
		else if(GlobalTransformManipulator.grab_axis == 1)
			matrix_rotate_y(matrix, -delta);
		else if(GlobalTransformManipulator.grab_axis == 2)
			matrix_rotate_z(matrix, -delta);
		matrix_multiply(matrix2, matrix, matrix3);
		clear_matrix(matrix2);
		transform_matrix(matrix2, -GlobalTransformManipulator.manipulator_pos[0], -GlobalTransformManipulator.manipulator_pos[1], -GlobalTransformManipulator.manipulator_pos[2]);
		matrix_multiply(matrix3, matrix2, matrix);
		func = matrix_func;
		data = matrix;
	}

	if(GlobalTransformManipulator.mode == TMM_SCALE)
	{
		double scale[3], vertex[3], length;
		p_get_projection_vertex_with_axis(vertex, GlobalTransformManipulator.manipulator_pos, input->pointer_x, input->pointer_y, input->mouse_button[1], snap, LA_ST_VERTEX);

		scale[0] = 0;
		scale[1] = 0;
		scale[2] = 0;

		for(i = 0; i < 3; i++)
		{
			if(vertex[i] > GlobalTransformManipulator.manipulator_pos[i])
			{
				if(GlobalTransformManipulator.max_scale[i] > GlobalTransformManipulator.manipulator_pos[i] + 0.001)
					scale[i] = (vertex[i] - GlobalTransformManipulator.manipulator_pos[i]) / (GlobalTransformManipulator.max_scale[i] - GlobalTransformManipulator.manipulator_pos[i]);
			}
			else
				if(GlobalTransformManipulator.min_scale[i] + 0.001 < GlobalTransformManipulator.manipulator_pos[i])
					scale[i] = (vertex[i] - GlobalTransformManipulator.manipulator_pos[i]) / (GlobalTransformManipulator.min_scale[i] - GlobalTransformManipulator.manipulator_pos[i]);
		}
		length = sqrt(scale[0] * scale[0] + scale[1] * scale[1] + scale[2] * scale[2]);
		for(i = 0; i < 3; i++)
		{
			if(scale[i] == 1 || (vertex[i] - GlobalTransformManipulator.manipulator_pos[i] > -0.0001 && vertex[i] - GlobalTransformManipulator.manipulator_pos[i] < 0.0001))
				scale[i] = 1;
			else
				scale[i] = length;
		}
		transform_matrix(matrix, (scale[0] - 1) * -GlobalTransformManipulator.manipulator_pos[0], (scale[1] - 1) * -GlobalTransformManipulator.manipulator_pos[1], (scale[2] - 1) * -GlobalTransformManipulator.manipulator_pos[2]);
		scale_matrix(matrix, scale[0], scale[1], scale[2]);
		func = matrix_func;
		data = matrix;
	}

	if(func == matrix_func && GlobalTransformManipulator.tags != NULL)
	{
		UNDOTag *tag;
		tag = udg_get_tags(&i);
		if(i == GlobalTransformManipulator.tag_length)
		{
			for(i = 0; i < GlobalTransformManipulator.tag_length; i++)
			{
				vertex[0] = GlobalTransformManipulator.tags[i * 3];
				vertex[1] = GlobalTransformManipulator.tags[i * 3 + 1];
				vertex[2] = GlobalTransformManipulator.tags[i * 3 + 2];

				point_threw_matrix3(matrix, &vertex[0], &vertex[1], &vertex[2]);
				vertex[0] = vertex[0] * tag[i].select + GlobalTransformManipulator.tags[i * 3] * (1 - tag[i].select);
				vertex[1] = vertex[1] * tag[i].select + GlobalTransformManipulator.tags[i * 3 + 1] * (1 - tag[i].select);
				vertex[2] = vertex[2] * tag[i].select + GlobalTransformManipulator.tags[i * 3 + 2] * (1 - tag[i].select);
				udg_move_tag(i, vertex);
			}
		}
	}

	if(data != NULL)
	{
		j = 0;
		if(GlobalTransformManipulator.update_rotate >= GlobalTransformManipulator.data_length)
			GlobalTransformManipulator.update_rotate = 0;
		for(i = GlobalTransformManipulator.update_rotate; i < GlobalTransformManipulator.data_length; i++)
		{
			select = udg_get_select(i);
			if(select > 0.0001)
			{
				state[0] = GlobalTransformManipulator.data[i * 3];
				state[1] = GlobalTransformManipulator.data[i * 3 + 1];
				state[2] = GlobalTransformManipulator.data[i * 3 + 2];
				func(vertex, i, data);
				udg_vertex_set(i, state, vertex[0], vertex[1], vertex[2]);
				if(++j > update_length)
				{
					GlobalTransformManipulator.update_rotate = i;
					break;
				}
			}
		}
		if(i == GlobalTransformManipulator.data_length)
			GlobalTransformManipulator.update_rotate = 0;
		if(input->mouse_button[2] != TRUE && input->last_mouse_button[2] == TRUE)
		{
			undo_event_done();
			la_t_extrude(GlobalTransformManipulator.data_length, func, data);
		}
	}else
	{
		for(i = 0; i < GlobalTransformManipulator.data_length; i++)
		{
			select = udg_get_select(i);
			if(select > 0.0001)
			{
				func(vertex, i, data);
				udg_vertex_move(i, vertex[0], vertex[1], vertex[2]);
			}
		}
	}

	if(input->mouse_button[0] != TRUE && input->last_mouse_button[0] != TRUE)
	{
		if(GlobalTransformManipulator.data != NULL);
			free(GlobalTransformManipulator.data);
		if(GlobalTransformManipulator.normal != NULL);
		{
			free(GlobalTransformManipulator.manipulator_normal_array);
			free(GlobalTransformManipulator.normal);
		}
		if(GlobalTransformManipulator.tags != NULL)
		{
			free(GlobalTransformManipulator.tags);
			GlobalTransformManipulator.tags = NULL;
		}
		GlobalTransformManipulator.mode = TMM_IDLE;
	}
}

void grab_one_vertex(BInputState *input, uint id, double *pos)
{
    static int direction, recursion;
	static double *select;
    uint i, j;
    double delta[3], base[3];
    if(input->mouse_button[0] == TRUE && input->last_mouse_button[0] == FALSE)
    {
        direction = 1;
        recursion = 0;
        lock_transform_vertexes(input, FALSE, FALSE, FALSE);
        select = malloc((sizeof *select) * GlobalTransformManipulator.data_length);
        for(i = 0; i < GlobalTransformManipulator.data_length; i++)
            select[i] = 0;
        select[id] = 1;
    }
    delta[0] = pos[0] - GlobalTransformManipulator.data[id * 3];
    delta[1] = pos[1] - GlobalTransformManipulator.data[id * 3 + 1];
    delta[2] = pos[2] - GlobalTransformManipulator.data[id * 3 + 2];
    if(input->mouse_button[0] == FALSE && input->last_mouse_button[0] == TRUE)
    {
        for(i = 0; i < GlobalTransformManipulator.data_length; i++)
        {
            if(select[i] > 0.0001)
            {
                base[0] = GlobalTransformManipulator.data[i * 3];
                base[1] = GlobalTransformManipulator.data[i * 3 + 1];
                base[2] = GlobalTransformManipulator.data[i * 3 + 2];
                udg_vertex_set(i, base, base[0] + delta[0] * select[i], base[1] + delta[1] * select[i], base[2] + delta[2] * select[i]);
            }
        }

        free(select);
        free(GlobalTransformManipulator.data);
        return;
    }
    if(input->mouse_button[2] == FALSE && input->last_mouse_button[2] == TRUE)
    {
        recursion += direction;
        if(direction < 0)
            for(i = 0; i < GlobalTransformManipulator.data_length; i++)
                if(select[i] > 0.0001)
                    udg_vertex_move(i, GlobalTransformManipulator.data[i * 3], GlobalTransformManipulator.data[i * 3 + 1], GlobalTransformManipulator.data[i * 3 + 2]);
        if(recursion == 0 || recursion == 5)
            direction = 0 - direction;
        for(i = 0; i < GlobalTransformManipulator.data_length; i++)
            select[i] = 0;
        select[id] = 1;
        if(recursion != 0)
        {
            uint  *count, ref_count, *ref;
            double *value, temp;
            udg_get_geometry(NULL, &ref_count, NULL, &ref, NULL);
            ref_count *= 4;
            count = malloc((sizeof *count) * GlobalTransformManipulator.data_length);
            value = malloc((sizeof *value) * GlobalTransformManipulator.data_length);

            for(j = 0; j < recursion; j++)
            {
            	for(i = 0; i < GlobalTransformManipulator.data_length; i++)
                {
                    count[i] = 0;
                    value[i] = 0;
                }
                for(i = 0; i < ref_count; i += 4)
                {
                    if(ref[i] < GlobalTransformManipulator.data_length)
                    {
                        temp = select[ref[i]] + select[ref[i + 1]] + select[ref[i + 2]];
                        if(ref[i + 3] < GlobalTransformManipulator.data_length)
                            temp = (temp + select[ref[i + 3]]) / 4;
                        else
                            temp = temp / 3;
                        count[ref[i]]++;
                        value[ref[i]] += temp;
                        count[ref[i + 1]]++;
                        value[ref[i + 1]] += temp;
                        count[ref[i + 2]]++;
                        value[ref[i + 2]] += temp;
                        if(ref[i + 3] < GlobalTransformManipulator.data_length)
                        {
                            count[ref[i + 3]]++;
                            value[ref[i + 3]] += temp;
                        }
                    }
                }
                for(i = 0; i < GlobalTransformManipulator.data_length; i++)
					if(count[i] > 0)
	                    select[i] = value[i] / (double)count[i];
            }
            temp = 0;
            for(i = 0; i < GlobalTransformManipulator.data_length; i++)
                if(temp < select[i])
                    temp = select[i];
            for(i = 0; i < GlobalTransformManipulator.data_length; i++)
                select[i] = select[i] / temp;
/*		for(i = 0; i < GlobalTransformManipulator.data_length; i++)
			printf("select[%u] = %f\n", i, select[i]);
*/
            free(count);
            free(value);
        }
    }
    for(i = 0; i < GlobalTransformManipulator.data_length; i++)
        if(select[i] > 0.0001)
            udg_vertex_move(i, GlobalTransformManipulator.data[i * 3] + delta[0] * select[i],
			    GlobalTransformManipulator.data[i * 3 + 1] + delta[1] * select[i],
			    GlobalTransformManipulator.data[i * 3 + 2] + delta[2] * select[i]);
}


text:
#pragma once

#ifdef ENVOY_PERF_ANNOTATION

#include <chrono>
#include <cstdint>
#include <mutex>
#include <unordered_map>

#include "common/common/utility.h"

#include "absl/strings/string_view.h"

// Performance Annotation system, enabled with
//   bazel --define=perf_annotation=enabled ...
// or, in individual .cc files:
//   #define ENVOY_PERF_ANNOTATION
// In the absense of such directives, the support classes are built and tested.
// However, the macros for instrumenting code for performance analysis will expand
// to nothing.
//
// See also: https://github.com/LLNL/Caliper -- it may be worth integrating with
// that for added functionality, partiicularly around loops.
//
// See also, for a much more comprehensive study in performance annotation:
// https://labs.vmware.com/vmtj/methodology-for-performance-analysis-of-vmware-vsphere-under-tier-1-applications
// https://dl.acm.org/citation.cfm?id=1899945&dl=ACM&coll=DL

/**
 * Initiates a performance operation, storing its state in perf_var. A perf_var
 * can then be reported multiple times.
 */
#define PERF_OPERATION(perf_var) Envoy::PerfOperation(perf_var)

/**
 * Records performance data initiated with PERF_OPERATION. The category and description
 * are joined with in the library, but only if perf is enabled. This way, any concatenation
 * overhead is skipped when perf-annotation is disabled.
 */
#define PERF_RECORD(perf, category, description)                                                   \
  do {                                                                                \
    perf.record(category, description);                                                            \
  } while (false)

/**
 * Dumps recorded performance data to stdout. Expands to nothing if not enabled.
 */
#define PERF_DUMP() Envoy::PerfAnnotationContext::dump()

/**
 * Returns the aggregated performance data as a formatted multi-line string, showing a
 * formatted table of values. Returns "" if perf-annotation is disabled.
 */
#define PERF_TO_STRING() Envoy::PerfAnnotationContext::toString()

/**
 * Clears all performance data.
 */
#define PERF_CLEAR() Envoy::PerfAnnotationContext::clear()

/**
 * Controls whether performacne collection and reporting is thread safe. For now,
 * leaving this enabled for predictability across multiiple applications, on the assumption
 * that an uncontended mutex lock has vanishingly small cost. In the future we may try
 * to make this system thread-unsafe if mutext contention disturbs the metrics.
 */
#define PERF_THREAD_SAFE true

namespace Envoy {

/**
 * Defines a context for collecting performance data. Note that this class is
 * fully declared and defined even if ENVOY_PERF_AUTOMATION is off. We depend on
 * the macros to disable performance collection for production.
 */
class PerfAnnotationContext {
public:
  /**
   * Records time consumed by a category and description, which are shown as separate
   * columns in the generated output table.
   *
   * @param duration the duration.
   * @param category the name of a category for the recording.
   * @param description the name of description for the recording.
   */
  void record(std::chrono::nanoseconds duration, absl::string_view category,
              absl::string_view description);

  /**
   * Renders the aggregated statistics as a string.
   * @return std::string the performance data as a formatted string.
   */
  static std::string toString();

  /**
   * Dumps aggregated statistics (if any) to stdout.
   */
  static void dump();

  /**
   * Thread-safe lazy-initialization of a PerfAnnotationContext on first use.
   * @return PerfAnnotationContext* the context.
   */
  static PerfAnnotationContext* getOrCreate();

  /**
   * Clears out all aggregated statistics.
   */
  static void clear();

private:
  /**
   * PerfAnnotationContext construction should be done via getOrCreate().
   */
  PerfAnnotationContext();

  using CategoryDescription = std::pair<std::string, std::string>;

  struct DurationStats {
    std::chrono::nanoseconds total_{0};
    std::chrono::nanoseconds min_{0};
    std::chrono::nanoseconds max_{0};
    WelfordStandardDeviation stddev_;
  };

  struct Hash {
    size_t operator()(const CategoryDescription& a) const {
      return std::hash<std::string>()(a.first) + 13 * std::hash<std::string>()(a.second);
    }
  };

  using DurationStatsMap = std::unordered_map<CategoryDescription, DurationStats, Hash>;

  DurationStatsMap duration_stats_map_; // Maps {category, description} to DurationStats.
#if PERF_THREAD_SAFE
  std::mutex mutex_;
#endif
};

/**
 * Represents an operation for reporting timing to the perf system. Usage:
 *
 * f() {
 *   PerfOperation perf_op;
 *   computeIntensiveWork();
 *   perf_op.record("category", "description");
 * }
 */
class PerfOperation {
public:
  PerfOperation();

  /**
   * Report an event relative to the operation in progress. Note report can be called
   * multiple times on a single PerfOperation, with distinct category/description combinations.
   * @param category the name of a category for the recording.
   * @param description the name of description for the recording.
   */
  void record(absl::string_view category, absl::string_view description);

private:
  MonotonicTime start_time_;
  PerfAnnotationContext* context_;
};

} // namespace Envoy

#else

// Macros that expand to nothing when performance collection is disabled. These are contrived to
// work syntactically as a C++ statement (e.g. if (foo) PERF_RECORD(...) else PERF_RECORD(...)).

#define PERF_OPERATION(perf_var)                                                                   \
  do {                                                                                \
  } while (false)
#define PERF_RECORD(perf, category, description)                                                   \
  do {                                                                                \
  } while (false)
#define PERF_DUMP()                                                                                \
  do {                                                                                \
  } while (false)
#define PERF_TO_STRING() ""
#define PERF_CLEAR()                                                                               \
  do {                                                                                \
  } while (false)

#endif

redpajama_set_name: RedPajamaGithub


text:
extern "Java"
{
  namespace gnu
  {
    namespace java
    {
      namespace security
      {
        namespace prng
        {
            class IRandom;
        }
        namespace util
        {
            class PRNG;
        }
      }
    }
    namespace javax
    {
      namespace crypto
      {
        namespace key
        {
            class BaseKeyAgreementParty;
            class IncomingMessage;
            class OutgoingMessage;
        }
      }
    }
  }
  namespace java
  {
    namespace math
    {
        class BigInteger;
    }
    namespace security
    {
        class SecureRandom;
    }
  }
}

class gnu::javax::crypto::key::BaseKeyAgreementParty : public ::java::lang::Object
{

public: // actually protected
  BaseKeyAgreementParty(::java::lang::String *);
public:
  virtual ::java::lang::String * name();
  virtual void init(::java::util::Map *);
  virtual ::gnu::javax::crypto::key::OutgoingMessage * processMessage(::gnu::javax::crypto::key::IncomingMessage *);
  virtual jboolean isComplete();
  virtual JArray< jbyte > * getSharedSecret();
  virtual void reset();
public: // actually protected
  virtual void engineInit(::java::util::Map *) = 0;
  virtual ::gnu::javax::crypto::key::OutgoingMessage * engineProcessMessage(::gnu::javax::crypto::key::IncomingMessage *) = 0;
  virtual JArray< jbyte > * engineSharedSecret() = 0;
  virtual void engineReset() = 0;
  virtual void nextRandomBytes(JArray< jbyte > *);
private:
  ::gnu::java::security::util::PRNG * getDefaultPRNG();
public: // actually protected
  static ::java::math::BigInteger * TWO;
  ::java::lang::String * __attribute__((aligned(__alignof__( ::java::lang::Object)))) name__;
  jboolean initialised;
  jint step;
  jboolean complete;
  ::java::security::SecureRandom * rnd;
  ::gnu::java::security::prng::IRandom * irnd;
private:
  ::gnu::java::security::util::PRNG * prng;
public:
  static ::java::lang::Class class$;
};

#endif // __gnu_javax_crypto_key_BaseKeyAgreementParty__


text:
using System;
using System.Threading.Tasks;

namespace Tampleworks.WindowsApplicationBlock.Demo.ApplicationLogic.ReportGeneration
{
    /// <summary>
    /// Services report generation process for every organisation.
    /// </summary>
    public interface IReportGenerationAgent
    {
        Task<ReportGenerationStartResult> StartGenerationAsync(Guid organisationId, bool requireNonbreakingBehavior);
        ReportGenerationStateInfo GetStateAsync(Guid organisationId);
        void ResetCompleted(Guid organisationId);
        void CancelByUser(Guid organisationId);
    }
}


text:
<resources>
    <string name="app_name">ChineseCalendar</string>
</resources>


text:
#include <bitcoin/transaction_pool.hpp>

#include <bitcoin/error.hpp>
#include <bitcoin/transaction.hpp>
#include <bitcoin/validate.hpp>
#include <bitcoin/utility/assert.hpp>

namespace libbitcoin {

using std::placeholders::_1;
using std::placeholders::_2;
using std::placeholders::_3;
using std::placeholders::_4;

transaction_pool::transaction_pool(
    threadpool& pool, blockchain& chain)
  : strand_(pool), chain_(chain), pool_(2000)
{
}

void transaction_pool::set_capacity(size_t capacity)
{
    pool_.set_capacity(capacity);
}

void transaction_pool::start()
{
    chain_.subscribe_reorganize(
        std::bind(&transaction_pool::reorganize, this, _1, _2, _3, _4));
}

void transaction_pool::validate(const transaction_type& tx,
    validate_handler handle_validate)
{
    strand_.queue(&transaction_pool::do_validate,
        this, tx, handle_validate);
}
void transaction_pool::do_validate(const transaction_type& tx,
    validate_handler handle_validate)
{
    validate_transaction_ptr validate =
        std::make_shared<validate_transaction>(
            chain_, tx, pool_, strand_);
    validate->start(strand_.wrap(
        &transaction_pool::validation_complete,
            this, _1, _2, hash_transaction(tx), handle_validate));
}

void transaction_pool::validation_complete(
    const std::error_code& ec, const index_list& unconfirmed,
    const hash_digest& tx_hash, validate_handler handle_validate)
{
    if (ec == error::input_not_found || ec == error::validate_inputs_failed)
    {
        BITCOIN_ASSERT(unconfirmed.size() == 1);
        //BITCOIN_ASSERT(unconfirmed[0] < tx.inputs.size());
        handle_validate(ec, unconfirmed);
    }
    else if (ec)
    {
        BITCOIN_ASSERT(unconfirmed.empty());
        handle_validate(ec, index_list());
    }
    // Re-check as another transaction might've been added in the interim
    else if (tx_exists(tx_hash))
    {
        handle_validate(error::duplicate, index_list());
    }
    else
    {
        handle_validate(std::error_code(), unconfirmed);
    }
}

bool transaction_pool::tx_exists(const hash_digest& tx_hash)
{
    for (const transaction_entry_info& entry: pool_)
        if (entry.hash == tx_hash)
            return true;
    return false;
}

void transaction_pool::store(const transaction_type& tx,
    confirm_handler handle_confirm, validate_handler handle_validate)
{
    auto perform_store = [this, tx, handle_confirm]
    {
        // When new tx are added to the circular buffer,
        // any tx at the front will be droppped.
        // We notify the API user of this through the handler.
        if (pool_.size() == pool_.capacity())
        {
            auto handle_confirm = pool_.front().handle_confirm;
            handle_confirm(error::pool_filled);
        }
        // We store a precomputed tx hash to make lookups faster.
        pool_.push_back(
            {hash_transaction(tx), tx, handle_confirm});
    };
    auto wrap_handle_validate = [perform_store, handle_validate](
        const std::error_code& ec, const index_list& unconfirmed)
    {
        if (!ec)
            perform_store();
        handle_validate(ec, unconfirmed);
    };
    validate(tx, wrap_handle_validate);
}

void transaction_pool::fetch(const hash_digest& transaction_hash,
    fetch_handler handle_fetch)
{
    strand_.queue(
        [this, transaction_hash, handle_fetch]()
        {
            for (const transaction_entry_info& entry: pool_)
                if (entry.hash == transaction_hash)
                {
                    handle_fetch(std::error_code(), entry.tx);
                    return;
                }
            handle_fetch(error::not_found, transaction_type());
        });
}

void transaction_pool::exists(const hash_digest& transaction_hash,
    exists_handler handle_exists)
{
    strand_.queue(
        [this, transaction_hash, handle_exists]()
        {
            handle_exists(tx_exists(transaction_hash));
        });
}

void transaction_pool::reorganize(const std::error_code& ec,
    size_t /* fork_point */,
    const blockchain::block_list& new_blocks,
    const blockchain::block_list& replaced_blocks)
{
    if (ec)
    {
        BITCOIN_ASSERT(ec == error::service_stopped);
        return;
    }
    if (!replaced_blocks.empty())
        strand_.queue(&transaction_pool::invalidate_pool, this);
    else
        strand_.queue(&transaction_pool::takeout_confirmed, this, new_blocks);
    // new blocks come in - remove txs in new
    // old blocks taken out - resubmit txs in old
    chain_.subscribe_reorganize(
        std::bind(&transaction_pool::reorganize, this, _1, _2, _3, _4));
}

void transaction_pool::invalidate_pool()
{
    // See http://www.jwz.org/doc/worse-is-better.html
    // for why we take this approach.
    // We return with an error_code and don't handle this case.
    for (const transaction_entry_info& entry: pool_)
        entry.handle_confirm(error::blockchain_reorganized);
    pool_.clear();
}

void transaction_pool::takeout_confirmed(
    const blockchain::block_list& new_blocks)
{
    for (auto new_block: new_blocks)
        for (const transaction_type& new_tx: new_block->transactions)
            try_delete(hash_transaction(new_tx));
}
void transaction_pool::try_delete(const hash_digest& tx_hash)
{
    for (auto it = pool_.begin(); it != pool_.end(); ++it)
        if (it->hash == tx_hash)
        {
            auto handle_confirm = it->handle_confirm;
            pool_.erase(it);
            handle_confirm(std::error_code());
            return;
        }
}

} // namespace libbitcoin


text:
import sys
from typing import Any, AsyncIterable, Callable, Dict, Optional, TypeVar
import urllib.parse

from azure.core.async_paging import AsyncItemPaged, AsyncList
from azure.core.exceptions import (
    ClientAuthenticationError,
    HttpResponseError,
    ResourceExistsError,
    ResourceNotFoundError,
    ResourceNotModifiedError,
    map_error,
)
from azure.core.pipeline import PipelineResponse
from azure.core.pipeline.transport import AsyncHttpResponse
from azure.core.rest import HttpRequest
from azure.core.tracing.decorator import distributed_trace
from azure.core.tracing.decorator_async import distributed_trace_async
from azure.core.utils import case_insensitive_dict
from azure.mgmt.core.exceptions import ARMErrorFormat

from ... import models as _models
from ..._vendor import _convert_request
from ...operations._image_versions_operations import build_get_request, build_list_by_image_request

if sys.version_info >= (3, 8):
    from typing import Literal  # pylint: disable=no-name-in-module, ungrouped-imports
else:
    from typing_extensions import Literal  # type: ignore  # pylint: disable=ungrouped-imports
T = TypeVar("T")
ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]]

class ImageVersionsOperations:
    """
    .. warning::
        **DO NOT** instantiate this class directly.

        Instead, you should access the following operations through
        :class:`~azure.mgmt.devcenter.aio.DevCenterMgmtClient`'s
        :attr:`image_versions` attribute.
    """

    models = _models

    def __init__(self, *args, **kwargs) -> None:
        input_args = list(args)
        self._client = input_args.pop(0) if input_args else kwargs.pop("client")
        self._config = input_args.pop(0) if input_args else kwargs.pop("config")
        self._serialize = input_args.pop(0) if input_args else kwargs.pop("serializer")
        self._deserialize = input_args.pop(0) if input_args else kwargs.pop("deserializer")

    @distributed_trace
    def list_by_image(
        self, resource_group_name: str, dev_center_name: str, gallery_name: str, image_name: str, **kwargs: Any
    ) -> AsyncIterable["_models.ImageVersion"]:
        """Lists versions for an image.

        :param resource_group_name: The name of the resource group. The name is case insensitive.
         Required.
        :type resource_group_name: str
        :param dev_center_name: The name of the devcenter. Required.
        :type dev_center_name: str
        :param gallery_name: The name of the gallery. Required.
        :type gallery_name: str
        :param image_name: The name of the image. Required.
        :type image_name: str
        :keyword callable cls: A custom type or function that will be passed the direct response
        :return: An iterator like instance of either ImageVersion or the result of cls(response)
        :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.mgmt.devcenter.models.ImageVersion]
        :raises ~azure.core.exceptions.HttpResponseError:
        """
        _headers = kwargs.pop("headers", {}) or {}
        _params = case_insensitive_dict(kwargs.pop("params", {}) or {})

        api_version = kwargs.pop(
            "api_version", _params.pop("api-version", self._config.api_version)
        )  # type: Literal["2022-11-11-preview"]
        cls = kwargs.pop("cls", None)  # type: ClsType[_models.ImageVersionListResult]

        error_map = {
            401: ClientAuthenticationError,
            404: ResourceNotFoundError,
            409: ResourceExistsError,
            304: ResourceNotModifiedError,
        }
        error_map.update(kwargs.pop("error_map", {}) or {})

        def prepare_request(next_link=None):
            if not next_link:

                request = build_list_by_image_request(
                    resource_group_name=resource_group_name,
                    dev_center_name=dev_center_name,
                    gallery_name=gallery_name,
                    image_name=image_name,
                    subscription_id=self._config.subscription_id,
                    api_version=api_version,
                    template_url=self.list_by_image.metadata["url"],
                    headers=_headers,
                    params=_params,
                )
                request = _convert_request(request)
                request.url = self._client.format_url(request.url)  # type: ignore

            else:
                # make call to next link with the client's api-version
                _parsed_next_link = urllib.parse.urlparse(next_link)
                _next_request_params = case_insensitive_dict(
                    {
                        key: [urllib.parse.quote(v) for v in value]
                        for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items()
                    }
                )
                _next_request_params["api-version"] = self._config.api_version
                request = HttpRequest(
                    "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params
                )
                request = _convert_request(request)
                request.url = self._client.format_url(request.url)  # type: ignore
                request.method = "GET"
            return request

        async def extract_data(pipeline_response):
            deserialized = self._deserialize("ImageVersionListResult", pipeline_response)
            list_of_elem = deserialized.value
            if cls:
                list_of_elem = cls(list_of_elem)
            return deserialized.next_link or None, AsyncList(list_of_elem)

        async def get_next(next_link=None):
            request = prepare_request(next_link)

            pipeline_response = await self._client._pipeline.run(  # type: ignore # pylint: disable=protected-access
                request, stream=False, **kwargs
            )
            response = pipeline_response.http_response

            if response.status_code not in [200]:
                map_error(status_code=response.status_code, response=response, error_map=error_map)
                raise HttpResponseError(response=response, error_format=ARMErrorFormat)

            return pipeline_response

        return AsyncItemPaged(get_next, extract_data)

    list_by_image.metadata = {"url": "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DevCenter/devcenters/{devCenterName}/galleries/{galleryName}/images/{imageName}/versions"}  # type: ignore

    @distributed_trace_async
    async def get(
        self,
        resource_group_name: str,
        dev_center_name: str,
        gallery_name: str,
        image_name: str,
        version_name: str,
        **kwargs: Any
    ) -> _models.ImageVersion:
        """Gets an image version.

        :param resource_group_name: The name of the resource group. The name is case insensitive.
         Required.
        :type resource_group_name: str
        :param dev_center_name: The name of the devcenter. Required.
        :type dev_center_name: str
        :param gallery_name: The name of the gallery. Required.
        :type gallery_name: str
        :param image_name: The name of the image. Required.
        :type image_name: str
        :param version_name: The version of the image. Required.
        :type version_name: str
        :keyword callable cls: A custom type or function that will be passed the direct response
        :return: ImageVersion or the result of cls(response)
        :rtype: ~azure.mgmt.devcenter.models.ImageVersion
        :raises ~azure.core.exceptions.HttpResponseError:
        """
        error_map = {
            401: ClientAuthenticationError,
            404: ResourceNotFoundError,
            409: ResourceExistsError,
            304: ResourceNotModifiedError,
        }
        error_map.update(kwargs.pop("error_map", {}) or {})

        _headers = kwargs.pop("headers", {}) or {}
        _params = case_insensitive_dict(kwargs.pop("params", {}) or {})

        api_version = kwargs.pop(
            "api_version", _params.pop("api-version", self._config.api_version)
        )  # type: Literal["2022-11-11-preview"]
        cls = kwargs.pop("cls", None)  # type: ClsType[_models.ImageVersion]

        request = build_get_request(
            resource_group_name=resource_group_name,
            dev_center_name=dev_center_name,
            gallery_name=gallery_name,
            image_name=image_name,
            version_name=version_name,
            subscription_id=self._config.subscription_id,
            api_version=api_version,
            template_url=self.get.metadata["url"],
            headers=_headers,
            params=_params,
        )
        request = _convert_request(request)
        request.url = self._client.format_url(request.url)  # type: ignore

        pipeline_response = await self._client._pipeline.run(  # type: ignore # pylint: disable=protected-access
            request, stream=False, **kwargs
        )

        response = pipeline_response.http_response

        if response.status_code not in [200]:
            map_error(status_code=response.status_code, response=response, error_map=error_map)
            raise HttpResponseError(response=response, error_format=ARMErrorFormat)

        deserialized = self._deserialize("ImageVersion", pipeline_response)

        if cls:
            return cls(pipeline_response, deserialized, {})

        return deserialized

    get.metadata = {"url": "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DevCenter/devcenters/{devCenterName}/galleries/{galleryName}/images/{imageName}/versions/{versionName}"}  # type: ignore


text:
package org.apache.parquet.column;

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

import static org.apache.parquet.column.Encoding.PLAIN_DICTIONARY;
import static org.apache.parquet.column.Encoding.RLE_DICTIONARY;

/**
 * EncodingStats track dictionary and data page encodings for a single column within a row group.
 * These are used when filtering row groups. For example, to filter a row group based on a column's
 * dictionary, all of the data pages in that column must be dictionary-encoded. This class provides
 * convenience methods for those checks, like {@link #hasNonDictionaryEncodedPages()}.
 */
public class EncodingStats {
  final Map<Encoding, Number> dictStats;
  final Map<Encoding, Number> dataStats;
  private final boolean usesV2Pages;

  private EncodingStats(Map<Encoding, Number> dictStats,
                        Map<Encoding, Number> dataStats,
                        boolean usesV2Pages) {
    this.dictStats = dictStats;
    this.dataStats = dataStats;
    this.usesV2Pages = usesV2Pages;
  }

  public Set<Encoding> getDictionaryEncodings() {
    return dictStats.keySet();
  }

  public Set<Encoding> getDataEncodings() {
    return dataStats.keySet();
  }

  public int getNumDictionaryPagesEncodedAs(Encoding enc) {
    final Number pageCount = dictStats.get(enc);
    return (pageCount == null) ? 0 : pageCount.intValue();
  }

  public int getNumDataPagesEncodedAs(Encoding enc) {
    final Number pageCount = dataStats.get(enc);
    return (pageCount == null) ? 0 : pageCount.intValue();
  }

  public boolean hasDictionaryPages() {
    return !dictStats.isEmpty();
  }

  public boolean hasDictionaryEncodedPages() {
    Set<Encoding> encodings = dataStats.keySet();
    return (encodings.contains(RLE_DICTIONARY) || encodings.contains(PLAIN_DICTIONARY));
  }

  public boolean hasNonDictionaryEncodedPages() {
    if (dataStats.isEmpty()) {
      return false; // no pages
    }

    // this modifies the set, so copy it
    Set<Encoding> encodings = new HashSet<>(dataStats.keySet());
    if (!encodings.remove(RLE_DICTIONARY) &&
        !encodings.remove(PLAIN_DICTIONARY)) {
      return true; // not dictionary encoded
    }

    if (encodings.isEmpty()) {
      return false;
    }

    // at least one non-dictionary encoding is present
    return true;
  }

  public boolean usesV2Pages() {
    return usesV2Pages;
  }

  /**
   * Used to build {@link EncodingStats} from metadata or to accumulate stats as pages are written.
   */
  public static class Builder {
    private final Map<Encoding, AtomicInteger> dictStats = new LinkedHashMap<>();
    private final Map<Encoding, AtomicInteger> dataStats = new LinkedHashMap<>();
    private boolean usesV2Pages = false;

    public Builder clear() {
      this.usesV2Pages = false;
      dictStats.clear();
      dataStats.clear();
      return this;
    }

    public Builder withV2Pages() {
      this.usesV2Pages = true;
      return this;
    }

    public Builder addDictEncoding(Encoding encoding) {
      return addDictEncoding(encoding, 1);
    }

    public Builder addDictEncoding(Encoding encoding, int numPages) {
      dictStats.computeIfAbsent(encoding, enc -> new AtomicInteger(0))
          .addAndGet(numPages);
      return this;
    }

    public Builder addDataEncodings(Collection<Encoding> encodings) {
      for (Encoding encoding : encodings) {
        addDataEncoding(encoding);
      }
      return this;
    }

    public Builder addDataEncoding(Encoding encoding) {
      return addDataEncoding(encoding, 1);
    }

    public Builder addDataEncoding(Encoding encoding, int numPages) {
      dataStats.computeIfAbsent(encoding, enc -> new AtomicInteger(0))
      .addAndGet(numPages);
      return this;
    }

    public EncodingStats build() {
      return new EncodingStats(
          Collections.unmodifiableMap(new LinkedHashMap<>(dictStats)),
          Collections.unmodifiableMap(new LinkedHashMap<>(dataStats)),
          usesV2Pages);
    }
  }
}


text:
package org.hisp.dhis.sms.config;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlElements;

import com.fasterxml.jackson.annotation.JsonProperty;

/**
 * Serializable configuration object for Sms.
 */

@XmlRootElement( name = "smsConfiguration" )
public class SmsConfiguration
    implements Serializable
{
    private static final long serialVersionUID = 7460688383539123303L;

    private List<SmsGatewayConfig> gateways = new ArrayList<>();

    // -------------------------------------------------------------------------
    // Constructors
    // -------------------------------------------------------------------------

    public SmsConfiguration()
    {
        this.gateways = new ArrayList<>();
    }

    public SmsConfiguration( boolean enabled )
    {
        this.gateways = new ArrayList<>();
    }

    // -------------------------------------------------------------------------
    // Getter && Setter
    // -------------------------------------------------------------------------

    @JsonProperty( value = "gateways" )
    @XmlElementWrapper( name = "gateways" )
    @XmlElements( { @XmlElement( name = "bulksms", type = BulkSmsGatewayConfig.class ),
        @XmlElement( name = "clickatell", type = ClickatellGatewayConfig.class ),
        @XmlElement( name = "http", type = GenericHttpGatewayConfig.class ) })
    public List<SmsGatewayConfig> getGateways()
    {
        return gateways;
    }

    public void setGateways( List<SmsGatewayConfig> gateways )
    {
        this.gateways = gateways;
    }
}


text:
package jenkins.plugins.gitbuilddata;

import hudson.Extension;
import hudson.model.Action;
import hudson.model.TransientProjectActionFactory;
import hudson.model.AbstractProject;

import java.util.Collection;
import java.util.Collections;

/**
 * Factory for {@link BuiltBranchesProjectAction}.
 *
 * @author Bernard MIEGEMOLLE
 * @version 1.0
 * @since 1.0
 */
@Extension
public class BuiltBranchesProjectActionFactory extends TransientProjectActionFactory {

    @Override
    public Collection<? extends Action> createFor(AbstractProject target) {
        return Collections.singleton(new BuiltBranchesProjectAction(target));
    }

}


text:
package org.apache.accumulo.core.trace;

import java.util.Collection;

import org.apache.accumulo.trace.thrift.RemoteSpan;

public interface SpanTreeVisitor {
  void visit(int level, RemoteSpan parent, RemoteSpan node, Collection<RemoteSpan> children);
}


text:
clear
echo "Installing all Sketch Plugins onto your Mac"
echo "Downloading the sketch plugins..."
cd ~/Documents/
curl -L https://github.com/paulfarino/Sketch-Shell/tarball/master -o master.tar.gz
echo "Extracting the plugins..."
mkdir -p sketch-plugins/plugins
tar -zxf master.tar.gz -C sketch-plugins/plugins
cd sketch-plugins
cd plugins
cd *
rm -rf LICENSE
rm -rf README.md
rm -rf sketch-plugins.sh
rm -rf sketch-plugins-voice.sh
cd ..
mv */* ~/Library/Containers/com.bohemiancoding.sketch/Data/Library/Application Support/sketch/Plugins

echo "Plugins installed; Cleaning up files..."
cd ~/Documents/
rm -f master.tar.gz
rm -rf sketch-plugins
echo "All done! All Sketch Plugins installed."