Jump to content
IGNORED

Death Star for Missing Link


Tursi

Recommended Posts

Apologies to the ports already done, but I had to take a stab at optimizing it. I got rid of the DEF and the SUBs, got rid of the lookup table (each value was only used once and there were a number of unused values in it anyway), and moved some of the processing out of the way when no work was being done. I also skipped a few latitudes that don't draw anyway.

 

The one thing I couldn't optimize was the circle draws - I tried. The X*C-Y*S etc code is used to step through a circle -- but the /entire/ circle is always calculated. On the main base itself, the /back/ is calculated first, and that's wasted time. But because we're stepping, we have to do it. I'm not sure if that math is faster or slower than the corresponding SIN/COS calls, but I ran out of patience and I didn't want to try to calculate the circles to redo them. Still, this version is markedly faster. The screenshot here shows it finished - the new version on the left was started when the old version on the right had already drawn a few rows. (It's still slow, of course, I did this in overdrive ;) ).

 

It'd also be nice if we could do away with the need to invert the Y axis, and the upper bound on the pixel draw in line 320 could be reduced, but I wasn't happy with the simple reductions I tried.

image.thumb.png.ec7e5a2bce93fca35d098b702832398b.png

 

100 REM Death Star by Electron Greg
110 REM Adapted by Tursilion - 256x192 version - optimized
120 REM TIXB with Missing Link
130 AL=2*PI/300
140 REM original lookup table boils down to just (idx=1-300):
150 REM (-COS(AL*IDX)*300)-40
160 REM SINCE NO VALUES ARE USED MORE THAN ONCE, JUST INLINE THAT
170 CALL LINK("CLEAR")
180 CALL SCREEN(2)
190 CALL LINK("COLOR",8,2)
200 REM draw globe
210 V=64 :: A=2*PI/360 :: S=SIN(A):: C=COS(A)
220 FOR N=120 TO 195
230 Z=(1080-(((-COS(AL*(219-N))*300)-40)*7))/5
240 Z2=Z/10
250 R=((-COS(AL*N)*300)-40)/2.5
260 X=R :: Y=0 :: N2=N/2
270 FOR W=1 TO 360 :: P=(INT(RND*W))-N2 :: IF P>99 THEN 340
280 B=X*C-Y*S :: Y=X*S+Y*C :: X=B
290 IF W<180 THEN 340
300 Q=((V+X)*1.3)-(Z/10)+100 :: O=((Z+Y)/4.0)*1.34+(X/3)
310 IF N>148 AND N<152 THEN CALL LINK("PIXEL",192-O,Q+12):: GOTO 340
320 LIM=(360-W)/30
330 FOR M=1 TO LIM :: CALL LINK("PIXEL",191-O,Q+INT(RND*8+1)):: NEXT M
340 NEXT W
350 NEXT N
360 REM clear out dish area
370 CALL LINK("PE")
380 RAD=40
390 REM Super fast filled circle (does require a single square root)
400 REM from https:://stackoverflow.com/questions/1201200/fast-algorithm-for-drawing-filled-circles
410 FOR X=-RAD TO RAD
420 HH=SQR(RAD*RAD-X*X)
430 RX=100+X
440 PH=130+HH
450 CALL LINK("LINE",HH+61,RX,191-PH,RX)
460 NEXT X
470 CALL LINK("PD")
480 REM draw the circles inside the dish
490 V=100 :: Z=130 :: A=2*PI/400 :: S=SIN(A):: C=COS(A)
500 FOR N=0 TO 40 STEP 4
510 X=N :: Y=0
520 FOR W=1 TO 400 :: B=X*C-Y*S :: Y=X*S+Y*C :: X=B
530 IF N>32 AND N<44 THEN 550
540 IF INT((RND*(44-N))/5)<>0 THEN 570
550 IF W>0 AND W<120+INT(RND*30+1)THEN CALL LINK("PIXEL",191-(Z+Y),V+X)
560 IF W>310+INT(RND*30+1)AND W<400 THEN CALL LINK("PIXEL",191-(Z+Y),V+X)
570 NEXT W
580 REM spin forever
590 NEXT N
600 GOTO 600

 

  • Like 5
