DOS logger now redirects stdout/stderr instead of providing a new
[dosdemo] / src / dos / gfx.c
1 #ifndef GFX_H_
2 #define GFX_H_
3
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <limits.h>
8 #include "vbe.h"
9 #include "dpmi.h"
10
11 #define REALPTR(s, o)   (void*)(((uint32_t)(s) << 4) + (uint32_t)(o))
12 #define VBEPTR(x)               REALPTR(((x) & 0xffff0000) >> 16, (x) & 0xffff)
13 #define VBEPTR_SEG(x)   (((x) & 0xffff0000) >> 16)
14 #define VBEPTR_OFF(x)   ((x) & 0xffff)
15
16 #define SAME_BPP(a, b)  \
17         ((a) == (b) || (a) == 16 && (b) == 15 || (a) == 15 && (b) == 16 || (a) == 32 && (b) == 24 || (a) == 24 && (b) == 32)
18
19 static unsigned int make_mask(int sz, int pos);
20
21 static struct vbe_info *vbe_info;
22 static struct vbe_mode_info *mode_info;
23 static int pal_bits = 6;
24
25 void *set_video_mode(int xsz, int ysz, int bpp)
26 {
27         int i;
28         uint16_t *modes, best = 0;
29         unsigned int fbsize;
30
31         /* check for VBE2 support and output some info */
32         if(!vbe_info) {
33                 if(!(vbe_info = vbe_get_info())) {
34                         fprintf(stderr, "VESA BIOS Extensions not available\n");
35                         return 0;
36                 }
37
38                 printf("VBE Version: %x.%x\n", vbe_info->version >> 8, vbe_info->version & 0xff);
39                 if(vbe_info->version < 0x200) {
40                         fprintf(stderr, "This program requires VBE 2.0 or greater. Try running UniVBE\n");
41                         return 0;
42                 }
43
44                 printf("Graphics adapter: %s, %s (%s)\n", VBEPTR(vbe_info->oem_vendor_name_ptr),
45                                 VBEPTR(vbe_info->oem_product_name_ptr), VBEPTR(vbe_info->oem_product_rev_ptr));
46                 printf("Video memory: %dkb\n", vbe_info->total_mem << 6);
47
48                 modes = VBEPTR(vbe_info->vid_mode_ptr);
49         }
50
51         for(i=0; i<1024; i++) { /* impose an upper limit to avoid inf-loops */
52                 if(modes[i] == 0xffff) {
53                         break;  /* reached the end */
54                 }
55
56                 mode_info = vbe_get_mode_info(modes[i] | VBE_MODE_LFB);
57                 if(!mode_info || mode_info->xres != xsz || mode_info->yres != ysz) {
58                         continue;
59                 }
60                 if(SAME_BPP(mode_info->bpp, bpp)) {
61                         best = modes[i];
62                 }
63         }
64
65         if(best) {
66                 mode_info = vbe_get_mode_info(best);
67         } else {
68                 fprintf(stderr, "Requested video mode (%dx%d %dbpp) is unavailable\n", xsz, ysz, bpp);
69                 return 0;
70         }
71
72         if(vbe_set_mode(best | VBE_MODE_LFB) == -1) {
73                 fprintf(stderr, "Failed to set video mode %dx%d %dbpp\n", mode_info->xres, mode_info->yres, mode_info->bpp);
74                 return 0;
75         }
76
77         /* attempt to set 8 bits of color per component in palettized modes */
78         /*if(bpp <= 8) {
79                 pal_bits = vbe_set_palette_bits(8);
80                 printf("palette bits per color primary: %d\n", pal_bits);
81         }
82         */
83
84         fbsize = xsz * ysz * mode_info->num_img_pages * (bpp / CHAR_BIT);
85         return (void*)dpmi_mmap(mode_info->fb_addr, fbsize);
86 }
87
88 int set_text_mode(void)
89 {
90         vbe_set_mode(0x3);
91         return 0;
92 }
93
94 int get_color_depth(void)
95 {
96         if(!mode_info) {
97                 return -1;
98         }
99         return mode_info->bpp;
100 }
101
102 int get_color_bits(int *rbits, int *gbits, int *bbits)
103 {
104         if(!mode_info) {
105                 return -1;
106         }
107         *rbits = mode_info->rmask_size;
108         *gbits = mode_info->gmask_size;
109         *bbits = mode_info->bmask_size;
110         return 0;
111 }
112
113 int get_color_mask(unsigned int *rmask, unsigned int *gmask, unsigned int *bmask)
114 {
115         if(!mode_info) {
116                 return -1;
117         }
118         *rmask = make_mask(mode_info->rmask_size, mode_info->rpos);
119         *gmask = make_mask(mode_info->gmask_size, mode_info->gpos);
120         *bmask = make_mask(mode_info->bmask_size, mode_info->bpos);
121         return 0;
122 }
123
124 int get_color_shift(int *rshift, int *gshift, int *bshift)
125 {
126         if(!mode_info) {
127                 return -1;
128         }
129         *rshift = mode_info->rpos;
130         *gshift = mode_info->gpos;
131         *bshift = mode_info->bpos;
132         return 0;
133 }
134
135 void set_palette(int idx, int r, int g, int b)
136 {
137         int col[3];
138         col[0] = r;
139         col[1] = g;
140         col[2] = b;
141         vbe_set_palette(idx, col, 1, pal_bits);
142 }
143
144 void wait_vsync(void)
145 {
146         __asm {
147                 mov dx, 0x3da
148         l1:
149                 in al, dx
150                 and al, 0x8
151                 jnz l1
152         l2:
153                 in al, dx
154                 and al, 0x8
155                 jz l2
156         }
157 }
158
159 static unsigned int make_mask(int sz, int pos)
160 {
161         unsigned int i, mask = 0;
162
163         for(i=0; i<sz; i++) {
164                 mask |= 1 << i;
165         }
166         return mask << pos;
167 }
168
169
170 #endif  /* GFX_H_ */