【问题标题】:Draw on screen border in Commodore 64在 Commodore 64 中的屏幕边框上绘制
【发布时间】:2009-11-17 16:51:37
【问题描述】:

我有 25 年的好奇心,我很想了解其中的诀窍。

在 Commodore 64 中,6569 VIC 无法寻址边界。您所能做的就是在光标移动的中心区域绘制像素。边框总是统一的,虽然你可以用戳 53280 改变它的颜色,如果我没记错的话。

不过,我清楚地记得游戏介绍中的边框带有图形,就像它是完全可寻址的一样。我试图了解它是如何工作的,但从未达到目的。传说这是对精灵的巧妙运用,在某些情况下可以绘制在边界上,但我不知道这是否是都市传说。

编辑:只需从提供的链接之一阅读此内容

Sprite 被多路复用 垂直光栅线(超过 8 个精灵, 有时多达 120 个精灵)。直到 Group Crest 发布了 Krestage 3 于 2007 年 5 月 认为不超过 8 个精灵 可能出现在一条光栅线上,但 分配新的 Y 坐标使它 再次出现在屏幕下方。

这是邪恶的......你击败了光栅并在精灵到达那里之前重新定位......

【问题讨论】:

  • 哇......即使你得到了答案——你有能力测试它吗?
  • 确实有一个技巧可以使用精灵摆脱边框。我最近在一些关于 4K 演示或类似的文章中读到了它。 Wikipedia 引用它,这可能足以让你走上正轨,找到如何去做。
  • 可惜没有'awesome'的标志。
  • 为什么哦为什么我记得 POKE 53280 和 POKE 53281 会改变 C64 上的背景和边框颜色这一无用的事实,尽管我努力用对依赖注入的理解来替换这些知识?跨度>
  • 是的......这是重复的,但这里也有很好的答案,删除它会很遗憾。

标签: retro-computing c64 commodore


【解决方案1】:

首先,只有精灵可以显示在边界区域或从视频库的最后一个字节读取的重复的 8 位模式(8 像素宽),通常是 $3fff。请注意,当您欺骗 VIC 芯片“不显示”边框时,您只能看到这些精灵或 8 位模式。见下文。

边框比精灵具有更高的优先级,因此通常当精灵在边框区域中绘制时,边框会覆盖精灵。使用一点 VIC 芯片技巧,您可以关闭边框。

您可以很容易地关闭顶部和底部边框(我将在下面解释),并在非常关键的时机关闭侧边框。

首先是关于 VIC 芯片如何在 c64 上工作的一些信息。

VIC 芯片从左上到右上绘制屏幕,​​然后下一行,再从左到右,直到绘制整个屏幕。它每秒执行 50 次重绘(对于 PAL 单位)或每秒执行 60 次(对于 NTSC 单位)。

有一个 8 位 VIC 寄存器,其中包含任何给定时间光栅的垂直位置。 $d012。实际上有超过 255 个可能的位置,因此第 9 位存储在第 7 位(最高位)或寄存器 $d011 中。因此,您可以随时读取这些寄存器并找出光栅的垂直位置。没有可用的寄存器来读取光栅的 x 位置。

VIC 芯片的另一个很酷的功能用于解决使用硬件滚动时出现的问题。基本的垂直滚动是通过使用硬件寄存器将屏幕垂直移动 0-7 个像素来实现的。一旦达到限制(0 或 7,取决于滚动方向),您将垂直移动每个字符块(8x8 像素)一个块并绘制新数据以显示在顶部(或底部取决于方向)。这很好用,除了每滚动 8 个像素你会看到数据“弹出”到屏幕上。为了解决这个问题,您可以通过清除寄存器 $d011 中的位 3 使边界区域垂直增长 8 个像素。这称为 24 行模式。默认情况下,屏幕设置为 25 行 8x8 像素字符。在 24 行模式下,您仍然可以将字符绘制到最下面一行,它们只是被边框隐藏了。

