After reading several article and unsucsessfuly trying to convert the calculation from the Tom's Blog (it works, but independently from portal angles, so if you rotate destination or source portal, everything get's **** up), I tried to create something by myself. Thank to those article, I somehow got the main idea of what I needed to do, so I came up with a small demo (only math calculations, no reflation and fancy stuff yet).

HERE IS THE SOURCE (just save it and run from SED):
Code:
ENTITY* heroEnt;
ENTITY* ghost1Ent;

ENTITY* portal1Ent;
ENTITY* portal2Ent;

void calculatePortal(ENTITY* ent, VECTOR* srcPos, VECTOR* dstPos, ANGLE* srcAng, ANGLE* dstAng){
	
	if(!heroEnt){ return; }
	
	ANGLE tempAng;
	vec_fill(tempAng.pan, 0);
	
	VECTOR tempPos;	
	vec_fill(tempPos.x, 0);
	
	ang_diff(tempAng.pan, dstAng.pan, srcAng.pan);
	vec_set(tempPos.x, srcPos.x);
	vec_sub(tempPos.x, heroEnt.x);
	vec_rotate(tempPos.x, tempAng.pan);
	// vec_inverse(tempPos.x); // uncomment this to mirror player's position at destination portal (comment ang_rotate 180 bellow!)
	vec_add(tempPos.x, dstPos.x);
	
	
	ANGLE temp2Ang, endAng;
	vec_fill(temp2Ang.pan, 0);
	vec_fill(endAng.pan, 0);
	
	ang_diff(temp2Ang.pan, srcAng.pan, heroEnt.pan);
	vec_inverse(temp2Ang.pan);
	ang_rotate(temp2Ang.pan, vector(180, 0, 0));
	vec_set(endAng.pan, dstAng.pan);
	ang_add(endAng.pan, temp2Ang.pan);
	
	
	// if player far away from us:
	if(vec_dist(heroEnt.x, ent.x) > 25){
		if(!is(ent.parent, INVISIBLE)){
			set(ent.parent, INVISIBLE);
		}
	}
	else{
		if(is(ent.parent, INVISIBLE)){
			reset(ent.parent, INVISIBLE);
		}
		
		vec_set(ent.parent.x, tempPos.x);
		vec_set(ent.parent.pan, endAng.pan);
		
		VECTOR tempVec;
		vec_fill(tempVec.x, 0);
		
		vec_set(tempVec.x, vector(2.5, 0, 0));
		vec_rotate(tempVec.x, ent.parent.pan);
		vec_add(tempVec.x, ent.parent.x);
		draw_point3d(tempVec.x, COLOR_RED, 100, 1);
	}
}

void portal1(){
	VECTOR tempVec;
	vec_fill(tempVec.x, 0);
	
	portal1Ent = my;
	
	vec_set(my.scale_x, vector(0.05, 1, 1));
	my.pan += random(360);
	set(my, LIGHT | UNLIT | PASSABLE);
	vec_set(my.blue, COLOR_RED);
	
	my.parent = ent_create(CUBE_MDL, my.x, NULL);
	vec_set(my.parent.scale_x, vector(0.25, 0.25, 0.25));
	set(my.parent, TRANSLUCENT | LIGHT | UNLIT | PASSABLE);
	vec_set(my.parent.blue, COLOR_RED);
	
	while(!portal2Ent){ wait(1); }
	
	while(1){
		
		my.pan += 5 * (key_cul - key_cur) * time_step;
		
		my.x += 5 * (key_t - key_g) * time_step;
		my.y += 5 * (key_f - key_h) * time_step;
		
		vec_set(tempVec.x, vector(5, 0, 0));
		vec_rotate(tempVec.x, my.pan);
		vec_add(tempVec.x, my.x);
		draw_line3d(tempVec.x, NULL, 100); 
		draw_line3d(tempVec.x, COLOR_RED, 100); 
		draw_line3d(my.x, COLOR_RED, 100); 
		draw_point3d(tempVec.x, COLOR_RED, 100, 1);
		
		calculatePortal(my, my.x, portal2Ent.x, my.pan, portal2Ent.pan);
		
		wait(1);
	}
}


