Looking for mouse picking code/example in GLM?

Started by
5 comments, last by _WeirdCat_ 7 years, 2 months ago

I'm creating a 3D windows and GUI implimentation and have clipping done nicely, but now need mouse picking in GLM vector library?

I will need the world position of the end of the pick ray so can use for a virtual mouse pointer.

Any help?

Thanks.

gui.jpg

Advertisement


inline vec3 GetDirectionFromScreen(mat4 modelview, TSpecCamera * FPP_CAM,  int x, int y, int sw, int sh, float fov, float z_near, float z_far)
{


mat4 mvm = modelview;
mvm.Transpose();
vec3 dirX, dirY;
dirX.x = mvm.m[0];
dirX.y = mvm.m[4];
dirX.z = mvm.m[8];


dirY.x = mvm.m[1];
dirY.y = mvm.m[5];
dirY.z = mvm.m[9];


float aspect = float(SCREEN_WIDTH) / float(SCREEN_HEIGHT);
float a = fov / 2.0;
float cotangent = 1.0 / tan( a * imopi );


float ax = z_near / cotangent;


float screen_w = 2.0*ax;


float screen_h = screen_w;// * yratio;


screen_w = screen_w * aspect;


float scr_coord_x = float(x) / float(sw);
float scr_coord_y = float(sh - y) / float(sh);




vec3 dir = FPP_CAM->ReturnFrontVector();


//move to lower left corner
vec3 start_pos = (FPP_CAM->pos + dir * z_near) + (-dirX * (screen_w / 2.0)) + (-dirY * (screen_h/2.0));


vec3 start = start_pos + (dirX * (screen_w * scr_coord_x)) + (dirY * (screen_h * scr_coord_y));


return Normalize( vectorAB(FPP_CAM->pos, start) );
}




usage


mvm.Transpose(); is called because code uses old opengl style matrix.


vec3 rdir = GetDirectionFromScreen(ACTUAL_MODEL * ACTUAL_VIEW, FPP_CAM, CursorX, CursorY, SCREEN_WIDTH, SCREEN_HEIGHT, 90.0, 0.1, 1000.0);


cursor XY is window coordinate cursor pos


FPP_CAM->pos is eye position
FPP_CAM->ReturnFrontVector() is a normalized vector where eye looks at (can get it from modelview matrix)




float scr_coord_y = float(sh - y) / float(sh); can be tricky

actually model matrix is always identity and should be always identity so its not modelview matrix but view mat

so finally


vec3 ray_end = eye_pos /*(FPP_CAM->pos)*/ + rdir*some_const_let_it_be_z_far;

Ill give it a try, thanks!


How can I make some_const_let_it_be_z_far; always be flat along my 3D window? for the mouse pointer.

I'm using a mat4 for the position and rotation of the window in the world.

Thinking about it I don't require a ray, just need to position the cursor in front of the window and move it parallel to it using the real mouse cursor x and y.. Easy.

Thanks though.

Then again I will be implementing models popping out the window and need to select them so Ill need full mouse picking with vertices, though I will need the world position of the hit, may as well use bullet physics library for it, why reinvent the wheel?

something like this:

pick closest object. each object

wont even cut code and explain, here you have findobjectbyray function that goes through all objects (but befiore that each object has its own bounding box to speedup collision check due to many models have way too many vertices)

[spoiler]


#ifndef terra_obj_insH
#define terra_obj_insH
#include "glwrapper.h"
#include "DxcMath.h"
#include "sim/mission.h"
#include "drop_menu.h"
#include "Spectator.h"
#include "glhelper.h"
#include "Editor/objins_forms/obj_prop.h"
#include "Editor/objins_forms/namebrief_form.h"
#include "Editor/objins_forms/condition_form.h"
#include "Editor/objins_forms/light_prop.h"
#include "Editor/objins_forms/trigger_form.h"
#include "Editor/objins_forms/aihuman_form.h"
#include "sim/game/game_init.h"
#include "editor_shared_data.h"
#include "const_vars.h"
struct TLineVertex
{
	vec3 v;
	vec3 c;
};

const int ROT_OSD_PITCH_UP 		= 0;
const int ROT_OSD_PITCH_DOWN 	= 1;

const int ROT_OSD_YAW_UP 		= 2;
const int ROT_OSD_YAW_DOWN 		= 3;

const int ROT_OSD_ROLL_UP 		= 4;
const int ROT_OSD_ROLL_DOWN 	= 5;

struct TGLEditorColStack
{
vec3 v;
int index;
TGLEditorColStack& operator=(const TGLEditorColStack& in)
{
v 		= in.v;
index 	= in.index;
}

};

struct TOBJINS_OSD
{

	bool isModal()
	{
		return !((!mission_brief_form.visible) 	&&
				(!condition_form.visible) 		&&
				(!object_property_editor.visible) &&
				(!light_property_editor.visible) &&
				(!FileMenu.unfolded) &&
				(!InsertMenu.unfolded) &&
				(!EditMenu.unfolded) &&
				(!GridMenu.unfolded) &&
				(!AIHUMAN_property_editor.visible) );
	}

	TOSD rot_osd;

	TObjectPropertyEditor object_property_editor;
	TLightPropertyEditor light_property_editor;
	TAIHumanPropertyEditor AIHUMAN_property_editor;
	TDropDownMenu FileMenu; //new, open, save, propereties>Brief, name, level, time, day, weather    / switch edit mode: <terrain, texture ed>, Exit
	TDropDownMenu InsertMenu;//Buildings, Flora, Misc <- everything opens opendialog and lists proper directory
	TDropDownMenu EditMenu;//Translate, Rotate, Edit info
	TDropDownMenu GridMenu;

	TNameInputPanel SaveDialog1;
	TFileExplorer OpenDialog1;
	TMission  * mission;
	bool initialized;
	TEntityType insert_type;

