OSDN Git Service

new file: 16/(RUN_RUN.TO)
authorsparky4 <sparky4@4ch.maidlab.jp>
Sun, 27 Apr 2014 02:41:58 +0000 (21:41 -0500)
committersparky4 <sparky4@4ch.maidlab.jp>
Sun, 27 Apr 2014 02:41:58 +0000 (21:41 -0500)
new file:   16/(_START_.__)
new file:   16/(_______.__)
new file:   16/(~~~~~~~.~~)
new file:   16/16.txt
new file:   16/BAKAPI.EXE
new file:   16/DOS_COMM.EXE
new file:   16/DOS_GFX.EXE
new file:   16/DOS_GFX.SMP
new file:   16/M13ORG.ASC
new file:   16/M13ORG.GIF
new file:   16/MXORG.ASC
new file:   16/MXORG.GIF
new file:   16/Project 16.bfproject
new file:   16/RUN.BAT
new file:   16/XINTRO.TXT
new file:   16/dos_gfx.cpp
new file:   16/dos_gfx.h
new file:   16/dos_kb.c
new file:   16/dos_kb.h
new file:   16/k.bat
new file:   16/lib_com.cpp
new file:   16/lib_com.h
new file:   16/project16.txt
new file:   16/x.bat

26 files changed:
16/(RUN_RUN.TO) [new file with mode: 0644]
16/(_START_.__) [new file with mode: 0644]
16/(_______.__) [new file with mode: 0644]
16/(~~~~~~~.~~) [new file with mode: 0644]
16/16.txt [new file with mode: 0644]
16/BAKAPI.EXE [new file with mode: 0644]
16/DOS_COMM.EXE [new file with mode: 0644]
16/DOS_GFX.EXE [new file with mode: 0644]
16/DOS_GFX.SMP [new file with mode: 0644]
16/M13ORG.ASC [new file with mode: 0644]
16/M13ORG.GIF [new file with mode: 0644]
16/MXORG.ASC [new file with mode: 0644]
16/MXORG.GIF [new file with mode: 0644]
16/PMDIBM.COM [new file with mode: 0644]
16/Project 16.bfproject [new file with mode: 0644]
16/RUN.BAT [new file with mode: 0644]
16/XINTRO.TXT [new file with mode: 0644]
16/dos_gfx.cpp [new file with mode: 0644]
16/dos_gfx.h [new file with mode: 0644]
16/dos_kb.c [new file with mode: 0644]
16/dos_kb.h [new file with mode: 0644]
16/k.bat [new file with mode: 0644]
16/lib_com.cpp [new file with mode: 0644]
16/lib_com.h [new file with mode: 0644]
16/project16.txt [new file with mode: 0644]
16/x.bat [new file with mode: 0644]

