Issues with a 3D plotting routine

This forum is dedicated to those who want support programming in ugBASIC.
Questo forum è dedicato a chi desidera supporto per programmare in ugBASIC.
Ce forum est dédié à ceux qui souhaitent prendre en charge la programmation en ugBASIC.
Post Reply
lightbeing
Posts: 1
Joined: Thu Oct 17, 2024 5:36 pm

Issues with a 3D plotting routine

Post by lightbeing »

Hi everybody

I need some help as I don't know if I'm doing things wrong or there is an issue with the compiler.

I tried to translate into UGBASIC's syntax, but without success, the following routine written with Epyx toolkit for the Commodore 64's BASIC. It works fine with Epyx toolkit installed, and draws a 3D picture of a figure that looks like a hat.

10 RESET:MULTI:BACKGROUNDBLACK:BORDERBLACK:
20 P=160
30 Q=100:XP=144:XR=1.5*pi:YP=56:YR=1
50 ZP=64:XF=XR/XP:YF=YP/YR:ZF=XR/ZP
60 FORZI=-QTOQ-1
70 IF ZI<-ZP OR ZI>ZP GOTO150
80 ZT=ZI*XP/ZP:ZZ=ZI
90 XL=INT (.5+SQR(XP*XP-ZT*ZT))
100 FOR XI=-XLTOXL
110 XT=SQR(XI*XI+ZT*ZT)*XF:XX=XI
120 YY=(SIN(XT)+.4*SIN(3*XT))*YF
130 GOSUB 170
140 NEXT XI
150 NEXT ZI
160 GOTO 160
170 X1=XX+ZZ+P:Y1=YY-ZZ+Q
180 COLORGREEN:DOT X1,Y1
190 IF Y1=0 GOTO 220
200 COLORBLACK: LINE X1,Y1-1TOX1,0
210 RETURN


My translation is the following. I can't see what's wrong but it does not work

BITMAP ENABLE (320,200,16):CLS BLACK:
p1=160
q=100:xp=144:xr=01.5*PI:yp=56:yr=01
zp=64:xf=xr/xp:yf=yp/yr:zf=xr/zp
FOR zi=-q TO q-1
IF zi<-zp OR zi>zp THEN GOTO endloop
zt=zi*xp/zp:zz=zi
xl=INT(.5+SQR(xp^2-zt^2))
FOR xi=-xl TO xl
DEGREE
xt=(SQR(xi*xi+zt*zt)*xf)*180/PI:xx=xi
yy=(SIN (xt)+.4*SIN (3*xt))*yf
GOSUB continue
NEXT
endloop:
NEXT
loop:
GOTO loop
continue:
x1=xx+zz+p1:y1=INT(yy-zz+q)
PLOT x1,y1,GREEN
IF y1=0 THEN GOTO draw_line
draw_line:
INK BLACK:LINE x1,y1-1 TO x1,0
RETURN

I tried an alternative with a similar but shorter routine, which works fine with Tool 64 installed.

10 graphic:sclear
20 xp=144:xr=4.71238905:xf=xr/xp
30 forzi=-64to64
40 zt=zi*2.25:zs=zt*zt
50 xl=int(sqr(20736-zs)+.5)
60 forxi=0-xltoxl
70 xt=sqr(xi*xi+zs)*xf
80 yy=(sin(xt)+sin(xt*3)*0.4)*56
90 x1=xi+zi+160:y1=110+yy-zi
100 plotx1,y1,1
110 rem ify1=0thengoto120
120 rem movex1,y1-1:drawx1,0,0: rem remplacer drawx1,y1-50,0
130 next:next
140 rem goto130

My translation was unsuccessful as well unfortunately:

10 graphic:sclear
20 xp=144:xr=4.71238905:xf=xr/xp
30 forzi=-64to64
40 zt=zi*2.25:zs=zt*zt
50 xl=int(sqr(20736-zs)+.5)
60 forxi=0-xltoxl
70 xt=sqr(xi*xi+zs)*xf
80 yy=(sin(xt)+sin(xt*3)*0.4)*56
90 x1=xi+zi+160:y1=110+yy-zi
100 plotx1,y1,1
110 rem ify1=0thengoto120
120 rem movex1,y1-1:drawx1,0,0: rem remplacer drawx1,y1-50,0
130 next:next
140 rem goto130

Do you have any idea what could be wrong?

Thanks in advance
spotlessmind1975
Site Admin
Posts: 171
Joined: Fri Oct 06, 2023 8:25 pm