Link to comment
Share on other sites

trying to port this to cortex basic, getting a weird error on line 340 which makes no sense as its just a next statement..

not sure what is up yet but here's the start

nm i found it, you can't then line number its then goto..  more bugs :)

 

ok i fixed a couple more things.. for next loops in xb if the value is <1 then it doesnt run in cortex it tries to do it anyway so added a check for lim <1 

 

other math issues seem to be happening 

 

 

DSTAR

Edited by arcadeshopper
Link to comment
Share on other sites

1 hour ago, arcadeshopper said:

trying to port this to cortex basic, getting a weird error on line 340 which makes no sense as its just a next statement..

not sure what is up yet but here's the start

nm i found it, you can't then line number its then goto..  more bugs :)

 

ok i fixed a couple more things.. for next loops in xb if the value is <1 then it doesnt run in cortex it tries to do it anyway so added a check for lim <1 

 

other math issues seem to be happening 

 

still learning cortex quirks..  heres updated.. still something very wrong ;)  but MAN is it faster than tml :)

 

ah ha, x,y instead of y,x  reversed coords.. still wrong tho

 

 

DSTARR

Edited by arcadeshopper
  • Like 2
Link to comment
Share on other sites

Been working on release of new version but occurred to me to use CALL PSAVE to copy the image to a file and load it instantly.

Would only require running the creation file once. 

I would only need to find the VDP memory location of the screen and copy it to a file.

Here is a previous example from years ago.

 

 

 

 

  • Like 1
Link to comment
Share on other sites

Attached is the Cortex BASIC version of the DeathStar.  I started with Greg’s (Arcade Shopper’s) conversion. Necessary changes were:

 

- I unpacked the single line FOR-NEXT loop at 330 into three statements. That eliminated the strange FOR-NEXT errors being thrown up there (the original should work, but it doesn’t).

 

- IF …… THEN  [line number]  doesn’t work in Cortex BASiC.  IF ……. THEN GOTO [line number] does.

 

- I reversed the axes of most PLOT statements.

 

- When drawlng the filled circle of the radar using lines, it is necessary to UNPLOT the lines to achieve the black disc rather than PLOT them. Otherwise the interior circles don’t draw correctly (color table left in wrong state by PLOT?).

 

- There is no need to repeatedly calculate RAD*RAD in line 420. I moved that calculation outside the loop.

 

On my 16-bit console Cortex BASIC running from FinalGROM99 DeathStar executes in 24 minutes, 28 seconds.

 

Cortex BASIC running from ROM executes DeathStar in 21 minutes, 6 seconds.

 

image.thumb.jpeg.7321f633ee327e8420af77f1e6a29f16.jpeg

 

 

DSTAR

 

 

  • Like 6
Link to comment
Share on other sites

Cortex Basic is dramatically faster than Extended Basic, particularly if you have 16-bit ram available (I'd say it averages 3x faster). It executes instantly (no prescan), lists and prints very quickly, etc. It also enables direct use of bitmap mode in addition to Graphics1, otherwise defaulting to a 40-column screen for program listings. When listing programs it indents loops.

 

RAM is limited, however, even though it requires 32K. When running from the FinalGROM99 it has about 16k available for programs. When running solely out of CPU RAM (20% faster, loaded as an E/A option 3 program) it has only about 6K available for programs. That said, programs do tend to be very compact. Access to system features is very limited. It does have sprites, but no auto-motion. No sound commands. No file handling other than saving and loading programs. No speech. 

 

By comparison XB excels in providing access to sound, sprites, speech etc. via GPL routines - a much richer environment in that respect.  

  • Like 4
  • Thanks 1
Link to comment
Share on other sites

On 12/13/2022 at 1:43 PM, Vorticon said:

Coleco Adam version in Turbo Pascal under CP/M 2.2. Takes about 29 minutes to complete.

Note to self: avoid future literal translations from an untyped and unstructured language to a strongly typed and structured one. Saves a lot on the Tums...

20221214_073303.thumb.jpg.3227f6cb1bd599124b791e4dc51f62c0.jpg

 

Could you post your Pascal code?

Imagine translating from an untyped and unstructured language to a structured language that has no algebraic notation. :)

 