所以关闭顶部和底部边框的技巧是:

1) 将屏幕设置为 25 行模式

2) 等待光栅到达 $f2 和 $fa 之间的垂直位置(在 24 行模式和 25 行模式下边界开始位置之间的 8 个像素)。

3) 将屏幕设置为 24 行模式...将边框的垂直起点移到当前光栅位置上方

4) 等到垂直光栅位置($fa)

5) 重复每一帧

第 3 步)诱使 VIC 芯片认为它已经开始绘制边框,因此它永远不会开始绘制它。瞧,顶部和底部边框是打开的。

关于边边框,您可以使用不同的寄存器做同样的事情,但是由于光栅的水平移动比垂直移动快很多,所以时间需要更紧。还有另一个问题需要考虑,称为抖动。

【讨论】:

  • 是的,24行模式我就知道了,但没想到还能这么用……唯一不明白的是:这基本上可以让你清底。 24 边框模式使底部边框增加 8 个像素,但是当您清除底部边框时,光栅会返回第 0 行并通过重置开始绘制边框。
  • 您错误地假设在屏幕刷新开始时重置了边框标志。根据 24 行或 25 行模式,停止绘制边界的标志出现在 48 行或 56 行附近。开始绘制边框的标志只发生在 $f2 和 $fa 行,同样取决于 24 或 25 字符行模式。因此,当边界“开始绘制”标志未设置在 $fa 附近时,它不会再次尝试,直到下一个 $f2-$fa 区域。
  • 哇...这是我在 SO 上见过的最好的答案之一。做得好! :D
  • 雅达利使用了不同的技巧。您可以在任意时刻更改边框颜色。因此,通过计时颜色随电子束行进的变化,您可以创建图形。
【解决方案2】:

请注意,Krestage 3 所做的(如问题中所述)是不同的。

一个级别的技巧是在“纸”的底部(工作区矩形,边框内的东西)刚刚被绘制时弄乱边框。这可以让您在上下边框中拥有精灵。

更高的级别是在纸张的右侧边缘,在每个光栅行中弄乱它,所有这些都在上面 JohnD 的回答中解释。这使您可以在左右边框中拥有精灵。

这些都不能让您在一行中拥有超过 8 个精灵。这只是 Krest 的魔法。

到目前为止,VIC 芯片的最佳资源(我知道)是 Christian Bauer 的 "The MOS 6567/6569 video controller (VIC-II) and its application in the Commodore 64",有用的附录是 Marko Mäkelä 的 "The memory accesses of the MOS 6569 VIC-II and MOS 8566 VIC-IIe Video Interface Controller"
警告讲师:这些有点技术性,在您自己编写了一些 VIC 效果器后,您可能会发现它们更容易理解。

如果链接失效,只需按标题搜索文章,它们就会被无休止地复制。

