9

私は C をよりよく学習するために DOS ゲーム フレームワークを作成しており、古いハードウェア (特に私が育ったシステム) でのプログラミングに一般的な関心を持っています。

ダブル バッファ システムを実装しようとしていますが、320*200 配列への far ポインタの割り当てに問題があります。

最初は malloc を使用しようとしていましたが、64kb 未満しか割り当てられないことがわかりました。farmalloc (malloc は NULL を返す) を使用する必要があることを読みましたが、正しく割り当てられました。ただし、_fmemset または _fmemcpy を実行すると、システム全体がフリーズします。

backBuffer = (unsigned char far*) farmalloc(64000);

使用するバッファを交換するとき

_fmemcpy(VGA, backBuffer, 64000);

プログラムはスモール メモリ モデルを使用しています。

4

1 に答える 1

8

非常に興味深い投稿です。私は古いハードウェアもとても好きです。

  • コードが正しく実行されるかどうかを確認するために、中規模または大規模なモデルでコンパイルを試みましたか?

  • VGA ディスプレイ メモリへのポインタが正しく初期化されていますか?

当時、メモリ コピーを使用して画面バッファをスワップするのは非常に遅く、メモリのコピーを開始するために垂直リトレース期間を待たなければならなかったことは言うまでもありません。(最低限の VGA カードを持っていたので、ハードウェアが優れていて、遅延が許容範囲を超えている可能性があります)。

興味のある方は、Michael Abrash のMode-Xコラムを読むことを強くお勧めします。

Mode-X とその派生物は、Michael Abrash によって最初に文書化された代替グラフィック モードです。基本的に、これらは 256 色 13H モードへのハックであり、VGA カードのいくつかのレジスタを微調整することで有効にすることができました。

アクティブ化すると、次の 2 つの大きな利点がありました。

  1. 4 ページの表示メモリ
  2. Square Pixels (元の ModeX では 320x240)、(プロットされた円は楕円ではなく円のように見えます)

ダブルまたはトリプル バッファの実装は非常に簡単でした。非アクティブ バッファに直接書き込み、それをアクティブにするには、VGA カードのレジスタを変更するだけで済み、memcopy はまったく必要ありませんでした。(まだ垂直リトレースを待つ必要があります。そうしないと、醜いちらつきが発生します)

欠点は、このモードのプログラミングが難しいことです。基本的にモード X では、1 つのメモリ アドレスが 4 つの連続するピクセルにマップされるため、1 つのピクセルの書き込みで実際には 4 つのピクセルが一度に変更されます。(これは、ポリゴン フィラー ルーチンの大幅な高速化です!)。

単一のピクセルを変更する場合は、ピクセルをプロットする直前に、4 つのピクセルのどれがメモリ書き込みの影響を受けるかを指定する「ピクセル マスク」(VGA カード レジスタも) をセットアップする必要があります。

プロットされるすべてのピクセルでマスクを設定する必要があるため、単純に行うと時間がかかります。通常、私たちは直感的に左から右、上から下に描画する傾向があります (VGA モード 13H でのビデオ メモリのマッピング方法が正確であるため)。 、上から下、左から右に物事を描きました。

なんで?これにより、描画された列ごとにピクセル マスクを 1 回だけ変更できるためです。ここにいくつかの擬似コードがあります:

素朴で直感的なプログラミング

pixelptr = start of screen memory
foreach row
   foreach column
      adjust pixel mask
      write pixel value
      pixelptr+= 1      // advance pointer to next pixel to the left
   next
next

プログラミングの回転モード

[Edit1: ポインタを次の列の先頭に移動する必要がある欠落しているステップを追加]

[編集 2: 修正、次の行に進むために 320 を追加していましたが、実際にはこれを 4 で割る必要があります。これは、ビデオ メモリ アドレスの連続したインクリメントが、前の行の右側にある次の 4 つのピクセルのグループにマップされるためです。 -ピクセルグループ]

for each column
   pixelptr = start of screen memory + current column index
   adjust pixel mask       // same mask applies to every pixel in the same column!
   for each row
      write pixel value
      pixelptr += (320 / 4)  // advance pointer to next pixel, to the bottom
   next
next

関連するすべての手順と登録アドレスは、私が提供した Michael Abrash のコラムへのリンクで詳しく説明されています。これは古いものですが、きっと魅力的だと思います。

乾杯!

于 2012-09-14T17:36:38.433 に答える