	TSpecCamera * FPP_CAM;
float grid_size;
void Insert(vec3 aposition, AnsiString fname)
{
ALOG("INSERTING: "+fname);
vec3 position = SnapToGrid(aposition, grid_size);

AObject ahue;
ahue.LoadObject(fname, false, true);
int index = find_object_index(ahue.lname, 32);
if (index < 0) { ALOG("ERROR ERROR object not found ffs"); return; }
AObject * p = OBJECT_LIST.container[ index ];

//temp_arr_object[mission->object_len].object = p;


TEntity * last_o = mission->FindLastObject();
TEntity * new_entity = new TEntity();
new_entity->testfname = fname;

new_entity->object = p;

for (int i=0; i < 32; i++)
{
	new_entity->caption[i] 	= ahue.caption[i];
	new_entity->lname[i] 	= ahue.lname[i];
}

new_entity->namelen = ahue.namelen;

new_entity->hp			= ahue.default_hp;
new_entity->type		= insert_type;
new_entity->pos 		= position;
new_entity->old 		= position;

if (!OBJECT_LIST.container[ index ]->preloaded) //load model if not loaded yet
{
OBJECT_LIST.container[ index ]->LoadObject(fname, true, false);
GetAllObjectsAABB();
}



/*
 * Dependant on object type fillin additional data (ex. fog -> set default size for fog box etc)
 */

if (insert_type == etLight)
{
	//radius
new_entity->info2[0] = 10.0;
//color
new_entity->info2[1] = 1.0;
new_entity->info2[2] = 0.0;
new_entity->info2[3] = 0.0;
}


if (insert_type == etFog)
{
	//color
new_entity->info2[0] = 1.0;
new_entity->info2[1] = 1.0;
new_entity->info2[2] = 1.0;
}


if (insert_type == etWaypoint)
{
	//range of contact
new_entity->info2[0] = 20.0;
}


if (insert_type == etFire)
{
	//color
new_entity->info2[0] = 1.0;
new_entity->info2[1] = 0.5;
new_entity->info2[2] = 0.0;
}


(*insert_mode) = false;
ClearSelection();
mission->AddObject(new_entity);
//mission->object_len = mission->object_len + 1;
sel_len = 1;
selection = new int[1];
selection[0] = mission->FindLastObject()->PID;

}



int * selection;
int sel_len;
vec3 * sel_pos;
vec3 rotation_center;
vec3 rotation_first_pos;
vec3 rotation_second_pos;


TTriggerPropertyEditor trigger_editor;

void EditObjectPropereties()
{
	if ( (sel_len == 0) || (sel_len > 1) ) { PUSH_EVENT("PLEASE SELECT ONE OBJECT ONLY"); return; }

	if (mission->ObjectByPID(selection[0])->type == etLight)
	{
		light_property_editor.apply_to = mission->ObjectByPID(selection[0]);
		light_property_editor.Show();
		return;
	}

	if (mission->ObjectByPID(selection[0])->type == etTrigger)
	{
	trigger_editor.apply_to = mission->ObjectByPID(selection[0]);
	trigger_editor.Show();
	return;
	}

	if (mission->ObjectByPID(selection[0])->type == etPerson)
	{
		AIHUMAN_property_editor.apply_to = mission->ObjectByPID(selection[0]);
		AIHUMAN_property_editor.Show();
		return;
	}

	object_property_editor.apply_to = mission->ObjectByPID(selection[0]);
	object_property_editor.Show();
}

void ClearSelection()
{
if (selection != NULL)
delete [] selection;
selection = NULL;
sel_len = 0;
}

int IsInTable(int * p, int len, int search_for)
{
	for (int i=0; i < len; i++)
		if (search_for == p[i]) return i;
	return -1;
}

void DeleteSelection()
{
if (sel_len == 0) return;

	for (int i=0; i < sel_len; i++)
		mission->DeleteByPID(selection[i]);

mission->object_len = mission->object_len - sel_len;
}

void Select(int index)
{
	PUSH_EVENT("TRYING TO SELECT: "+IntToStr(index));
	bool found = false;
	//check if we already selected that model then unselect it

	for (int i=0; i < sel_len; i++)
if (index == selection[i]) found = true;

int num = 1;
if (found) num = -1;
int * tmp = new int [ sel_len + num ];

int cnt = -1;
for (int i=0; i < sel_len; i++)
	if (index != selection[i])
	{
	cnt = cnt + 1;
	tmp[cnt] = selection[i];
	}


if (found == false)
tmp[sel_len] = index;

sel_len = sel_len + num;

if (selection != NULL)
delete [] selection;
selection = NULL;
selection = tmp;
}


//float getBiggestDimensionOutOfSelection()
//{
	/*
	 * first compute AABB (bounding box) of selected models
	 * To do that find minimal x,y,z and maximal x,y,z
	 */
//	vec3 min = vec3(99999.9, 99999.9, 99999.9);
//	vec3 max = vec3(-99999.9, -99999.9, -99999.9);
//	for (int i=0; i < sel_len; i++)
//	{
//		vec3 local_min = mission->object[ selection[i] ].getMin();
//		vec3 local_max = mission->object[ selection[i] ].getMax();
//		if (min.x > local_min.x) min.x = local_min.x;
//		if (min.y > local_min.y) min.y = local_min.y;
//		if (min.z > local_min.z) min.z = local_min.z;
//
//		if (max.x < local_max.x) max.x = local_max.x;
//		if (max.y < local_max.y) max.y = local_max.y;
//		if (max.z < local_max.z) max.z = local_max.z;
//	}
//
//
//	vec3 dst = absvf(max - min);
//	return maxfa(maxfa(dst.x,dst.y),dst.z);
//}

vec3 getSelectionCenter()
{
	vec3 rc;
	for (int i=0; i < sel_len; i++)
	{
		TEntity * p = mission->ObjectByPID(selection[i]);
		rc = rc + p->pos;
	}

return rc / float(sel_len);
}

typrNota rotation_mat;
bool update_rotate;
void EnableRotationMode()
{
	rotation_mat.reset();
	StoreTranslation();
	rotation_center = getSelectionCenter();

	request_switch_mode = true;
	switch_to = rotation_mode;
//	PUSH_EVENT("ROTATION MODE ENABLED");
//	first_run = true;

}

void EnableSelectMode()
{
	if (!select_mode)
	{
//		PUSH_EVENT("SELECT MODE ENABLED");
		request_switch_mode = true;
		switch_to = &select_mode;
	(*insert_mode) = true;
	} else
		{
//		PUSH_EVENT("SELECT MODE DISABLED");
DisableAllModes();
		(*insert_mode) 	= false;
		select_mode 	= false;
		}
}


void StoreTranslation()
{
if (sel_pos != NULL) delete [] sel_pos;
sel_pos = new vec3[ sel_len ];

for (int i=0; i < sel_len; i++)
{
	TEntity * p = mission->ObjectByPID(selection[i]);
	sel_pos[i] = p->pos;
}

}

vec3 translation_pos;
vec3 translation_facenormal;
float translation_facedist;
vec3 translation_center;

void BeginTranslationMode(vec3 rA, vec3 rB)
{
	if (sel_len == 0) { PUSH_EVENT("NOTHING SELECTED ABORTING"); return; }

	translation_center = vec3(0.0, 0.0, 0.0);
	for (int i=0; i < sel_len; i++)
	{
		TEntity * p = mission->ObjectByPID(selection[i]);
		translation_center = translation_center + p->pos;
	}
	translation_center = translation_center / float(sel_len);
	StoreTranslation();
	vec3 objn = -FPP_CAM->ReturnFrontVector();

	TEntity * p = mission->ObjectByPID(selection[0]);
	if (!SegmentPlaneIntersection(objn, getplaneD(objn, translation_center), rA, rA+Normalize(vectorAB(rA,rB))*9999.0, translation_pos))
	{
	PUSH_EVENT("Well that was unexpected...");
	return;
	}
/*
	vec3 center;
	for (int i=0; i < sel_len; i++)
	{
		TEntity * p = mission->ObjectByPID(selection[i]);
		center = center + p->pos;
	}
	center = center / float(sel_len);

	translation_pos = center;
	StoreTranslation();
	GetTranslationMatrix(ACTUAL_MODEL * ACTUAL_VIEW);

	switch_to = translation_mode;
	request_switch_mode = true;
//	PUSH_EVENT("ROTATION MODE ENABLED");
	first_run = true;
	(*insert_mode) = true;
*/
}


void EnableResizeColboxMode()
{
	switch_to = &colbox_resize_mode;
	request_switch_mode = true;


	request_resize_colbox = true;
	first_run = true;
//	(*insert_mode) = true;
}
void EnableInsertMode()
{

	switch_to = insert_mode;
	request_switch_mode = true;
//	PUSH_EVENT("Insert mode enabled");
}

vec3 BillboardX;
vec3 BillboardY;
void GetTranslationMatrix(mat4 ModelViewMatrix)
{
	mat4 mvm = ModelViewMatrix;
	mvm.Transpose();

BillboardX.x = mvm.m[0];
BillboardX.y = mvm.m[4];
BillboardX.z = mvm.m[8];

BillboardY.x =	mvm.m[1];
BillboardY.y =	mvm.m[5];
BillboardY.z =	mvm.m[9];

translation_facenormal = Normalize(vectorcross(BillboardX * 1000.0, BillboardY * 1000.0));


translation_facedist = -dot(translation_facenormal, translation_pos);

}

void TranslateSelected(vec3 rA, vec3 rB)
{
vec3 sec_col;
	vec3 objn = -FPP_CAM->ReturnFrontVector();

	TEntity * p = mission->ObjectByPID(selection[0]);
	if (!SegmentPlaneIntersection(objn, getplaneD(objn, translation_center), rA, rA+Normalize(vectorAB(rA,rB))*9999.0, sec_col))
	{
	PUSH_EVENT("Well that was unexpected...");
	return;
	}


	vec3 t = vectorAB(translation_pos, sec_col);
	for (int i=0; i < sel_len; i++)
	{
		TEntity * p = mission->ObjectByPID(selection[i]);
		p->pos = sel_pos[i] + t;
		p->pos = SnapToGrid(p->pos, grid_size);
	}
	/*
	vec3 t = vectorAB(translation_pos, GetPointOnPlaneFromRay(translation_facenormal,translation_facedist, rA, rB));


	for (int i=0; i < sel_len; i++)
	{
		TEntity * p = mission->ObjectByPID(selection[i]);
		p->pos = sel_pos[i] + t;
	}
	*/
//	PUSH_EVENT("TRANSLATING BY: "+POINT_TO_TEXT(t));

}

	void InsertInfoNull()
	{
		insert_type = etInfoNull;
		EnableInsertMode();
	}

	void InsertModel()
		{
		OpenDialog1.basedir = appdir+"objects/";
		OpenDialog1.mask = ".tga";
		OpenDialog1.ListFiles(appdir+"objects/");
		OpenDialog1.visible = true;
		insert_type = etModel;
		EnableInsertMode();
		}


	void InsertLight()
	{
		insert_type = etLight;
		EnableInsertMode();
	}

	void InsertTornado()
	{
	insert_type = etTornado;
	EnableInsertMode();
	}

	void InsertFog()
	{
	insert_type = etFog;
	EnableInsertMode();
	}

	void InsertTrigger()
	{
		insert_type = etTrigger;
		EnableInsertMode();
	}

	void InsertWaypoint()
	{
		insert_type = etWaypoint;
		EnableInsertMode();
	}

	void InsertFire()
	{
	insert_type = etFire;
	EnableInsertMode();
	}

	void InsertPlayerSpawn()
	{
	insert_type = etPlayerSpawn;
	EnableInsertMode();
	}

	void BrowseBuildings()
	{
		OpenDialog1.basedir = appdir+"objects/buildings/";
		OpenDialog1.mask = ".tga";
		OpenDialog1.ListFiles(appdir+"objects/buildings/");
		OpenDialog1.visible = true;
		insert_type = etModel;
		EnableInsertMode();
	}



	void BrowseFlora()
	{
		OpenDialog1.basedir = appdir+"objects/flora/";
		OpenDialog1.mask = ".tga";
		OpenDialog1.ListFiles(appdir+"objects/flora/");
		OpenDialog1.visible = true;
		insert_type = etModel;
		EnableInsertMode();
	}


	void BrowseFauna()
	{
		OpenDialog1.basedir = appdir+"objects/fauna/";
		OpenDialog1.mask = ".tga";
		OpenDialog1.ListFiles(appdir+"objects/fauna/");
		OpenDialog1.visible = true;
		insert_type = etModel;
		EnableInsertMode();
	}


	void CreateNewMission()
	{
		if (mission->object != NULL)
			delete [] mission->object;
		mission->Nullify();

	}






	TOBJINS_OSD()
	{
		grid_size = 1.0;
		request_resize_colbox = false;
		resizing_colbox = false;
		colbox_resize_mode = false;
		initialized = false;
		EDITOR_LINES = NULL;
		EDITOR_LINES_LEN = 0;

		select_mode 		= false;
		select_waypoint 	= false;
	}

	~TOBJINS_OSD()
	{
		if (!initialized) return;
if (EDITOR_LINES != NULL) delete [] EDITOR_LINES;
glDeleteBuffers(1, &EDITOR_LINES_VBUFF);
delete ModelInsertShader;
delete LineShader;
delete ROT_BTN_SHADER;
delete TriggerShader;
	}