Link to comment
Share on other sites

13 hours ago, TheBF said:

Could you post your Pascal code?

Imagine translating from an untyped and unstructured language to a structured language that has no algebraic notation. :)

 

Here you go. It's not very pretty as I just mostly transliterated Tursi's XB code out of laziness. With some extra effort this could leverage the Pascal language features much better. The code also has a couple of include files for the Coleco Adam specific CP/M graphics and text extensions I created with some leverage from some inline Z80 assembly code. Also this was coded directly on real hardware using my homebrew 40 col CP/M text editor (ADAMED) coded in 8080 assembly, hence why the listing is in 40 columns...

 

                 
{Original version for BBC micro}
program deathstar;

type
  TextString = String[42];

var
  ChrSet : array[1..6144] of Byte;
  AR : array[1..300] of real;
  V,Z,R : real;
  A,S,C,X,Y,B : real;
  N,W : integer;
  pstatus : boolean;

{$I BMPBASE.PAS}
{$I BMPTEXT.PAS}

procedure plot(X,Y : real);

var
  MY : integer;

begin
  if (Y < 0) or (Y > 191) then
     exit;
  if (X < 0) or (X > 255) then
     exit;
  MY := 191 - Round(Y);
  Pixel(MY,Round(X),pstatus,4,1)
end;


procedure procc(INV,INZ,INR,INN : real);
var
  P,Q,O,N : real;
  W,M : integer;

label
  endproc;

begin
  V := INV;
  Z := INZ;
  R := INR;
  N := INN;
  A := 2 * Pi / 360;
  S := sin(A);
  C := cos(A);
  X := R;
  Y := 0;

  for W := 1 to 360 do
     begin
        P := (Random(W)+1) - (N / 2);
        if P > 100 then
           goto endproc;
        B := X * C - Y * S;
        Y := X * S + Y * C;
        X := B;
        Q := ((V + X) * 1.3) -
             (Z / 10) + 100;
        O := ((Z + Y) / 4.0) *
             1.34 + (X / 3);
        if W < 180 then
           goto endproc;
        if (N > 148) and (N < 152) then
           begin
              plot(Q + 12, O - 1);
              goto endproc
           end;
        for M := 1 to Round((360 -
                 W) / 30) do
           plot(Q + Random(8) + 1,O);
     endproc:
     end;
end;

procedure proccg(INV,INZ,INR : real);

label
  endproc;

var
  W,N : integer;

  begin
     V := INV;
     Z := INZ;
     R := INR;
     N := Round(INR);
     A := 2 * Pi / 400;
     S := sin(A);
     C := cos(A);
     X := R;
     Y := 0;

     for W := 1 to 400 do
        begin
           B := X * C - Y * S;
           Y := X * S + Y * C;
           X := B;
           if (N <= 32) or (N >= 44)
              then
                 if Round((Random(44 - N
                    ) + 1) / 5) <> 1
                    then
                       goto endproc;
           if (W > 0) and (W < (120 +
              Random(30)+1)) then
              plot(V + X, Z + Y);
           if (W > (310 + Random(30) + 1
              )) and (W < 400) then
              plot(V + X, Z + Y);
        endproc:
        end;
end;

procedure procb(INV,INZ,INR : real);

var
  IX,IY,PH : integer;
  RAD,HH,RX : real;

begin
  pstatus := false;
  RAD := INR;
  for IX := Round(-RAD) to Round(RAD) do
     begin
        HH := Sqrt(Sqr(RAD) -
              Sqr(IX));
        RX := INV + IX;
        PH := Round(INZ + HH);
        for IY := Round(INZ - HH) to PH
           do
              plot(RX,IY)
     end;
  pstatus := true
