Extern doesn't work?

BlitzMax Forums/BlitzMax Programming/Extern doesn't work?

AntonyWells(Posted 2005) [#1]
Keep's telling it's an undefined reference, even though it's clearly not.

The code belows imports a C++ file. it compiles fine, but whenever I call a function contained within it, that's when it fails at the linking stage.

C:/Program Files/BlitzMax/ARPG/.bmx/AI.bmx.gui.debug.win32.o(code+0x185): undefined reference to `CreateLine'
C:/Program Files/BlitzMax/ARPG/.bmx/AI.bmx.gui.debug.win32.o(code+0x1ac): undefined reference to `CreateLine'



Referencing the two times I called the function in the test code below..

BlitzMax Code.
Import "Line2D.cpp"


Public

Extern "win32"
	Function CreateLine:Int( x1#,y1#,x2#,y2# )="CreateLine"
	Function SetLine( line,x1#,y1#,x2#,y2# )
	Function LineCast:Int( line1,line2,result )
	Function ResultX:Int(result)
	Function ResultY:Int(result)
	Function CreateResult:Int()
	
End Extern



Graphics 640,480,0

Local x1#,y1#,x2#,y2#

x1=20
y1=20

Local lin1,lin2

lin1 = createLine( x1,y1,x2,y2 )
lin2 = createLine( 320,0,325,480 )

If lin1=0 RuntimeError "Line was not created."

Repeat
Cls
	x2=MouseX()
	y2=MouseY()	
	
	DrawLine x1,y1,x2,y2
	DrawLine 320,0,325,480
Flip
Until KeyDown(1)



C++ Code, call it "Lines2d.cpp"


class XPOINT
{
public:
float x, y;
};

class XLINE
{
public:
XPOINT o, p;
float m;
float c;
};

float min( float v1,float v2 )
{
     if(v1<v2) return v2;
     return v1;
}

float max( float v1,float v2) 
{
     if(v1>v2) return v1;
     return v2;
}

XLINE CreateLine( float x1,float y1,float x2,float y2){
   XLINE out;
   out.o.x=x1;
   out.o.y=y1;
   out.p.x=x2;
   out.p.y=y2;
   return out;
}

void SetLine( XLINE &l,float x1,float y1,float x2,float y2){
    l.o.x=x1;
    l.o.y=y1;
    l.p.x=x2;
    l.p.y=y2;
}


XPOINT * CreateResult(){
   return( new XPOINT);
}

float ResultX( XPOINT *i){
   return i->x;
}

float ResultY( XPOINT *i){
  return i->y;
}



int LineCast( XLINE &a, XLINE &b, XPOINT *i )
{
// null width lines cannot intercept
if ( (a.p.x == a.o.x) || (b.p.x == b.o.x) )
{
return false;
}
// calculate gradients
a.m = (a.p.y - a.o.y) / (a.p.x - a.o.x);
b.m = (b.p.y - b.o.y) / (b.p.x - b.o.x);
// parallel lines can't intercept
if (a.m == b.m)
{
return false;
}
// calculate axis intersect values
a.c = a.o.y - (a.m * a.o.x);
b.c = b.o.y - (b.m * b.o.x);
// calculate x point of intercept
i->x = (b.c - a.c) / (a.m - b.m);
// is intersection point in segment
if ( i->x < min(a.o.x, a.p.x) || i->x > max(a.o.x, a.p.x) )
{
return false;
}
if ( i->x < min(b.o.x, b.p.x) || i->x > max(b.o.x, b.p.x) )
{
return false;
}
// calculate y point of intercept
i->y = (a.m * i->x) + a.c;
// points intercept
return true;
};




Dreamora(Posted 2005) [#2]
exchange Extern "win32" with extern (without "win32")

extern "win32" is a predefined extern link to win32 libraries.


AntonyWells(Posted 2005) [#3]
That was the first thing I tried, same deal. Just remember having to use a certain "blah" extern directive when this happened before.

Know of the others? I havn't even bothered looking in the docs. Last place they'll be.


Robert(Posted 2005) [#4]
Hi Antony, I think C++ name-mangling may be a problem, your cpp file may not be exporting a function called "CreateLine" as a result.

try this:

extern "C" XLINE CreateLine( float x1,float y1,float x2,float y2){
   XLINE out;
   out.o.x=x1;
   out.o.y=y1;
   out.p.x=x2;
   out.p.y=y2;
   return out;
}



Dreamora(Posted 2005) [#5]
btw: even if you get that to work, you can't work with C++ objects in BM


Robert(Posted 2005) [#6]
Hi Dremora,

That isn't true. If you read the 'Advanced Topics' section of the language help, you'll see that you can work with C++ classes in BlitzMAX.


Dreamora(Posted 2005) [#7]
Then you should have seen the restrictions of that, that you can't work with it in BM as you are used by normal types.


Sweenie(Posted 2005) [#8]
Either as Robert said...
extern "C" XLINE CreateLine( float x1,float y1,float x2,float y2)

or
Function CreateLine:Int( x1#,y1#,x2#,y2# )="_Z10CreateLineffff"

10 is the length of the function name and ffff stands for 4 floats


AntonyWells(Posted 2005) [#9]
Robert's suggestion worked. Thanks.

But, turns out the code wasn't worth importing anyway. It has to be most inaccurate line intersection routine ever devised by crack addled man.

Anyone got a good one? Or you know, one that just actually works? (Frustration rising.)


AntonyWells(Posted 2005) [#10]
Don't matter, found swift's one in the code archives.
WHY DIDN'T I CHECK THERE FIRST!.

[morphs into the incredible hulk]


AntonyWells(Posted 2005) [#11]
Great, swift's func doesn't work either.


Function Lines_Intersect(Ax#, Ay#, Bx#, By#, Cx#, Cy#, Dx#, Dy#)
	Local Rn# = (Ay#-Cy#)*(Dx#-Cx#) - (Ax#-Cx#)*(Dy#-Cy#)
    Local Rd# = (Bx#-Ax#)*(Dy#-Cy#) - (By#-Ay#)*(Dx#-Cx#)
	Print RD+":"+rn
	If Rd# = 0
		Return False
	Else
         Local Sn# = (Ay#-Cy#)*(Bx#-Ax#) - (Ax#-Cx#)*(By#-Ay#)
		 Intersection_AB# = Rn# / Rd#
         Intersection_CD# = Sn# / Rd#
         Intersection_X# = Ax# + Intersection_AB#*(Bx#-Ax#)
         Intersection_Y# = Ay# + Intersection_AB#*(By#-Ay#)
    Return True
    EndIf
End Function



always returns true, yet the itnersection point is always accurate, but it's as if the second line is infinitely long.


Gabriel(Posted 2005) [#12]
You're correct that SSwift's code checks if the first line crosses an infinitely long line on the angle defined by the two points.

Here's a slightly modified and commented version of SSwift's code which only returns true if the lines intersect within the length of the second line.

Function Lines_Intersect(Ax#,Ay#,Bx#,By#,Cx#,Cy#,Dx#,Dy#)
  

	Rn#=(Ay#-Cy#)*(Dx#-Cx#)-(Ax#-Cx#)*(Dy#-Cy#)
	Rd#=(Bx#-Ax#)*(Dy#-Cy#)-(By#-Ay#)*(Dx#-Cx#)
	If Rd# = 0 
		; Lines are parallel.
		; If Rn# is also 0 then lines are coincident.  All points intersect. 
		; Otherwise, there is no intersection point.
		Return False
	Else
		; The lines intersect at some point.  Calculate the intersection point.
		Sn# = (Ay#-Cy#)*(Bx#-Ax#) - (Ax#-Cx#)*(By#-Ay#)
		Intersection_AB# = Rn# / Rd#
		Intersection_CD# = Sn# / Rd#
		
		; MAKE SURE IT FITS WITHIN THE FIRST LINE
		If Intersection_AB#<0.0 Or Intersection_AB#>1.0	
			; THEY INTERSECT, BUT BEYOND THE LENGTH OF LINE 2.
			Return False
		Else
			; MAKE SURE IT FITS WITHIN THE SECOND LINE
			If Intersection_CD#<0.0 Or Intersection_CD#>1.0
				Return False
			Else
				Intersection_X# = Ax# + Intersection_AB#*(Bx#-Ax#)
				Intersection_Z# = Ay# + Intersection_AB#*(By#-Ay#)	
				Return True		
			End If
		End If
	EndIf

End Function



Robert(Posted 2005) [#13]
Graphics 640,480,0
 
Local a:Vector2=New Vector2
Local b:Vector2=New Vector2
Local c:Vector2=New Vector2
Local d:Vector2=New Vector2

Local i:Vector2=New Vector2

a.x=34
a.y=62
b.x=42
b.y=87

c.x=50
c.y=0
d.x=43
d.y=100

While Not KeyHit(KEY_ESCAPE)
	
	'Draw a circle
	
	DrawLine a.x,a.y,b.x,b.y
	DrawLine c.x,c.y,d.x,d.y
	
	If (linesIntersect2D(a,b,c,d,Null))
		DrawText "Lines Intersect",300,300
	Else
		DrawText "No Intersection",300,300
	End If

	Flip
	Cls
	
	FlushMem
End While


Type Vector2
	Field x:Float
	Field y:Float
	
End Type

Type Vector3 Extends Vector2
	Field z:Float
End Type


'Tests for the intersection of two lines in 2 dimensions.  Each line is defined by a start and an end point.
'Returns True if the lines intersect or false otherwise.  If they do intersect, outIntersect
'is set to the coordinates of the intersection.  outIntersect can be Null.

Function linesIntersect2D(p1:Vector2,p2:Vector2,p3:Vector2,p4:Vector2, outIntersect:Vector2)

	'Eqn of two lines:
	'	lineA = p1 + uA(p2-p1)
	'	lineB = p3 + uB(p4-p3)
	
	'Put lineA = lineB, and solve for uA, gives us:	

	uA:Float=	((p4.x-p3.x)*(p1.y-p3.y)) - ((p4.y-p3.y)*(p1.x-p3.x))
	temp:Float= ((p4.y-p3.y)*(p2.x-p1.x)) - ((p4.x-p3.x)*(p2.y-p1.y))
	
	uB:Float =  ((p2.x-p1.x)*(p1.y-p3.y)) - ((p2.y-p1.y)*(p1.x-p3.x))
	
	
	'Check if lines are parallel
	If (temp=0)
		Return False
	End If
	
	uA :/ temp
	uB :/ temp
	
	intersectX:Float = p1.x+uA*(p2.x-p1.x)
	intersectY:Float = p1.y+uA*(p2.y-p1.y)
	
	If ((uA >= 0) And (uA <= 1) And (uB >= 0) And (uB <= 1))	
		If (outIntersect)
			outIntersect.x=intersectX
			outIntersect.y=intersectY
		End If
		
		Return True
	Else
		Return False
	End If

End Function



AntonyWells(Posted 2005) [#14]
Your turn Syb? :)

Thanks both, I'll use them both equally..or something. :)