blitterbox Posted November 30, 2010 Share Posted November 30, 2010 There's probably something here somewhere, but my searches aren't finding it. Can somebody give a brief explanation/example/pointer to how to set up PM Graphics to be manipulated via strings? I'm confusing something about how to get the PM graphics area and strings lined up. I just got back into this 8-bit stuff and I'm mighty rusty, plus missing needed documentation. Quote Link to comment Share on other sites More sharing options...
+David_P Posted November 30, 2010 Share Posted November 30, 2010 As I recall: DIM a string of one character; find its address; calculate the offset needed to start the PM area on the appropriate boundary; DIM a second string of that length., then finally DIM a string of 2 or 4K for the PMG. Alternatively, lower MEMTOP and use that memory. (Adn this is all from memory too, so assume a significant amount of rust on my brain) Quote Link to comment Share on other sites More sharing options...
blitterbox Posted November 30, 2010 Author Share Posted November 30, 2010 As I recall: DIM a string of one character; find its address; calculate the offset needed to start the PM area on the appropriate boundary; DIM a second string of that length., then finally DIM a string of 2 or 4K for the PMG. I'm staring at an example from a program listing from this forum, and that appears to be what it's doing, except I don't know what that means. Leaving out the bits I understand: DIM A$(1),B$((((INT(ADR(A$)/1024)+1.5)*1024)-ADR(A$))-5),BUF2$(128) POKE 54279,(ADR(BUF2$)-512)/256 I can't seem to wrap my head around what the dimensioning of B$ is accomplishing exactly or how. I understand that 512 is the offset from the PMBASE address to PLAYER 1 as the program's using low resolution PMs, but not why BUF2$ should wind up being appropriate to calculate the offset from. Quote Link to comment Share on other sites More sharing options...
atariksi Posted November 30, 2010 Share Posted November 30, 2010 As I recall: DIM a string of one character; find its address; calculate the offset needed to start the PM area on the appropriate boundary; DIM a second string of that length., then finally DIM a string of 2 or 4K for the PMG. I'm staring at an example from a program listing from this forum, and that appears to be what it's doing, except I don't know what that means. Leaving out the bits I understand: DIM A$(1),B$((((INT(ADR(A$)/1024)+1.5)*1024)-ADR(A$))-5),BUF2$(128) POKE 54279,(ADR(BUF2$)-512)/256 I can't seem to wrap my head around what the dimensioning of B$ is accomplishing exactly or how. I understand that 512 is the offset from the PMBASE address to PLAYER 1 as the program's using low resolution PMs, but not why BUF2$ should wind up being appropriate to calculate the offset from. This online book has a chapter on strings for PM graphics: http://www.atariarchives.org/pmgraphics/ Quote Link to comment Share on other sites More sharing options...
blitterbox Posted November 30, 2010 Author Share Posted November 30, 2010 This online book has a chapter on strings for PM graphics: http://www.atariarchives.org/pmgraphics/ Thanks. Missed that one. Quote Link to comment Share on other sites More sharing options...
Rybags Posted November 30, 2010 Share Posted November 30, 2010 The better way by far is to use forced String Relocation via the Variable Value Table. I don't have an example, but the technique is - DIM a string of one byte, store it's address in a variable. Then chain through the VVT, find the string's offset that matches that saved value. Then change the Offset and Length parameters to suit what you're doing. It's a much more efficient way - by reserving an area such that the RAM you need is guaranteed to be there, you're potentially wasting hundreds or more bytes. Quote Link to comment Share on other sites More sharing options...
blitterbox Posted November 30, 2010 Author Share Posted November 30, 2010 When I heard of manipulating PMs with strings, I did imagine it would be a matter of pointing the string to the PM location rather than the PM location to the string. I thought this would be easier though wasteful, because I don't recall all the ins and outs of how the variable table works, but I'm not having much luck getting the offsets correct for some reason. Quote Link to comment Share on other sites More sharing options...
Rybags Posted November 30, 2010 Share Posted November 30, 2010 (edited) I'll see if I can whip something up quickly later. The "Atari BASIC Source Book" comes in useful if you've got it, although I don't think it has examples, it does have the table descriptions. First off, you need to find the string's entry in the Variable Value Table. First byte of each entry in the VVT should indicate what kind of variable it is (number, string, array etc) The descriptor field doesn't actually point to the string itself, it's used as an offset into STARP (String/Array Space). So the thing to do is find ADR(string) then keep a variable with that value - STARP. Then once you find the string's entry, change the offset such that it now equals the location you want. In theory you could even point it "backwards", e.g. if you wanted to put RAM at $400-$47F into a string or similar. Edited November 30, 2010 by Rybags Quote Link to comment Share on other sites More sharing options...
+Philsan Posted November 30, 2010 Share Posted November 30, 2010 Your topic's question is clear (PMG with strings) so perhaps my reply isn't useful for you. If you want to use PM inside Basic (or Turbo-Basic XL) programs, the best routine is the one in my signature. 1 Quote Link to comment Share on other sites More sharing options...
Rybags Posted November 30, 2010 Share Posted November 30, 2010 (edited) Here's a sample program I just whipped up. The problem with using this technique is that Immediate Mode debugging can become a pain. Because strings are stored straight after the program, that space actually moves around. If you enter an Immediate Mode command, the strings will usually get moved to accomodate it. To illustrate it, DIM a string then set a variable name to it's ADR. Then try stacked immediate commmands followed by ? ADR(string$) This program as an example points a string to the Colour Shadow registers, then changes the background colour. 10 A=1:B=2:C=3 20 DIM C$(1),B$(1) 30 S=ADR(C$):T=708:NL=5:GOSUB 1000 40 ? "OLD ";S;"NEW ";ADR(C$) 50 C$(3,3)=CHR$(130) 999 STOP 1000 STARP=PEEK(140)+PEEK(141)*256 1010 VVT=PEEK(134)+PEEK(135)*256 1015 VVTEND=PEEK(136)+PEEK(137)*256 1020 COFF=S-STARP:NOFF=T-STARP:IF NOFF<0 THEN NOFF=NOFF+65536 1030 FOR Z=VVT TO VVTEND-8 STEP 8 1040 IF PEEK(Z)<>129 THEN 1190 1050 L=STARP+PEEK(Z+2)+PEEK(Z+3)*256 1060 IF L<>S THEN 1190 1070 ? "FOUND STRING @ ";S 1080 H=INT(NOFF/256):L=NOFF-H*256:POKE Z+2,L:POKE Z+3,H 1090 H=INT(NL/256):L=NL-H*256:POKE Z+4,L:POKE Z+6,L:POKE Z+5,H:POKE Z+7,H 1190 NEXT Z 1490 RETURN Set variable "S" to the ADR of the string who's location is to change. Set variable "T" to the new address where the string is to go. Set variable "NL" to the new length that the string is to inherit. Note that it's best to just DIM such strings as size (1), any more is just going to waste since you're changing it anyway. Edited November 30, 2010 by Rybags 1 Quote Link to comment Share on other sites More sharing options...
analmux Posted November 30, 2010 Share Posted November 30, 2010 (edited) ...DIM A$(1),B$((((INT(ADR(A$)/1024)+1.5)*1024)-ADR(A$))-5),BUF2$(128)POKE 54279,(ADR(BUF2$)-512)/256... I don't get why the -5 is subtracted there. Possibly you don't need to do that anyway. And, I'd write: INT(ADR(A$)/1024)*1024+512 Instead of (INT(ADR(A$)/1024)+1.5)*1024 (not trusting the floating point routines ) Edited November 30, 2010 by analmux Quote Link to comment Share on other sites More sharing options...
+therealbountybob Posted November 30, 2010 Share Posted November 30, 2010 I finally used PMGs with stings for my latest game (below), the book I found very useful was Atari Player Missile Graphics in BASIC (on atariachives.org). There are a few bugs but otherwise it's step by step, and comprehensive. Hey I managed to follow it, it's the first time I have got PMGs to do anything :!: [edit - Chapter 3 covers using filler strings to get the PMG strings onto a page boundary. ] Quote Link to comment Share on other sites More sharing options...
MaPa Posted November 30, 2010 Share Posted November 30, 2010 And, I'd write: INT(ADR(A$)/1024)*1024+512 Instead of (INT(ADR(A$)/1024)+1.5)*1024 (not trusting the floating point routines ) So then you should write: INT(ADR(A$)/1024)*1024+1536 IMHO Quote Link to comment Share on other sites More sharing options...
analmux Posted November 30, 2010 Share Posted November 30, 2010 [..]So then you should write: INT(ADR(A$)/1024)*1024+1536 IMHO Oh yes...Exactly! (my bad ) Quote Link to comment Share on other sites More sharing options...
analmux Posted November 30, 2010 Share Posted November 30, 2010 (edited) So, I would change DIM A$(1),B$((((INT(ADR(A$)/1024)+1.5)*1024)-ADR(A$))-5),BUF2$(128) POKE 54279,(ADR(BUF2$)-512)/256 into DIM A$(1),B$((INT(ADR(A$)/1024)*1024+1536)-ADR(A$)-5),BUF2$(128) POKE 54279,(ADR(BUF2$)-512)/256 (EDIT: the -5 is needed indeed) Edited November 30, 2010 by analmux Quote Link to comment Share on other sites More sharing options...
analmux Posted November 30, 2010 Share Posted November 30, 2010 OK, found it out: We could have the following programm-lines: 10 DIM A$(1),B$((INT(ADR(A$)/1024)*1024+1536)-ADR(A$)-5),BUF2$(128) 20 POKE 54279,(ADR(BUF2$)-512)/256 but instead also 10 DIM A$(1) 20 DIM B$((INT(ADR(A$)/1024)*1024+1536)-ADR(A$)-1) 30 DIM BUF2$(128) 40 POKE 54279,(ADR(BUF2$)-512)/256 Indeed, I'd expect a -1 instead of a -5. The -1 of course comes from the length of A$ itself. But, in the first example, the -1 is changed into -5 to compensate some 'mysterious' internal computations, done by the basic application itself, apparently. Quote Link to comment Share on other sites More sharing options...
analmux Posted November 30, 2010 Share Posted November 30, 2010 Still new mysteries...just forget my previous post please Trying again and again, now the following code just gives the correct starting address of PMBase: 10 DIM A$(1),B$((INT(ADR(A$)/1024)*1024+1536)-ADR(A$)-1),BUF2$(128) 20 POKE 54279,(ADR(BUF2$)-512)/256 30 ? ADR(BUF2$) It will print 3584 (which is page 14) However, in immediate mode I can ask the address of BUF2$ again, and then it will spit out: ? ADR(BUF2$) 3588 READY █ OK, nevermind. Anyway, the -5 can be replaced by a -1, but all following 3 examples should be correct: 10 DIM A$(1),B$((((INT(ADR(A$)/1024)*1024)+1.5)-ADR(A$))-1),BUF2$(128) 20 POKE 54279,(ADR(BUF2$)-512)/256 10 DIM A$(1),B$((INT(ADR(A$)/1024)*1024+1536)-ADR(A$)-1),BUF2$(128) 20 POKE 54279,(ADR(BUF2$)-512)/256 10 DIM A$(1) 20 DIM B$((INT(ADR(A$)/1024)*1024+1536)-ADR(A$)-1) 30 DIM BUF2$(128) 40 POKE 54279,(ADR(BUF2$)-512)/256 And, the exact syntax layout doesn't matter. Quote Link to comment Share on other sites More sharing options...
bfollett Posted November 30, 2010 Share Posted November 30, 2010 I wonder if the -5 should be -0.5 I see there is an INT() command being issued, don't you sometime have to add or subtract .5 when using Int() to compensate for the number getting rounded? Bob Quote Link to comment Share on other sites More sharing options...
Rybags Posted November 30, 2010 Share Posted November 30, 2010 Strings move around in memory if you enter/delete lines or even enter Immediate mode commands. Quote Link to comment Share on other sites More sharing options...
Kylev Posted November 30, 2010 Share Posted November 30, 2010 From reading the original code posted, as well as the subsequent conversation, I thought the goal was to find the beginning of the first player's memory space. If that is true, then the original addition of 512 would seem to be the proper code. Please correct me if I am wrong. This is not an area where I can even begin to claim to be an expert. I am having problems understanding the addition of 1536 to the ADR of A$, myself. Quote Link to comment Share on other sites More sharing options...
analmux Posted November 30, 2010 Share Posted November 30, 2010 (edited) From reading the original code posted, as well as the subsequent conversation, I thought the goal was to find the beginning of the first player's memory space. If that is true, then the original addition of 512 would seem to be the proper code. Please correct me if I am wrong. This is not an area where I can even begin to claim to be an expert. I am having problems understanding the addition of 1536 to the ADR of A$, myself. Extra 1024 bytes (1 kB) needs to be added. For example, if the starting address of the A$ variable (at the end of the basic code) is f.e. N*1024+M, where M>>512, then computing the location of the first byte free for PM usage would give a conflictuous situation. That's why another 1024 is added, so you'll end up with 1536. Another example, let's say ADR(A$)=2048+768, then INT(ADR(A$)/1024)*1024 = 2048 thus INT(ADR(A$)/1024)*1024+512 will be BEFORE the start of the array. Thus, writing to that area will corrupt your basic programm for sure. Edited November 30, 2010 by analmux Quote Link to comment Share on other sites More sharing options...
analmux Posted November 30, 2010 Share Posted November 30, 2010 Another thing to know: The length of B$ will always be greater than 512, thus there's possibility to fill it up with shape data instead. So, instead you could add 1024 instead of 1536. Then fill up the 512 bytes with a C1$, C2$, C3$ etc. Each of these strings may contain a block of shape data. Then it's only a matter of moving the shapes around: f.e. BUF2$(Y) = C3$ Quote Link to comment Share on other sites More sharing options...
+therealbountybob Posted November 30, 2010 Share Posted November 30, 2010 Pretty sure this is covered in detail in the book I posted on post #12 Quote Link to comment Share on other sites More sharing options...
phaeron Posted December 1, 2010 Share Posted December 1, 2010 Wasn't there some bug in Atari BASIC with 256*N byte string moves that you had to avoid, too? Quote Link to comment Share on other sites More sharing options...
+therealbountybob Posted December 1, 2010 Share Posted December 1, 2010 Wasn't there some bug in Atari BASIC with 256*N byte string moves that you had to avoid, too? Chapter 9 >>> LINES 11045 AND 11047 Here I am initializing MISSILES$ and PLAYER0$ in a slightly different way. This is necessary because of an apparent bug in Atari BASIC. It seems that a statement such as MISSILES$=ERASE$ won't work if MISSILES$ is 256 bytes or more. <<< Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.