end;


begin
  BitmapInit;
  ScreenColor(1,1);
  Randomize;
  pstatus := true;
  V := 640;
  Z := 522;
  R := 300;
  A := 2 * Pi / 300;
  S := sin(A);
  C := cos(A);
  X := R;
  Y := 0;
  for W := 1 to 300 do
     begin
        B := X * C - Y * S;
        Y := X * S + Y * C;
        X := B;
        AR[W] := 600 - (V + X);
     end;
  for N := 115 to 210 do
     procc(64,(1080 - (AR[219 - N] * 7))
           / 5,AR[N] / 2.5,N);
  procb(100,130,40);
  N := 0;
  repeat
     proccg(100,130,N);
     N := N + 4;
  until N = 44;
  repeat
  until GetKey = 32;
  VDPInit;
end.

 

 

 

  • Like 4
Link to comment
Share on other sites

1 hour ago, Vorticon said:

Here you go. It's not very pretty as I just mostly transliterated Tursi's XB code out of laziness. With some extra effort this could leverage the Pascal language features much better. The code also has a couple of include files for the Coleco Adam specific CP/M graphics and text extensions I created with some leverage from some inline Z80 assembly code. Also this was coded directly on real hardware using my homebrew 40 col CP/M text editor (ADAMED) coded in 8080 assembly, hence why the listing is in 40 columns...

 

                 
{Original version for BBC micro}
program deathstar;

type
  TextString = String[42];

var
  ChrSet : array[1..6144] of Byte;
  AR : array[1..300] of real;
  V,Z,R : real;
  A,S,C,X,Y,B : real;
  N,W : integer;
  pstatus : boolean;

{$I BMPBASE.PAS}
{$I BMPTEXT.PAS}

procedure plot(X,Y : real);

var
  MY : integer;

begin
  if (Y < 0) or (Y > 191) then
     exit;
  if (X < 0) or (X > 255) then
     exit;
  MY := 191 - Round(Y);
  Pixel(MY,Round(X),pstatus,4,1)
end;


procedure procc(INV,INZ,INR,INN : real);
var
  P,Q,O,N : real;
  W,M : integer;

label
  endproc;

begin
  V := INV;
  Z := INZ;
  R := INR;
  N := INN;
  A := 2 * Pi / 360;
  S := sin(A);
  C := cos(A);
  X := R;
  Y := 0;

  for W := 1 to 360 do
     begin
        P := (Random(W)+1) - (N / 2);
        if P > 100 then
           goto endproc;
        B := X * C - Y * S;
        Y := X * S + Y * C;
        X := B;
        Q := ((V + X) * 1.3) -
             (Z / 10) + 100;
        O := ((Z + Y) / 4.0) *
             1.34 + (X / 3);
        if W < 180 then
           goto endproc;
        if (N > 148) and (N < 152) then
           begin
              plot(Q + 12, O - 1);
              goto endproc
           end;
        for M := 1 to Round((360 -
                 W) / 30) do
           plot(Q + Random(8) + 1,O);
     endproc:
     end;
end;

procedure proccg(INV,INZ,INR : real);

label
  endproc;

var
  W,N : integer;

  begin
     V := INV;
     Z := INZ;
     R := INR;
     N := Round(INR);
     A := 2 * Pi / 400;
     S := sin(A);
     C := cos(A);
     X := R;
     Y := 0;

     for W := 1 to 400 do
        begin
           B := X * C - Y * S;
           Y := X * S + Y * C;
           X := B;
           if (N <= 32) or (N >= 44)
              then
                 if Round((Random(44 - N
                    ) + 1) / 5) <> 1
                    then
                       goto endproc;
           if (W > 0) and (W < (120 +
              Random(30)+1)) then
              plot(V + X, Z + Y);
           if (W > (310 + Random(30) + 1
              )) and (W < 400) then
              plot(V + X, Z + Y);
        endproc:
        end;