	TLineVertex * EDITOR_LINES;
	unsigned int EDITOR_LINES_VBUFF;
	int EDITOR_LINES_LEN;
TGLFont * font;


TShaderObject * ModelInsertShader; //draw plain with light
TShaderObject * LineShader;
TShaderObject * TriggerShader;
TShaderObject * EntityLightShader;

bool select_mode;
bool select_waypoint;
bool * translation_mode;
bool * rotation_mode;
bool * insert_mode;
vec3 * ray_trace_result;


void DisableAllModes()
{
(*cam_mode)			= false;
(*translation_mode) = false;
select_mode 		= false;
select_waypoint		= false;
(*rotation_mode)	= false;
colbox_resize_mode  = false;
resizing_colbox	= false;
request_resize_colbox = false;
//(*insert_mode)		= false;
ALOG("ALL MODES DISABLED");
}



TCollisionBoxPoints old_colbox;
bool request_resize_colbox;
bool colbox_resize_mode;
vec3 CollisionBoxResizeStartPoint;
vec3 CollisionBoxResizeActualPoint;

vec3 trans_direction;

vec3 box_size_base[4];

void BeginColBoxResizeMode(vec3 rA, vec3 rB)
{
//	PUSH_EVENT("................COLBOX BEGIN MODE");

vec3 objn = -FPP_CAM->ReturnFrontVector();


TEntity * p = mission->ObjectByPID(selection[0]);
if (!SegmentPlaneIntersection(objn, getplaneD(objn, p->pos), rA, rA+Normalize(vectorAB(rA,rB))*9999.0, CollisionBoxResizeStartPoint))
{
PUSH_EVENT("Well that was unexpected...");
return;
}


mat4 invrot;
invrot = p->rotation_mat;
invrot.Inverse();

vec3 hit_vec = Normalize(vectorAB(p->pos, CollisionBoxResizeStartPoint));
hit_vec = invrot * hit_vec;
//ALOG("HIT VECTOR: "+POINT_TO_TEXT(hit_vec));





bool xalgined = false;
bool yalgined = false;
bool zalgined = false;
trans_direction = vec3(0.0, 0.0, 1.0);
if ( ( absnf(hit_vec.x) >= absnf(hit_vec.y) ) && ( absnf(hit_vec.x) >= absnf(hit_vec.z) ) ) //mostly x algined
{
	xalgined = true;
	trans_direction = vec3(float(PLUSORMINUS2(hit_vec.x)), 0.0, 0.0);
}

if ( ( absnf(hit_vec.y) >= absnf(hit_vec.x) ) && ( absnf(hit_vec.y) >= absnf(hit_vec.z) ) ) //mostly y algined
{
	yalgined = true;
	trans_direction = vec3(0.0, float(PLUSORMINUS2(hit_vec.y)), 0.0);
}

if ( ( absnf(hit_vec.z) >= absnf(hit_vec.x) ) && ( absnf(hit_vec.z) >= absnf(hit_vec.y) ) ) //mostly z algined
{
	zalgined = true;
	trans_direction = vec3(0.0, 0.0, float(PLUSORMINUS2(hit_vec.z)));
}
//PUSH_EVENT("TDir: "+POINT_TO_TEXT(trans_direction));



int side_to_use = 0;
if (zalgined)
{
	if (hit_vec.z >= 0.0) side_to_use = FRONT;
	else side_to_use = BACK;
}

if (xalgined)
{
	if (hit_vec.x >= 0.0) side_to_use = LEFT;
	else side_to_use = RIGHT;
}


if (yalgined)
{
	if (hit_vec.y >= 0.0) side_to_use = TOP;
	else side_to_use = BOTTOM;
}
//determine side


//PUSH_EVENT("HIT SIDE: "+SideToStr(side_to_use));
p->colbox.IntersectionIndexToVertArray(side_to_use);


for (int i=0; i < 4; i++)
	box_size_base[i] = (*p->colbox.move_verts[i]);

//recreateBoundingBoxGrid();
		resizing_colbox = true;
		(*insert_mode) = false;
}
bool resizing_colbox;

void ProcessColBoxResizeMode(vec3 rA, vec3 rB)
{

	TEntity * p = mission->ObjectByPID(selection[0]);
	if (p == NULL) return;

	vec3 objn = -FPP_CAM->ReturnFrontVector();

if (!SegmentPlaneIntersection(objn, getplaneD(objn, p->pos), rA, rB, CollisionBoxResizeActualPoint))
{
PUSH_EVENT("Well that was unexpected...");
return;
}


float size = VectorLength(vectorAB(CollisionBoxResizeStartPoint, CollisionBoxResizeActualPoint));

if ( (size < 0.001) || IsNan(size) )
	{
	PUSH_EVENT("Translation less than 1 cm");
	return;
	}

//determine the sign to fix sizing
float the_SIGN = dot(
		Normalize(vectorAB(p->pos, CollisionBoxResizeStartPoint)),
		Normalize(vectorAB(CollisionBoxResizeStartPoint, CollisionBoxResizeActualPoint)));
the_SIGN = float(PLUSORMINUS2(the_SIGN));


for (int i=0; i < 4; i++)
{
	(*p->colbox.move_verts[i]) = box_size_base[i] + trans_direction*size*the_SIGN;
}

	recreateBoundingBoxGrid();

}


void EndColBoxResizeMode()
{
	if (colbox_resize_mode)
	{
		request_resize_colbox = true;
		(*insert_mode) = false;
	}

}

void GetAllObjectsAABB()
{
	TEntity * p = mission->object; //mission->ObjectByPID(selection[i]);
	while (p != NULL)
	{
		if (p->isModel())
			p->object->model->CalculateMinMax();

		if (p->isShip())
			p->object->ship->model->CalculateMinMax();


		if (p->isSizeable() && (!p->colbox.colboxset))
		{
			ALOG("Sizeable and colbox not set");
			p->colbox.SetBoxSize(p->object->model->MIN, p->object->model->MAX);
		}
p = p->next;
	}
}

void recreateBoundingBoxGrid()
{

	//remember to call GetAllObjectsAABB before
	TEntity * p = mission->object; //mission->ObjectByPID(selection[i]);
	while (p != NULL)
	{
		if (!p->colbox.init)
		{
		vec3 min;
		vec3 max;

		if (p->isModel())
		{
			min = p->object->model->MIN;
			max = p->object->model->MAX;
		}

		if (p->isShip())
		{
			min = p->object->ship->model->MIN;
			max = p->object->ship->model->MAX;
		}


//		min = mission->object[i].rotation_mat * min;
//		max = mission->object[i].rotation_mat * max;
		min = min + p->pos;
		max = max + p->pos;

		p->colbox.center = p->pos;

		p->colbox.fA = min;
		p->colbox.fB = vec3(max.x, min.y, min.z);
		p->colbox.fC = vec3(max.x, max.y, min.z);
		p->colbox.fD = vec3(min.x, max.y, min.z);


		p->colbox.bA = vec3(min.x, min.y, max.z);
		p->colbox.bB = vec3(max.x, min.y, max.z);
		p->colbox.bC = vec3(max.x, max.y, max.z);
		p->colbox.bD = vec3(min.x, max.y, max.z);

		p->colbox.FasterFaster();

		if (p->isSizeable())
			p->colbox.TextureMe();

		p->colbox.initializebox();
		} else
		{

			p->colbox.fA = p->rotation_mat * p->colbox.bfA;
			p->colbox.fB = p->rotation_mat * p->colbox.bfB;
			p->colbox.fC = p->rotation_mat * p->colbox.bfC;
			p->colbox.fD = p->rotation_mat * p->colbox.bfD;


			p->colbox.bA = p->rotation_mat * p->colbox.bbA;
			p->colbox.bB = p->rotation_mat * p->colbox.bbB;
			p->colbox.bC = p->rotation_mat * p->colbox.bbC;
			p->colbox.bD = p->rotation_mat * p->colbox.bbD;

			p->colbox.FasterFaster();

			for (int n=0; n < 8; n++)
			(*p->colbox.fast[n]) = p->pos + (*p->colbox.fast[n]);

			if (p->isSizeable())
			p->colbox.TextureMe();

			p->colbox.initializebox();
		}

		p = p->next;
	}

}

TEntity * FindObjectByRay(vec3 rA, vec3 rB) //performs raycast through all objects in scene then when found multiple intersections selects the closest one
{
	TGLEditorColStack col_stack[333]; //o'rly? D:
int col_stack_cnt = -1;
	//remember to call recreateBoundingBoxGrid before
TEntity * p = mission->object; //mission->ObjectByPID(selection[i]);
while (p != NULL)
	{
		TGLEditorColStack res;
vec3 ahue;
if (p->colbox.RayIntersectsBox(rA, rB, ahue))
{
	col_stack_cnt = col_stack_cnt + 1;
	if (col_stack_cnt >= 333) { PUSH_EVENT("TOO MUCH HIT INTERSECTIONS 333 aborting."); return NULL; }
	col_stack[col_stack_cnt].index 	= p->PID;
	col_stack[col_stack_cnt].v 		= ahue;
}
p = p->next;
	}


float mindst = 999999999.90;
int dsti = -1;
TEntity * result = NULL;

for (int i=0; i < col_stack_cnt+1; i++)
{
	float dst = n3ddistance(rA, col_stack[i].v);

	if (dst < mindst)
	{
		mindst 	= dst;
		dsti 	= col_stack[i].index;

		result = mission->ObjectByPID(dsti);

	}

	return result; //returns NULL if nothing found
}

return NULL;
}


//***************************************************************************************************************************************

TEntity* FindWaypointByRay(vec3 rA, vec3 rB) //performs raycast through all waypoints
{
	TGLEditorColStack col_stack[333]; //o'rly? D:
int col_stack_cnt = -1;
	//remember to call recreateBoundingBoxGrid before
TEntity * p = mission->object; //mission->ObjectByPID(selection[i]);
while (p != NULL)
	{
		TGLEditorColStack res;
vec3 ahue;
if ( (p->colbox.RayIntersectsBox(rA, rB, ahue)) && (p->type == etWaypoint) )
{
	col_stack_cnt = col_stack_cnt + 1;
if (col_stack_cnt >= 333) { PUSH_EVENT("TOO MUCH HIT INTERSECTIONS 333 aborting."); return NULL; }
	col_stack[col_stack_cnt].index 	= p->PID;
	col_stack[col_stack_cnt].v 		= ahue;
}
p = p->next;
	}


float mindst = 999999999.90;
int dsti = -1;
TEntity * result = NULL;
for (int i=0; i < col_stack_cnt+1; i++)
{
	float dst = n3ddistance(rA, col_stack[i].v);
	if (dst < mindst)
	{
		mindst 	= dst;
		dsti 	= col_stack[i].index;
		result = mission->ObjectByPID(dsti);
	}

	return result; //returns NULL if nothing found
}

return NULL;
}




//***************************************************************************************************************************************
void GoAway()
{
	std::exit(0);
}

bool first_run;

bool * position_set;
TShaderObject * ROT_BTN_SHADER;

int * edit_mode;



void SwitchToHeightmapEditor()
{
(*edit_mode) = TERRAED_OSD;
}

void SwitchToTerraTextureEditor()
{
(*edit_mode) = TERRATEX_OSD;
}



void OpenNameBriefForm()
{
	mission_brief_form.apply_to = mission;
	mission_brief_form.visible = true;
}

void OpenConditionForm()
{
	condition_form.apply_to = mission;
	condition_form.visible = true;
}


void SetGridSize0001() {	grid_size = 0.001; }
void SetGridSize001() {	grid_size = 0.01; }
void SetGridSize01() {	grid_size = 0.1; }
void SetGridSize1() {	grid_size = 1.0; }
void SetGridSize2() {	grid_size = 2.0; }
void SetGridSize4() {	grid_size = 4.0; }
void SetGridSize5() {	grid_size = 5.0; }
void SetGridSize8() {	grid_size = 8.0; }
void SetGridSize10() {	grid_size = 10.0; }
void SetGridSize20() {	grid_size = 20.0; }
TMissionBriefForm mission_brief_form;
TMissionConditionForm condition_form;
bool * cam_mode;




