-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBANK_ROM_SHADOW_DRAWBUFFERS.asm
executable file
·369 lines (280 loc) · 16.6 KB
/
BANK_ROM_SHADOW_DRAWBUFFERS.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
; Sokoboo - a Sokoban implementation
; using a generic tile-based display engine for the Atari 2600
; Sokoban (倉庫番)™ is © Falcon Co., Ltd.
;
; Code related to this Sokoban™ implementation was developed by Andrew Davie.
;
; Code related to the generic tile-based display engine was developed by
; Andrew Davie and Thomas Jentzsch during 2003-2011 and is
; Copyright(C)2003-2019 Thomas Jentzsch and Andrew Davie - contacts details:
; Andrew Davie ([email protected]), Thomas Jentzsch ([email protected]).
;
; Code related to music and sound effects uses the TIATracker music player
; Copyright 2016 Andre "Kylearan" Wichmann - see source code in the "sound"
; directory for Apache licensing details.
;
; Some level data incorporated in this program were created by Lee J Haywood.
; See the copyright notices in the License directory for a list of level
; contributors.
;
; Except where otherwise indicated, this software is released under the
; following licensing arrangement...
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
; see https://www.gnu.org/licenses/gpl-3.0.en.html
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;------------------------------------------------------------------------------
;##############################################################################
;------------------------------------------------------------------------------
NEWBANK ROM_SHADOW_OF_BANK_DRAW_BUFFERS
; NOTE: Access to these buffers must NOT overlap pages...
; NOTE: We get auto-initialisation of these variables from the ROM values by
; copying the whole bank into the RAM bank. Neato.
DRAW_STACK_SIZE = SCREEN_ARRAY_SIZE ; <-- TJ TRY CHANGING THIS TO (SAY) 15 (!!)
DrawStack ds DRAW_STACK_SIZE,0 ; a stack of character #'s to draw
DrawFlag ds SCREEN_ARRAY_SIZE,0 ; holds new character to draw at position
OPTIONAL_PAGEBREAK "ScreenBuffer", SCREEN_ARRAY_SIZE
; D7 of ScreenBuffer indicates if a DirectDraw is to be used to draw this character
; Note: this may actually cause two characters to be drawn -- for the price of one. This is *exactly*
; what we want to happen!
ScreenBuffer ds SCREEN_ARRAY_SIZE,0 ; the char buffer for delta-drawing
CHECKPAGEX ScreenBuffer, "ScreenBuffer"
;------------------------------------------------------------------------------
; RAM-BASED SUBROUTINES...
; NOTE: When calling these routines, remember you are actually calling the ROM routine
; as it is the ROM bank that is switched in. The first thing to do to access the RAM
; is to switch the appropriate RAM bank in. It would be nicer to be able to direct-call
; the RAM-based routine.
;------------------------------------------------------------------------------
waitForDraw rts ; 6
;------------------------------------------------------------------------------
DEFINE_SUBROUTINE DrawStackUpdate ; @39✅
; Parse the DrawFlags buffer and create a draw stack
; so that the actual draw doesn't need to scan for characters to draw.
;@TJ -- let's see if we see any bad lag/shear in screen drawing without this wait in.
; symptoms would be missing parts of screen when scrolling.
; Gameplay (not visual) lag noticed - re-enabled 11/8/11
; disabled for sokoban 27/7/2019
;lda DrawStackPointer
;bpl waitForDraw ; Wait for previously not-drawn characters to be drawn
lda INTIM ;4
cmp #SEGTIME_BDS ;2
bcc waitForDraw ;2/3
; =>[39]+(9)+6rts = 54✅ when exit
; Now that all characters are drawn, recalculate/move sprite. Doing this here prevents the player
; moving into the middle of dirt, or BOXs when pushing, or TARGETs when grabbing.
; sec already set
lda ManY ;3
sbc BoardScrollY ;3
cmp #SCREEN_LINES
bcs offy
sta ManDrawY ;3 = 9✅
sec ;2
lda ManX ;3
sbc BoardScrollX ;3
cmp #SCREEN_WIDTH ;2
bcc onsc ;2/3 = 12(13)✅
; if the man is offscreen, we have a timing issue between the horizontal positioning code and the player
; draw code. The following gets around this by setting the Y offscreen (causing the player draw code to
; blank the graphic) and leaving the X alone (so we don't see a brief flash in left of screen).
offy lda #-1 ;SCREEN_LINES ;2
sta ManDrawY ;3
bne offsc
onsc sta ManDrawX ;3
offsc
;32✅ worst
DEFINE_SUBROUTINE AnimateCharReplacements2 ; =38
; This manages character animation on a per-object basis. Morph/animate these characters
; individually or as required. Change will affect all characters of the same type in the
; visible display.
inc animate_char_index ; 5
lda animate_char_index ; 3
lsr ; 2
lsr
and #3 ; 2
tax ; 2 = 14
lda targetReplaceChar,x ; 4
sta ANIM_TARGET + RAM_WRITE ; 4 = 8
;lda targetReplaceChar2,x ; 4
;sta ANIM_TARGET2 + RAM_WRITE ; 4
;@54 worst
lda #SCREEN_ARRAY_SIZE-1 ;2
sta DSL ;3
inc ScreenDrawPhase ;5
rts ; 6 TEST allows segtime test to be smaller on next part
; ==> @70 worst
;---------------------------------------------------------------------------
DEFINE_SUBROUTINE DrawIntoStack ; @39✅
tsx ; 2
stx save_SP ; 3
ldx DrawStackPointer ; 3
txs ; 2 = 10
ldy DSL ; 3
; @ 52✅
; worst-case DrawStackOne loop = 61 cycles per character (+11 for first one)
; + exit cost which is +10 cycles
; TJ: I count 63
; + 14 for the wtf2 exit
; + 22 for the end of loop exit
; This loops 80 times/frame and is called 1-2 times/frame, so any saving inside the loop will make up for a lot of overhead outside
; For 80 iterations that is 640 cycles, just for checking INTIM
; Worst case we would have ~5000. Though that will most likely never happen, we have to optimize for it, since
; it also will require a lot of CPU time for updating the screen data.
; TODO: optimize!
;
; idea #4: the mixed draw idea (two different characters have to be redrawn),
; first do a QuickDraw and then a SlowDraw, faster than two SlowDraws
; costs some detection time here, but saves ~240 cylces for drawing the two
.loopDrawStack ; @100✅ from bottom of loop
lda INTIM ; 4
cmp #SEGTIME_DSL ; 2
bcc .exitDrawStack ; 2(3) + [costs 18 more to exit fully at .exit..]
; => full exit on 1st pass = 78✅ cycles
; => full exit on a single loop = 127✅ cycles
; @0✅
lda DrawFlag,y ; 4
cmp ScreenBuffer,y ; 4 Is the character already there the same as the new one?
beq .next0 ; 2/3=10/11 yes, so we don't draw anything
; @10✅
; Character is NOT the same. Figure out how it should be drawn.
; If it is in column 0 or 5 then it can be DirectDrawn (indirectly found by a A:A compare)
; If it is the same as its paired character (sharing same PF byte) then it can be DirectDrawn
; The top bit of the ScreenBuffer character indicates the DirectDrawn hint
ldx PairedCharacter,y ; 4 the "paired" character for this one
cmp DrawFlag,x ; 4 same as partner character in new drawn screen?
bne .notPaired0 ; 2(3)
; @20✅
; Consider two 'paired' characters. Either A:A or A:B
; When we're scanning, and we check the first, if they are NOT paired, then the second character
; can be considered in isolation -- its check comes later, will determine itself if the pair can be written
; If, however, the first character IS paired, then the write below will cause the second check to FAIL
; on the comparison, so the character will not be added to the draw stack. So our first character will
; do the job of drawing BOTH characters to the screen.
sta ScreenBuffer+RAM_WRITE,x ; 5 mark paired character as drawn already (!!)
ora #$80 ; 2 = 7 DirectDraw this character 'pair'
; @27✅
; In the case of columns 0 and 5, the X and Y registers will be the same -- no problemo, because
; the last write(below) marks the character as to be direct-drawn.
.notPaired0 ; @27✅ worst
sta ScreenBuffer+RAM_WRITE,y ; 5 NEW character to draw + DirectDraw flag (128)
; The following 'pla' really just increments the draw-stack pointer. Value is unimportant. Unusual!
pla ; 4 ASSUMPTION IS WE DON'T OvERFLOW DRAW STACK
tya ; 2
tsx ; 2 << now X holds drawstackpointer
sta DrawStack+RAM_WRITE,x ; 5 = 18 index of character to draw
.next0 dey ; 2
bmi .finishedDrawStack ; 2(3)= 4/5
; @50✅
; unrolled 2nd loop:
lda DrawFlag,y ; 4
cmp ScreenBuffer,y ; 4 Is the character already there the same as the new one?
beq .next1 ; 2(3) yes, so we don't draw anything
ldx PairedCharacter,y ; 4 the "paired" character for this one
cmp DrawFlag,x ; 4 same as partner character in new drawn screen?
bne .notPaired1 ; 2(3)
sta ScreenBuffer+RAM_WRITE,x ; 5 mark paired character as drawn already (!!)
ora #$80 ; 2 = 7 DirectDraw this character 'pair'
.notPaired1 ; @77✅ worst
sta ScreenBuffer+RAM_WRITE,y ; 5 NEW character to draw + DirectDraw flag (128)
pla ; 4 ASSUMPTION IS WE DON'T OvERFLOW DRAW STACK
tya ; 2
tsx ; 2
sta DrawStack+RAM_WRITE,x ; 5 = 18 index of character to draw
; @95✅
.next1 dey ; 2
bpl .loopDrawStack ; 2(3)
; @100✅ --> @.loopDrawStack
;worst case: 111-4
;40 loops(-4), max. 2 calls(+20) -> -160+40=-120, +8 bytes
; THE FOLLOWING OPTIMISATION IS STUFFED IF PROCESSOBJSTACK is not first in the vector processor!
.finishedDrawStack
inc ScreenDrawPhase ;5 = 5
tsx ;2
stx DrawStackPointer ;3
ldx save_SP ;3
txs ;2 = 10
rts ;6 = 6
.exitDrawStack
sty DSL ;3 = 3
tsx ;2
stx DrawStackPointer ;3
ldx save_SP ;3
txs ;2 = 10
rts ;6 = 6
PairedCharacter
SOFF SET 0
REPEAT SCREEN_LINES
.byte SOFF,SOFF+2,SOFF+1,SOFF+4,SOFF+3,SOFF+5,SOFF+7,SOFF+6,SOFF+9,SOFF+8
SOFF SET SOFF + SCREEN_WIDTH
REPEND
;------------------------------------------------------------------------------
; Gives character replacements used during screen drawing.
; The character from the board is morphed via this array into an actual character
; to draw. This allows global animation and replacment of characters without
; individual objects needing to do this. Note, the draw-time replacement happens,
; not board-time.
DEFINE_SUBROUTINE CharReplacement ; in RAM -- BANK_DRAW_BUFFERS
; Converts a character # to an animated creature type
; The array is indexed by CHARACTER_...
.byte CHARACTER_BLANK ; 0
.byte CHARACTER_SOIL ; 1
.byte CHARACTER_BOX ; 2
ANIM_TARGET .byte CHARACTER_TARGET ; 3 XOR'd to give flashing target squares
.byte CHARACTER_TARGET2 ; 4
.byte CHARACTER_MANOCCUPIED ; 5
.byte CHARACTER_STEEL ; 6
.byte CHARACTER_RIVET ; 7
.byte CHARACTER_WALL ; 8
.byte CHARACTER_STRIPE
ANIM_TARGET2 .byte CHARACTER_BOX_ON_TARGET ; 8 box on target
; .byte CHARACTER_BOX_ON_TARGET2
.byte CHARACTER_BLANK ; 9
.byte CHARACTER_TARGET1
.byte CHARACTER_TARGET3
.byte CHARACTER_TARGET5
.byte CHARACTER_TARGET7
#if DIGITS
.byte CHARACTER_0
.byte CHARACTER_1
.byte CHARACTER_2
.byte CHARACTER_3
.byte CHARACTER_4
.byte CHARACTER_5
.byte CHARACTER_6
.byte CHARACTER_7
.byte CHARACTER_8
.byte CHARACTER_9
#endif
IF (* - CharReplacement != CHARACTER_MAXIMUM)
ECHO "ERROR: Incorrect CharReplacement table!"
ERR
ENDIF
CHECKPAGEX CharReplacement, "CharReplacement in BANK_ROM_SHADOW_DRAWBUFFERS"
targetReplaceChar
.byte CHARACTER_TARGET1
.byte CHARACTER_TARGET3
.byte CHARACTER_TARGET5
.byte CHARACTER_TARGET7
;targetReplaceChar2
; .byte CHARACTER_BOX
; .byte CHARACTER_BOX
; .byte CHARACTER_BOX_ON_TARGET
; .byte CHARACTER_BOX_ON_TARGET
;------------------------------------------------------------------------------
OPTIONAL_PAGEBREAK "ROW_BankChar", SCREEN_LINES * SCREEN_WIDTH
DEFINE_SUBROUTINE ROW_BankChar
.BANK SET BANK_SCREENMARKII1
REPEAT SCREEN_LINES
REPEAT SCREEN_WIDTH
.byte .BANK
REPEND
.BANK SET .BANK + 1
REPEND
CHECK_HALF_BANK_SIZE "ROM_SHADOW_OF_BANK_DRAW_BUFFERS"
CHECK_BANK_SIZE "ROM_SHADOW_OF_BANK_DRAW_BUFFERS -- full 2K"