end;

procedure procb(INV,INZ,INR : real);

var
  IX,IY,PH : integer;
  RAD,HH,RX : real;

begin
  pstatus := false;
  RAD := INR;
  for IX := Round(-RAD) to Round(RAD) do
     begin
        HH := Sqrt(Sqr(RAD) -
              Sqr(IX));
        RX := INV + IX;
        PH := Round(INZ + HH);
        for IY := Round(INZ - HH) to PH
           do
              plot(RX,IY)
     end;
  pstatus := true
end;


begin
  BitmapInit;
  ScreenColor(1,1);
  Randomize;
  pstatus := true;
  V := 640;
  Z := 522;
  R := 300;
  A := 2 * Pi / 300;
  S := sin(A);
  C := cos(A);
  X := R;
  Y := 0;
  for W := 1 to 300 do
     begin
        B := X * C - Y * S;
        Y := X * S + Y * C;
        X := B;
        AR[W] := 600 - (V + X);
     end;
  for N := 115 to 210 do
     procc(64,(1080 - (AR[219 - N] * 7))
           / 5,AR[N] / 2.5,N);
  procb(100,130,40);
  N := 0;
  repeat
     proccg(100,130,N);
     N := N + 4;
  until N = 44;
  repeat
  until GetKey = 32;
  VDPInit;
end.

 

 

 

Thanks very much.

It's a thing of beauty.

(Says the guy who had a Pascal program pin-up on his locker door) :) 

 

  • Thanks 1
Link to comment
Share on other sites

A light improvement to play with. In the For-Next loop that begins at line 330 (a loop that is on one line in the original, but expanded to three in the Cortex BASIC version), substitute:

 

Plot Q+INT(RND*4)+1 

 

for 

 

Plot Q+INT(RND*8)+1

 

This reduces the randomized wiggle of pixel placement to a degree that is proportionate to the overall reduction in resolution that results from the translation from BBC to TI.

 

I think it gives a result that subtly better resembles the original BBC version.  

 

Before and after:

 

 

image.thumb.jpeg.e2018d5a20d5f752f2350f5170c789cb.jpegimage.thumb.jpeg.88e6eab1a8633ef98d7abd0c94bdc6f6.jpeg

 

 

 

Edited by Reciprocating Bill
  • Like 5
Link to comment
Share on other sites

  • 2 weeks later...
On 12/10/2022 at 7:47 PM, DuaneAL said:

Would this benefit from compiling? Is it compiler compatible?  I'm not asking because I think it needs it, but more of a general question about what is possible.

Yes, and yes. There are a few things to iron out because the compiler does not support floating point. At one point a value is divided by 2.5. To get around that, you can multiply by 2 and divide by 5. There are no trig functions so you have to come up with another way to do that. I made DATA statements that contain sine values from 0 to 90, multiplied by 255. These are read into the array SINE(N). Now when you want the sine of 5 degrees you can  use SINE(5). Cosine of 5 degrees is SINE(5+90). And so on. Note that I use degrees and the TI99 uses radians. The FOR N/NEXT N loop uses angles in 1.2 degree steps. I had hoped to be able to round to the nearest degree, but the results were not so good. So I have a subroutine that interpolates and returns a value closer to the right one. You will see that the edge of the death star is not as sharp as the XB version that used floating point. There are 2 possibilities - rounding due to the integer math, or perhaps my math conversions are not quite right.  In the video below both Classic99's are running at the normal speed. If you look hard enough, you can probably see that the performance has been somewhat enhanced.

 

DEATHSTAR.gif

 