	void Init(
			TGLFont * afont, bool * terra_ed_mode_bool,
			vec3 * hit_result, bool * depth_recreated,
			bool * translate_mode, bool * rotate_mode,
			TSpecCamera * CAM, int * edit_modea,
			bool * cameramode, TMission * amiss)
	{
		mission = amiss;
		cam_mode = cameramode;
		trigger_editor.Init();
		mission_brief_form.Init();
		condition_form.Init();
		light_property_editor.Init();
		edit_mode = edit_modea;
		object_property_editor.Init();

		AIHUMAN_property_editor.Init();

		btn_down = false;
		first_run = true;
		FPP_CAM = CAM;
		ALOG("DOING INIT OBJ INS");
//		CreateNewMission();
		translation_mode 	= translate_mode;
		insert_mode 		= terra_ed_mode_bool;
		ray_trace_result 	= hit_result;
		position_set		= depth_recreated;
		rotation_mode		= rotate_mode;
		request_switch_mode	= false;
		update_rotate 		= false;
ALOG("POINTERS ACCEPTED");
font = afont;

GridMenu.MakeMain(4);
GridMenu.Items[0].caption = "Meters";
GridMenu.MakeSub(0, 7);
GridMenu.Items[0].Items[0].caption = " 1";
GridMenu.Items[0].Items[0].MenuOnClick = [this]() { this->SetGridSize1(); };
GridMenu.Items[0].Items[1].caption = " 2";
GridMenu.Items[0].Items[1].MenuOnClick = [this]() { this->SetGridSize2(); };
GridMenu.Items[0].Items[2].caption = " 4";
GridMenu.Items[0].Items[2].MenuOnClick = [this]() { this->SetGridSize4(); };
GridMenu.Items[0].Items[3].caption = " 5";
GridMenu.Items[0].Items[3].MenuOnClick = [this]() { this->SetGridSize5(); };
GridMenu.Items[0].Items[4].caption = " 8";
GridMenu.Items[0].Items[4].MenuOnClick = [this]() { this->SetGridSize8(); };
GridMenu.Items[0].Items[5].caption = " 10";
GridMenu.Items[0].Items[5].MenuOnClick = [this]() { this->SetGridSize10(); };
GridMenu.Items[0].Items[6].caption = " 20";
GridMenu.Items[0].Items[6].MenuOnClick = [this]() { this->SetGridSize20(); };


GridMenu.Items[1].caption = "Centimeters";
GridMenu.MakeSub(1, 3);
GridMenu.Items[1].Items[0].caption = " 0.001";
GridMenu.Items[1].Items[0].MenuOnClick = [this]() { this->SetGridSize0001(); };
GridMenu.Items[1].Items[1].caption = " 0.01";
GridMenu.Items[1].Items[1].MenuOnClick = [this]() { this->SetGridSize001(); };
GridMenu.Items[1].Items[2].caption = " 0.1";
GridMenu.Items[1].Items[2].MenuOnClick = [this]() { this->SetGridSize01(); };

GridMenu.Items[2].caption = "-----------";
GridMenu.Items[3].caption = "Disable";
		//no grid, 0.001, 0.01, 0.1, 0.5, 1.0, 2.0,

	FileMenu.MakeMain(7);
	FileMenu.Items[0].caption = "New mission";
	FileMenu.Items[0].MenuOnClick = [this]() { this->CreateNewMission(); };

	FileMenu.Items[1].caption = "Open mission";
	FileMenu.Items[2].caption = "Save mission";
	FileMenu.Items[3].caption = "------------";

	FileMenu.Items[4].caption = "Propereties";
	FileMenu.MakeSub(4, 2);
	FileMenu.Items[4].Items[0].caption = " Brief and name";
	FileMenu.Items[4].Items[0].MenuOnClick = [this]() { this->OpenNameBriefForm(); };
	FileMenu.Items[4].Items[1].caption = " Time and weather";
	FileMenu.Items[4].Items[1].MenuOnClick = [this]() { this->OpenConditionForm(); };

	FileMenu.MakeSub(5, 2);
	FileMenu.Items[5].caption = "Switch mode";//expandable
	FileMenu.Items[5].Items[0].caption = " Terrain Editor";
	FileMenu.Items[5].Items[0].MenuOnClick = [this]() { this->SwitchToHeightmapEditor(); };
	FileMenu.Items[5].Items[1].caption = " Terra Tex Editor";
	FileMenu.Items[5].Items[1].MenuOnClick = [this]() { this->SwitchToTerraTextureEditor(); };

	FileMenu.Items[6].caption = "Exit";
	FileMenu.Items[6].MenuOnClick = [this]() { this->GoAway(); };


	InsertMenu.MakeMain(5);
	InsertMenu.Items[0].caption = "Misc";//expandable
	InsertMenu.MakeSub(0,9);
	InsertMenu.Items[0].Items[0].caption = " Info NULL";
	InsertMenu.Items[0].Items[0].MenuOnClick = [this]() { this->InsertInfoNull(); };

	InsertMenu.Items[0].Items[1].caption = " Model";
	InsertMenu.Items[0].Items[1].MenuOnClick = [this]() { this->InsertModel(); };

	InsertMenu.Items[0].Items[2].caption = " Light";
	InsertMenu.Items[0].Items[2].MenuOnClick = [this]() { this->InsertLight(); };

	InsertMenu.Items[0].Items[3].caption = " Tornado";
	InsertMenu.Items[0].Items[3].MenuOnClick = [this]() { this->InsertTornado(); };

	InsertMenu.Items[0].Items[4].caption = " Fog";
	InsertMenu.Items[0].Items[4].MenuOnClick = [this]() { this->InsertFog(); };

	InsertMenu.Items[0].Items[5].caption = " Trigger";
	InsertMenu.Items[0].Items[5].MenuOnClick = [this]() { this->InsertTrigger(); };

	InsertMenu.Items[0].Items[6].caption = " Waypoint";
	InsertMenu.Items[0].Items[6].MenuOnClick = [this]() { this->InsertWaypoint(); };

	InsertMenu.Items[0].Items[7].caption = " Fire";
	InsertMenu.Items[0].Items[7].MenuOnClick = [this]() { this->InsertFire(); };

	InsertMenu.Items[0].Items[8].caption = " Player Spwan";
	InsertMenu.Items[0].Items[8].MenuOnClick = [this]() { this->InsertPlayerSpawn(); };



	InsertMenu.Items[1].caption = "AI";//expandable: Human, Cannon, Ship
	InsertMenu.MakeSub(1,3);
	InsertMenu.Items[1].Items[0].caption = "Human";
	InsertMenu.Items[1].Items[1].caption = "Cannon";
	InsertMenu.Items[1].Items[2].caption = "Ship";

	InsertMenu.Items[2].caption = "Buildings";//Forts, houses, other buildings
	InsertMenu.Items[2].MenuOnClick = [this]() { this->BrowseBuildings(); };

	InsertMenu.Items[3].caption = "Flora";
	InsertMenu.Items[3].MenuOnClick = [this]() { this->BrowseFlora(); };

	InsertMenu.Items[4].caption = "Fauna";
	InsertMenu.Items[4].MenuOnClick = [this]() { this->BrowseFauna(); };



	EditMenu.MakeMain(7);
	EditMenu.Items[0].caption = "Translate";
	EditMenu.Items[0].MenuOnClick = [this]() { this->EnableTranslationMode(); };

	EditMenu.Items[1].caption = "Rotate";
	EditMenu.Items[1].MenuOnClick = [this]() { this->EnableRotationMode(); };

	EditMenu.Items[2].caption = "Edit info";
	EditMenu.Items[2].MenuOnClick = [this]() { this->EditObjectPropereties(); };

	EditMenu.Items[3].caption = "Target";
	EditMenu.MakeSub(3,3);
	EditMenu.Items[3].Items[0].caption = " deselect";
	EditMenu.Items[3].Items[1].caption = " --------";
	EditMenu.Items[3].Items[2].caption = " select";
	EditMenu.MakeSub(4,3);
	EditMenu.Items[4].caption = "Selection";
	EditMenu.Items[4].Items[0].caption = " Select";
	EditMenu.Items[4].Items[0].MenuOnClick = [this]() { this->EnableSelectMode(); };
	EditMenu.Items[4].Items[1].caption = " ------";
	EditMenu.Items[4].Items[2].caption = " Delete";
	EditMenu.Items[4].Items[2].MenuOnClick = [this]() { this->DeleteSelection(); };

	EditMenu.MakeSub(5,3);
	EditMenu.Items[5].caption = "Waypoint";
	EditMenu.Items[5].Items[0].caption = " Attach";
	EditMenu.Items[5].Items[1].caption = " ------";
	EditMenu.Items[5].Items[2].caption = " Deattach";
	EditMenu.Items[6].caption = "Size colbox";
	EditMenu.Items[6].MenuOnClick = [this]() { this->EnableResizeColboxMode(); };



	FileMenu.glyph.LoadTGA(appdir+"textures/editor/terratexed_file_menu.tga");
	InsertMenu.glyph.LoadTGA(appdir+"textures/editor/insert_menu.tga");
	EditMenu.glyph.LoadTGA(appdir+"textures/editor/edit_menu.tga");
	ALOG("LOADIN GRID MENU TGA");
	GridMenu.glyph.LoadTGA(appdir+"textures/editor/grid_menu.tga");
float sw = float(SCREEN_WIDTH);
float sh = float(SCREEN_HEIGHT);

	FileMenu.Init(sw*0.1, sh*0.9, sw*0.1, sh*0.1, font);
	InsertMenu.Init(sw*0.2, sh*0.9, sw*0.1, sh*0.1, font);
	EditMenu.Init(sw*0.4, sh*0.9, sw*0.1, sh*0.1, font);
	GridMenu.Init(sw*0.3, sh*0.9, sw*0.1, sh*0.1, font);
OpenDialog1.Init();





rot_osd.Make( 2 * 3 );
	float btn_w = sh*0.1;

PlaceButtonOGL(sw*0.2, (sh / 2.0) - btn_w/2.0, btn_w, btn_w, rot_osd.VBUFF, rot_osd.Buttons, ROT_OSD_PITCH_UP, sw, sh);
PlaceButtonOGL(sw*0.2, (sh / 2.0) + btn_w/2.0, btn_w, btn_w, rot_osd.VBUFF, rot_osd.Buttons, ROT_OSD_PITCH_DOWN, sw, sh);


PlaceButtonOGL(sw*0.2, 0.0, btn_w, btn_w, rot_osd.VBUFF, rot_osd.Buttons, ROT_OSD_ROLL_UP, sw, sh);
PlaceButtonOGL(sw*0.2+btn_w, 0.0, btn_w, btn_w, rot_osd.VBUFF, rot_osd.Buttons, ROT_OSD_ROLL_DOWN, sw, sh);

PlaceButtonOGL(sw*0.4, 0.0, btn_w, btn_w, rot_osd.VBUFF, rot_osd.Buttons, ROT_OSD_YAW_UP, sw, sh);
PlaceButtonOGL(sw*0.4+btn_w, 0.0, btn_w, btn_w, rot_osd.VBUFF, rot_osd.Buttons, ROT_OSD_YAW_DOWN, sw, sh);

rot_osd.SendToGPU();

AStringList*s = new AStringList();
s->LoadFromFile(appdir+"textures/osd/rot.txt");
for (int i=0; i < 6; i++)
	rot_osd.Buttons[i].tex.LoadTGA24IntensityColorToAlpha(appdir+s->Strings[i]);

delete s;

	ModelInsertShader = new TShaderObject();
	ModelInsertShader->LoadShaderProgram(appdir+"shaders/editor/editor_model_vp.shader", appdir+"shaders/editor/editor_model_fp.shader");

	LineShader = new TShaderObject();
	LineShader->LoadShaderProgram(appdir+"shaders/editor/editor_line_vp.shader", appdir+"shaders/editor/editor_line_fp.shader");

	TriggerShader = new TShaderObject();
	TriggerShader->LoadShaderProgram(appdir+"shaders/editor/trigger_vp.shader", appdir+"shaders/editor/trigger_fp.shader");


	EntityLightShader = new TShaderObject();
	EntityLightShader->LoadShaderProgram(appdir+"shaders/editor/entitylight_vp.shader", appdir+"shaders/editor/entitylight_fp.shader");

	ROT_BTN_SHADER = new TShaderObject();
	ROT_BTN_SHADER->LoadShaderProgram(appdir+"shaders/HUD/osd/main_vp.shader", appdir+"shaders/HUD/osd/main_fp.shader");
initialized = true;
ALOG("DONE OBJ INS INIT");
	}

void UpdateLineBuffer()
{
	int line_len = 0;
TEntity * p = mission->object;
while (p != NULL)
{
if (	p->atarget != NULL ) line_len = line_len + 1;
if (	p->waypoint != NULL) line_len = line_len + 1;
p = p->next;
}

line_len = line_len * 2;
bool update = false;

if (EDITOR_LINES_LEN != line_len)
{
	EDITOR_LINES_LEN = line_len;
	if (EDITOR_LINES != NULL)
		delete [] EDITOR_LINES;
	EDITOR_LINES = NULL;
	EDITOR_LINES = new TLineVertex[ EDITOR_LINES_LEN ];
	glDeleteBuffers(1, &EDITOR_LINES_VBUFF);
	glGenBuffers(1, &EDITOR_LINES_VBUFF);
	update = true;
}

int cnt = -1;
p = mission->object;
while (p != NULL)
{
if  (p->atarget != NULL )
	{
	cnt = cnt + 1;
	EDITOR_LINES[cnt*2 + 0].v = p->pos;
	EDITOR_LINES[cnt*2 + 1].v = p->atarget->pos;
	EDITOR_LINES[cnt*2 + 0].c = vec3(0.0, 1.0, 0.0);
	EDITOR_LINES[cnt*2 + 1].c = vec3(0.0, 1.0, 0.0);
	}

if  (p->waypoint != NULL)
{
	cnt = cnt + 1;
	EDITOR_LINES[cnt*2 + 0].v = p->pos;
	EDITOR_LINES[cnt*2 + 1].v = p->waypoint->pos;
	EDITOR_LINES[cnt*2 + 0].c = vec3(1.0, 0.5, 0.0);
	EDITOR_LINES[cnt*2 + 1].c = vec3(1.0, 0.5, 0.0);
}

p = p->next;
}

glBindBuffer(GL_ARRAY_BUFFER, EDITOR_LINES_VBUFF);

if (update)
	 glBufferData(GL_ARRAY_BUFFER, sizeof(TLineVertex) * EDITOR_LINES_LEN, EDITOR_LINES, GL_STATIC_DRAW);
else
	glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(TLineVertex) * EDITOR_LINES_LEN, EDITOR_LINES);

glBindBuffer(GL_ARRAY_BUFFER, 0);
}