【讨论】:

    【解决方案3】:

    你可以用一个简单的 BASIC 程序打开上下边框:

    1戳56334,0:戳53266,212:戳53265,27:戳16383,0 2 h=53265:i=53273:h1=19:h2=27:i1=1 3 pokei,i1:waiti,i1:pokeh,h1:pokeh,h2:goto3

    【讨论】:

      【解决方案4】:

      我要在这里暗中尝试一下(我自己还没有这样做过)。我在维基百科上找到了这个。

      c64demo section 解释说:

      认为不可能的效果是 在演示中实现,主要是由于 未记录的副作用 到MOS Technology VIC-II chip。 VIC诡计的一些例子:

      提到的其中一个技巧是:

      Sprite 滚动条被放置在 边界。通过欺骗硬件不 在屏幕周围绘制边框, 精灵可以移动到这个区域 并显示出来。

      当然,这个问题的有趣之处在于它是如何完成的。我建议查看一些包含源代码的 demo database,以搜索使用该 hack 的演示。

      【讨论】:

        【解决方案5】:

        微软飞行模拟器画在边界上。一方面,我们可以通过适时改变边框颜色来实现边框绘制效果。例如,LOGO 为 Turtle 图形提供了分屏模式,屏幕在上面的 HiRes 图形和下面的几行文本之间切换。框架的颜色也不同。所以很容易做一个地平线效果,下面的绿色牧场和上面的蓝天(就像在飞行模拟器中一样),效果延伸到框架。

        当你运行wild frame flicker程序时,比如

           C000 LDX #00
                STX D020
                INX
                STX D020
                DEX
                BEQ C002
        

        然后你会得到颜色每 10-20 像素左右改变一次。我认为这是你能得到的最快的改变。所以你可以在边框上画一条水平线。

        您可以通过使用 VIC 中 $D012 和 $D011 的第 7 位的相同垂直行寄存器来计时,您可以从该寄存器读取当前扫描行。但是如果你写入它,并且你启用寄存器 $D01A 中的低位,那么当扫描到达该行时,VIC 将发出信号并发出 IRQ。这样就实现了分屏效果。

        这是一个例子。首先我设置了我的中断程序:

           C000 SEI        ; disable interrupt
                LDA #1F    ; set interrupt routine to C01F
                STA 0314   ; set low byte
                LDA #C0    ; high byte
                STA 0315   ; set
                LDA #C0    ; raster position for horizon
                STA D012   ; set to raster position interrupt
                LDA D011   ; and for the high bit of the raster position
                AND #7F    ; clear the high bit
                STA D011   ; and set the cleared high bit
                LDA #F1    ; enable the raster interrupt
                STA D01A   ; in the appropriate register
                CLI        ; allow interrupt
                RTS        ; return from subroutine
        

        这是我现在的实际中断程序:

           C01F LDA D019   ; load VIC interrupt register
                STA D019   ; and clear it
                BMI C02E   ; if highest bit is set, go to our routine
                LDA DC0D   ; else disable CIA interrupt
                CLI        ; enable interrupt
                JMP EA31   ; continue with normal system interrupt routine
        
           C02E LDA D012   ; load current vertical scan line
                CMP #01    ; is it just about the first line?
                BCS C042   ; if not jump to bottom part
                LDA #03    ; cyan
                STA D020   ; set border color (sky)
                LDA #C0    ; horizon level 
                STA D012   ; set vertical scan interrupt to occur at horizon
                JMP EA81   ; continue with normal interrupt minus cursor blink
        
           C042 LDA #00    ; black to draw a piece of horizontal line on the horizon
                STA D020   ; set border color
                LDX #08    ; a short busy loop
           C049 DEX
                BNE C049
                LDA #01    ; white to draw on the right side horizon
                STA D020   ; set border color
                LDX #02    ; very short busy loop
           C053 DEX
                BNE C053
                LDA #05    ; finally green as the grass
                STA D020   ; set border color
                LDA #00    ; next scan line interrupt at top of screen
                STA DO12   ; set scan line interrupt
                JMP EA81   ; continue normal interrupt sans cursor blink 
        

        有了以下辉煌的结果:

        【讨论】:

        • 源代码中的错字(在 C64 屏幕抓取上正确):“LDC #02 ;very short busy loop”应该是“LDX #02”
        【解决方案6】:

        打印“它是 53280,伙计。”

        【讨论】:

        • 是的 - 里面是 53281。
        【解决方案7】:

        据我了解,这仅适用于精灵。

        精灵被允许在边界区域,并且边界被绘制在上面。通过一些诡计,可以移除边框。

        【讨论】:

          【解决方案8】:

          边框中的图形:精灵或使用 $3FFF 效果(实际上根本不是精灵)。详细介绍需要比我在这里可用的更多的空间和时间。

          【讨论】:

            【解决方案9】:

            您还可以在基本中将精灵设置为边框:BASIC Sprites in Border

            iirc,还有一些方法可以混淆视频芯片,使其绘制第 26 行文本。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2022-09-23
              • 1970-01-01
              • 2017-10-22
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多