1 !CALL LINK("tml16")
2 !DEATHSTAR modifed to be compatible with XB compiler
100 REM Death Star by Electron Greg
110 REM Adapted by Tursilion - 256x192 version - optimized
120 REM TIXB with Missing Link
121 !MAKE SINE TABLE. All values are *255 and rounded to nearest integer. Could do with 0 to 90, but this should speed it up a bit.
122 DIM SINE(450)
124 FOR I=0 TO 90 :: READ S :: SINE(I)=S :: SINE(180-I)=S :: SINE(180+I)=-S :: SINE(360-I)=-S :: SINE(360+I)=S :: NEXT I
140 REM original lookup table boils down to just (idx=1-300):
170 CALL LINK("CLEAR")
180 CALL SCREEN(2)
190 CALL LINK("COLOR",8,2)
200 REM draw globe
210 V=64
220 FOR N=120 TO 195
231 GOSUB 800 :: Z=(1080-(-COSINE*60/51-40)*7)/5
240 Z2=Z/10
251 GOSUB 810 :: R=(-COSINE*60/51-40)*2/5
260 X=R :: Y=0 :: N2=N/2
268 TOT=0
270 FOR W=1 TO 360 :: P=(INT(RND*W))-N2 :: IF P>99 THEN 340
275 TOT=TOT+1
281 X=R*SINE(TOT+90)/255 :: Y=R*SINE(TOT)/255
290 IF W<180 THEN 340
301 Q=((V+X)*13/10)-(Z/10)+100 :: O=((Z+Y)/4)*134/100+X/3
310 IF N>148 AND N<152 THEN CALL LINK("PIXEL",192-O,Q+12):: GOTO 340
320 LIM=(360-W)/30
330 FOR M=1 TO LIM :: CALL LINK("PIXEL",191-O,Q+INT(RND*8+1)):: NEXT M
340 NEXT W
350 NEXT N
360 REM clear out dish area
370 CALL LINK("PE")
380 RAD=40
390 REM Super fast filled circle (does require a single square root)
400 REM from https:://stackoverflow.com/questions/1201200/fast-algorithm-for-drawing-filled-circles
410 FOR X=-RAD TO RAD
420 HH=SQR(RAD*RAD-X*X)
430 RX=100+X
440 PH=130+HH
450 CALL LINK("LINE",HH+61,RX,191-PH,RX)
460 NEXT X
470 CALL LINK("PD")
480 REM draw the circles inside the dish
490 V=100 :: Z=130 !:: A=2*PI/400 :: S=SIN(A):: C=COS(A)
500 FOR N=0 TO 40 STEP 4
510 !X=N :: Y=0
520 FOR W=1 TO 360 :: Y=SINE(W)*N/255 :: X=SINE(W+90)*N/255 !B=X*C-Y*S :: Y=X*S+Y*C :: X=B
530 IF N>32 AND N<44 THEN 550
540 IF INT((RND*(44-N))/5)<>0 THEN 570
550 IF W>0 AND W<108+INT(RND*30+1)THEN CALL LINK("PIXEL",191-(Z+Y),V+X):: GOTO 570
560 IF W>279+INT(RND*30+1)AND W<400 THEN CALL LINK("PIXEL",191-(Z+Y),V+X)
570 NEXT W
580 REM spin forever
590 NEXT N
600 GOTO 600
800 ANG=219-N :: GOTO 820
810 ANG=N
820 A6=ANG*6 :: A65=INT(A6/5):: RMD=A6-5*A65
830 COS0=SINE(A65+90):: COS1=SINE(A65+91)
840 COSINE=INT(((5-RMD)*COS0+RMD*COS1)/5)
850 RETURN
1000 DATA 0,4,9,13,18,22,27,31,35,40,44,49,53,57,62,66,70,75,79,83,87,91,96,100,104,108,112,116,120,124
1001 DATA 128,131,135,139,143,146,150,153,157,160,164,167,171,174,177,180,183,186,190,192,195,198,201
1002 DATA 204,206,209,211,214,216,219,221,223,225,227,229,231,233,235,236,238,240,241,243,244,245,246
1003 DATA 247,248,249,250,251,252,253,253,254,254,254,255,255,255,255

 

 

 

Edited by senior_falcon
  • Like 6
  • Thanks 2
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...