bool request_switch_mode;
bool * switch_to;
void SwitchMode(bool * p)
{
	DisableAllModes();
	(*p) = true;
}

void YawSelectionBy(float angle)
{
	for (int i=0; i < sel_len; i++)
	{
		TEntity * p = mission->ObjectByPID(selection[i]);
		p->rotation.yaw(cos(angle*imopi), sin(angle*imopi));
		p->rotation.DoRotation();
		p->rotation_mat.LoadGLMatrix(p->rotation.AIR_MATRIX);
	}


	mat4 ahue;
	TEntity * p = new TEntity();
	p->rotation.yaw(cos(angle*imopi), sin(angle*imopi));
	p->rotation.DoRotation();
	p->rotation_mat.LoadGLMatrix(p->rotation.AIR_MATRIX);

vec3 zp = vec3(0.0, 0.0, 1.0);
vec3 zrot = p->rotation_mat* zp;

mat4 invrot;
invrot = p->rotation_mat;
//invrot.Transpose();
invrot.Inverse();

vec3 irot = invrot * zrot;


mat4 res;
res = p->rotation_mat * invrot;

vec3 test = res * zp;

ALOG("BASE VEC: "+POINT_TO_TEXT(zp));
ALOG("ROTATED VEC: "+POINT_TO_TEXT(zrot));
ALOG("Inverted rotation VEC: "+POINT_TO_TEXT(irot));
ALOG("test VEC: "+POINT_TO_TEXT(test));
}

void PitchSelectionBy(float angle)
{
	for (int i=0; i < sel_len; i++)
	{
		TEntity * p = mission->ObjectByPID(selection[i]);
		p->rotation.pitch(cos(angle*imopi), sin(angle*imopi));
		p->rotation.DoRotation();
		p->rotation_mat.LoadGLMatrix(p->rotation.AIR_MATRIX);
	}
}


void RollSelectionBy(float angle)
{
	for (int i=0; i < sel_len; i++)
	{
		TEntity * p = mission->ObjectByPID(selection[i]);
		p->rotation.roll(cos(angle*imopi), sin(angle*imopi));
		p->rotation.DoRotation();
		p->rotation_mat.LoadGLMatrix(p->rotation.AIR_MATRIX);
	}
}

float CursorX;
float CursorY;

float RotStartX;
float RotStartY;
bool btn_down;













void InsertNonModel(vec3 epos)
{
	AnsiString fname;
	if (insert_type == etInfoNull) // non sizeable just a box
fname = appdir + "objects/info_null.objspec";

	if (insert_type == etLight) // non sizeable just a box
		fname = appdir + "objects/light.objspec";

	if (insert_type == etWaypoint) // non sizeable just a box
		fname = appdir + "objects/waypoint.objspec";

	if (insert_type == etPlayerSpawn) // non sizeable just a box
		fname = appdir + "objects/player_spawn.objspec";

	if (insert_type == etTrigger) // sizeable box
		fname = appdir + "objects/trigger.objspec";

	if (insert_type == etTornado) // sizeable box
		fname = appdir + "objects/tornado.objspec";

	if (insert_type == etFog) // sizeable box
		fname = appdir + "objects/fog.objspec";

	if (insert_type == etFire) // sizeable box
		fname = appdir + "objects/fire.objspec";


Insert(epos, fname);
recreateBoundingBoxGrid();

}







void EnableTranslationMode()
{
switch_to = translation_mode;
request_switch_mode = true;
}








