--- /dev/null
+#!/bin/sh
+
+dosbox -exit demo.exe $*
g3d_viewport(0, 0, width, height);
}
+/* set the framebuffer pointer, without resetting the size */
+void g3d_framebuffer_addr(void *pixels)
+{
+ st->pixels = pixels;
+ pfill_fb.pixels = pixels;
+}
+
void g3d_viewport(int x, int y, int w, int h)
{
st->vport[0] = x;
void g3d_destroy(void);
void g3d_framebuffer(int width, int height, void *pixels);
+void g3d_framebuffer_addr(void *pixels);
void g3d_viewport(int x, int y, int w, int h);
void g3d_enable(unsigned int opt);
-#ifndef GFX_H_
-#define GFX_H_
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
+#include "gfx.h"
#include "vbe.h"
#include "cdpmi.h"
static struct vbe_mode_info *mode_info;
static int pal_bits = 6;
+static void *vpgaddr[2];
+
+
void *set_video_mode(int xsz, int ysz, int bpp)
{
int i;
static uint16_t *modes;
uint16_t best = 0;
- unsigned int fbsize;
+ unsigned int fbsize, pgsize;
#ifdef __DJGPP__
__djgpp_nearptr_enable();
}
*/
- fbsize = xsz * ysz * mode_info->num_img_pages * (bpp / CHAR_BIT);
- return (void*)dpmi_mmap(mode_info->fb_addr, fbsize);
+ printf("avail video pages: %d\n", mode_info->num_img_pages);
+ printf("bytes per scanline: %d (%d pixels)\n", vbe_get_scanlen(VBE_SCANLEN_BYTES),
+ vbe_get_scanlen(VBE_SCANLEN_PIXELS));
+
+ pgsize = xsz * ysz * (bpp / CHAR_BIT);
+ fbsize = mode_info->num_img_pages * pgsize;
+ vpgaddr[0] = (void*)dpmi_mmap(mode_info->fb_addr, fbsize);
+
+ if(mode_info->num_img_pages > 1) {
+ vpgaddr[1] = (char*)vpgaddr[0] + pgsize;
+ } else {
+ vpgaddr[1] = 0;
+ }
+ return vpgaddr[0];
}
int set_text_mode(void)
vbe_set_palette(idx, col, 1, pal_bits);
}
+void *page_flip(int vsync)
+{
+ static int frame;
+ void *nextaddr;
+ int y, when, bufidx;
+
+ if(!vpgaddr[1]) {
+ /* page flipping not supported */
+ return 0;
+ }
+
+ bufidx = ++frame & 1;
+
+ y = bufidx ? mode_info->yres : 0;
+ nextaddr = vpgaddr[bufidx];
+
+ when = vsync ? VBE_SET_DISP_START_VBLANK : VBE_SET_DISP_START_NOW;
+ if(vbe_set_disp_start(0, y, when) == -1) {
+ return 0;
+ }
+
+ if(vsync == FLIP_VBLANK_WAIT) {
+ wait_vsync();
+ }
+ return nextaddr;
+}
+
static unsigned int make_mask(int sz, int pos)
{
unsigned int i, mask = 0;
}
return mask << pos;
}
-
-
-#endif /* GFX_H_ */
void set_palette(int idx, int r, int g, int b);
+enum {
+ FLIP_NOW,
+ FLIP_VBLANK,
+ FLIP_VBLANK_WAIT
+};
+/* page flip and return pointer to the start of the display area (front buffer) */
+void *page_flip(int vsync);
+
#ifdef __WATCOMC__
void wait_vsync(void);
#pragma aux wait_vsync = \
#include <math.h>
#include <string.h>
#include <limits.h>
+#include <assert.h>
#include <conio.h>
#include "demo.h"
#include "keyb.h"
return 1;
}
- if(!(vmem_front = set_video_mode(fb_width, fb_height, fb_bpp))) {
+ if(!(vmem_back = set_video_mode(fb_width, fb_height, fb_bpp))) {
return 1;
}
- /* TODO implement multiple video memory pages for flipping */
- vmem_back = vmem_front;
+ if(!(vmem_front = page_flip(FLIP_NOW))) {
+ /* page flipping not supported */
+ vmem_front = vmem_back;
+ } else {
+ assert(vmem_back != vmem_front);
+ }
if(demo_init(argc, argv) == -1) {
set_text_mode();
void swap_buffers(void *pixels)
{
- /* TODO implement page flipping */
if(pixels) {
+ /* just memcpy to the front buffer */
if(opt.vsync) {
wait_vsync();
}
drawFps(pixels);
memcpy(vmem_front, pixels, fbsize);
+
} else {
- drawFps(vmem_back);
+ /* attempt page flipping */
+ void *next;
- if(opt.vsync) {
- wait_vsync();
+ drawFps(vmem_back);
+ if((next = page_flip(opt.vsync ? FLIP_VBLANK_WAIT : FLIP_NOW))) {
+ assert(next == vmem_back);
+ vmem_back = vmem_front;
+ vmem_front = next;
+ } else {
+ /* failed to page flip, assume we drew in the front buffer then
+ * and just wait for vsync if necessary
+ */
+ if(opt.vsync) {
+ wait_vsync();
+ }
}
}
}
}
}
+int vbe_set_disp_start(int x, int y, int when)
+{
+ struct dpmi_real_regs regs;
+
+ memset(®s, 0, sizeof regs);
+ regs.eax = 0x4f07;
+ regs.ebx = when & 0xffff;
+ regs.ecx = x & 0xffff;
+ regs.edx = y & 0xffff;
+ dpmi_real_int(0x10, ®s);
+
+ if(regs.eax == 0x100) {
+ return -1;
+ }
+ return 0;
+}
+
+int vbe_set_scanlen(int len, int mode)
+{
+ struct dpmi_real_regs regs;
+
+ memset(®s, 0, sizeof regs);
+ regs.eax = 0x4f06;
+ regs.ebx = mode;
+ regs.ecx = len & 0xffff;
+ dpmi_real_int(0x10, ®s);
+
+ if(regs.eax == 0x100) {
+ return -1;
+ }
+ return regs.ecx & 0xffff;
+}
+
+int vbe_get_scanlen(int mode)
+{
+ int res;
+ struct dpmi_real_regs regs;
+
+ memset(®s, 0, sizeof regs);
+ regs.eax = 0x4f06;
+ regs.ebx = 1;
+ dpmi_real_int(0x10, ®s);
+
+ if(regs.eax == 0x100) {
+ return -1;
+ }
+
+ if(mode == VBE_SCANLEN_PIXELS) {
+ res = regs.ecx & 0xffff;
+ } else {
+ res = regs.ebx & 0xffff;
+ }
+ return res;
+}
+
+
static unsigned int get_mask(int sz, int pos)
{
unsigned int i, mask = 0;
int vbe_set_palette_bits(int bits);
void vbe_set_palette(int idx, int *col, int count, int bits);
+#define VBE_SET_DISP_START_NOW 0
+#define VBE_SET_DISP_START_VBLANK 0x80
+int vbe_set_disp_start(int x, int y, int when);
+
+#define VBE_SCANLEN_PIXELS 0
+#define VBE_SCANLEN_BYTES 2
+int vbe_set_scanlen(int len, int mode);
+int vbe_get_scanlen(int mode);
+
void print_mode_info(FILE *fp, struct vbe_mode_info *modei);
#endif /* VBE_H_ */
static void draw(void)
{
- int i, j;
- uint16_t *fbptr = fb_pixels;
- static float vdir[3];
- float t = (float)time_msec / 16.0f;
-
update();
+ g3d_framebuffer_addr(fb_pixels);
+
backdrop();
g3d_matrix_mode(G3D_MODELVIEW);