Re: Issues with a 3D plotting routine

Post by spotlessmind1975 »

Hi lightbeing, and welcome! :D
lightbeing wrote: Fri Oct 18, 2024 4:43 pm I need some help as I don't know if I'm doing things wrong or there is an issue with the compiler.
First of all I ask you to kindly download the latest COLDFIX released today, which contains a series of fixes on the trigonometric section for MOS 6502 processors, as well as on the management of numeric constants of type FLOAT. This could be the basis of the problem encountered.

I would like to point out that, for performance reasons, ugBASIC is an "Integer BASIC" and does not use float types natively. This has a series of consequences, the most notable of which is that variables are born integer, and not floating point. Therefore, it is not always possible to directly port the sources of other BASICs to floating point without a minimal adaptation. In this case, there are some things that cannot work on ugBASIC, and that should be rethought. I started from your first rewrite, not from the original source, although I was unable to get a significant figure, but I think it depends on the fact that I did not understand well the algorithm with which the points are calculated (I am very sorry!).

DEFINING VARIABLES
When working with the FLOAT type, it is necessary to define all variables correctly, to prevent the compiler from "promoting" them to integers, as already written. The solution of defining them all as FLOAT is only viable if you are sure of what you want to do, and taking into account that the memory footprint grows as you use them.

In this case (if I understood well):

Code: Select all

DIM p AS FLOAT, q AS INT
	DIM xp AS FLOAT, yp AS FLOAT, zp AS FLOAT
	DIM xf AS FLOAT, yf AS FLOAT, zf AS FLOAT
	DIM xr AS FLOAT, yr AS FLOAT, zr AS FLOAT
	DIM xt AS FLOAT, yt AS FLOAT, zt AS FLOAT
	DIM xx AS FLOAT, yy AS FLOAT, zz AS FLOAT
	DIM zi AS INTEGER, p1 AS INTEGER, zt AS FLOAT
	DIM xl AS INTEGER, yl AS INTEGER
	DIM x1 AS INTEGER, y1 AS INTEGER
If you need help from the compiler, you can require that all variables be defined before they are used, with the OPTION EXPLICIT command. This way, the compiler will warn you (with an error) if you are using a variable that has not yet been defined, and you will be able to choose the type.

RADIANS VERSUS DEGREES
Although the DEGREE statement is present, for easy of use, using it for trigonometric functions means introducing a slowdown for each operation, in addition to taking up much more space in terms of assembly code. It would therefore be advisable to work without making translations proportional to the PI. This avoid additional divisions and multiplications, too.

"RAISE TO A POWER" ONLY FOR INTEGER
The exponentiation instruction is only available for integer types, and not for floating point types. In this specific case there are no particular problems in replacing them, because exponentiation is done with a constant (2). So the instruction:

Code: Select all

xt=(SQR(xi^2i+zt^2)*xf)*180/PI:xx=xi
Should be rewritten as:

Code: Select all

xt=(SQR(xi*xi+zt*zt)*xf)*180/PI:xx=xi
APPROXIMATE SQUARE ROOT
Also the square root function is implemented only for integer types, and this introduces a large approximation, which could compromise the execution of this specific program.
lightbeing wrote: Fri Oct 18, 2024 4:43 pm I tried an alternative with a similar but shorter routine, which works fine with Tool 64 installed.
I tried to rewrite it as best I could, so I apologize if I made any mistakes.

Code: Select all

OPTION EXPLICIT

DIM xp AS FLOAT, xf AS FLOAT, xr AS FLOAT
DIM zt AS FLOAT, zi AS INT, xi AS INT
DIM zs AS FLOAT, xl AS INT, xt AS FLOAT
DIM yy AS FLOAT, x1 AS INT, y1 AS INT

BITMAP ENABLE(320,200)
CLS

xp=144
xr=4.71238905
xf=xr/xp

FOR zi = -64 TO 64
	zt = zi*2.25
	zs = zt*zt
	xl = INT(SQR(20736-zs)+.5)
	FOR xi = 0-xl TO xl
		xt = SQR(xi*xi+zs)*xf
		yy = (SIN(xt)+SIN(xt*3)*0.4)*56
		x1=xi+zi+160
		y1=yy-zi
		PLOT x1,y1,YELLOW
	NEXT
NEXT
Here the result on some platforms:Amstrad CPC 664 - Commodore 128 - ColecoVision

Again, the result is not particularly significant on 6502 based processors, but this could depend on the approximations introduced by the use of functions that work with integers.

Let me know if I can be of any help!
Post Reply