void Draw()
{
if (!initialized) return;
glActiveTexture(GL_TEXTURE0);
	if (request_switch_mode)
	{
		request_switch_mode = false;
		SwitchMode(switch_to);
	}

//if ((!OpenDialog1.file_is_awaiting) && (!OpenDialog1.visible) ) (*insert_mode) = false;
OpenDialog1.Draw();

if (!(*cam_mode))
if ( (*rotation_mode) && (update_rotate) )
{
	update_rotate = false;
recreateBoundingBoxGrid();
}

if (!(*cam_mode))
if (btn_down)
if ( (*translation_mode) )
{
	vec3 rdir =	GetDirectionFromScreen(ACTUAL_MODEL * ACTUAL_VIEW, FPP_CAM, CursorX, CursorY, SCREEN_WIDTH, SCREEN_HEIGHT, 90.0, 0.1, 1000.0);


	if (!first_run)
	{
	TranslateSelected(FPP_CAM->pos, FPP_CAM->pos + rdir*1000.0);
	recreateBoundingBoxGrid();
	} else
		BeginTranslationMode(FPP_CAM->pos, FPP_CAM->pos + rdir*1000.0);

	first_run = false;
}

if (!(*cam_mode))
if ( (*position_set) && (select_mode) )
{
	(*position_set) 			 = false;
TEntity * found_index = FindObjectByRay(FPP_CAM->pos, (*ray_trace_result));
if (found_index == NULL) PUSH_EVENT("Hit nothing");
else
	Select(found_index->PID);

}


if ( (OpenDialog1.file_is_awaiting) && ((*position_set)) )
{

	(*position_set) 			 = false;
	OpenDialog1.file_is_awaiting = false;

//		 * Convert filename coz we are viewing only tga files (otga exension - for model previev during search) and objspec file of that file is in files/objects/ dir
	#ifndef WINDOWS_CMP
	AnsiString fname = appdir+"objects/"+StringReplace(ExtractFileName(OpenDialog1.FileName),".tga",".objspec");
	#endif

	#ifdef WINDOWS_CMP
	AnsiString fname = appdir+"objects/"+StringReplace(ExtractFileName(OpenDialog1.FileName),".tga",".objspec", TReplaceFlags() << rfReplaceAll);
	#endif
	if (!FileExists(fname)) ALOG("WRONG FILENAME");
Insert((*ray_trace_result), fname);

recreateBoundingBoxGrid();

if ((*insert_mode)) {ALOG("SOMETHING IS REALLY WRONG. "); (*insert_mode) = false; }


}

if (!(*cam_mode))
if (btn_down)
if (colbox_resize_mode)
if (request_resize_colbox)
{

vec3 rdir =	GetDirectionFromScreen(ACTUAL_MODEL * ACTUAL_VIEW, FPP_CAM, CursorX, CursorY, SCREEN_WIDTH, SCREEN_HEIGHT, 90.0, 0.1, 1000.0);

	BeginColBoxResizeMode(FPP_CAM->pos, FPP_CAM->pos + rdir*1000.0);
	request_resize_colbox 	= false;
}

if (!(*cam_mode))
if (btn_down)
if (colbox_resize_mode)
if ( resizing_colbox && !request_resize_colbox )
{
	if (!first_run)
	{
		vec3 rdir =	GetDirectionFromScreen(ACTUAL_MODEL * ACTUAL_VIEW, FPP_CAM, CursorX, CursorY, SCREEN_WIDTH, SCREEN_HEIGHT, 90.0, 0.1, 1000.0);
	ProcessColBoxResizeMode(FPP_CAM->pos, FPP_CAM->pos + rdir*1000.0);
	}
	first_run = false;
}



//insert something that is not from opendialog but still choosen
if (!(*cam_mode))
if ( ( ((*insert_mode)) && ((*position_set)) ) && (!(*translation_mode) ) && (!(*rotation_mode) && (!select_mode) && (!resizing_colbox) ))
{
	(*insert_mode) 	= false;
	(*position_set) = false;
	ALOG("INSERTING SOMETHING");
	InsertNonModel((*ray_trace_result));
}

	glActiveTexture(GL_TEXTURE0);
	DrawObjects(true);



	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glDepthMask(GL_FALSE);
	glDisable(GL_DEPTH_TEST);

	if (!(*cam_mode))
if ((*rotation_mode))
	rot_osd.DrawButtons(ROT_BTN_SHADER);

	FileMenu.Draw();
	InsertMenu.Draw();
	EditMenu.Draw();
	GridMenu.Draw();
	glDisable(GL_BLEND);


	glEnable(GL_DEPTH_TEST);
	glDepthMask(GL_TRUE);


	object_property_editor.Draw();
	mission_brief_form.Draw();
		condition_form.Draw();
		light_property_editor.Draw();
		trigger_editor.Draw();
}


/*
 * draws all objects in mission
 * with_lines bool says if we want to draw connections between different objects
 */
void DrawObjects(bool with_lines)
{
if (mission->object == NULL)
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	//first draw all objects with standard lighting model (no shadows)
	glActiveTexture(GL_TEXTURE0);

	//draw standard Entities
	TEntity * p = mission->object;
	ModelInsertShader->Enable();

	while (p != NULL)
	{

	if ( p->object != NULL )
	{


		mat4 wrld;
		wrld.TranslateP(p->pos);
		wrld = p->rotation_mat * wrld;
		mat4 MVP = (wrld * ACTUAL_VIEW) * ACTUAL_PROJECTION;
		ModelInsertShader->SendMVPtoShader(MVP);

		if (p->isModel()) //draw model
			p->object->model->DrawSimpleModel(ModelInsertShader);

		if (p->isShip())
			p->object->ship->model->DrawSimpleModel(ModelInsertShader);

		//additionally draw blended cube that covers the area of the 'trigger'


	}
	p = p->next;
	}

	ModelInsertShader->Disable();

	glBindBuffer(GL_ARRAY_BUFFER, 0);
p = mission->object;
	//draw misc Entities

ACTUAL_MODEL.LoadIdentity();
while (p != NULL)
{
		if ( p->object != NULL )
		{
			if (p->isSizeable())
				DrawSizeable(p);

			/*
			 * Draw light sphere (blended with radius and color of light
			 */
			if (p->type == etLight)
			{
				DrawLight(p);

//				info2[0] <- light radius
			}

			/*
			 * Draw sphere of radius of contact
			 */
			if (p->type == etWaypoint)
			{

			}


		}

p = p->next;
}

glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);
//now draw selection boxes
		ACTUAL_MODEL.LoadIdentity();

		COLOR_PICK_SHADER->Enable();
		COLOR_PICK_SHADER->Send3F(glGetUniformLocation(COLOR_PICK_SHADER->gProgram, "COLOR"), vec3(1.0, 1.0, 0.0));
		COLOR_PICK_SHADER->SendMVPtoShader((ACTUAL_MODEL * ACTUAL_VIEW) * ACTUAL_PROJECTION);

		for (int i=0; i < sel_len; i++)
		{
			p = mission->ObjectByPID(selection[i]);

	glBindBuffer(GL_ARRAY_BUFFER, p->colbox.vbuff);
	glVertexAttribPointer(COLOR_PICK_SHADER->vertex_pos, 3, GL_FLOAT, GL_FALSE, sizeof(TBoundingBoxVertex), (void*)(offsetof(struct TBoundingBoxVertex, v)));

	glEnableVertexAttribArray(COLOR_PICK_SHADER->vertex_pos);

	for (int n=0; n < 6; n++)	glDrawArrays(GL_LINE_LOOP, n*4, 4);

	glDisableVertexAttribArray(COLOR_PICK_SHADER->vertex_pos);
	glBindBuffer(GL_ARRAY_BUFFER, 0);

		}

		COLOR_PICK_SHADER->Disable();

		glBindBuffer(GL_ARRAY_BUFFER, 0);


		glDepthMask(GL_TRUE);
		glEnable(GL_DEPTH_TEST);
//draw lines that are connecting objects



//draw lights along with blended sphere with lights color and radius



}

void DrawLight(TEntity * object)
{
		if (object 			== NULL) return;
		if (object->object 	== NULL) return;
		if (object->info2[0] <= 0.01) return;
		glActiveTexture(GL_TEXTURE0);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);


			mat4 wrld;
			mat4 scale;
			scale.Scale(object->info2[0],object->info2[0],object->info2[0]);
			wrld.TranslateP(object->pos);
			mat4 MVP = ((scale * wrld)  * ACTUAL_VIEW) * ACTUAL_PROJECTION;


EntityLightShader->Enable();
EntityLightShader->SendMVPtoShader(MVP);

EntityLightShader->Send3F(glGetUniformLocation(EntityLightShader->gProgram, "light_color"),
		vec3(object->info2[1],object->info2[2],object->info2[3]));

low_sphere->DrawSimpleModel(EntityLightShader);


EntityLightShader->Disable();

	glDisable(GL_BLEND);

}