diff --git a/16/(RUN_RUN.TO) b/16/(RUN_RUN.TO)
new file mode 100644 (file)
index 0000000..0519ecb
--- /dev/null
@@ -0,0 +1 @@
\ No newline at end of file
diff --git a/16/(_START_.__) b/16/(_START_.__)
new file mode 100644 (file)
index 0000000..0519ecb
--- /dev/null
@@ -0,0 +1 @@
\ No newline at end of file
diff --git a/16/(_______.__) b/16/(_______.__)
new file mode 100644 (file)
index 0000000..0519ecb
--- /dev/null
@@ -0,0 +1 @@
\ No newline at end of file
diff --git a/16/(~~~~~~~.~~) b/16/(~~~~~~~.~~)
new file mode 100644 (file)
index 0000000..0519ecb
--- /dev/null
@@ -0,0 +1 @@
\ No newline at end of file
diff --git a/16/16.txt b/16/16.txt
new file mode 100644 (file)
index 0000000..17cae05
--- /dev/null
+++ b/16/16.txt
@@ -0,0 +1,209 @@
+Current task: 2D scrolling tile engine
+Initial conditions:
+1. Total amount of program memory: This is tricky part because the OS has something called conveance memory and it is limited to 640k but there is may waya around it. using EMS and XMS the game should load a bunch of itself into the areas away from conventional memory as much as possible but if it like my current XT then we are forced to have less than that. I am still building up the official testing enviorment!
+2. Total amount of video memory: 256K, 320x240 screen, 256 colours //screen is 192K of memory! Only 64K is left free We can use it for buffering and storing game graphics!
+3. Tile size: 16x16, 256 bytes (0.25K) per tile
+4. Total amount of tiles used: n/a
+5. Total amount of tiles stored in memory at a time: 256 (64K) //reduce to 128 or less if there's not enough memory
+//31K for sprites which is about 124 sprites!
+//there is 3 pages advalible for us that are 75K each!
+Task explanation:
+Tiles are rendered as a background. Background needs to be scrolled from up to down and from left to right.
+Tiles currently used are stored in the video memory. World, consisting of tiles, is represented as a matrix.
+World is split into areas. Changing area means changing used tileset. Tiles in two neighbouring areas should not overlap.
+Viewport matrix holds 20x15 to 21x16 tiles at once. As we only have 256 tiles in our set, each tile is one byte long.
+The best variant to change matrix contents FAST seems to be 2D linked list. The downside is memory lookup time.
+An alternative is a 2D array. Fast lookup, less memory, expensive relocation.
+Something like
+#define NTILES_X = 21
+#define NTILES_Y = 16
+#define TILES_X = NTILES_X - 1
+#define TILES_Y = NTILES_Y - 1
+struct vp_node {
+    uint8_t tile;
+    struct vp_node *up;
+    struct vp_node *right;
+    struct vp_node *down;
+    struct vp_node *left;
+};
+struct viewport {
+    uint8_t offset_x; //X offset in pixels
+    uint8_t offset_y; //Y offset in pixels
+    uint16_t world_offset_x;
+    uint16_t world_offset_y;
+    struct vp_node *upper_left; //pointer to the upper left tile
+};
+void initvp(struct viewport *vp, uint8_t **world_matrix, uint16_t offset_x, uint16_t offset_y) {
+    int i, j;
+    struct vp_node *vp_tmp[NTILES_Y][NTILES_X]; //i'd like to copy it
+    for(i=0; i<NTILES_Y; i++) {
+        for(j=0; j<NTILES_X; j++) {
+            vp_tmp[i][j] = malloc(sizeof(struct vp_node));
+            vp_tmp[i][j]->tile = world_matrix[offset_x + i][offset_y + j];
+        }
+    }
+    // i for line, j for column
+    // linking neighbouring tiles
+    // wait, do we need links to left and up?
+    for(i=0; i<NTILES_Y; i++) {
+        for(j=0; j<NTILES_X; j++) {
+            if(i) vp_tmp[i][j]->up = vp_tmp[i-1][j];
+            else vp_tmp[i][j]->up = NULL;
+            if(j) vp_tmp[i][j]->left = vp_tmp[i][j-1];
+            else vp_tmp[i][j]->left = NULL;
+            if(i<20) vp_tmp[i][j]->down = vp_tmp[i+1][j];
+            else vp_tmp[i][j]->down = NULL;
+            if(j<15) vp_tmp[i][j]->right = vp_tmp[i][j+1];
+            else vp_tmp[i][j]->right = NULL;
+        }
+    }
+    vp = malloc(sizeof(struct viewport));
+    vp->offset_x = 0;
+    vp->offset_y = 0;
+    vp->world_offset_x = offset_x;
+    vp->world_offset_y = offset_y;
+    vp->upper_left = vp_tmp[0][0];
+}
+void scroll(struct viewport *vp, uint8_t **world_matrix, int8_t offset_x, int8_t offset_y) {
+    int8_t offset_x_total = offset_x + vp->offset_x;
+    int8_t offset_y_total = offset_y + vp->offset_y;
+    if(offset_x_total > 15) shift_right(vp, world_matrix);
+    if(offset_x_total < 0) shift_left(vp, world_matrix);
+    if(offset_y_total > 15) shift_down(vp, world_matrix);
+    if(offset_y_total < 0) shift_up(vp, world_matrix);
+    vp->offset_x = offset_x_total % 16;
+    vp->offset_y = offset_y_total % 16;
+}
+void shift_right(struct viewport *vp, uint8_t **world_matrix) {
+    vp->world_offset_x += 1;
+    struct vp_node *tmp = vp->upper_left;
+    vp->upper_left = vp->upper_left->right;
+    while(tmp->down) {
+        tmp->right->left = NULL;
+        tmp = tmp->down;
+        free(tmp->up);
+    }
+    tmp->right->left = NULL;
+    free(tmp);
+    // Starting from the upper left corner
+    tmp = vp->upper_left;
+    // Looking up the rightmost tile
+    while(tmp->right) tmp = tmp->right;
+    // Here and below: allocating and linking new neighbouring tiles
+    int i=0;
+    tmp->right = malloc(sizeof(struct vp_node));
+    tmp->right->tile = world_matrix[vp->world_offset_y + i++][vp->world_offset_x +20];
+    tmp->right->left = tmp;
+    tmp->right->up = NULL;
+    tmp->right->right = NULL;
+    while(tmp->down) {
+        tmp = tmp->down;
+        tmp->right = malloc(sizeof(struct vp_node));
+        tmp->right->tile = world_matrix[vp->world_offset_y + i++][vp->world_offset_x + 20];
+        tmp->right->left = tmp;
+        tmp->right->up = tmp->up->right;
+        tmp->up->right->down = tmp->right;
+        tmp->right->right = NULL;
+    }
+    tmp->right->down = NULL;
+    // looks like we've just added a column
+}
+void shift_left(struct viewport *vp, uint8_t **world_matrix) {
+    vp->world_offset_x -= 1;
+    // Removing the rightmost column first
+    struct vp_node *tmp = vp->upper_left;
+    while(tmp->right) tmp = tmp->right;
+    while(tmp->down) {
+        tmp->left->right = NULL;
+        tmp = tmp->down;
+        free(tmp->up);
+    }
+    tmp->left->right = NULL;
+    free(tmp);
+    // Now we need to add a new column to the left
+    tmp = vp->upper_left;
+    // Here and below: allocating and linking new neighbouring tiles
+    int i=0;
+    tmp->left = malloc(sizeof(struct vp_node));
+    tmp->left->tile = world_matrix[vp->world_offset_y + i++][vp->world_offset_x];
+    tmp->left->right = tmp;
+    tmp->left->up = NULL;
+    tmp->left->left = NULL;
+    while(tmp->down) {
+        tmp = tmp->down;
+        tmp->left = malloc(sizeof(struct vp_node));
+        tmp->left->tile = world_matrix[vp->world_offset_y + i++][vp->world_offset_x];
+        tmp->left->right = tmp;
+        tmp->left->up = tmp->up->left;
+        tmp->up->left->down = tmp->left;
+        tmp->left->left = NULL;
+    }
+    tmp->left->down = NULL;
+    // looks like we've just added a column to the left
+}
+void shift_down(struct viewport *vp, uint8_t **world_matrix) {
+    vp->world_offset_y += 1;
+    // Removing the upper row first
+    struct vp_node *tmp = vp->upper_left->down;
+    vp->upper_left = tmp;
+    do {
+        free(tmp->up);
+        tmp->up = NULL;
+    } while(tmp->right);
+    // Now we need to add a new column to the bottom
+    tmp = vp->upper_left;
+    while(tmp->down) tmp = tmp->down;
+    // Here and below: allocating and linking new neighbouring tiles
+    int i=0;
+    tmp->down = malloc(sizeof(struct vp_node));
+    tmp->dpwn->tile = world_matrix[vp->world_offset_y + i++][vp->world_offset_x];
+    tmp->down->left = NULL;
+    tmp->down->up = tmp;
+    tmp->down->down = NULL;
+    while(tmp->right) {
+        tmp = tmp->right;
+        tmp->down = malloc(sizeof(struct vp_node));
+        tmp->down->tile = world_matrix[vp->world_offset_y + i++][vp->world_offset_x];
+        tmp->down->up = tmp;
+        tmp->down->left = tmp->left->down;
+        tmp->left->down->right = tmp->down;
+        tmp->down->down = NULL;
+    }
+    tmp->down->right = NULL;
+    // looks like we've just added a row to the bottom
+}
+void shift_up(struct viewport *vp, uint8_t **world_matrix) {
+    vp->world_offset_y += 1;
+    // Removing the bottom row first
+    struct vp_node *tmp = vp->upper_left;
+    while(tmp->down) tmp = tmp->down;
+    while(tmp->right) {
+        tmp->up->down = NULL;
+        tmp = tmp->right;
+        free(tmp->left);
+    }
+    tmp->up->down = NULL;
+    free(tmp);
+    // Now we need to add a new row to the top
+    tmp = vp->upper_left;
+    // Here and below: allocating and linking new neighbouring tiles
+    int i=0;
+    tmp->up = malloc(sizeof(struct vp_node));
+    tmp->up->tile = world_matrix[vp->world_offset_y + i++][vp->world_offset_x];
+    tmp->up->left = NULL;
+    tmp->up->down = tmp;
+    tmp->up->up = NULL;
+    while(tmp->right) {
+        tmp = tmp->right;
+        tmp->up = malloc(sizeof(struct vp_node));
+        tmp->up->tile = world_matrix[vp->world_offset_y + i++][vp->world_offset_x];
+        tmp->up->down = tmp;
+        tmp->up->left = tmp->left->up;
+        tmp->left->up->right = tmp->up;
+        tmp->up->up = NULL;
+    }
+    tmp->up->right = NULL;
+    // looks like we've just added a row to the top
+}
+void render_vp(struct viewport *vp);
+
diff --git a/16/BAKAPI.EXE b/16/BAKAPI.EXE
new file mode 100644 (file)
index 0000000..ba0690e
Binary files /dev/null and b/16/BAKAPI.EXE differ
diff --git a/16/DOS_COMM.EXE b/16/DOS_COMM.EXE
new file mode 100644 (file)
index 0000000..3527174
Binary files /dev/null and b/16/DOS_COMM.EXE differ
diff --git a/16/DOS_GFX.EXE b/16/DOS_GFX.EXE
new file mode 100644 (file)
index 0000000..bbd903d
Binary files /dev/null and b/16/DOS_GFX.EXE differ
diff --git a/16/DOS_GFX.SMP b/16/DOS_GFX.SMP
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/16/M13ORG.ASC b/16/M13ORG.ASC
new file mode 100644 (file)
index 0000000..906ec42
--- /dev/null
@@ -0,0 +1,55 @@
+Figure 1: Memory organization in mode 13h (ASCII version)\r
+         by Robert Schmidt\r
+          (C) 1993 Ztiff Zox Softwear\r
+\r
+a. Imagine that the top of the screen looks like this (pixel values are\r
+   represented by color digits 0-9 for simplicity - actual colors may\r
+   range from 0 to 255) - a screen width of 320 pixels is assumed:\r
+\r
+    address:  0         10                310      319\r
+             ----------------------------------------\r
+             |0123456789012345    .....   0123456789|\r
+             |                                      |\r
+             |                                      |\r
+             |\r
+\r
+b. In VGA memory, the screen is represented as follows (question marks\r
+   represent unused bytes):\r
+\r
+   Plane 0:\r
+\r
+    address:  0         10                310      319\r
+             ----------------------------------------\r
+             |0???4???8???2???    .....   ??2???6???|\r
+             |                                      |\r
+             |                                      |\r
+\r
+   Plane 1:\r
+\r
+    address:  0         10                310      319\r
+             ----------------------------------------\r
+             |?1???5???9???3??    .....   ???3???7??|\r
+             |                                      |\r
+             |                                      |\r
+\r
+   Plane 2:\r
+\r
+    address:  0         10                310      319\r
+             ----------------------------------------\r
+             |??2???6???0???4?    .....   0???4???8?|\r
+             |                                      |\r
+             |                                      |\r
+\r
+   Plane 3:\r
+\r
+    address:  0         10                310      319\r
+             ----------------------------------------\r
+             |???3???7???1???5    .....   ?1???5???9|\r
+             |                                      |\r
+             |                                      |\r
+\r
+   I.e. a plane is selected automatically by the two least significant\r
+   bits of the address of the byte being read from or written two.\r
+   This renders 3/4 of the video memory unavailable and useless, but\r
+   all visible pixels are easily accessed, as each address in the video\r
+   segment provides access to one and ONLY ONE pixel.\r
diff --git a/16/M13ORG.GIF b/16/M13ORG.GIF
new file mode 100644 (file)
index 0000000..1fb4fc4
Binary files /dev/null and b/16/M13ORG.GIF differ
diff --git a/16/MXORG.ASC b/16/MXORG.ASC
new file mode 100644 (file)
index 0000000..295766b
--- /dev/null
@@ -0,0 +1,49 @@
+Figure 2: Memory organization in unchained 256-color modes (like\r
+          Mode X) (ASCII version)\r
+         by Robert Schmidt\r
+          (C) 1993 Ztiff Zox Softwear\r
+\r
+\r
+Imagine that the screen looks the same as in figure 1a.  A screen width\r
+of 320 pixels is still assumed.\r
+\r
+In VGA memory, the screen will be represented as follows:\r
+\r
+   Plane 0:\r
+\r
+    address:  0         10                70       79 (NOT 319!)\r
+             ----------------------------------------\r
+             |0482604826048260    .....   0482604826|\r
+             |                                      |\r
+             |                                      |\r
+\r
+   Plane 1:\r
+\r
+    address:  0         10                70       79\r
+             ----------------------------------------\r
+             |1593715937159371    .....   1593715937|\r
+             |                                      |\r
+             |                                      |\r
+\r
+   Plane 2:\r
+\r
+    address:  0         10                70       79\r
+             ----------------------------------------\r
+             |2604826048260482    .....   2604826048|\r
+             |                                      |\r
+             |                                      |\r
+\r
+   Plane 3:\r
+\r
+    address:  0         10                70       79\r
+             ----------------------------------------\r
+             |3715937159371593    .....   3715937159|\r
+             |                                      |\r
+             |                                      |\r
+\r
+Note that if pixel i is in plane p, pixel i+1 is in plane (p+1)%4.\r
+When the planes are unchained, we need to set the Write Plane Enable\r
+register to select which planes should receive the data when writing,\r
+or the Read Plane Select register when reading.  As is evident, one \r
+address in the video segment provides access to no less than FOUR\r
+different pixels.\r
diff --git a/16/MXORG.GIF b/16/MXORG.GIF
new file mode 100644 (file)
index 0000000..31c0ac5
Binary files /dev/null and b/16/MXORG.GIF differ
diff --git a/16/PMDIBM.COM b/16/PMDIBM.COM
new file mode 100644 (file)
index 0000000..091bff9
Binary files /dev/null and b/16/PMDIBM.COM differ
diff --git a/16/Project 16.bfproject b/16/Project 16.bfproject
new file mode 100644 (file)
index 0000000..6054ca5
--- /dev/null
@@ -0,0 +1,110 @@
+c2e.convert_special: 0
+e2c.convert_num: 0
+openfiles: /dos/z/4x4_16/16/dos_gfx.cpp:12460:12437:0:
+openfiles: /dos/z/4x4_16/16/dos_gfx.h:0:0:0:
+openfiles: /dos/z/4x4_16/16/dos_comm.c:3700:2769:1:
+openfiles: /dos/z/4x4_16/16/dos_comm.h:476:0:0:
+openfiles: /dos/z/4x4_16/16/lib_com.cpp:0:0:0:
+openfiles: /dos/z/4x4_16/16/lib_com.h:0:0:0:
+openfiles: /dos/z/4x4_16/16/project16.txt:0:0:0:
+snr_recursion_level: 0
+convertcolumn_horizontally: 0
+adv_open_matchname: 0
+show_mbhl: 1
+view_line_numbers: 1
+fb_show_backup_f: 0
+htmlbar_thumbnailwidth: 300
+view_left_panel: 0
+default_mime_type: text/plain
+e2c.convert_xml: 1
+c2e.convert_iso: 0
+opendir: file:///dos/z/4x4_16/16
+wrap_text_default: 0
+bookmarks_filename_mode: 1
+snr_casesens: 1
+view_blocks: 1
+name: Project 16
+replacelist: width
+replacelist: height
+replacelist: getFont()
+fb_show_hidden_f: 0
+editor_tab_width: 4
+template: /usr/share/bluefish/templates/C_header_GPL
+show_visible_spacing: 0
+view_statusbar: 1
+display_right_margin: 0
+c2e.IE_apos_workaround: 0
+outputb_scroll_mode: 0
+leftpanel_active_tab: 0
+enable_syntax_scan: 1
+ssearch_regex: 0
+e2c.convert_iso: 0
+ssearch_casesens: 0
+charmap_block: 1
+recent_files: file:///dos/z/sparky4/bakapi/BAKAPI.C
+recent_files: file:///dos/z/4x4_16/tweak/DEMO.CPP
+recent_files: file:///dos/z/4x4_16/tweak/TG.CPP
+recent_files: file:///dos/z/4x4_16/16/dos_gfx.h
+recent_files: file:///dos/z/4x4_16/16/lib_com.cpp
+recent_files: file:///dos/z/4x4_16/16/lib_com.h
+recent_files: file:///dos/z/4x4_16/16/dos_gfx.cpp
+recent_files: file:///dos/z/4x4_16/16/project16.txt
+recent_files: file:///dos/z/4x4_16/16/dos_comm.c
+recent_files: file:///dos/z/4x4_16/16/dos_comm.h
+snr_replacetype: 0
+savedir: file:///dos/z/4x4_16/16
+spell_check_default: 1
+spell_insert_entities: 0
+last_filefilter: 
+htmlbar_notebooktab: 0
+view_blockstack: 1
+snr_escape_chars: 0
+htmlbar_view: 1
+spell_lang: en
+ssearch_dotmatchall: 0
+searchlist: .drawText(
+searchlist: drawText(
+searchlist: drawChar
+searchlist: getFont()
+searchlist: vga
+searchlist: uint
+searchlist: *vga
+searchlist: uint
+searchlist: char
+searchlist: fontAddr
+autocomplete: 1
+outputb_show_all_output: 0
+bookmarks_show_mode: 0
+snippets_show_as_menu: 1
+adv_open_recursive: 0
+encoding: SHIFT_JIS
+e2c.convert_special: 0
+autoindent: 1
+fb_viewmode: 0
+filegloblist: *.xml
+filegloblist: *.txt
+filegloblist: *.shtml
+filegloblist: *.py
+filegloblist: *.pl
+filegloblist: *.php
+filegloblist: *.js
+filegloblist: *.java
+filegloblist: *.htm
+filegloblist: *.html
+filegloblist: *.h
+filegloblist: *.css
+filegloblist: *.cpp
+filegloblist: *.cgi
+filegloblist: *.c
+fb_focus_follow: 1
+ssearch_unescape: 0
+c2e.convert_symbol: 0
+snr_dotmatchall: 0
+c2e.convert_xml: 1
+editor_indent_wspaces: 0
+view_cline: 1
+snr_type: 0
+snr_scope: 3
+bmarksearchmode: 0
+view_main_toolbar: 1
+e2c.convert_symbol: 0
diff --git a/16/RUN.BAT b/16/RUN.BAT
new file mode 100644 (file)
index 0000000..ed9144d
--- /dev/null
@@ -0,0 +1,4 @@
+wsample dos_gfx.exe\r
+call \z\bat\hres.bat\r
+wprof dos_gfx.smp\r
+rem vi DOS_GFX.CPP\r
diff --git a/16/XINTRO.TXT b/16/XINTRO.TXT
new file mode 100644 (file)
index 0000000..0ac0585
--- /dev/null
@@ -0,0 +1,569 @@
+Title:         INTRODUCTION TO MODE X (XINTRO.TXT)\r
+\r
+Version:        1.8\r
+\r
+Author:                Robert Schmidt <robert@stud.unit.no>\r
+\r
+Copyright:     (C) 1993 of Ztiff Zox Softwear - refer to Status below.\r
+\r
+Last revision:  25-Nov-93\r
+\r
+Figures:       1. M13ORG - memory organization in mode 13h\r
+               2. MXORG - memory organization in unchained modes\r
+\r
+               The figures are available both as 640x480x16 bitmaps\r
+               (in GIF format), and as 7-bit ASCII text (ASC) files.\r
+\r
+C sources:     1. LIB.C v1.2 - simple graphics library for planar,\r
+                   256-color modes - optionally self-testing.\r
+\r
+                Excerpts from the source(s) appear in this article.\r
+                Whenever there are conflicts, the external source file(s)\r
+               are correct (or, at least, newest), _not_ the excerpts\r
+               provided here.\r
+\r
+Status:                This article, its associated figures and source listings\r
+               named above, are all donated to the public domain.\r
+               Do with it whatever you like, but give credit where\r
+               credit is due.  I would prefer it if this archive was\r
+               distributed in its entirety, including the files\r
+               mentioned above.\r
+\r
+               The standard disclaimer applies.\r
+\r
+Index:         0. ABSTRACT\r
+               1. INTRODUCTION TO THE VGA AND ITS 256-COLOR MODE\r
+               2. GETTING MORE PAGES AND PUTTING YOUR FIRST PIXEL\r
+               3. THE ROAD FROM HERE\r
+               4. BOOKS ON THE SUBJECT\r
+                5. BYE - FOR NOW\r
+\r
+\r
+0. ABSTRACT\r
+\r
+This text gives a fairly basic, yet technical, explanation to what, why\r
+and how Mode X is.  It first tries to explain the layout of the VGA\r
+memory and the shortcomings of the standard 320x200 256-color mode,\r
+then gives instructions on how one can progress from mode 13h to a\r
+multipage, planar 320x200 256-color mode, and from there to the\r
+quasi-standard 320x240 mode, known as Mode X.\r
+\r
+A little experience in programming the standard VGA mode 13h\r
+(320x200 in 256 colors) is assumed.  Likewise a good understanding of\r
+hexadecimal notation and the concepts of segments and I/O ports is\r
+assumed.  Keep a VGA reference handy, which at least should have\r
+definitions of the VGA registers at bit level.\r
+\r
+Throughout the article, a simple graphics library for unchained (planar)\r
+256-color modes is developed.  The library supports the 320x200 and\r
+320x240 modes, active and visible pages, and writing and reading\r
+individual pixels.\r
+\r
+\r
+1. INTRODUCTION TO THE VGA AND ITS 256-COLOR MODE\r
+\r
+Since its first appearance on the motherboards of the IBM PS/2 50, 60\r
+and 80 models in 1987, the Video Graphics Array has been the de facto\r
+standard piece of graphics hardware for IBM and compatible personal\r
+computers.  The abbreviation, VGA, was to most people synonymous with\r
+acceptable resolution (640x480 pixels), and a stunning rainbow of colors\r
+(256 from a palette of 262,144), at least compared to the rather gory\r
+CGA and EGA cards.\r
+\r
+Sadly, to use 256 colors, the VGA BIOS limited the users to 320x200\r
+pixels, i.e. the well-known mode 13h.  This mode has one good and one\r
+bad asset.  The good one is that each one of the 64,000 pixels is easily\r
+addressable in the 64 Kb video memory segment at 0A000h.  Simply calculate\r
+the offset using this formula:\r
+\r
+offset = (y * 320) + x;\r
+\r
+Set the byte at this address (0A000h:offset) to the color you want, and\r
+the pixel is there.  Reading a pixel is just as simple: just read the\r
+corresponding byte.  This was heaven, compared to the havoc of planes and\r
+masking registers needed in 16-color modes.  Suddenly, the distance from a\r
+graphics algorithm on paper to an implemented graphics routine in assembly\r
+was cut down to a fraction.  The results were impressively fast, too!\r
+\r
+The bad asset is that mode 13h is also limited to only one page, i.e.\r
+the VGA can hold only one screenful at any one time (plus 1536 pixels, or\r
+about four lines).  Most 16-color modes let the VGA hold more than one page,\r
+and this enables you to show one of the pages to the user, while drawing on\r
+another page in the meantime.  Page flipping is an important concept in making\r
+flicker free animations.  Nice looking and smooth scrolling is also almost\r
+impossible in mode 13h using plain VGA hardware.\r
+\r
+Now, the alert reader might say: "Hold on a minute!  If mode 13h enables\r
+only one page, this means that there is memory for only one page.  But I\r
+know for a fact that all VGAs have at least 256 Kb RAM, and one 320x200\r
+256-color page should consume only 320*200=64000 bytes, which is less\r
+than 64 Kb.  A standard VGA should room a little more than four 320x200\r
+pages!"  Quite correct, and to see how the BIOS puts this limitation on\r
+mode 13h, I'll elaborate a little on the memory organization of the VGA.\r
+\r
+The memory is separated into four bit planes.  The reason for this stems\r
+from the EGA, where graphics modes were 16-color.  Using bit planes, the\r
+designers chose to let each pixel on screen be addressable by a single\r
+bit in a single byte in the video segment.  Assuming the palette has\r
+not been modified from the default, each plane represent one of the EGA\r
+primary colors: red, green, blue and intensity.  When modifying the bit\r
+representing a pixel, the Write Plane Enable register is set to the\r
+wanted color.  Reading is more complex and slower, since you can\r
+only read from a single plane at a time, by setting the Read Plane\r
+Select register.  Now, since each address in the video segment can\r
+access 8 pixels, and there are 64 Kb addresses, 8 * 65,536 = 524,288\r
+16-color pixels can be accessed.  In a 320x200 16-color mode, this makes\r
+for about 8 (524,288/(320*200)) pages, in 640x480 you get nearly 2\r
+(524,288/(640*480)) pages.\r
+\r
+In a 256-color mode, the picture changes subtly.  The designers decided\r
+to fix the number of bit planes to 4, so extending the logic above to 8\r
+planes and 256 colors does not work.  Instead, one of their goals was to\r
+make the 256-color mode as easily accessible as possible.  Comparing the\r
+8 pixels/address in 16-color modes to the 1-to-1 correspondence of\r
+pixels and addresses of mode 13h, one can say that they have\r
+succeeded, but at a certain cost.  For reasons I am not aware of, the\r
+designers came up with the following effective, but memory-wasting\r
+scheme:\r
+\r
+The address space of mode 13h is divided evenly across the four bit\r
+planes.  When an 8-bit color value is written to a 16-bit address in the\r
+VGA segment, a bit plane is automatically selected by the 2 least\r
+significant bits of the address.  Then all 8 bits of the data is written\r
+to the byte at the 16-bit address in the selected bitplane (have a look at\r
+figure 1).  Reading works exactly the same way.  Since the bit planes are so\r
+closely tied to the address, only every fourth byte in the video memory is\r
+accessible, and 192 Kb of a 256 Kb VGA go to waste.  Eliminating the\r
+need to bother about planes sure is convenient and beneficial, but to\r
+most people the loss of 3/4 of the total VGA memory sounds just hilarious.\r
+\r
+To accomodate this new method of accessing video memory, the VGA\r
+designers introduced a new configuration bit called Chain-4, which\r
+resides as bit number 3 in index 4 of the Sequencer.  In 16-color modes,\r
+the default state for this bit is off (zero), and the VGA operates as\r
+described earlier.  In the VGA's standard 256-color mode, mode 13h, this\r
+bit is turned on (set to one), and this turns the tieing of bit\r
+planes and memory address on.\r
+\r
+In this state, the bit planes are said to be chained together, thus mode\r
+13h is often called a _chained mode_.\r
+\r
+Note that Chain-4 in itself is not enough to set a 256-color mode -\r
+there are other registers which deals with the other subtle changes in\r
+nature from 16 to 256 colors.  But, as we now will base our work with\r
+mode X on mode 13h, which already is 256-color, we won't bother about\r
+these for now.\r
+\r
+\r
+\r
+2. GETTING MORE PAGES AND PUTTING YOUR FIRST PIXEL\r
+\r
+The observant reader might at this time suggest that clearing the\r
+Chain-4 bit after setting mode 13h will give us access to all 256 Kb of\r
+video memory, as the two least significant bits of the byte address\r
+won't be `wasted' on selecting a bit plane.  This is correct.  You might\r
+also start feeling a little uneasy, because something tells you that\r
+you'll instantly loose the simple addressing scheme of mode 13h.  Sadly,\r
+that is also correct.\r
+\r
+At the moment Chain-4 is cleared, each byte offset addresses *four*\r
+sequential pixels, corresponding to the four planes addressed in 16-color\r
+modes.  Every fourth pixel belong in the same plane.  Before writing to a byte\r
+offset in the video segment, you should make sure that the 4-bit mask in the\r
+Write Plane Enable register is set correctly, according to which of the four\r
+addressable pixels you want to modify.  In essence, it works like a 16-color\r
+mode with a twist.  See figure 2.\r
+\r
+So, is this mode X?  Not quite.  We need to elaborate to the VGA how to\r
+fetch data for refreshing the monitor image.  Explaining the logic\r
+behind this is beyond the scope of this getting-you-started text, and it\r
+wouldn't be very interesting anyway.  Also, mode 13h has only 200 lines,\r
+while I promised 240 lines.  I'll fix that later below.  Here is the minimum\r
+snippet of code to initiate the 4 page variant of mode 13h (320x200), written\r
+in plain C, using some DOS specific features (see header for a note about the\r
+sources included):\r
+\r
+----8<-------cut begin------\r
+\r
+/* width and height should specify the mode dimensions.  widthBytes\r
+   specify the width of a line in addressable bytes. */\r
+\r
+int width, height, widthBytes;\r
+\r
+/* actStart specifies the start of the page being accessed by\r
+   drawing operations.  visStart specifies the contents of the Screen\r
+   Start register, i.e. the start of the visible page */\r
+\r
+unsigned actStart, visStart;\r
+\r
+/*\r
+ * set320x200x256_X()\r
+ *     sets mode 13h, then turns it into an unchained (planar), 4-page\r
+ *     320x200x256 mode.\r
+ */\r
+\r
+set320x200x256_X()\r
+       {\r
+\r
+       union REGS r;\r
+\r
+       /* Set VGA BIOS mode 13h: */\r
+\r
+       r.x.ax = 0x0013;\r
+       int86(0x10, &r, &r);\r
+\r
+       /* Turn off the Chain-4 bit (bit 3 at index 4, port 0x3c4): */\r
+\r
+       outport(SEQU_ADDR, 0x0604);\r
+\r
+       /* Turn off word mode, by setting the Mode Control register\r
+          of the CRT Controller (index 0x17, port 0x3d4): */\r
+\r
+       outport(CRTC_ADDR, 0xE317);\r
+\r
+       /* Turn off doubleword mode, by setting the Underline Location\r
+          register (index 0x14, port 0x3d4): */\r
+\r
+       outport(CRTC_ADDR, 0x0014);\r
+\r
+       /* Clear entire video memory, by selecting all four planes, then\r
+          writing 0 to the entire segment. */\r
+\r
+       outport(SEQU_ADDR, 0x0F02);\r
+       memset(vga+1, 0, 0xffff); /* stupid size_t exactly 1 too small */\r
+       vga[0] = 0;\r
+\r
+       /* Update the global variables to reflect the dimensions of this\r
+          mode.  This is needed by most future drawing operations. */\r
+\r
+        width   = 320;\r
+       height  = 200;\r
+\r
+        /* Each byte addresses four pixels, so the width of a scan line\r
+           in *bytes* is one fourth of the number of pixels on a line. */\r
+\r
+        widthBytes = width / 4;\r
+\r
+        /* By default we want screen refreshing and drawing operations\r
+           to be based at offset 0 in the video segment. */\r
+\r
+       actStart = visStart = 0;\r
+\r
+       }\r
+\r
+----8<-------cut end------\r
+\r
+As you can see, I've already provided some of the mechanics needed to\r
+support multiple pages, by providing the actStart and visStart variables.\r
+Selecting pages can be done in one of two contexts:\r
+\r
+       1) selecting the visible page, i.e. which page is visible on\r
+          screen, and\r
+\r
+       2) selecting the active page, i.e. which page is accessed by\r
+          drawing operations\r
+\r
+Selecting the active page is just a matter of offsetting our graphics\r
+operations by the address of the start of the page, as demonstrated in\r
+the put pixel routine below.  Selecting the visual page must be passed\r
+in to the VGA, by setting the Screen Start register.  Sadly enough, the\r
+resolution of this register is limited to one addressable byte, which\r
+means four pixels in unchained 256-color modes.  Some further trickery is \r
+needed for 1-pixel smooth, horizontal scrolling, but I'll make that a subject \r
+for later.  The setXXXStart() functions provided here accept byte\r
+offsets as parameters, so they'll work in any mode.  If widthBytes and\r
+height are set correctly, so will the setXXXPage() functions.\r
+\r
+----8<-------cut begin------\r
+\r
+/*\r
+ * setActiveStart() tells our graphics operations which address in video\r
+ * memory should be considered the top left corner.\r
+ */\r
+\r
+setActiveStart(unsigned offset)\r
+       {\r
+       actStart = offset;\r
+       }\r
+\r
+/*\r
+ * setVisibleStart() tells the VGA from which byte to fetch the first\r
+ * pixel when starting refresh at the top of the screen.  This version\r
+ * won't look very well in time critical situations (games for\r
+ * instance) as the register outputs are not synchronized with the\r
+ * screen refresh.  This refresh might start when the high byte is\r
+ * set, but before the low byte is set, which produces a bad flicker.\r
+ * I won't bother with this now.\r
+ */\r
+\r
+setVisibleStart(unsigned offset)\r
+       {\r
+       visStart = offset;\r
+       outport(CRTC_ADDR, 0x0C);               /* set high byte */\r
+       outport(CRTC_ADDR+1, visStart >> 8);\r
+       outport(CRTC_ADDR, 0x0D);               /* set low byte */\r
+       outport(CRTC_ADDR+1, visStart & 0xff);\r
+       }\r
+\r
+/*\r
+ * setXXXPage() sets the specified page by multiplying the page number\r
+ * with the size of one page at the current resolution, then handing the\r
+ * resulting offset value over to the corresponding setXXXStart()\r
+ * function.  The first page number is 0.\r
+ */\r
+\r
+setActivePage(int page)\r
+       {\r
+       setActiveStart(page * widthBytes * height);\r
+       }\r
+\r
+setVisiblePage(int page)\r
+       {\r
+       setVisibleStart(page * widthBytes * height);\r
+       }\r
+\r
+----8<-------cut end------\r
+\r
+Due to the use of bit planes, the graphics routines tend to get more\r
+complex than in mode 13h, and your first versions will generally tend to\r
+be a little slower than mode 13h algorithms.  Here's a put pixel routine\r
+for any unchained 256-color mode (it assumes that the 'width' variable\r
+from the above code is set correctly).  Optimizing is left as an exercise\r
+to you, the reader.  This will be the only drawing operation I'll cover\r
+in this article, but all general primitives like lines and circles can be \r
+based on this routine.  (You'll probably not want to do that though, due\r
+to the inefficiency.)\r
+\r
+----8<-------cut begin------\r
+\r
+putPixel_X(int x, int y, char color)\r
+       {\r
+\r
+       /* Each address accesses four neighboring pixels, so set\r
+          Write Plane Enable according to which pixel we want\r
+          to modify.  The plane is determined by the two least\r
+          significant bits of the x-coordinate: */\r
+\r
+       outportb(0x3c4, 0x02);\r
+       outportb(0x3c5, 0x01 << (x & 3));\r
+\r
+       /* The offset of the pixel into the video segment is\r
+          offset = (width * y + x) / 4, and write the given\r
+          color to the plane we selected above.  Heed the active\r
+          page start selection. */\r
+\r
+       vga[(unsigned)(widthBytes * y) + (x / 4) + actStart] = color;\r
+\r
+       }\r
+\r
+char getPixel_X(int x, int y)\r
+       {\r
+\r
+       /* Select the plane from which we must read the pixel color: */\r
+\r
+       outport(GRAC_ADDR, 0x04);\r
+       outport(GRAC_ADDR+1, x & 3);\r
+\r
+       return vga[(unsigned)(widthBytes * y) + (x / 4) + actStart];\r
+\r
+       }\r
+\r
+----8<-------cut end------\r
+\r
+\r
+However, by now you should be aware of that the Write Plane Enable\r
+register isn't limited to selecting just one bit plane, like the\r
+Read Plane Select register is.  You can enable any combination of all\r
+four to be written.  This ability to access 4 pixels with one\r
+instruction helps quadrupling the speed in certain respects, especially when \r
+drawing horizontal lines and filling polygons of a constant color.  Also, most \r
+block algorithms can be optimized in various ways so that they need only\r
+a constant number of OUTs (typically four) to the Write Plane Enable\r
+register.  OUT is a relatively slow instruction.\r
+\r
+The gained ability to access the full 256 Kb of memory on a standard\r
+VGA enables you to do paging and all the goodies following from that:\r
+smooth scrolling over large maps, page flipping for flicker free\r
+animation... and I'll leave something for your own imagination.\r
+\r
+In short, the stuff gained from unchaining mode 13h more than \r
+upweighs the additional complexity of using a planar mode.  \r
+\r
+Now, the resolution of the mode is of little interest in this\r
+context.  Nearly any 256-color resolution from (about) 80x8 to 400x300\r
+is available for most VGAs.  I'll dwell particularly by 320x240, as this\r
+is the mode that Michael Abrash introduced as 'Mode X' in his DDJ\r
+articles.  It is also the resolution that most people refer to when\r
+using that phrase.\r
+\r
+The good thing about the 320x240 mode is that the aspect ratio is\r
+1:1, which means that each pixel is 'perfectly' square, i.e. not\r
+rectangular like in 320x200.  An ellipse drawn with the same number of\r
+pixels along both main axes will look like a perfect circle in 320x240,\r
+but like a subtly tall ellipse in 320x200.\r
+\r
+Here's a function which sets the 320x240 mode.  You'll notice that\r
+it depends on the first piece of code above:\r
+\r
+----8<-------cut begin------\r
+\r
+set320x240x256_X()\r
+       {\r
+\r
+       /* Set the unchained version of mode 13h: */\r
+\r
+       set320x200x256_X();\r
+\r
+       /* Modify the vertical sync polarity bits in the Misc. Output\r
+          Register to achieve square aspect ratio: */\r
+\r
+       outportb(0x3C2, 0xE3);\r
+\r
+       /* Modify the vertical timing registers to reflect the increased\r
+          vertical resolution, and to center the image as good as\r
+          possible: */\r
+\r
+       outport(0x3D4, 0x2C11);         /* turn off write protect */\r
+       outport(0x3D4, 0x0D06);         /* vertical total */\r
+       outport(0x3D4, 0x3E07);         /* overflow register */\r
+       outport(0x3D4, 0xEA10);         /* vertical retrace start */\r
+       outport(0x3D4, 0xAC11);         /* vertical retrace end AND wr.prot */\r
+       outport(0x3D4, 0xDF12);         /* vertical display enable end */\r
+       outport(0x3D4, 0xE715);         /* start vertical blanking */\r
+       outport(0x3D4, 0x0616);         /* end vertical blanking */\r
+\r
+       /* Update mode info, so future operations are aware of the\r
+          resolution: */\r
+\r
+       height = 240;\r
+\r
+       }\r
+\r
+----8<-------cut end------\r
+\r
+\r
+As you've figured out, this mode will be completely compatible with the\r
+utility functions presented earlier, thanks to the global variable\r
+'height'.  Boy, am I foreseeing or what!\r
+\r
+Other resolutions are achieved through giving other values to the sync\r
+timing registers of the VGA, but this is quite a large and complex\r
+subject, so I'll postpone this to later, if ever.\r
+\r
+Anyway, I hope I've helped getting you started using mode X.  As far as\r
+I know, the two modes I've used above should work on *any* VGA and Super\r
+VGA available, so this is pretty stable stuff.  Let me know of any \r
+trouble, and - \r
+                       good luck!\r
+\r
+\r
+\r
+3. THE ROAD FROM HERE\r
+\r
+I'm providing information on various libraries and archives which relate\r
+to what this article deals with.  If you want me to add anything to this\r
+list (for future articles), let me know, although I can't promise anything.\r
+I am assuming you have ftp access.\r
+\r
+\r
+wuarchive.wustl.edu:/pub/MSDOS_UPLOADS/programming/xlib06.zip\r
+\r
+This is the current de facto C/assembler library for programming\r
+unchained modes (do not confuse with a X Windows library).  All sources\r
+are included, and the library is totally free.  It has functions for\r
+pixels, lines, circles, bezier curves, mouse handling, sprites (bitmaps),\r
+compiled bitmaps, and supports a number of resolutions.  The version number\r
+('06') is current as of November 1993.\r
+\r
+\r
+graphprg.zip\r
+\r
+Michael Abrash' articles in Doctor Dobbs Journal is always mentioned\r
+with awe.  In this 350 Kb archive, most of his interesting stuff has\r
+been gathered.  Read about Mode X development and techniques from month\r
+to month.  Included is also all the individual source code snippets from\r
+each article, and also the full XSHARP library providing linedrawing,\r
+polygons, bitmaps, solid 3D projection and speedy rendering, and even an\r
+implementation of 2D texture mapping (can be used for quasi-3D texture\r
+mapping), plus an article on assembly optimization on the i86 processor\r
+family.  Definitely recommended.\r
+\r
+\r
+oak.oakland.edu:/pub/msdos/vga/vgadoc2.zip\r
+\r
+This is a bare bones VGA register reference.  It also contains register\r
+references for the CGA, EGA and Hercules cards, in addition to dozens of\r
+SuperVGAs.  Check out the BOOKS section for some decent VGA references\r
+though - you don't want to start tweaking without a real one.\r
+\r
+\r
+wuarchive.wustl.edu:/pub/MSDOS_UPLOADS/programming/tweak15b.zip\r
+\r
+TWEAK might be of interest to the more adventurous reader.  TWEAK lets you\r
+play around with the registers of the VGA in an interactive manner.\r
+Various testing screens for viewing your newmade modes are applied at\r
+the press of a key.  Version 1.5 adds a test screen which autodetects your \r
+graphics mode and displays various information about resolutions etc.\r
+Keep a VGA reference handy.  Don't try it if this is the first time you've \r
+heard of 'registers' or 'mode X' or 'tweaking'.  I was planning a version\r
+based on the Turbo Vision interface, but time has been short.  Maybe later!\r
+\r
+\r
+\r
+\r
+4. BOOKS ON THE SUBJECT\r
+\r
+Extremely little has been published in written form about using\r
+'Mode X'-style modes.  Below are some books which cover VGA programming\r
+at varying degrees of technical level, but the only one to mention\r
+unchained modes and Mode X, is Michael Abrash'.  I'd get one of the VGA\r
+references first, though.\r
+\r
+  o  George Sutty & Steve Blair : "Advanced Pogrammer's Guide to the\r
+     EGA/VGA" from Brady.  A bit old perhaps, but covers all *standard*\r
+     EGA/VGA registers, and discusses most BIOS functions and other\r
+     operations.  Contains disk with C/Pascal/assembler source code.\r
+     There's a sequel out for SuperVGAs, which I haven't seen.\r
+\r
+  o  Michael Abrash : "Power Graphics Programming" from QUE/Programmer's\r
+     Journal.  Collections of (old) articles from Programmer's Journal on\r
+     EGA/VGA, read modes and write modes, animation, tweaking (320x400\r
+     and 360x480).  His newer ravings in DDJ covers fast 256-color\r
+     bitmaps, compiled bitmaps, polygons, 3D graphics, texture mapping\r
+     among other stuff.\r
+\r
+  o  Richard F. Ferraro : "Programmer's Guide to the EGA and VGA video\r
+     cards including Super VGA".  I don't have this one, but heard it's\r
+     nice.  Detailed coverage of all EGA/VGA registers.  The Super VGA\r
+     reference makes it attractive.\r
+\r
+  o  Richard Wilton : "Programmer's Guide to PC & PS/2 Video Systems"\r
+     Less technical, more application/algorithm oriented.  Nice enough,\r
+     even though it is a bit outdated, in that he discusses CGA and\r
+     Hercules cards just as much as EGA/VGA.\r
+\r
+\r
+\r
+\r
+5. BYE - FOR NOW\r
+\r
+I am considering writing a text describing in more detail the process of\r
+using TWEAK to achieve the VGA resolution you want or need.  However, I\r
+thought I'd let this document go first, and see if I get any reactions.\r
+If I don't, I'll stop.  Feel free to forward any suggestions,\r
+criticisms, bombs and beers.\r
+\r
+I can be reached via:\r
+\r
+  o  e-mail: robert@stud.unit.no\r
+\r
+  o  land mail:\r
+\r
+     Robert Schmidt\r
+     Stud.post 170\r
+     NTH\r
+     N-7034 Trondheim\r
+     NORWAY\r
+\r
+Nothing would encourage or please me more than a postcard from where you\r
+live!\r
diff --git a/16/dos_gfx.cpp b/16/dos_gfx.cpp
new file mode 100644 (file)
index 0000000..5e0abde
--- /dev/null
@@ -0,0 +1,587 @@
+/*\r
+ * LIB.C v1.2a\r
+ *\r
+ * by Robert Schmidt\r
+ * (C)1993 Ztiff Zox Softwear\r
+ *\r
+ * Simple graphics library to accompany the article\r
+ * \r
+ *                     INTRODUCTION TO MODE X.\r
+ * \r
+ * This library provides the basic functions for initializing and using\r
+ * unchained (planar) 256-color VGA modes.  Currently supported are:\r
+ *\r
+ *     - 320x200\r
+ *     - 320x240\r
+ *\r
+ * Functions are provided for:\r
+ *\r
+ *     - initializing one of the available modes\r
+ *     - setting the start address of the VGA refresh data\r
+ *     - setting active and visible display pages\r
+ *     - writing and reading a single pixel to/from video memory\r
+ *\r
+ * The library is provided as a demonstration only, and is not claimed\r
+ * to be particularly efficient or suited for any purpose.  It has only\r
+ * been tested with Borland C++ 3.1 by the author.  Comments on success\r
+ * or disaster with other compilers are welcome.\r
+ *\r
+ * This file is public domain.  Do with it whatever you'd like, but\r
+ * please don't distribute it without the article.\r
+ *\r
+ * Thanks go out to various helpful netters who spotted the 0xE7 bug\r
+ * in the set320x240x256() function!\r
+ *\r
+ * modified by sparky4 so it can be compiled in open watcom ^^\r
+ */\r
+\r
+\r
+/*\r
+ * We 'require' a large data model simply to get rid of explicit 'far'\r
+ * pointers and compiler specific '_fmemset()' functions and the likes.\r
+ */\r
+#if !defined(__COMPACT__)\r
+# if !defined(__LARGE__)\r
+#  if !defined(__HUGE__)\r
+#   error Large data model required!  Try compiling with 'bcc -ml lib.c'.\r
+#  endif\r
+# endif\r
+#endif\r
+\r
+#include <dos.h>\r
+#include <mem.h>\r
+#include <conio.h>\r
+\r
+//code from old library!\r
+/*src\lib\*/\r
+#include "dos_gfx.h"\r
+\r
+int old_mode;\r
+//color \82Ä\82·\82Æ\r
+int gq = LGQ;\r
+//\82Ä\82·\82Æ\r
+int q = 0;\r
+int bakax = 0, bakay = 0;\r
+int xx = rand()&0%320, yy = rand()&0%240, sx = 0, sy = 0;\r
+byte coor;\r
+\r
+/*\r
+ * Comment out the following #define if you don't want the testing main()\r
+ * to be included.\r
+ */\r
+#define TESTING\r
+\r
+/*\r
+ * Define the port addresses of some VGA registers.\r
+ */\r
+#define CRTC_ADDR      0x3d4   /* Base port of the CRT Controller (color) */\r
+\r
+#define SEQU_ADDR      0x3c4   /* Base port of the Sequencer */\r
+#define GRAC_ADDR      0x3ce   /* Base port of the Graphics Controller */\r
+\r
+\r
+/*\r
+ * Make a far pointer to the VGA graphics buffer segment.  Your compiler\r
+ * might not have the MK_FP macro, but you'll figure something out.\r
+ */\r
+byte *vga = (byte *) MK_FP(0xA000, 0);\r
+\r
+//fontAddr = getFont();\r
+\r
+/*\r
+ * width and height should specify the mode dimensions.  widthBytes\r
+ * specify the width of a line in addressable bytes.\r
+ */\r
+unsigned width, height, widthBytes;\r
+\r
+/*\r
+ * actStart specifies the start of the page being accessed by\r
+ * drawing operations.  visStart specifies the contents of the Screen\r
+ * Start register, i.e. the start of the visible page.\r
+ */\r
+unsigned actStart, visStart;\r
+\r
+/*\r
+ * set320x200x256_X()\r
+ *     sets mode 13h, then turns it into an unchained (planar), 4-page\r
+ *     320x200x256 mode.\r
+ */\r
+void set320x200x256_X(void)\r
+       {\r
+       union REGS r;\r
+\r
+       /* Set VGA BIOS mode 13h: */\r
+       r.x.ax = 0x0013;\r
+       int86(0x10, &r, &r);\r
+\r
+       /* Turn off the Chain-4 bit (bit 3 at index 4, port 0x3c4): */\r
+       outpw(SEQU_ADDR, 0x0604);\r
+\r
+       /* Turn off word mode, by setting the Mode Control register\r
+       of the CRT Controller (index 0x17, port 0x3d4): */\r
+       outpw(CRTC_ADDR, 0xE317);\r
+\r
+       /* Turn off doubleword mode, by setting the Underline Location\r
+          register (index 0x14, port 0x3d4): */\r
+       outpw(CRTC_ADDR, 0x0014);\r
+\r
+       /* Clear entire video memory, by selecting all four planes, then\r
+          writing 0 to entire segment. */\r
+       outpw(SEQU_ADDR, 0x0F02);\r
+       memset(vga+1, 0, 0xffff); /* stupid size_t exactly 1 too small */\r
+       vga[0] = 0;\r
+\r
+       /* Update the global variables to reflect dimensions of this\r
+          mode.  This is needed by most future drawing operations. */\r
+       width           = 320;\r
+       height  = 200;\r
+\r
+       /* Each byte addresses four pixels, so the width of a scan line\r
+          in *bytes* is one fourth of the number of pixels on a line. */\r
+       widthBytes = width / 4;\r
+\r
+       /* By default we want screen refreshing and drawing operations\r
+          to be based at offset 0 in the video segment. */\r
+       actStart = visStart = 0;\r
+       }\r
+\r
+/*\r
+ * setActiveStart() tells our graphics operations which address in video\r
+ * memory should be considered the top left corner.\r
+ */\r
+void setActiveStart(unsigned offset)\r
+       {\r
+       actStart = offset;\r
+       }\r
+\r
+/*\r
+ * setVisibleStart() tells the VGA from which byte to fetch the first\r
+ * pixel when starting refresh at the top of the screen.  This version\r
+ * won't look very well in time critical situations (games for\r
+ * instance) as the register outputs are not synchronized with the\r
+ * screen refresh.  This refresh might start when the high byte is\r
+ * set, but before the low byte is set, which produces a bad flicker.\r
+ */\r
+void setVisibleStart(unsigned offset)\r
+       {\r
+       visStart = offset;\r
+       outpw(CRTC_ADDR, 0x0C);         /* set high byte */\r
+       outpw(CRTC_ADDR+1, visStart >> 8);\r
+       outpw(CRTC_ADDR, 0x0D);         /* set low byte */\r
+       outpw(CRTC_ADDR+1, visStart & 0xff);\r
+       }\r
+\r
+/*\r
+ * setXXXPage() sets the specified page by multiplying the page number\r
+ * with the size of one page at the current resolution, then handing the\r
+ * resulting offset value over to the corresponding setXXXStart()\r
+ * function.  The first page is number 0.\r
+ */\r
+void setActivePage(int page)\r
+       {\r
+       setActiveStart(page * widthBytes * height);\r
+       }\r
+\r
+void setVisiblePage(int page)\r
+       {\r
+       setVisibleStart(page * widthBytes * height);\r
+       }\r
+\r
+void putPixel_X(int x, int y, byte color)\r
+       {\r
+       /* Each address accesses four neighboring pixels, so set\r
+          Write Plane Enable according to which pixel we want\r
+          to modify.  The plane is determined by the two least\r
+          significant bits of the x-coordinate: */\r
+       outp(0x3c4, 0x02);\r
+       outp(0x3c5, 0x01 << (x & 3));\r
+\r
+       /* The offset of the pixel into the video segment is\r
+          offset = (width * y + x) / 4, and write the given\r
+          color to the plane we selected above.  Heed the active\r
+          page start selection. */\r
+       vga[(unsigned)(widthBytes * y) + (x / 4) + actStart] = color;\r
+\r
+       }\r
+\r
+byte getPixel_X(int x, int y)\r
+       {\r
+       /* Select the plane from which we must read the pixel color: */\r
+       outpw(GRAC_ADDR, 0x04);\r
+       outpw(GRAC_ADDR+1, x & 3);\r
+\r
+       return vga[(unsigned)(widthBytes * y) + (x / 4) + actStart];\r
+\r
+       }\r
+\r
+void set320x240x256_X(void)\r
+       {\r
+       /* Set the unchained version of mode 13h: */\r
+       set320x200x256_X();\r
+\r
+       /* Modify the vertical sync polarity bits in the Misc. Output\r
+          Register to achieve square aspect ratio: */\r
+       outp(0x3C2, 0xE3);\r
+\r
+       /* Modify the vertical timing registers to reflect the increased\r
+          vertical resolution, and to center the image as good as\r
+          possible: */\r
+       outpw(0x3D4, 0x2C11);           /* turn off write protect */\r
+       outpw(0x3D4, 0x0D06);           /* vertical total */\r
+       outpw(0x3D4, 0x3E07);           /* overflow register */\r
+       outpw(0x3D4, 0xEA10);           /* vertical retrace start */\r
+       outpw(0x3D4, 0xAC11);           /* vertical retrace end AND wr.prot */\r
+       outpw(0x3D4, 0xDF12);           /* vertical display enable end */\r
+       outpw(0x3D4, 0xE715);           /* start vertical blanking */\r
+       outpw(0x3D4, 0x0616);           /* end vertical blanking */\r
+\r
+       /* Update mode info, so future operations are aware of the\r
+          resolution */\r
+       height = 240;\r
+\r
+       }\r
+\r
+\r
+/*-----------XXXX-------------*/\r
+//---------------------------------------------------\r
+//\r
+// Use the bios to get the address of the 8x8 font\r
+//\r
+// You need a font if you are going to draw text.\r
+//\r
+\r
+int far *\r
+getFont()\r
+{\r
+    union REGPACK rg;\r
+    int seg;\r
+    int off;\r
+    memset(&rg, 0, sizeof(rg));\r
+\r
+    rg.w.ax = 0x1130;\r
+    rg.h.bh = 0x03;\r
+    intr(0x10, &rg);\r
+    seg = rg.w.es;\r
+    off = rg.w.bp;\r
+    \r
+\r
+    return (int far *)MK_FP(seg, off);\r
+}\r
+\r
+void drawChar(int x, int y, int color, byte c)\r
+{\r
+       int i, j;\r
+       int mask;\r
+       int far *font = getFont() + (c * 8);\r
+\r
+       for (i = 0; i < 8; i++)\r
+       {\r
+               mask = *font;\r
+               for (j = 0; j < 8; j++)\r
+               {\r
+                       if (mask & 0x80)\r
+                       {\r
+                               //pixel(x + j, y + i, color);\r
+                               putPixel_X(x + j, y + i, color);\r
+                       }\r
+                       mask <<= 1;\r
+               }\r
+               font++;\r
+       }\r
+}\r
+\r
+void drawText(int x, int y, int color, byte string)\r
+{\r
+       while (string)\r
+       {\r
+               drawChar(x, y, color, string);\r
+               x += 8;\r
+               string++;\r
+       }\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//                                                                         //\r
+// setvideo() - This function Manages the video modes                      //\r
+//                                                                         //\r
+/////////////////////////////////////////////////////////////////////////////\r
+void setvideo(/*byte mode, */int vq){\r
+       union REGS in, out;\r
+\r
+       if(!vq){ // deinit the video\r
+               // change to the video mode we were in before we switched to mode 13h\r
+               in.h.ah = 0x00;\r
+               in.h.al = old_mode;\r
+               int86(0x10, &in, &out);\r
+\r
+       }else if(vq == 1){ // init the video\r
+               // get old video mode\r
+               in.h.ah = 0xf;\r
+               int86(0x10, &in, &out);\r
+               old_mode = out.h.al;\r
+\r
+               // enter mode\r
+               set320x240x256_X();\r
+       }\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//                                                                         //\r
+// cls() - This clears the screen to the specified color, on the VGA or on //\r
+//         the Virtual screen.                                             //\r
+//                                                                         //\r
+/////////////////////////////////////////////////////////////////////////////\r
+void cls(byte color, byte *Where){\r
+       _fmemset(Where, color, width*height);\r
+}\r
+\r
+//color \82Ä\82·\82Æ\r
+int colortest(){\r
+       if(gq < NUM_COLORS){\r
+               cls(gq, vga);\r
+               gq++;\r
+       }else gq = 0;\r
+       return gq;\r
+}\r
+\r
+//color \82Ä\82·\82Æ\r
+int colorz(){\r
+       if(gq < HGQ){\r
+//----         cls(gq, vaddr);\r
+               cls(gq, vga);\r
+               gq++;\r
+       }else gq = LGQ;\r
+       return gq;\r
+}\r
+\r
+//slow spectrum down\r
+void ssd(int svq){\r
+       if(sy < height+1){\r
+               if(sx < width+1){\r
+                       //plotpixel(xx, yy, coor, vga);\r
+                       //ppf(sx, sy, coor, vga);\r
+                       putPixel_X(sx, sy, coor);\r
+                       //printf("%d %d %d %d\n", sx, sy, svq, coor);\r
+                       sx++;\r
+               }else sx = 0;\r
+               if(sx == width){\r
+                       sy++;\r
+                       if(svq == 7) coor++;\r
+                       if(sy == height && svq == 8) coor = rand()%NUM_COLORS;\r
+               }\r
+       }else sy = 0;\r
+}\r
+\r
+/*-----------ding-------------*/\r
+int ding(int q){\r
+       setActivePage(0);\r
+       setVisiblePage(0);\r
+       int d3y;\r
+\r
+//++++ if(q <= 4 && q!=2 && gq == BONK-1) coor = rand()%HGQ;\r
+       if((q == 2
+       ||q==4
+       ) && gq == BONK-1){\r
+                       if(coor < HGQ && coor < LGQ) coor = LGQ;\r
+                       if(coor < HGQ-1){\r
+                               coor++;\r
+               }else{ coor = LGQ;\r
+                       bakax = rand()%3; bakay = rand()%3;\r
+               }\r
+       }\r
+\r
+       if(q == 5){ colortest(); return gq; }\r
+       if(q == 10){ colorz(); return gq; }\r
+       if(q == 11){ colorz(); delay(100); return gq; }\r
+       if(q == 8){ ssd(q); /*printf("%d\n", coor);*/ }\r
+       if(q == 6){\r
+               coor = rand()%NUM_COLORS;\r
+//----         cls(coor, vaddr);\r
+               cls(coor, vga);\r
+               //updatevbuff();\r
+       }\r
+\r
+       if(q == 7 || q== 9){\r
+               if(gq < HGQ){\r
+                       if(q == 7) ssd(q);\r
+                       if(q == 9){ ssd(q); coor++; }\r
+                       gq++;\r
+               }else gq = LGQ;\r
+       }\r
+       if(q<5 && gq<BONK){ // the number variable make the colors more noticable\r
+               if(q==1){\r
+                       if(xx==width){bakax=0;}\r
+                       if(xx==0){bakax=1;}\r
+                       if(yy==height){bakay=0;}\r
+                       if(yy==0){bakay=1;}\r
+               }else if(q==3){\r
+                       if(xx!=width||yy!=height){\r
+                               if(xx==0){bakax=1;bakay=-1;d3y=1;}\r
+                               if(yy==0){bakax=1;bakay=0;d3y=1;}\r
+                               if(xx==width){bakax=-1;bakay=-1;d3y=1;}\r
+                               if(yy==height){bakax=1;bakay=0;d3y=1;}\r
+                       }else if(xx==width&&yy==height) xx=yy=0;\r
+               }\r
+               if(q==3){\r
+                       if(d3y){\r
+                               if(bakay<0){\r
+                                       yy--;\r
+                                       d3y--;\r
+                               }else\r
+                               if(bakay>0){\r
+                                       yy++;\r
+                                       d3y--;\r
+                               }\r
+                       }\r
+                       if(bakax<0){\r
+                               xx--;\r
+                       }else\r
+                       if(bakax>0){\r
+                               xx++;\r
+                       }\r
+               }else{\r
+                       if(!bakax){\r
+                               xx--;\r
+                       }else if(bakax>1){\r
+                               xx++;\r
+                       }\r
+                       if(!bakay){\r
+                               yy--;\r
+                       }else if(bakay>1){\r
+                               yy++;\r
+                       }\r
+               }\r
+               // fixer\r
+               if(xx<0) xx=width;\r
+               if(yy<0) yy=height;\r
+               if(xx>width) xx=0;\r
+               if(yy>height) yy=0;\r
+\r
+               // plot the pixel\r
+//----         ppf(xx, yy, coor, vga);\r
+               putPixel_X(xx, yy, coor);\r
+//----         if(q==2) ppf(rand()%, rand()%height, 0, vga);\r
+               if(q==2) putPixel_X(rand()%width, rand()%height, 0);\r
+               if(q==2||q==4){ bakax = rand()%3; bakay = rand()%3; }\r
+               gq++;\r
+//if(xx<0||xx>320||yy<0||yy>240)\r
+//     printf("%d %d %d %d %d %d\n", xx, yy, coor, bakax, bakay, getPixel_X(xx,yy));\r
+//     printf("%d\n", getPixel_X(xx,yy));\r
+//0000\r
+//     drawText(0, 0, 15, getPixel_X(xx,yy));\r
+       }else gq = LGQ;\r
+       return gq;\r
+}\r
+\r
+\r
+/*\r
+ * The library testing routines follows below.\r
+ */\r
+\r
+\r
+#ifdef TESTING\r
+\r
+#include <stdio.h>\r
+#include <conio.h>\r
+\r
+void doTest(void)\r
+       {\r
+       int p, x, y, pages;\r
+\r
+       /* This is the way to calculate the number of pages available. */\r
+       pages = 65536L/(widthBytes*height); // apparently this takes the A000 address
+\r
+       printf("%d\n", pages);
+
+       for (p = 0; p <= pages; ++p)\r
+               {\r
+               setActivePage(p);\r
+\r
+               /* On each page draw a single colored border, and dump the palette\r
+                  onto a small square about the middle of the page. */
+                  
+                  //{\r
+                       for (x = 0; x <= width; ++x)\r
+                               {\r
+                               putPixel_X(x, 0, p+1);\r
+                               if(p!=pages) putPixel_X(x, height-1, p+1);
+                                       else putPixel_X(x, 99-1, p+1);\r
+                               }\r
+\r
+                       for (y = 0; y <= height; ++y)\r
+                               {\r
+                               putPixel_X(0, y, p+1);\r
+                               if(p!=pages) putPixel_X(width-1, y, p+1);
+                                       else putPixel_X(width-1, y, p+1);\r
+                               }\r
+\r
+                       for (x = 0; x < 16; ++x)\r
+                               for (y = 0; y < 16; ++y)\r
+                                       putPixel_X(x+(p+2)*16, y+(p+2)*16, x + y*16);\r
+                       //}
+
+               drawText(0, 0, 15, p);
+\r
+               }\r
+\r
+       /* Each pages will now contain a different image.  Let the user cycle\r
+          through all the pages by pressing a key. */\r
+       for (p = 0; p <= pages; ++p)\r
+               {\r
+               setVisiblePage(p);
+               //drawText(0, 240, 15, "bakapi");\r
+               getch();\r
+               }\r
+\r
+       }\r
+\r
+/*\r
+ * Library test (program) entry point.\r
+ */\r
+\r
+int main(void)\r
+       {\r
+       int key,d;\r
+       // main variables\r
+       d=1; // switch variable\r
+       key=4; // default screensaver number\r
+//     puts("First, have a look at the 320x200 mode.  I will draw some rubbish");\r
+//     puts("on all of the four pages, then let you cycle through them by");\r
+//     puts("hitting a key on each page.");\r
+//     puts("Press a key when ready...");\r
+//     getch();\r
+\r
+//     doTest();\r
+\r
+//     puts("Then, check out Mode X, 320x240 with 3 (and a half) pages.");\r
+//     puts("Press a key when ready...");\r
+//     getch();\r
+\r
+       setvideo(1);\r
+// screen savers\r
+\r
+/*while(d!=0){ // on!\r
+               if(!kbhit()){ // conditions of screen saver\r
+                       ding(key);\r
+               }else{\r
+                       setvideo(0);\r
+                       // user imput switch\r
+                       printf("Enter 1, 2, 3, 4, or 6 to run a screensaver, or enter 5 to quit.\n", getch());  // prompt the user\r
+                       scanf("%d", &key);\r
+                       //if(key==3){xx=yy=0;} // crazy screen saver wwww\r
+                       if(key==5) d=0;\r
+                       setvideo(1);\r
+               }\r
+       }*/ // else off\r
+       while(!kbhit()){ // conditions of screen saver\r
+               ding(4);
+       }
+       //end of screen savers
+       doTest();\r
+       setvideo(0);\r
+       puts("Where to next?  It's your move! wwww");\r
+       printf("bakapi ver. 1.04.09a\nis made by sparky4\81i\81\86\83Ö\81\85\81j feel free to use it ^^\nLicence: GPL v2\n");\r
+       return 0;\r
+       }\r
+\r
+#endif\r
diff --git a/16/dos_gfx.h b/16/dos_gfx.h
new file mode 100644 (file)
index 0000000..08908b0
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef _DOSLIB_GFX_H_\r
+#define _DOSLIB_GFX_H_\r
+#include <iostream.h>\r
+#include <stdlib.h>\r
+#include "lib_com.h"\r
+\r
+#define NUM_COLORS      256 // number of colors in vga mode\r
+//static lgq=NUM_COLORS/(1/8)\r
+//static hgq=NUM_COLORS/(1/8)\r
+#define BONK            400\r
+#define LGQ             32\r
+#define HGQ             56\r
+//#define VMEM            0xA000 // = vga\r
+//int width = 320;\r
+//int height = 240;\r
+
+void drawChar(int x, int y, int color, byte c);\r
+void drawText(int x, int y, int color, byte string);\r
+void setvideo(/*byte mode, */int vq);\r
+//void setvbuff(int vq);\r
+//void updatevbuff();\r
+void cls(byte color, byte *Where);\r
+//void clearscr();\r
+//void plotpixel(int x, int y, byte color, byte *Where);\r
+//void plotpixelfast(int x, int y, byte color, byte *Where);\r
+//void BlockMove();\r
+//void eraseplayer(int x, int y);\r
+//void drawplayer(int x, int y, int color);\r
+int colortest();\r
+int colorz();\r
+void ssd(int svq);\r
+//void pdump(int mult);\r
+//void tulip();\r
+int ding(int q);\r
+\r
+#endif/*_DOSLIB_GFX_H_*/\r
diff --git a/16/dos_kb.c b/16/dos_kb.c
new file mode 100644 (file)
index 0000000..9e813b8
--- /dev/null
@@ -0,0 +1,140 @@
+/* Thanks to Alex Russell for example code */
+/* Thanks to Gary Neal for example code */
+#include "dos_kb.h"
+
+// keyboard buffer
+static byte key[NUM_SCANCODES]; // pressed
+static byte kea[NUM_SCANCODES]; // released
+
+#ifdef __cplusplus             /* Function must be declared C style */
+extern "C" {
+#endif
+static void interrupt (far *oldkb)(void) = NULL; /* BIOS keyboard handler */
+#ifdef __cplusplus
+}
+#endif
+
+/*
+ * Comment out the following #define if you don't want the testing main()
+ * to be included.
+ */
+#define TESTING
+
+/*****************NEW KEYBOARD 09h ISR***********************/
+void interrupt newkb(void){
+       byte kee;
+       register char qx;
+
+       kee = inp(0x60);        /* Read the keyboard scan code */
+
+       /* Clear keyboard controller on XT machines */
+       qx = inp(0x61);           /* Get keyboard control register */
+       qx |= 0x82;
+       outp(0x61, qx);           /* Toggle acknowledge bit high */
+       qx &= 0x7F;
+       outp(0x61, qx);           /* Toggle acknowledge bit low */
+
+       /* Interpret the scan code and set our flags */
+       #ifdef TESTING
+       printf("%d[%d]\n",kee,key[kee]);
+       #endif
+       if(kee & 0x80)
+               key[kee & 0x7F] = 0; // a key is released
+       else
+               key[kee] = kea[kee] = 1; // a key is pressed
+
+       /* Acknowledge the interrupt to the programmable interrupt controller */
+       outp(0x20, 0x20);      /* Signal non specific end of interrupt */
+}
+
+/* ---------------------- init_keyboard() ---------------- April 17,1993 */
+/* restore the bios keyboard handler */
+/* ---------------------- deinit_keyboard() -------------- April 17,1993 */
+void setkb(int vq){
+       int i;  /* Index variable */
+       if(!vq){ // deinitiation
+               /* Abort if our function pointer has no valid address */
+               if(oldkb == NULL) return;
+               /* Set address in our function pointer in interrupt vector table */
+               _dos_setvect(9, oldkb);
+               /* Reset our function pointer to contain no valid address */
+               oldkb = NULL;
+               #ifdef TESTING
+               /* Print the key heap */
+               printf("\n");
+               for(i=0; i<NUM_SCANCODES; i++){
+                       if(i==NUM_SCANCODES/2) printf("================================\n");
+                       printf("%03d[%d][%d]",i+1,key[i],kea[i]);
+                       if(key[i]==1)printf("====");
+                       printf(",\n");
+               }
+               #endif
+       }else if(vq == 1){ // initiation
+               byte far *lock_key;
+
+               /* Abort if our function pointer has a valid address. */
+               if(oldkb != NULL) return;
+
+               /* Clear the keyboard buttons state arrays */
+               for(i = 0; i < NUM_SCANCODES; i++)
+                       key[i] = kea[i] = 0;
+
+               /* save old BIOS key board handler */
+               oldkb = _dos_getvect(9);
+
+               // turn off num-lock via BIOS
+               lock_key = MK_FP(0x040, 0x017); // Pointing to the address of the bios shift state keys
+               *lock_key&=(~(16 | 32 | 64)); // toggle off the locks by changing the values of the 4th, 5th, and 6th bits of the address byte of 0040:0017
+               oldkb();        // call BIOS keyhandler to change keyboard lights
+
+               /* setup our own handler */
+               _dos_setvect(9, newkb);
+       }
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
+ * keyp                                                              *
+ *                                                                         *
+ * Returns the status of the key requested.                                *
+ * The status is 1 if the key is pressed or has been pressed since the     *
+ * last call to this function for that particular key.                     *
+\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+int keyp(byte c){
+       register char retVal;
+
+       /* Key value in range of keyboard keys available */
+       c &= 0x7F;
+
+       /* Get the status of the key requested */
+       retVal = key[c] | kea[c];
+
+       /* Reset the was pressed status for the requested key */
+       kea[c] = 0;
+
+       /* Return the requested key's state */
+       return retVal;
+}
+
+
+/*
+ * The library testing routines follows below.
+ */
+
+#ifdef TESTING
+
+/*
+ * Library test (program) entry point.
+ */
+
+void main(void)
+{
+       byte q;
+       setkb(1);
+       while(!keyp(1))
+       {
+               keyp(q);
+       }
+       setkb(0);
+}
+
+#endif
diff --git a/16/dos_kb.h b/16/dos_kb.h
new file mode 100644 (file)
index 0000000..1c4112a
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef _DOSLIB_KB_H_\r
+#define _DOSLIB_KB_H_\r
+#include "lib_com.h"\r
+\r
+/* Maximum number of scan codes on keyboard controllers */\r
+#define NUM_SCANCODES   128\r
+\r
+#ifdef __cplusplus      /* Functions must be declared C style */\r
+extern "C" {\r
+#endif\r
+void interrupt far newkb(void);\r
+//extern void interrupt (far *oldkb)(void);\r
+void setkb(int vq);\r
+int keyp(byte c);\r
+\r
+/* Define macro */\r
+//#define kepn(c) key[c & 0x7F]\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif/*_DOSLIB_KB_H_*/\r
diff --git a/16/k.bat b/16/k.bat
new file mode 100644 (file)
index 0000000..92a9953
--- /dev/null
+++ b/16/k.bat
@@ -0,0 +1 @@
+wcl -0 /l=dos DOS_COMM\r
diff --git a/16/lib_com.cpp b/16/lib_com.cpp
new file mode 100644 (file)
index 0000000..b985161
--- /dev/null
@@ -0,0 +1,20 @@
+#include "src\lib\lib_com.h"\r
+\r
+/* local function */\r
+void wait(clock_t wait);\r
+\r
+/* Function: Wait **********************************************************\r
+*\r
+*     Parameters:    wait - time in microseconds\r
+*\r
+*     Description:    pauses for a specified number of microseconds.\r
+*\r
+*/\r
+void wait(clock_t wait){\r
+       clock_t goal;\r
+\r
+       if(!wait) return;\r
+\r
+       goal = wait + clock();\r
+       while((goal > clock()) && !kbhit()) ;\r
+} /* End of wait */
\ No newline at end of file
diff --git a/16/lib_com.h b/16/lib_com.h
new file mode 100644 (file)
index 0000000..d43b717
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef _LIBCOM_H_\r
+#define _LIBCOM_H_\r
+#include <dos.h>\r
+#include <stdio.h>\r
+#include <conio.h> // just for wait\r
+#include <time.h> // just for wait\r
+\r
+/* Control codes for all keys on the keyboard */\r
+//here temperarly\r
+#define KEY_A          (0x1E)\r
+#define KEY_B          (0x30)\r
+#define KEY_C          (0x2E)\r
+#define KEY_D          (0x20)\r
+#define KEY_E          (0x12)\r
+#define KEY_F          (0x21)\r
+#define KEY_G          (0x22)\r
+#define KEY_H          (0x23)\r
+#define KEY_I          (0x17)\r
+#define KEY_J          (0x24)\r
+#define KEY_K          (0x25)\r
+#define KEY_L          (0x26)\r
+#define KEY_M          (0x32)\r
+#define KEY_N          (0x31)\r
+#define KEY_O          (0x18)\r
+#define KEY_P          (0x19)\r
+#define KEY_Q          (0x10)\r
+#define KEY_R          (0x13)\r
+#define KEY_S          (0x1F)\r
+#define KEY_T          (0x14)\r
+#define KEY_U          (0x16)\r
+#define KEY_V          (0x2F)\r
+#define KEY_W          (0x11)\r
+#define KEY_X          (0x2D)\r
+#define KEY_Y          (0x15)\r
+#define KEY_Z          (0x2C)\r
+#define KEY_1          (0x02)\r
+#define KEY_2          (0x03)\r
+#define KEY_3          (0x04)\r
+#define KEY_4          (0x05)\r
+#define KEY_5          (0x06)\r
+#define KEY_6          (0x07)\r
+#define KEY_7          (0x08)\r
+#define KEY_8          (0x09)\r
+#define KEY_9          (0x0A)\r
+#define KEY_0          (0x0B)\r
+#define KEY_DASH               (0x0C)  /* -_ */\r
+#define KEY_EQUAL              (0x0D)  /* =+ */\r
+#define KEY_LBRACKET   (0x1A)  /* [{ */\r
+#define KEY_RBRACKET   (0x1B)  /* ]} */\r
+#define KEY_SEMICOLON  (0x27)  /* ;: */\r
+#define KEY_RQUOTE     (0x28)  /* '" */\r
+#define KEY_LQUOTE     (0x29)  /* `~ */\r
+#define KEY_PERIOD     (0x33)  /* .> */\r
+#define KEY_COMMA              (0x34)  /* ,< */\r
+#define KEY_SLASH              (0x35)  /* /? */\r
+#define KEY_BACKSLASH  (0x2B)  /* \| */\r
+#define KEY_F1         (0x3B)\r
+#define KEY_F2         (0x3C)\r
+#define KEY_F3         (0x3D)\r
+#define KEY_F4         (0x3E)\r
+#define KEY_F5         (0x3F)\r
+#define KEY_F6         (0x40)\r
+#define KEY_F7         (0x41)\r
+#define KEY_F8         (0x42)\r
+#define KEY_F9         (0x43)\r
+#define KEY_F10                (0x44)\r
+#define KEY_ESC                (0x01)\r
+#define KEY_BACKSPACE   (0x0E)\r
+#define KEY_TAB                (0x0F)\r
+#define KEY_ENTER              (0x1C)\r
+#define KEY_CONTROL    (0x1D)\r
+#define KEY_LSHIFT     (0x2A)\r
+#define KEY_RSHIFT     (0x36)\r
+#define KEY_PRTSC              (0x37)\r
+#define KEY_ALT                (0x38)\r
+#define KEY_SPACE              (0x39)\r
+#define KEY_CAPSLOCK   (0x3A)\r
+#define KEY_NUMLOCK    (0x45)\r
+#define KEY_SCROLLLOCK (0x46)\r
+#define KEY_HOME               (0x47)\r
+#define KEY_UP         (0x48)\r
+#define KEY_PGUP               (0x49)\r
+#define KEY_MINUS              (0x4A)\r
+#define KEY_LEFT               (0x4B)\r
+#define KEY_CENTER     (0x4C)\r
+#define KEY_RIGHT              (0x4D)\r
+#define KEY_PLUS               (0x4E)\r
+#define KEY_END                (0x4F)\r
+#define KEY_DOWN               (0x50)\r
+#define KEY_PGDOWN     (0x51)\r
+#define KEY_INS                (0x52)\r
+#define KEY_DEL                (0x53)\r
+\r
+#define KEY_LWIN               (0x73)\r
+#define KEY_RWIN               (0x74)\r
+#define KEY_MENU               (0x75)\r
+\r
+\r
+typedef unsigned char byte;\r
+\r
+void wait(clock_t wait);\r
+\r
+#endif/*_LIBCOM_H_*/\r
diff --git a/16/project16.txt b/16/project16.txt
new file mode 100644 (file)
index 0000000..8bcd34e
--- /dev/null
@@ -0,0 +1,213 @@
+Current task: 2D scrolling tile engine
+Initial conditions:
+1. Total amount of program memory: This is tricky part because the OS has something called conveance memory and it is limited to 640k but there is may waya around it. using EMS and XMS the game should load a bunch of itself into the areas away from conventional memory as much as possible but if it like my current XT then we are forced to have less than that. I am still building up the official testing enviorment!
+
+2. Total amount of video memory: 256K, 320x240 screen, 256 colours //screen is 192K of memory! Only 64K is left free We can use it for buffering and storing game graphics!
+3. Tile size: 16x16, 256 bytes (0.25K) per tile
+4. Total amount of tiles used: n/a
+5. Total amount of tiles stored in memory at a time: 256 (64K) //reduce to 128 or less if there's not enough memory
+
+//31K for sprites which is about 124 sprites!
+//there is 3 pages advalible for us that are 75K each!
+Task explanation:
+Tiles are rendered as a background. Background needs to be scrolled from up to down and from left to right.
+
+Tiles currently used are stored in the video memory. World, consisting of tiles, is represented as a matrix.
+World is split into areas. Changing area means changing used tileset. Tiles in two neighbouring areas should not overlap.
+Viewport matrix holds 20x15 to 21x16 tiles at once. As we only have 256 tiles in our set, each tile is one byte long.
+
+The best variant to change matrix contents FAST seems to be 2D linked list. The downside is memory lookup time.
+An alternative is a 2D array. Fast lookup, less memory, expensive relocation.
+Something like
+#define NTILES_X = 21
+#define NTILES_Y = 16
+#define TILES_X = NTILES_X - 1
+#define TILES_Y = NTILES_Y - 1
+struct vp_node {
+    uint8_t tile;
+    struct vp_node *up;
+    struct vp_node *right;
+    struct vp_node *down;
+    struct vp_node *left;
+};
+struct viewport {
+    uint8_t offset_x; //X offset in pixels
+    uint8_t offset_y; //Y offset in pixels
+    uint16_t world_offset_x;
+    uint16_t world_offset_y;
+    struct vp_node *upper_left; //pointer to the upper left tile
+};
+void initvp(struct viewport *vp, uint8_t **world_matrix, uint16_t offset_x, uint16_t offset_y) {
+    int i, j;
+    struct vp_node *vp_tmp[NTILES_Y][NTILES_X]; //i'd like to copy it
+    for(i=0; i<NTILES_Y; i++) {
+        for(j=0; j<NTILES_X; j++) {
+            vp_tmp[i][j] = malloc(sizeof(struct vp_node));
+            vp_tmp[i][j]->tile = world_matrix[offset_x + i][offset_y + j];
+        }
+    }
+    // i for line, j for column
+    // linking neighbouring tiles
+    // wait, do we need links to left and up?
+    for(i=0; i<NTILES_Y; i++) {
+        for(j=0; j<NTILES_X; j++) {
+            if(i) vp_tmp[i][j]->up = vp_tmp[i-1][j];
+            else vp_tmp[i][j]->up = NULL;
+            if(j) vp_tmp[i][j]->left = vp_tmp[i][j-1];
+            else vp_tmp[i][j]->left = NULL;
+            if(i<20) vp_tmp[i][j]->down = vp_tmp[i+1][j];
+            else vp_tmp[i][j]->down = NULL;
+            if(j<15) vp_tmp[i][j]->right = vp_tmp[i][j+1];
+            else vp_tmp[i][j]->right = NULL;
+        }
+    }
+    vp = malloc(sizeof(struct viewport));
+    vp->offset_x = 0;
+    vp->offset_y = 0;
+    vp->world_offset_x = offset_x;
+    vp->world_offset_y = offset_y;
+    vp->upper_left = vp_tmp[0][0];
+}
+void scroll(struct viewport *vp, uint8_t **world_matrix, int8_t offset_x, int8_t offset_y) {
+    int8_t offset_x_total = offset_x + vp->offset_x;
+    int8_t offset_y_total = offset_y + vp->offset_y;
+    if(offset_x_total > 15) shift_right(vp, world_matrix);
+    if(offset_x_total < 0) shift_left(vp, world_matrix);
+    if(offset_y_total > 15) shift_down(vp, world_matrix);
+    if(offset_y_total < 0) shift_up(vp, world_matrix);
+    vp->offset_x = offset_x_total % 16;
+    vp->offset_y = offset_y_total % 16;
+}
+void shift_right(struct viewport *vp, uint8_t **world_matrix) {
+    vp->world_offset_x += 1;
+    struct vp_node *tmp = vp->upper_left;
+    vp->upper_left = vp->upper_left->right;
+    while(tmp->down) {
+        tmp->right->left = NULL;
+        tmp = tmp->down;
+        free(tmp->up);
+    }
+    tmp->right->left = NULL;
+    free(tmp);
+    // Starting from the upper left corner
+    tmp = vp->upper_left;
+    // Looking up the rightmost tile
+    while(tmp->right) tmp = tmp->right;
+    // Here and below: allocating and linking new neighbouring tiles
+    int i=0;
+    tmp->right = malloc(sizeof(struct vp_node));
+    tmp->right->tile = world_matrix[vp->world_offset_y + i++][vp->world_offset_x +20];
+    tmp->right->left = tmp;
+    tmp->right->up = NULL;
+    tmp->right->right = NULL;
+    while(tmp->down) {
+        tmp = tmp->down;
+        tmp->right = malloc(sizeof(struct vp_node));
+        tmp->right->tile = world_matrix[vp->world_offset_y + i++][vp->world_offset_x + 20];
+        tmp->right->left = tmp;
+        tmp->right->up = tmp->up->right;
+        tmp->up->right->down = tmp->right;
+        tmp->right->right = NULL;
+    }
+    tmp->right->down = NULL;
+    // looks like we've just added a column
+}
+void shift_left(struct viewport *vp, uint8_t **world_matrix) {
+    vp->world_offset_x -= 1;
+    // Removing the rightmost column first
+    struct vp_node *tmp = vp->upper_left;
+    while(tmp->right) tmp = tmp->right;
+    while(tmp->down) {
+        tmp->left->right = NULL;
+        tmp = tmp->down;
+        free(tmp->up);
+    }
+    tmp->left->right = NULL;
+    free(tmp);
+    // Now we need to add a new column to the left
+    tmp = vp->upper_left;
+    // Here and below: allocating and linking new neighbouring tiles
+    int i=0;
+    tmp->left = malloc(sizeof(struct vp_node));
+    tmp->left->tile = world_matrix[vp->world_offset_y + i++][vp->world_offset_x];
+    tmp->left->right = tmp;
+    tmp->left->up = NULL;
+    tmp->left->left = NULL;
+    while(tmp->down) {
+        tmp = tmp->down;
+        tmp->left = malloc(sizeof(struct vp_node));
+        tmp->left->tile = world_matrix[vp->world_offset_y + i++][vp->world_offset_x];
+        tmp->left->right = tmp;
+        tmp->left->up = tmp->up->left;
+        tmp->up->left->down = tmp->left;
+        tmp->left->left = NULL;
+    }
+    tmp->left->down = NULL;
+    // looks like we've just added a column to the left
+}
+void shift_down(struct viewport *vp, uint8_t **world_matrix) {
+    vp->world_offset_y += 1;
+    // Removing the upper row first
+    struct vp_node *tmp = vp->upper_left->down;
+    vp->upper_left = tmp;
+    do {
+        free(tmp->up);
+        tmp->up = NULL;
+    } while(tmp->right);
+    // Now we need to add a new column to the bottom
+    tmp = vp->upper_left;
+    while(tmp->down) tmp = tmp->down;
+    // Here and below: allocating and linking new neighbouring tiles
+    int i=0;
+    tmp->down = malloc(sizeof(struct vp_node));
+    tmp->dpwn->tile = world_matrix[vp->world_offset_y + i++][vp->world_offset_x];
+    tmp->down->left = NULL;
+    tmp->down->up = tmp;
+    tmp->down->down = NULL;
+    while(tmp->right) {
+        tmp = tmp->right;
+        tmp->down = malloc(sizeof(struct vp_node));
+        tmp->down->tile = world_matrix[vp->world_offset_y + i++][vp->world_offset_x];
+        tmp->down->up = tmp;
+        tmp->down->left = tmp->left->down;
+        tmp->left->down->right = tmp->down;
+        tmp->down->down = NULL;
+    }
+    tmp->down->right = NULL;
+    // looks like we've just added a row to the bottom
+}
+void shift_up(struct viewport *vp, uint8_t **world_matrix) {
+    vp->world_offset_y += 1;
+    // Removing the bottom row first
+    struct vp_node *tmp = vp->upper_left;
+    while(tmp->down) tmp = tmp->down;
+    while(tmp->right) {
+        tmp->up->down = NULL;
+        tmp = tmp->right;
+        free(tmp->left);
+    }
+    tmp->up->down = NULL;
+    free(tmp);
+    // Now we need to add a new row to the top
+    tmp = vp->upper_left;
+    // Here and below: allocating and linking new neighbouring tiles
+    int i=0;
+    tmp->up = malloc(sizeof(struct vp_node));
+    tmp->up->tile = world_matrix[vp->world_offset_y + i++][vp->world_offset_x];
+    tmp->up->left = NULL;
+    tmp->up->down = tmp;
+    tmp->up->up = NULL;
+    while(tmp->right) {
+        tmp = tmp->right;
+        tmp->up = malloc(sizeof(struct vp_node));
+        tmp->up->tile = world_matrix[vp->world_offset_y + i++][vp->world_offset_x];
+        tmp->up->down = tmp;
+        tmp->up->left = tmp->left->up;
+        tmp->left->up->right = tmp->up;
+        tmp->up->up = NULL;
+    }
+    tmp->up->right = NULL;
+    // looks like we've just added a row to the top
+}
+void render_vp(struct viewport *vp);
+
diff --git a/16/x.bat b/16/x.bat
new file mode 100644 (file)
index 0000000..737f4f7
--- /dev/null
+++ b/16/x.bat
@@ -0,0 +1,2 @@
+wcl -d1 -0 -ml /l=dos dos_gfx\r
+copy /y dos_gfx.exe c:\z\bakapi.exe\r