void portal2(){
	VECTOR tempVec;
	vec_fill(tempVec.x, 0);
	
	portal2Ent = my;
	
	vec_set(my.scale_x, vector(0.05, 1, 1));
	my.pan += random(360);
	set(my, LIGHT | UNLIT | PASSABLE);
	vec_set(my.blue, COLOR_GREEN);
	
	my.parent = ent_create(CUBE_MDL, my.x, NULL);
	vec_set(my.parent.scale_x, vector(0.25, 0.25, 0.25));
	set(my.parent, TRANSLUCENT | LIGHT | UNLIT | PASSABLE);
	vec_set(my.parent.blue, COLOR_GREEN);
	
	while(!portal1Ent){ wait(1); }
	
	while(1){
		
		my.pan += 5 * (key_cuu - key_cud) * time_step;
		
		my.x += 5 * (key_i - key_k) * time_step;
		my.y += 5 * (key_j - key_l) * time_step;
		
		vec_set(tempVec.x, vector(5, 0, 0));
		vec_rotate(tempVec.x, my.pan);
		vec_add(tempVec.x, my.x);
		draw_line3d(tempVec.x, NULL, 100); 
		draw_line3d(tempVec.x, COLOR_GREEN, 100); 
		draw_line3d(my.x, COLOR_GREEN, 100); 
		draw_point3d(tempVec.x, COLOR_GREEN, 100, 1);
		
		calculatePortal(my, my.x, portal1Ent.x, my.pan, portal1Ent.pan);
		
		wait(1);
	}
}


void main(){
	
	fps_max = 60;
	level_load("");
	
	random_seed(0);
	
	// create portals:	
	ent_create(CUBE_MDL, vector(-25, 25, 0), portal1);	
	ent_create(CUBE_MDL, vector(25, -25, 0), portal2);
	
	VECTOR tempVec;
	vec_fill(tempVec.x, 0);
	
	heroEnt = ent_create(CUBE_MDL, nullvector, NULL);
	vec_set(heroEnt.scale_x, vector(0.25, 0.25, 0.25));
	set(heroEnt, TRANSLUCENT | LIGHT | UNLIT);
	vec_set(heroEnt.blue, COLOR_WHITE);
	c_setminmax(heroEnt);	
	
	sun_light = 0;
	set(camera, ISOMETRIC);
	camera.arc = 10;
	camera.z = 100;
	camera.tilt = -90;
	
	while(1){
		
		DEBUG_VAR(heroEnt.pan, 210);
		DEBUG_VAR(portal1Ent.pan, 250);
		DEBUG_VAR(portal2Ent.pan, 270);
		
		heroEnt.skill1 = 5 * (key_w - key_s) * time_step;
		heroEnt.skill2 = 5 * (key_a - key_d) * time_step;
		heroEnt.pan += 5 * (key_z - key_x) * time_step;
		c_move(heroEnt, nullvector, heroEnt.skill1, IGNORE_PASSABLE | GLIDE);
		
		vec_set(tempVec.x, vector(2.5, 0, 0));
		vec_rotate(tempVec.x, heroEnt.pan);
		vec_add(tempVec.x, heroEnt.x);
		draw_point3d(tempVec.x, COLOR_RED, 100, 1);
		
		draw_text("green and red cubes are 'ghost' players position in the destination portals\nwhite cube is player, and those two red/green lines are portals\nyou can see the way they are facing from the lines comming out of portals\nthe green one is source portal and the other one is destination portal (and visa versa)\nuse cursor keys to rotate the portals use WSAD to move the player around \nand TGFH and IKJL to move portals", 10, 10, COLOR_WHITE);
		
		wait(1);
	}
}

Please give it a try guys and tell me, am I even on the right track?

Edit: I think, this will at least help me with object duplication, to get the seamless transition of object from one portal to another.

Edit2: I edited the code (updated).

Best regards!


Looking for free stuff?? Take a look here: http://badcom.at.ua
Support me on: https://boosty.to/3rung