void DrawSizeable(TEntity * object)
{
	if (object 			== NULL) return;
	if (object->object 	== NULL) return;

	glActiveTexture(GL_TEXTURE0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	if (object->type == etTrigger) 	Trigger_texture.Bind();
	if (object->type == etFog) 		Fog_texture.Bind();
	if (object->type == etFire) 	Fire_texture.Bind();

//		mat4 wrld;
//		wrld.TranslateP(object->pos);
//		wrld = object->rotation_mat * wrld;
		mat4 MVP = (ACTUAL_MODEL * ACTUAL_VIEW) * ACTUAL_PROJECTION;


TriggerShader->Enable();
TriggerShader->SendMVPtoShader(MVP);
TriggerShader->Send1I(glGetUniformLocation(TriggerShader->gProgram, "trigger_tex"), 0);
	glBindBuffer(GL_ARRAY_BUFFER, object->colbox.vbuff);

	glVertexAttribPointer(TriggerShader->vertex_pos, 3, GL_FLOAT, GL_FALSE, sizeof(TBoundingBoxVertex), (void*)(offsetof(struct TBoundingBoxVertex, v)));
	glVertexAttribPointer(TriggerShader->texture_coord, 2, GL_FLOAT, GL_FALSE, sizeof(TBoundingBoxVertex), (void*)(offsetof(struct TBoundingBoxVertex, t)));

	glEnableVertexAttribArray(TriggerShader->vertex_pos);
	glEnableVertexAttribArray(TriggerShader->texture_coord);

	for (int n=0; n < 6; n++)
	glDrawArrays(GL_TRIANGLE_FAN, n*4, 4);

	glDisableVertexAttribArray(TriggerShader->vertex_pos);
	glDisableVertexAttribArray(TriggerShader->texture_coord);

	glBindBuffer(GL_ARRAY_BUFFER, 0);

TriggerShader->Disable();
glDisable(GL_BLEND);
}




void OnMouseMove(float x, float y)
{

	if (object_property_editor.visible)
			object_property_editor.OnMouseMove(x,y);

	if (condition_form.visible) 			condition_form.OnMouseMove(x, y);
	if (object_property_editor.visible) 	object_property_editor.OnMouseMove(x,y);
	if (light_property_editor.visible) 	light_property_editor.OnMouseMove(x,y);
	if (trigger_editor.visible) trigger_editor.OnMouseMove(x,y);
}

void OnMouseUp(float x, float y)
{

	if (trigger_editor.visible) trigger_editor.OnMouseUp(x,y);
	if (object_property_editor.visible) object_property_editor.OnMouseUp(x,y);

	if (condition_form.visible) 			condition_form.OnMouseUp(x, y);
	if (object_property_editor.visible) 	object_property_editor.OnMouseUp(x,y);
	if (light_property_editor.visible) 	light_property_editor.OnMouseUp(x,y);


	btn_down = false;
	first_run = true;
	EndColBoxResizeMode();
}

bool OnClick(float x, float y)
{
	if (trigger_editor.visible)			{ 	trigger_editor.OnClick(x, y);			return true;	}
	if (mission_brief_form.visible) 	{	mission_brief_form.OnClick(x, y); 		return true;	}
	if (condition_form.visible) 		{	condition_form.OnClick(x, y); 			return true;	}
	if (object_property_editor.visible) {	object_property_editor.OnClick(x,y); 	return true;	}
	if (light_property_editor.visible)  {	light_property_editor.OnClick(x,y); 	return true;	}

	if (OpenDialog1.visible) if(OpenDialog1.OnClick(x, y)) return true;
	if (FileMenu.OnClick(x, y)) 	{ return true; }
	if (InsertMenu.OnClick(x, y)) 	{ return true; }
	if (EditMenu.OnClick(x, y))		{ return true; }
	if (GridMenu.OnClick(x, y))		{ return true; }
	btn_down = true;


	if ((*rotation_mode))
	{

	if ( BtnClicked(x, y, rot_osd.Buttons, ROT_OSD_PITCH_UP) )
			{
		PitchSelectionBy(5.0);
		update_rotate = true;
					return true;
			}


	if ( BtnClicked(x, y, rot_osd.Buttons, ROT_OSD_PITCH_DOWN) )
			{
		PitchSelectionBy(-5.0);
		update_rotate = true;
					return true;
			}



	if ( BtnClicked(x, y, rot_osd.Buttons, ROT_OSD_ROLL_UP) )
			{
		RollSelectionBy(5.0);
		update_rotate = true;
					return true;
			}

	if ( BtnClicked(x, y, rot_osd.Buttons, ROT_OSD_ROLL_DOWN) )
			{
		RollSelectionBy(-5.0);
		update_rotate = true;
					return true;
			}


	if ( BtnClicked(x, y, rot_osd.Buttons, ROT_OSD_YAW_UP) )
			{
		YawSelectionBy(90.0);
		update_rotate = true;
					return true;
			}

	if ( BtnClicked(x, y, rot_osd.Buttons, ROT_OSD_YAW_DOWN) )
			{
		YawSelectionBy(-90.0);
		update_rotate = true;
					return true;
			}
	}

	if (!(*cam_mode))
if (colbox_resize_mode) {return true;}




	return false; //osd is always hit no matter what
}

};


#endif
 

#ifndef collisionH
#define collisionH
#include "DxcMath.h"
#include "modelloading/TachoGLModelSRC.h"
#include "glwrapper.h" //for fucking bounding box drawing
#include "txtfile/stringlist.h"




inline AnsiString SideToStr(int side)
{
if (side == 0) return "FRONT";
if (side == 1) return "BACK";
if (side == 2) return "LEFT";
if (side == 3) return "RIGHT";
if (side == 4) return "TOP";
if (side == 5) return "BOTTOM";
}

struct TBoundingBoxVertex
{
	vec3 v;
	vec2 t;
	TBoundingBoxVertex&operator=(const TBoundingBoxVertex & in)
	{
		v = in.v;
		t = in.t;
	}
};

extern bool RayTPolygonIntersection(TPolygon<float> face, vec3 rA, vec3 rB, vec3 & res);
struct TCollisionBoxPoints
{
//-- the base

	vec3 bbA; //bottom left
	vec3 bbB; //bottom right
	vec3 bbC; //top right
	vec3 bbD; //top left

	vec3 bfA; //bottom left
	vec3 bfB; //bottom right
	vec3 bfC; //top right
	vec3 bfD; //top left


//-- the base


vec3 bA; //bottom left
vec3 bB; //bottom right
vec3 bC; //top right
vec3 bD; //top left

vec3 fA; //bottom left
vec3 fB; //bottom right
vec3 fC; //top right
vec3 fD; //top left
vec3 center;
vec3P fast[8];

bool colboxset;
unsigned int vbuff;
TBoundingBoxVertex boxbuff[24];

bool init;
int last_hit;

void SetBoxSize(vec3 amin, vec3 amax)
{
	if (colboxset) {ALOG("COLBOX ALREADY SET ABORTING"); return; }
colboxset = true;

center = (amin + amax) / 2.0;




	vec3 min = amin + center;
	vec3 max = amax + center;



	fA = min;
	fB = vec3(max.x, min.y, min.z);
	fC = vec3(max.x, max.y, min.z);
	fD = vec3(min.x, max.y, min.z);


	bA = vec3(min.x, min.y, max.z);
	bB = vec3(max.x, min.y, max.z);
	bC = vec3(max.x, max.y, max.z);
	bD = vec3(min.x, max.y, max.z);

	FasterFaster();
	initializebox();

}


void initializebox() //use only after creation of the bounding box
{

	if (!init)
	{
		bbA = bA;
		bbB = bB;
		bbC = bC;
		bbD = bD;

		bfA = fA;
		bfB = fB;
		bfC = fC;
		bfD = fD;

		bbA = bbA - center;
		bbB = bbB - center;
		bbC = bbC - center;
		bbD = bbD - center;

		bfA = bfA - center;
		bfB = bfB - center;
		bfC = bfC - center;
		bfD = bfD - center;

		for (int i=0; i < 6; i++)
		{
			boxbuff[i*4+0].t = vec2(0.0, 0.0);
			boxbuff[i*4+1].t = vec2(1.0, 0.0);
			boxbuff[i*4+2].t = vec2(1.0, 1.0);
			boxbuff[i*4+3].t = vec2(0.0, 1.0);
		}

	}


boxbuff[0].v = fA;
boxbuff[1].v = fB;
boxbuff[2].v = fC;
boxbuff[3].v = fD;

boxbuff[4].v = bA;
boxbuff[5].v = bB;
boxbuff[6].v = bC;
boxbuff[7].v = bD;

boxbuff[8].v 	= bA;
boxbuff[9].v 	= fA;
boxbuff[10].v 	= fD;
boxbuff[11].v 	= bD;

boxbuff[12].v =bB;
boxbuff[13].v =fB;
boxbuff[14].v =fC;
boxbuff[15].v =bC;

boxbuff[16].v =bD;
boxbuff[17].v =bC;
boxbuff[18].v =fC;
boxbuff[19].v =fD;

boxbuff[20].v =bA;
boxbuff[21].v =bB;
boxbuff[22].v =fB;
boxbuff[23].v =fA;


if (!init)
{
    glGenBuffers(1, &vbuff);
    glBindBuffer(GL_ARRAY_BUFFER, vbuff);
    glBufferData(GL_ARRAY_BUFFER, sizeof(TBoundingBoxVertex) * 24, boxbuff, GL_STATIC_DRAW);
} else
{
    glBindBuffer(GL_ARRAY_BUFFER, vbuff);
    glBufferSubData(GL_ARRAY_BUFFER, 0,  sizeof(TBoundingBoxVertex) * 24, boxbuff);
}

	glBindBuffer(GL_ARRAY_BUFFER, 0);

init = true;
}

TCollisionBoxPoints()
{
	colboxset = false;
	init = false;
}


TCollisionBoxPoints& operator=(const TCollisionBoxPoints& in)
{
ALOG("HEY IM COPYING MYSELF HELP ME");
		 bA = in.bA; //bottom left
		 bB = in.bB; //bottom right
		 bC = in.bC; //top right
		 bD = in.bD; //top left

		 fA = in.fA; //bottom left
		 fB = in.fB; //bottom right
		 fC = in.fC; //top right
		 fD = in.fD; //top left

		 for (int i=0; i < 8; i++)
		 fast[i] = in.fast[i];


		 colboxset = in.colboxset;

		 for (int i=0; i < 24; i++)
			 boxbuff[i] = in.boxbuff[i];

		 bbA = in.bA; //bottom left
		 bbB = in.bB; //bottom right
		 bbC = in.bC; //top right
		 bbD = in.bD; //top left

		 bfA = in.bfA; //bottom left
		 bfB = in.bfB; //bottom right
		 bfC = in.bfC; //top right
		 bfD = in.bfD; //top left
		 vbuff = in.vbuff;

	init = in.init;

	if (init)
	{
	    glGenBuffers(1, &vbuff);
	    glBindBuffer(GL_ARRAY_BUFFER, vbuff);
	    glBufferData(GL_ARRAY_BUFFER, sizeof(TBoundingBoxVertex) * 24, boxbuff, GL_STATIC_DRAW);
	}
	return *this;
}

/*
 * Depending on size of side calculate coords
 */
void TextureMe()
{

for (int i=0; i < 6; i++)
{
	float size = n3ddistance(boxbuff[i*4+0].v, boxbuff[i*4+2].v);
//	ALOG("size of a box: "+FloatToStr(size));
	if (size <= 1.010)
	{
		boxbuff[i*4+0].t = vec2(0.0, 0.0);
		boxbuff[i*4+1].t = vec2(1.0, 0.0);
		boxbuff[i*4+2].t = vec2(1.0, 1.0);
		boxbuff[i*4+3].t = vec2(0.0, 1.0);
	} else
	{

		boxbuff[i*4+0].t = vec2(0.0, 0.0);
		boxbuff[i*4+1].t = vec2(size, 0.0);
		boxbuff[i*4+2].t = vec2(size, size);
		boxbuff[i*4+3].t = vec2(0.0, size);
	}



}


}

void FasterFaster()
{
	fast[0] = &fA;
	fast[1] = &fB;
	fast[2] = &fC;
	fast[3] = &fD;

	fast[4] = &bA;
	fast[5] = &bB;
	fast[6] = &bC;
	fast[7] = &bD;
}


vec3 * move_verts[4];

void IntersectionIndexToVertArray(int ahue)
{


if (ahue == BACK)
{
	move_verts[0] = &bfA;
	move_verts[1] = &bfB;
	move_verts[2] = &bfC;
	move_verts[3] = &bfD;
	return;
}

if (ahue == FRONT)
{
	move_verts[0] = &bbA;
	move_verts[1] = &bbB;
	move_verts[2] = &bbC;
	move_verts[3] = &bbD;
	return;
}

if (ahue == LEFT)
{
	move_verts[0] = &bbB;
	move_verts[1] = &bfB;
	move_verts[2] = &bfC;
	move_verts[3] = &bbC;
	return;
}

if (ahue == RIGHT)
{

	move_verts[0] = &bbA;
	move_verts[1] = &bfA;
	move_verts[2] = &bfD;
	move_verts[3] = &bbD;
	return;
}

if (ahue == TOP)
{
	move_verts[0] = &bbD;
	move_verts[1] = &bbC;
	move_verts[2] = &bfC;
	move_verts[3] = &bfD;
	return;
}

if (ahue == BOTTOM)
{
	move_verts[0] = &bbA;
	move_verts[1] = &bbB;
	move_verts[2] = &bfB;
	move_verts[3] = &bfA;
	return;
}

ALOG("EXCEUSE ME BUT WHAT THE FUCK "+IntToStr(ahue));

}

bool RayIntersectsBox(vec3 rA, vec3 rB, vec3 & result)
{
//combine points with sides
	//front
	TPolygon<float> poly;
	poly.AddVertex(fA);
	poly.AddVertex(fB);
	poly.AddVertex(fC);
	poly.AddVertex(fD);
if (RayTPolygonIntersection(poly, rA, rB, result)) { last_hit = FRONT; return true; }

//back
poly.Count = 0;
poly.AddVertex(bA);
poly.AddVertex(bB);
poly.AddVertex(bC);
poly.AddVertex(bD);
if (RayTPolygonIntersection(poly, rA, rB, result)) { last_hit = BACK; return true; }


//right
poly.Count = 0;
poly.AddVertex(bA);
poly.AddVertex(fA);
poly.AddVertex(fD);
poly.AddVertex(bD);
if (RayTPolygonIntersection(poly, rA, rB, result)) { last_hit = RIGHT; return true; }


//left
poly.Count = 0;
poly.AddVertex(bB);
poly.AddVertex(fB);
poly.AddVertex(fC);
poly.AddVertex(bC);
if (RayTPolygonIntersection(poly, rA, rB, result)) { last_hit = LEFT; return true; }


//top
poly.Count = 0;
poly.AddVertex(bD);
poly.AddVertex(bC);
poly.AddVertex(fC);
poly.AddVertex(fD);
if (RayTPolygonIntersection(poly, rA, rB, result)) { last_hit = TOP; return true; }

//bottom
poly.Count = 0;
poly.AddVertex(bA);
poly.AddVertex(bB);
poly.AddVertex(fB);
poly.AddVertex(fA);
if (RayTPolygonIntersection(poly, rA, rB, result)) { last_hit = BOTTOM; return true; }

return false;
}

};













struct TCollisionResponsePacket
{
vec3 point_of_collision;
bool isCollision;

TCollisionResponsePacket()
{
	isCollision = false;
}
};

struct TCollisionBoxResponse
{
vec3 col_pos;
bool collision;
};



struct TCollisionBox
{
	vec3 pos;
	TPolygon<float> 		SIDES	[6];
	TCollisionBoxResponse 	response[6];
	TachoGLModel<float>   *	highpoly_model;
	bool 					use_highp;

	TCollisionBox()
	{
		highpoly_model 	= NULL;
		use_highp 		= false;
	}


	~TCollisionBox()
	{
		if (highpoly_model 	!= NULL) delete highpoly_model;
	}

//	TCollisionBox operator=(const TCollisionBox & in)
//	{
//pos = in.pos;
//for (int i=0; i < 6; i++)
//SIDES[i].CopyVerticesFrom(in.SIDES[i]);
//	}

void MakeCollisionBoxOutofModel(TachoGLModel<float> * model);

/*
 *  So box is rotated with rotMat and translated with objpos
 */
	TCollisionResponsePacket BoxSegmentIntersection(vec3 A, vec3 B, Matrix44<float> rotMat, vec3 objpos)
	{
		TCollisionResponsePacket result;
		TPolygon<float> T;

		mat4 Trotmat;
		Trotmat.TranslateP(objpos);
		mat4 outputmat = rotMat * Trotmat;

vec3 res;
for (int i=0; i < 6; i++) //through all sides
{
	T.CopyVerticesFrom(SIDES[i]);

	for (int n=0; n < T.Count; n++) T.V[n] = outputmat * T.V[n];

	response[i].collision = RayTPolygonIntersection(T, A, B, response[i].col_pos);

	if (response[i].collision) result.isCollision = true;
}

if (!result.isCollision) return result;

/*
 * If we're here theres a collision
 */

/*
 *  Find closest point to the A point
 */


vec3 cp;
float dst = 999999999.9;
int index = 0;
for (int i=0; i < 6; i++)
	if (response[i].collision)
	{
float Adst = n3ddistance(A, response[i].col_pos);
if (Adst < dst)
{
	index 	= i;
	dst 	= Adst;
}
	}

result.point_of_collision = response[index].col_pos;

return result;
}


};


typedef TCollisionBox * TCollisionBoxPointer;

#endif

[/spoiler]

you could modify the code to check through each obect face

collision.cpp

[spoiler]


#include "collision.h"











void TCollisionBox::MakeCollisionBoxOutofModel(TachoGLModel<float> * model)
{
model->CalculateMinMax();
vec3 dim = model->MAX - model->MIN;
for (int i=0; i < 6; i++) SIDES[i].Count = 4;

SIDES[FRONT].V[0] = model->MIN;
SIDES[FRONT].V[1] = model->MIN + vec3(dim.x, 0.0, 0.0);
SIDES[FRONT].V[2] = model->MIN + vec3(dim.x, dim.y, 0.0);
SIDES[FRONT].V[3] = model->MIN + vec3(0.0, dim.y, 0.0);

SIDES[BACK].V[0] = model->MIN + vec3(0.0, 0.0, dim.z);
SIDES[BACK].V[1] = model->MIN + vec3(dim.x, 0.0, dim.z);
SIDES[BACK].V[2] = model->MIN + vec3(dim.x, dim.y, dim.z);
SIDES[BACK].V[3] = model->MIN + vec3(0.0, dim.y, dim.z);

SIDES[LEFT].V[0] = model->MIN;
SIDES[LEFT].V[1] = model->MIN + vec3(0.0, 0.0, dim.z);
SIDES[LEFT].V[2] = model->MIN + vec3(0.0, dim.y, dim.z);
SIDES[LEFT].V[3] = model->MIN + vec3(0.0, dim.y, 0.0);

SIDES[RIGHT].V[0] = model->MIN + vec3(dim.x, 0.0, 0.0);
SIDES[RIGHT].V[1] = model->MIN + vec3(dim.x, 0.0, dim.z);
SIDES[RIGHT].V[2] = model->MIN + vec3(dim.x, dim.y, dim.z);
SIDES[RIGHT].V[3] = model->MIN + vec3(dim.x, dim.y, 0.0);

SIDES[TOP].V[0] = model->MIN + vec3(0.0, dim.y, 0.0);
SIDES[TOP].V[1] = model->MIN + vec3(dim.x, dim.y, 0.0);
SIDES[TOP].V[1] = model->MIN + vec3(dim.x, dim.y, dim.z);
SIDES[TOP].V[1] = model->MIN + vec3(0.0, dim.y, dim.z);

SIDES[BOTTOM].V[0] = model->MIN;
SIDES[BOTTOM].V[1] = model->MIN + vec3(dim.x, 0.0, 0.0);
SIDES[BOTTOM].V[2] = model->MIN + vec3(dim.x, 0.0, dim.z);
SIDES[BOTTOM].V[3] = model->MIN + vec3(0.0, 0.0, dim.z);


}






















































bool RayTPolygonIntersection(TPolygon<float> face, vec3 rA, vec3 rB, vec3 & res)
{

	vec3  A = vectorAB(face.V[0],face.V[1]);
	vec3  B = vectorAB(face.V[0],face.V[ face.Count - 1 ]);
	vec3  n = Normalize(A * B);

	vec3 PointOnPlane;

 long double originDistance = -1.0 * ((n.x * face.V[0].x) +
						   (n.y * face.V[0].y) +
						   (n.z * face.V[0].z));


  long double		distance1 = ((n.x * rA.x)  +
				 (n.y * rA.y)  +
				 (n.z * rA.z)) + originDistance;

  long double		distance2 = ((n.x * rB.x)  +
				 (n.y * rB.y)  +
				 (n.z * rB.z)) + originDistance;

	if(distance1 * distance2 >= 0.0)
										return false;



 vec3 vLineDir = Normalize(rB - rA);


	long double 	Numerator = -1.0 * (n.x * rA.x +
						   n.y * rA.y +
							 n.z * rA.z + originDistance);




 long double 	Denominator = ( (n.x * vLineDir.x) + (n.y * vLineDir.y) + (n.z * vLineDir.z) );

	if( absnf(Denominator) <= 0.0001)    {
PointOnPlane = rA;
	} else	{
long double		dist = Numerator / Denominator;
  PointOnPlane = (rA + (vLineDir * double(dist)));
}

res = PointOnPlane;


const long double MATCH_FACTOR = 0.9999;
long double Angle = 0.0;
	vec3 vA, vB;


	for (int i = 0; i < face.Count; i++)
	{
		vA = vectorAB(PointOnPlane, face.V[i]);

		vB = vectorAB(PointOnPlane, face.V[(i + 1) % face.Count]);

		Angle += (long double)AngleBetweenVectors(vA, vB);
	}



	if(Angle >= (MATCH_FACTOR * (2.0 * pi)) )
		return true;

	return false;

}

[/spoiler]

you could modify the code to check through each obect face

That's too much code to edit to include in my engine. As I'm including bullet physics which includes mouse picking by bounding box/sphere/vertex ect, ill be using that.

Thanks.

yeah no innovations and self thinking these days

This topic is closed to new replies.

Advertisement