initial commit

This commit is contained in:
Gered 2017-11-26 13:18:33 -05:00
commit e5415c977c
33 changed files with 3121 additions and 0 deletions

6
.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
.DS_Store
*.exe
*.a
*.o
/dgl_test.gdt
/dgl_test.gpr

204
BLIT.C Normal file
View file

@ -0,0 +1,204 @@
#include "blit.h"
#include "clipping.h"
#include "internal.h"
static inline boolean clip_blit(const RECT *dest_clip_region,
RECT *src_blit_region,
int *dest_x,
int *dest_y) {
int dest_clip_right = rect_right(dest_clip_region);
int dest_clip_bottom = rect_bottom(dest_clip_region);
int offset;
// off the left edge?
if (*dest_x < dest_clip_region->x) {
// completely off the left edge?
if ((*dest_x + src_blit_region->width) < dest_clip_region->x)
return FALSE;
offset = src_blit_region->x - *dest_x;
src_blit_region->x += offset;
src_blit_region->width -= offset;
*dest_x = dest_clip_region->x;
}
// off the right edge?
if (*dest_x > (dest_clip_region->width - src_blit_region->width)) {
// completely off the right edge?
if (*dest_x > dest_clip_right)
return FALSE;
offset = *dest_x + src_blit_region->width - dest_clip_region->width;
src_blit_region->width -= offset;
}
// off the top edge?
if (*dest_y < dest_clip_region->y) {
// completely off the top edge?
if ((*dest_y + src_blit_region->height) < dest_clip_region->y)
return FALSE;
offset = dest_clip_region->y - *dest_y;
src_blit_region->y += offset;
src_blit_region->height -= offset;
*dest_y = dest_clip_region->y;
}
// off the bottom edge?
if (*dest_y > (dest_clip_region->height - src_blit_region->height)) {
// completely off the bottom edge?
if (*dest_y > dest_clip_bottom)
return FALSE;
offset = *dest_y + src_blit_region->height - dest_clip_region->height;
src_blit_region->height -= offset;
}
return TRUE;
}
void surface_blit_region(const SURFACE *src,
SURFACE *dest,
int src_x,
int src_y,
int src_width,
int src_height,
int dest_x,
int dest_y) {
RECT src_region = rect(src_x, src_y, src_width, src_height);
boolean on_screen = clip_blit(&dest->clip_region, &src_region, &dest_x, &dest_y);
if (!on_screen)
return;
surface_blit_region_f(src, dest,
src_region.x, src_region.y,
src_region.width, src_region.height,
dest_x, dest_y);
}
void surface_blit_region_f(const SURFACE *src,
SURFACE *dest,
int src_x,
int src_y,
int src_width,
int src_height,
int dest_x,
int dest_y) {
byte *psrc, *pdest;
int src_y_inc, dest_y_inc;
int width;
int lines_left;
int num_dwords;
psrc = surface_pointer(src, src_x, src_y);
src_y_inc = src->width;
pdest = surface_pointer(dest, dest_x, dest_y);
dest_y_inc = dest->width;
width = src_width;
lines_left = src_height;
if (width % 4 == 0) {
num_dwords = width / 4;
while (lines_left) {
REP_MOVSL(psrc, pdest, num_dwords);
psrc += src_y_inc;
pdest += dest_y_inc;
--lines_left;
}
} else {
while (lines_left) {
REP_MOVSB(psrc, pdest, width);
psrc += src_y_inc;
pdest += dest_y_inc;
--lines_left;
}
}
}
void surface_blit_sprite_region(const SURFACE *src,
SURFACE *dest,
int src_x,
int src_y,
int src_width,
int src_height,
int dest_x,
int dest_y) {
RECT src_region = rect(src_x, src_y, src_width, src_height);
boolean on_screen = clip_blit(&dest->clip_region, &src_region, &dest_x, &dest_y);
if (!on_screen)
return;
surface_blit_sprite_region_f(src, dest,
src_region.x, src_region.y,
src_region.width, src_region.height,
dest_x, dest_y);
}
void surface_blit_sprite_region_f(const SURFACE *src,
SURFACE *dest,
int src_x,
int src_y,
int src_width,
int src_height,
int dest_x,
int dest_y) {
byte *psrc, *pdest;
byte pixel;
int src_y_inc, dest_y_inc;
int width;
int lines_left;
int x;
psrc = surface_pointer(src, src_x, src_y);
src_y_inc = src->width;
pdest = surface_pointer(dest, dest_x, dest_y);
dest_y_inc = dest->width;
width = src_width;
lines_left = src_height;
// based on benchmarking on a DX2-66, there is VERY significant
// diminishing returns for loop unrolling beyond these sizes
// (in fact, even the one for 8 is a very small gain over 4)
if (width % 8 == 0) {
while (lines_left) {
for (x = 0; x < width; x += 8) {
if ((pixel = psrc[x + 0])) pdest[x + 0] = pixel;
if ((pixel = psrc[x + 1])) pdest[x + 1] = pixel;
if ((pixel = psrc[x + 2])) pdest[x + 2] = pixel;
if ((pixel = psrc[x + 3])) pdest[x + 3] = pixel;
if ((pixel = psrc[x + 4])) pdest[x + 4] = pixel;
if ((pixel = psrc[x + 5])) pdest[x + 5] = pixel;
if ((pixel = psrc[x + 6])) pdest[x + 6] = pixel;
if ((pixel = psrc[x + 7])) pdest[x + 7] = pixel;
}
psrc += src_y_inc;
pdest += dest_y_inc;
--lines_left;
}
} else if (width % 4 == 0) {
while (lines_left) {
for (x = 0; x < width; x += 4) {
if ((pixel = psrc[x + 0])) pdest[x + 0] = pixel;
if ((pixel = psrc[x + 1])) pdest[x + 1] = pixel;
if ((pixel = psrc[x + 2])) pdest[x + 2] = pixel;
if ((pixel = psrc[x + 3])) pdest[x + 3] = pixel;
}
psrc += src_y_inc;
pdest += dest_y_inc;
--lines_left;
}
} else {
while (lines_left) {
for (x = 0; x < width; ++x) {
if ((pixel = psrc[x]))
pdest[x] = pixel;
}
psrc += src_y_inc;
pdest += dest_y_inc;
--lines_left;
}
}
}

67
BLIT.H Normal file
View file

@ -0,0 +1,67 @@
#ifndef DGL_BLIT_H_INCLUDED
#define DGL_BLIT_H_INCLUDED
#include "gfx.h"
void surface_blit_region(const SURFACE *src,
SURFACE *dest,
int src_x,
int src_y,
int src_width,
int src_height,
int dest_x,
int dest_y);
void surface_blit_region_f(const SURFACE *src,
SURFACE *dest,
int src_x,
int src_y,
int src_width,
int src_height,
int dest_x,
int dest_y);
static inline void surface_blit(const SURFACE *src, SURFACE *dest, int x, int y);
static inline void surface_blit_f(const SURFACE *src, SURFACE *dest, int x, int y);
void surface_blit_sprite_region(const SURFACE *src,
SURFACE *dest,
int src_x,
int src_y,
int src_width,
int src_height,
int dest_x,
int dest_y);
void surface_blit_sprite_region_f(const SURFACE *src,
SURFACE *dest,
int src_x,
int src_y,
int src_width,
int src_height,
int dest_x,
int dest_y);
static inline void surface_blit_sprite(const SURFACE *src, SURFACE *dest, int x, int y);
static inline void surface_blit_sprite_f(const SURFACE *src, SURFACE *dest, int x, int y);
// --------------------------------------------------------------------------
static inline void surface_blit(const SURFACE *src, SURFACE *dest, int x, int y) {
surface_blit_region(src, dest, 0, 0, src->width, src->height, x, y);
}
static inline void surface_blit_f(const SURFACE *src, SURFACE *dest, int x, int y) {
surface_blit_region_f(src, dest, 0, 0, src->width, src->height, x, y);
}
static inline void surface_blit_sprite(const SURFACE *src, SURFACE *dest, int x, int y) {
surface_blit_sprite_region(src, dest, 0, 0, src->width, src->height, x, y);
}
static inline void surface_blit_sprite_f(const SURFACE *src, SURFACE *dest, int x, int y) {
surface_blit_sprite_region_f(src, dest, 0, 0, src->width, src->height, x, y);
}
#endif

111
CLIPPING.C Normal file
View file

@ -0,0 +1,111 @@
#include "clipping.h"
#include "common.h"
#include "mathext.h"
static inline boolean is_in_bounds(int clip_x,
int clip_y,
int clip_right,
int clip_bottom,
int x1,
int y1,
int x2,
int y2) {
if (y1 < clip_y && y2 < clip_y)
return FALSE;
if (y1 > clip_bottom && y2 > clip_bottom)
return FALSE;
if (x1 < clip_x && x2 < clip_x)
return FALSE;
if (x1 > clip_right && x2 > clip_right)
return FALSE;
return TRUE;
}
boolean is_point_in_bounds(const RECT *clip_region, int x, int y) {
return (
x >= clip_region->x &&
y >= clip_region->y &&
x <= rect_right(clip_region) &&
y <= rect_bottom(clip_region)
);
}
boolean clamp_to_region(const RECT *clip_region,
int *x1,
int *y1,
int *x2,
int *y2) {
int clip_x = clip_region->x;
int clip_y = clip_region->y;
int clip_right = rect_right(clip_region);
int clip_bottom = rect_bottom(clip_region);
if (!is_in_bounds(clip_x, clip_y, clip_right, clip_bottom, *x1, *y1, *x2, *y2))
return FALSE;
// at least partially within bounds
if (*y1 < clip_y) *y1 = clip_y;
if (*y1 > clip_bottom) *y1 = clip_bottom;
if (*y2 < clip_y) *y2 = clip_y;
if (*y2 > clip_bottom) *y2 = clip_bottom;
if (*x1 < clip_x) *x1 = clip_x;
if (*x1 > clip_right) *x1 = clip_right;
if (*x2 < clip_x) *x2 = clip_x;
if (*x2 > clip_right) *x2 = clip_right;
return TRUE;
}
boolean clip_to_region(const RECT *clip_region, RECT *r) {
int clip_right = rect_right(clip_region);
int clip_bottom = rect_bottom(clip_region);
int offset;
// off the left edge?
if (r->x < clip_region->x) {
// completely off the left edge?
if (rect_right(r) < clip_region->x)
return FALSE;
offset = clip_region->x - r->x;
r->x += offset;
r->width -= offset;
}
// off the right edge?
if (r->x > (clip_region->width - r->width)) {
// completely off the right edge?
if (r->x > clip_right)
return FALSE;
offset = r->x + r->width - clip_region->width;
r->width -= offset;
}
// off the top edge?
if (r->y < clip_region->y) {
// completely off the top edge?
if (rect_bottom(r) < clip_region->y)
return FALSE;
offset = clip_region->y - r->y;
r->y += offset;
r->height -= offset;
}
// off the bottom edge?
if (r->y > (clip_region->height - r->height)) {
// completely off the bottom edge?
if (r->y > clip_bottom)
return FALSE;
offset = r->y + r->height - clip_region->height;
r->height -= offset;
}
return TRUE;
}

39
CLIPPING.H Normal file
View file

@ -0,0 +1,39 @@
#ifndef DGL_CLIPPING_H_INCLUDED
#define DGL_CLIPPING_H_INCLUDED
#include "common.h"
#include "rect.h"
/*
* Determines if the given point lies within the clipping region.
* @param clip_region the clipping region to check against
* @param x x coordinate of the point
* @param y y coordinate of the point
* @return TRUE if the point lies inside the clipping region
*/
boolean is_point_in_bounds(const RECT *clip_region, int x, int y);
/*
* Clamps the coordinates given to the clipping region, assuming that the
* region defined by the coordinates lies at least partially within the
* clipping region.
* @param clip_region the clipping region to check against and clamp to
* @param x1 x coordinate of the top-left point of the region to clamp
* @param y1 y coordinate of the top-left point of the region to clamp
* @param x2 x coordinate of the bottom-right point of the region to clamp
* @param y2 y coordinate of the bottom-right point of the region to clamp
* @return TRUE if the given region was clamped and was at least partially
* within the clipping region to begin with. If the region was
* totally outside of the clipping region, returns FALSE and the
* coordinates will not be modified.
*/
boolean clamp_to_region(const RECT *clip_region,
int *x1,
int *y1,
int *x2,
int *y2);
boolean clip_to_region(const RECT *clip_region, RECT *r);
#endif

36
COMMON.H Normal file
View file

@ -0,0 +1,36 @@
#ifndef DGL_COMMON_H_INCLUDED
#define DGL_COMMON_H_INCLUDED
typedef int boolean;
typedef char byte;
typedef short word;
typedef int dword;
typedef unsigned char ubyte;
typedef unsigned short uword;
typedef unsigned int udword;
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
#define TRUE 1
#define FALSE 0
#define BIT_0 0x1
#define BIT_1 0x2
#define BIT_2 0x4
#define BIT_3 0x8
#define BIT_4 0x10
#define BIT_5 0x20
#define BIT_6 0x40
#define BIT_7 0x80
#define BIT_ISSET(bit, x) ((x) & (bit) != 0)
#define BIT_SET(bit, x) ((x) |= (bit))
#define BIT_CLEAR(bit, x) ((x) &= ~(bit))
#define BIT_TOGGLE(bit, x) ((x) ^= (bit))
#endif

106
DGL.C Normal file
View file

@ -0,0 +1,106 @@
#include "dgl.h"
#include "keyboard.h"
#include "mouse.h"
#include "gfx.h"
#include "util.h"
#include <stdlib.h>
#include <go32.h>
#include <sys/nearptr.h>
static boolean _initialized = FALSE;
static DGL_ERROR _last_error = DGL_NONE;
boolean dgl_init(void) {
if (_initialized) {
dgl_set_error(DGL_ALREADY_INIT);
return FALSE;
}
if (__djgpp_nearptr_enable() == 0) {
dgl_set_error(DGL_NEARPTR_ENABLE_FAILURE);
return FALSE;
}
srandom((int)sys_clock());
// first call will return zero, so call here just to "init"
sys_clock();
sys_ticks();
if (!video_init())
return FALSE;
if (!keyboard_init())
return FALSE;
if (!mouse_init())
return FALSE;
_initialized = TRUE;
return TRUE;
}
boolean dgl_shutdown(void) {
if (!_initialized)
return TRUE; // don't care
// remove installed services
if (!mouse_shutdown())
return FALSE;
if (!keyboard_shutdown())
return FALSE;
if (!video_shutdown())
return FALSE;
__djgpp_nearptr_disable();
_initialized = FALSE;
return TRUE;
}
DGL_ERROR dgl_last_error(void) {
return _last_error;
}
const char* dgl_last_error_message(void) {
switch (_last_error) {
case DGL_NONE:
return "No error.";
case DGL_ALREADY_INIT:
return "DGL is already initialized.";
case DGL_NEARPTR_ENABLE_FAILURE:
return "Failed to enable DJGPP near pointers.";
case DGL_VIDEO_ALREADY_INITIALIZED:
return "Video subsystem is already initialized.";
case DGL_VIDEO_MODE_13H_INIT_FAILURE:
return "Failed to set VGA mode 13h.";
case DGL_VIDEO_TEXT_MODE_INIT_FAILURE:
return "Failed to set text mode.";
case DGL_KEYBOARD_ALREADY_INITIALIZED:
return "Keyboard subsystem is already initialized.";
case DGL_KEYBOARD_IRQ_INSTALL_FAILURE:
return "Failed to install IRQ handler for keyboard.";
case DGL_KEYBOARD_IRQ_RESTORE_FAILURE:
return "Failed to restore original keyboard IRQ handler.";
case DGL_KEYBOARD_UPDATE_LED_FAILURE:
return "Failed to update keyboard LED state.";
case DGL_MOUSE_ALREADY_INITIALIZED:
return "Mouse subsystem is already initialized.";
case DGL_MOUSE_ALLOCATE_CALLBACK_FAILURE:
return "Failed to allocate mouse handler callback.";
case DGL_MOUSE_FREE_CALLBACK_FAILURE:
return "Failed to free mouse handler callback.";
case DGL_MOUSE_INT_CALLBACK_SET_FAILURE:
return "Failed to set mouse interrupt handler callback.";
case DGL_MOUSE_INT_CALLBACK_RESTORE_FAILURE:
return "Failed to restore original mouse interrupt handler callback.";
case DGL_IO_ERROR:
return "File IO error.";
case DGL_PCX_BAD_FORMAT:
return "PCX file unsupported format or bad file.";
default:
return "Unknown error.";
}
}
void dgl_set_error(DGL_ERROR error) {
_last_error = error;
}

24
DGL.H Normal file
View file

@ -0,0 +1,24 @@
#ifndef DGL_DGL_H_INCLUDED
#define DGL_DGL_H_INCLUDED
#include "common.h"
#include "error.h"
#include "keyboard.h"
#include "mouse.h"
#include "gfx.h"
#include "clipping.h"
#include "draw.h"
#include "blit.h"
#include "mathext.h"
#include "rect.h"
#include "vector2.h"
#include "matrix33.h"
#include "util.h"
#include "pcx.h"
boolean dgl_init(void);
boolean dgl_shutdown(void);
#endif

365
DRAW.C Normal file
View file

@ -0,0 +1,365 @@
#include "draw.h"
#include "gfx.h"
#include "mathext.h"
#include "util.h"
#include "internal.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
static char printf_buffer[1024];
void surface_hline_f(SURFACE *surface, int x1, int x2, int y, int color) {
byte *p = surface_pointer(surface, x1, y);
memset(p, color, x2 - x1 + 1);
}
void surface_vline_f(SURFACE *surface, int x, int y1, int y2, int color) {
byte *p = surface_pointer(surface, x, y1);
int line_inc = surface->width;
int y;
for (y = y1; y <= y2; ++y, p += line_inc) {
*p = (byte)color;
}
}
void surface_line(SURFACE *surface, int x1, int y1, int x2, int y2, int color) {
int delta_x, delta_y;
int delta_x_abs, delta_y_abs;
int delta_x_sign, delta_y_sign;
int x, y;
byte *p;
int p_x_inc;
int p_y_inc;
int i;
int dx = x1;
int dy = y1;
int clip_x1 = surface->clip_region.x;
int clip_y1 = surface->clip_region.y;
int clip_x2 = rect_right(&surface->clip_region);
int clip_y2 = rect_bottom(&surface->clip_region);
delta_x = x2 - x1;
delta_y = y2 - y1;
delta_x_abs = abs(delta_x);
delta_y_abs = abs(delta_y);
delta_x_sign = SIGN(delta_x);
delta_y_sign = SIGN(delta_y);
x = delta_y_abs / 2;
y = delta_x_abs / 2;
p = surface_pointer(surface, x1, y1);
p_x_inc = delta_x_sign;
p_y_inc = delta_y_sign * surface->width;
if (dx >= clip_x1 &&
dy >= clip_y1 &&
dx <= clip_x2 &&
dy <= clip_y2)
*p = (byte)color;
if (delta_x_abs >= delta_y_abs) {
for (i = 0; i < delta_x_abs; ++i) {
y += delta_y_abs;
if (y >= delta_x_abs) {
y -= delta_x_abs;
p += p_y_inc;
dy += delta_y_sign;
}
p += p_x_inc;
dx += delta_x_sign;
if (dx >= clip_x1 &&
dy >= clip_y1 &&
dx <= clip_x2 &&
dy <= clip_y2)
*p = (byte)color;
}
} else {
for (i = 0; i < delta_y_abs; ++i) {
x += delta_x_abs;
if (x >= delta_y_abs) {
x -= delta_y_abs;
p += p_x_inc;
dx += delta_x_sign;
}
p += p_y_inc;
dy += delta_y_sign;
if (dx >= clip_x1 &&
dy >= clip_y1 &&
dx <= clip_x2 &&
dy <= clip_y2)
*p = (byte)color;
}
}
}
void surface_line_f(SURFACE *surface, int x1, int y1, int x2, int y2, int color) {
int delta_x, delta_y;
int delta_x_abs, delta_y_abs;
int delta_x_sign, delta_y_sign;
int x, y;
byte *p;
int p_x_inc;
int p_y_inc;
int i;
delta_x = x2 - x1;
delta_y = y2 - y1;
delta_x_abs = abs(delta_x);
delta_y_abs = abs(delta_y);
delta_x_sign = SIGN(delta_x);
delta_y_sign = SIGN(delta_y);
x = delta_y_abs / 2;
y = delta_x_abs / 2;
p = surface_pointer(surface, x1, y1);
p_x_inc = delta_x_sign;
p_y_inc = delta_y_sign * surface->width;
*p = (byte)color;
if (delta_x_abs >= delta_y_abs) {
for (i = 0; i < delta_x_abs; ++i) {
y += delta_y_abs;
if (y >= delta_x_abs) {
y -= delta_x_abs;
p += p_y_inc;
}
p += p_x_inc;
*p = (byte)color;
}
} else {
for (i = 0; i < delta_y_abs; ++i) {
x += delta_x_abs;
if (x >= delta_y_abs) {
x -= delta_y_abs;
p += p_x_inc;
}
p += p_y_inc;
*p = (byte)color;
}
}
}
void surface_rect(SURFACE *surface, int x1, int y1, int x2, int y2, int color) {
byte *p1, *p2;
int width;
int y;
int y_inc = surface->width;
int clipped_x1 = x1;
int clipped_y1 = y1;
int clipped_x2 = x2;
int clipped_y2 = y2;
int clip_right = rect_right(&surface->clip_region);
int clip_bottom = rect_bottom(&surface->clip_region);
if (x1 < surface->clip_region.x)
clipped_x1 = surface->clip_region.x;
if (x2 > clip_right)
clipped_x2 = clip_right;
width = clipped_x2 - clipped_x1 + 1;
// top line, only if y1 was within bounds
if (y1 < surface->clip_region.y)
clipped_y1 = surface->clip_region.y;
else
memset(surface_pointer(surface, clipped_x1, clipped_y1), color, width);
// bottom line, only if y2 was within bounds
if (y2 > clip_bottom)
clipped_y2 = clip_bottom;
else
memset(surface_pointer(surface, clipped_x1, clipped_y2), color, width);
// draw both left and right lines if neither x1 nor x2 were clipped
if (x1 == clipped_x1 && x2 == clipped_x2) {
p1 = surface_pointer(surface, x1, y1);
p2 = surface_pointer(surface, x2, y1);
for (y = y1; y <= y2; ++y, p1 += y_inc, p2 += y_inc) {
*p1 = (byte)color;
*p2 = (byte)color;
}
// draw left line if x1 was not clipped
} else if (x1 == clipped_x1) {
p1 = surface_pointer(surface, x1, y1);
for (y = y1; y <= y2; ++y, p1 += y_inc)
*p1 = (byte)color;
// draw right line if x2 was not clipped
} else if (x2 == clipped_x2) {
p1 = surface_pointer(surface, x2, y1);
for (y = y1; y <= y2; ++y, p1 += y_inc)
*p1 = (byte)color;
}
}
void surface_rect_f(SURFACE *surface, int x1, int y1, int x2, int y2, int color) {
byte *p1, *p2;
int width = x2 - x1 + 1;
int y;
int y_inc = surface->width;
p1 = surface_pointer(surface, x1, y1);
p2 = surface_pointer(surface, x1, y2);
memset(p1, color, width);
memset(p2, color, width);
p1 = surface_pointer(surface, x1, y1);
p2 = surface_pointer(surface, x2, y1);
for (y = y1; y <= y2; ++y, p1 += y_inc, p2 += y_inc) {
*p1 = (byte)color;
*p2 = (byte)color;
}
}
void surface_filled_rect(SURFACE *surface,
int x1,
int y1,
int x2,
int y2,
int color) {
if (!clamp_to_region(&surface->clip_region, &x1, &y1, &x2, &y2))
return;
surface_filled_rect_f(surface, x1, y1, x2, y2, color);
}
void surface_filled_rect_f(SURFACE *surface,
int x1,
int y1,
int x2,
int y2,
int color) {
byte *p;
int width = x2 - x1 + 1;
int y;
int y_inc = surface->width;
p = surface_pointer(surface, x1, y1);
for (y = y1; y <= y2; ++y) {
memset(p, (byte)color, width);
p += y_inc;
}
}
#define CHAR_WIDTH 8
#define CHAR_HEIGHT 8
#define CHAR_LINE_BITMASK(x) (1 << ((CHAR_WIDTH - 1) - (x)))
#define IS_CHAR_PIXEL(x, line) ((line) & CHAR_LINE_BITMASK(x))
// dest_x, dest_y - original unclipped render x,y coords
// dest_clipped - clipped destination render region
static inline void print_char(SURFACE *surface,
int dest_x,
int dest_y,
const RECT *dest_clipped,
int color,
char c) {
byte *p;
byte *rom_char;
char char_line_bits;
int cx, cy;
int offset_x, offset_y;
int width, height;
int y_inc = surface->width;
p = surface_pointer(surface, dest_clipped->x, dest_clipped->y);
rom_char = map_dos_memory(0xffa6e) + (c * CHAR_HEIGHT);
// get offset x,y to start rendering char from (will be in range 0-7)
offset_x = dest_clipped->x - dest_x;
offset_y = dest_clipped->y - dest_y;
width = dest_clipped->width + offset_x;
height = dest_clipped->height + offset_y;
// cx,cy are always in "char coordinate space" (that is, 0-7)
for (cy = offset_y; cy < height; ++cy) {
char_line_bits = rom_char[cy];
for (cx = offset_x; cx < width; ++cx) {
if (IS_CHAR_PIXEL(cx, char_line_bits))
p[cx - offset_x] = (byte)color;
}
p += y_inc;
}
}
static inline void print_text(SURFACE *surface,
int x,
int y,
int color,
boolean clip,
const char *text) {
const char *c;
RECT r;
RECT draw_r;
r = rect(x, y, CHAR_WIDTH, CHAR_HEIGHT);
for (c = text; *c; ++c) {
if (*c == '\n') {
r.x = x;
r.y += r.height;
} else if (*c == ' ') {
r.x += r.width;
} else {
if (clip) {
draw_r = r;
if (clip_to_region(&surface->clip_region, &draw_r))
print_char(surface, r.x, r.y, &draw_r, color, *c);
} else {
print_char(surface, r.x, r.y, &r, color, *c);
}
r.x += r.width;
}
}
}
void surface_text(SURFACE *surface, int x, int y, int color, const char *text) {
print_text(surface, x, y, color, TRUE, text);
}
void surface_text_f(SURFACE *surface, int x, int y, int color, const char *text) {
print_text(surface, x, y, color, FALSE, text);
}
void surface_printf(SURFACE *surface,
int x,
int y,
int color,
const char *format, ...) {
va_list args;
va_start(args, format);
vsprintf(printf_buffer, format, args);
va_end(args);
print_text(surface, x, y, color, TRUE, printf_buffer);
}
void surface_printf_f(SURFACE *surface,
int x,
int y,
int color,
const char *format, ...) {
va_list args;
va_start(args, format);
vsprintf(printf_buffer, format, args);
va_end(args);
print_text(surface, x, y, color, FALSE, printf_buffer);
}

68
DRAW.H Normal file
View file

@ -0,0 +1,68 @@
#ifndef DGL_DRAW_H_INCLUDED
#define DGL_DRAW_H_INCLUDED
#include "gfx.h"
#include "clipping.h"
#include "util.h"
static inline void surface_pset(SURFACE *surface, int x, int y, int color);
static inline void surface_pset_f(SURFACE *surface, int x, int y, int color);
static inline int surface_point(const SURFACE *surface, int x, int y);
static inline int surface_point_f(const SURFACE *surface, int x, int y);
static inline void surface_hline(SURFACE *surface, int x1, int x2, int y, int color);
void surface_hline_f(SURFACE *surface, int x1, int x2, int y, int color);
static inline void surface_vline(SURFACE *surface, int x, int y1, int y2, int color);
void surface_vline_f(SURFACE *surface, int x, int y1, int y2, int color);
void surface_line(SURFACE *surface, int x1, int y1, int x2, int y2, int color);
void surface_line_f(SURFACE *surface, int x1, int y1, int x2, int y2, int color);
void surface_rect(SURFACE *surface, int x1, int y1, int x2, int y2, int color);
void surface_rect_f(SURFACE *surface, int x1, int y1, int x2, int y2, int color);
void surface_filled_rect(SURFACE *surface, int x1, int y1, int x2, int y2, int color);
void surface_filled_rect_f(SURFACE *surface, int x1, int y1, int x2, int y2, int color);
void surface_text(SURFACE *surface, int x, int y, int color, const char *text);
void surface_text_f(SURFACE *surface, int x, int y, int color, const char *text);
void surface_printf(SURFACE *surface, int x, int y, int color, const char *format, ...);
void surface_printf_f(SURFACE *surface, int x, int y, int color, const char *format, ...);
// --------------------------------------------------------------------------
static inline void surface_pset(SURFACE *surface, int x, int y, int color) {
if (is_point_in_bounds(&surface->clip_region, x, y))
surface_pset_f(surface, x, y, color);
}
static inline void surface_pset_f(SURFACE *surface, int x, int y, int color) {
*(surface_pointer(surface, x, y)) = (byte)color;
}
static inline int surface_point(const SURFACE *surface, int x, int y) {
if (is_point_in_bounds(&surface->clip_region, x, y))
return surface_point_f(surface, x, y);
else
return 0;
}
static inline int surface_point_f(const SURFACE *surface, int x, int y) {
return (int)*(surface_pointer(surface, x, y));
}
static inline void surface_hline(SURFACE *surface, int x1, int x2, int y, int color) {
if (x2 < x1)
SWAP(int, x1, x2);
if (clamp_to_region(&surface->clip_region, &x1, &y, &x2, &y))
surface_hline_f(surface, x1, x2, y, color);
}
static inline void surface_vline(SURFACE *surface, int x, int y1, int y2, int color) {
if (y2 < y1)
SWAP(int, y1, y2);
if (clamp_to_region(&surface->clip_region, &x, &y1, &x, &y2))
surface_vline_f(surface, x, y1, y2, color);
}
#endif

31
ERROR.H Normal file
View file

@ -0,0 +1,31 @@
#ifndef DGL_ERROR_H_INCLUDED
#define DGL_ERROR_H_INCLUDED
#include "common.h"
typedef enum {
DGL_NONE = 0,
DGL_ALREADY_INIT,
DGL_NEARPTR_ENABLE_FAILURE,
DGL_VIDEO_ALREADY_INITIALIZED,
DGL_VIDEO_MODE_13H_INIT_FAILURE,
DGL_VIDEO_TEXT_MODE_INIT_FAILURE,
DGL_KEYBOARD_ALREADY_INITIALIZED,
DGL_KEYBOARD_IRQ_INSTALL_FAILURE,
DGL_KEYBOARD_IRQ_RESTORE_FAILURE,
DGL_KEYBOARD_UPDATE_LED_FAILURE,
DGL_MOUSE_ALREADY_INITIALIZED,
DGL_MOUSE_ALLOCATE_CALLBACK_FAILURE,
DGL_MOUSE_FREE_CALLBACK_FAILURE,
DGL_MOUSE_INT_CALLBACK_SET_FAILURE,
DGL_MOUSE_INT_CALLBACK_RESTORE_FAILURE,
DGL_IO_ERROR,
DGL_PCX_BAD_FORMAT
} DGL_ERROR;
DGL_ERROR dgl_last_error(void);
const char* dgl_last_error_message(void);
void dgl_set_error(DGL_ERROR error);
#endif

151
GFX.C Normal file
View file

@ -0,0 +1,151 @@
#include "gfx.h"
#include "blit.h"
#include "util.h"
#include "internal.h"
#include "error.h"
#include <stdlib.h>
#include <string.h>
#include <dpmi.h>
#include <pc.h>
static boolean _initialized = FALSE;
SURFACE *screen = NULL;
static SURFACE* surface_create_internal(int width, int height, byte *pixels) {
SURFACE *surface = malloc(sizeof(SURFACE));
surface->width = width;
surface->height = height;
surface->clip_region = rect(0, 0, width, height);
if (pixels != NULL) {
surface->aliased = TRUE;
surface->pixels = pixels;
} else {
surface->aliased = FALSE;
surface->pixels = malloc(width * height);
memset(surface->pixels, 0, width * height);
}
return surface;
}
boolean video_init(void) {
__dpmi_regs regs;
void *framebuffer;
if (_initialized) {
dgl_set_error(DGL_VIDEO_ALREADY_INITIALIZED);
return FALSE;
}
memset(&regs, 0, sizeof(__dpmi_regs));
regs.h.ah = 0x00;
regs.h.al = 0x13;
if (__dpmi_int(0x10, &regs)) {
dgl_set_error(DGL_VIDEO_MODE_13H_INIT_FAILURE);
return FALSE;
}
framebuffer = map_dos_memory(0xa0000);
screen = surface_create_internal(320, 200, framebuffer);
surface_clear(screen, 0);
_initialized = TRUE;
return TRUE;
}
boolean video_shutdown(void) {
__dpmi_regs regs;
if (!_initialized)
return TRUE; // don't care
memset(&regs, 0, sizeof(__dpmi_regs));
regs.h.ah = 0x00;
regs.h.al = 0x03;
if (__dpmi_int(0x10, &regs)) {
dgl_set_error(DGL_VIDEO_TEXT_MODE_INIT_FAILURE);
return FALSE;
}
surface_free(screen);
screen = NULL;
_initialized = FALSE;
return TRUE;
}
boolean video_is_initialized(void) {
return _initialized;
}
void video_wait_vsync(void) {
do {} while (inportb(0x3da) & 0x8);
do {} while (!(inportb(0x3da) & 0x8));
}
void video_set_color(ubyte color, ubyte r, ubyte g, ubyte b) {
outportb(0x3c6, 0xff);
outportb(0x3c8, color);
outportb(0x3c9, r);
outportb(0x3c9, g);
outportb(0x3c9, b);
}
void video_get_color(ubyte color, ubyte *r, ubyte *g, ubyte *b) {
outportb(0x3c6, 0xff);
outportb(0x3c7, color);
*r = inportb(0x3c9);
*g = inportb(0x3c9);
*b = inportb(0x3c9);
}
void video_set_palette(const byte *palette) {
int i = 0;
for (i = 0; i < 256; ++i) {
video_set_color(i, palette[0], palette[1], palette[2]);
palette += 3;
}
}
void video_get_palette(byte *palette) {
int i = 0;
for (i = 0; i < 256; ++i) {
video_get_color(i, palette, palette + 1, palette + 2);
palette += 3;
}
}
SURFACE* surface_create(int width, int height) {
return surface_create_internal(width, height, NULL);
}
void surface_free(SURFACE *surface) {
if (!surface)
return;
if (!surface->aliased)
free(surface->pixels);
free(surface);
}
void surface_clear(SURFACE *surface, int color) {
int length = surface->width * surface->height;
if (length % 4 == 0) {
color *= 0x01010101;
REP_STOSL(color, surface->pixels, length / 4);
} else {
memset(surface->pixels, color, surface->width * surface->height);
}
}
void surface_copy(const SURFACE *src, SURFACE *dest) {
if (src->width == dest->width && src->height == dest->height) {
memcpy(dest->pixels, src->pixels, src->width * src->height);
} else {
surface_blit(src, dest, 0, 0);
}
}

47
GFX.H Normal file
View file

@ -0,0 +1,47 @@
#ifndef DGL_GFX_H_INCLUDED
#define DGL_GFX_H_INCLUDED
#include "common.h"
#include "rect.h"
typedef struct {
int width;
int height;
byte *pixels;
boolean aliased;
RECT clip_region;
} SURFACE;
extern SURFACE *screen;
boolean video_init(void);
boolean video_shutdown(void);
boolean video_is_initialized(void);
void video_wait_vsync(void);
void video_set_color(ubyte color, ubyte r, ubyte g, ubyte b);
void video_get_color(ubyte color, ubyte *r, ubyte *g, ubyte *b);
void video_set_palette(const byte *palette);
void video_get_palette(byte *palette);
SURFACE* surface_create(int width, int height);
void surface_free(SURFACE *surface);
void surface_clear(SURFACE *surface, int color);
void surface_copy(const SURFACE *src, SURFACE *dest);
static inline int surface_offset(const SURFACE *surface, int x, int y);
static inline byte* surface_pointer(const SURFACE *surface, int x, int y);
// --------------------------------------------------------------------------
static inline int surface_offset(const SURFACE *surface, int x, int y) {
return surface->width * y + x;
}
static inline byte* surface_pointer(const SURFACE *surface, int x, int y) {
return surface->pixels + surface_offset(surface, x, y);
}
#endif

36
INTERNAL.C Normal file
View file

@ -0,0 +1,36 @@
#include "internal.h"
#include <dpmi.h>
#include <go32.h>
#include <string.h>
boolean _install_irq(int irq,
void* irq_handler,
_go32_dpmi_seginfo* new_handler,
_go32_dpmi_seginfo* old_handler) {
memset((void*)new_handler, 0, sizeof(_go32_dpmi_seginfo));
if (_go32_dpmi_get_real_mode_interrupt_vector(irq, old_handler) != 0)
return FALSE;
new_handler->pm_offset = (int)irq_handler;
new_handler->pm_selector = _go32_my_cs();
if (_go32_dpmi_allocate_iret_wrapper(new_handler) != 0)
return FALSE;
if (_go32_dpmi_set_protected_mode_interrupt_vector(irq, new_handler) != 0)
return FALSE;
return TRUE;
}
boolean _restore_irq(int irq,
_go32_dpmi_seginfo* new_handler,
_go32_dpmi_seginfo* old_handler) {
if (_go32_dpmi_set_real_mode_interrupt_vector(irq, old_handler) != 0)
return FALSE;
if (_go32_dpmi_free_iret_wrapper(new_handler) != 0)
return FALSE;
return TRUE;
}

60
INTERNAL.H Normal file
View file

@ -0,0 +1,60 @@
#ifndef DGL_INTERNAL_H_INCLUDED
#define DGL_INTERNAL_H_INCLUDED
#include "common.h"
#include <dpmi.h>
#define END_OF_FUNCTION(x) void x##_end() {}
#define LOCK_VARIABLE(x) _go32_dpmi_lock_data((void*)&x, sizeof(x))
#define LOCK_MEMORY(ptr, len) _go32_dpmi_lock_data((void*)(ptr), (len))
#define LOCK_FUNCTION(x) _go32_dpmi_lock_code(x, (long)x##_end - (long)x)
static inline void _enable_interrupts(void) {
asm volatile ("sti");
}
static inline void _disable_interrupts(void) {
asm volatile ("cli");
}
boolean _install_irq(int irq,
void* irq_handler,
_go32_dpmi_seginfo* new_handler,
_go32_dpmi_seginfo* old_handler);
boolean _restore_irq(int irq,
_go32_dpmi_seginfo* new_handler,
_go32_dpmi_seginfo* old_handler);
#define REP_MOVSL(src, dest, num_dwords) \
__asm__ __volatile__ ( \
"cld\n\t" \
"rep\n\t" \
"movsl" \
: : "S" (src), "D" (dest), "c" (num_dwords) \
: "%ecx", "%esi", "%edi" )
#define REP_MOVSB(src, dest, num_bytes) \
__asm__ __volatile__ ( \
"cld\n\t" \
"rep\n\t" \
"movsb" \
: : "S" (src), "D" (dest), "c" (num_bytes) \
: "%ecx", "%esi", "%edi" )
#define REP_STOSL(value, dest, num_dwords) \
__asm__ __volatile__ ( \
"cld\n\t" \
"rep\n\t" \
"stosl" \
: : "a" (value), "D" (dest), "c" (num_dwords) \
: "%ecx", "%edi" )
#define REP_STOSB(value, dest, num_bytes) \
__asm__ __volatile__ ( \
"cld\n\t" \
"rep\n\t" \
"stosb" \
: : "a" (value), "D" (dest), "c" (num_bytes) \
: "%ecx", "%edi" )
#endif

194
KEYBOARD.C Normal file
View file

@ -0,0 +1,194 @@
#include "keyboard.h"
#include "internal.h"
#include "util.h"
#include "error.h"
#include <string.h>
#include <dpmi.h>
#include <pc.h>
#include <sys/nearptr.h>
#define PIC_CTRL_PORT 0x20
#define KEYBRD_DATA_PORT 0x60
#define KEYBRD_CTRL_PORT 0x61
#define KEYBRD_STATUS_PORT 0x64
#define KEYBRD_CMD_SET_LED 0xED
#define KEYBRD_FLAGS_ADDR 0x417
#define KEYBRD_FLAGS_SCROLLOCK 0x10
#define KEYBRD_FLAGS_NUMLOCK 0x20
#define KEYBRD_FLAGS_CAPSLOCK 0x40
#define KEYBRD_LED_SCROLLOCK 0x1
#define KEYBRD_LED_NUMLOCK 0x2
#define KEYBRD_LED_CAPSLOCK 0x4
static boolean _installed = FALSE;
volatile ubyte keys[128];
volatile KEY _key_last_scan;
volatile KEY _key_scan;
uword _old_flags;
_go32_dpmi_seginfo _old_handler;
_go32_dpmi_seginfo _new_handler;
static inline void reset_key_states() {
memset((void*)keys, 0, 128);
}
// waits until the keyboard status port indicates the data port
// can be read from once again
static inline void wait_kb_data_read() {
while ((inportb(KEYBRD_STATUS_PORT) & BIT_0) == 0) {
}
}
// waits until the keyboard status port indicates the data port
// can be written to once again
static inline void wait_kb_data_write() {
while ((inportb(KEYBRD_STATUS_PORT) & BIT_1) != 0) {
}
}
// sends data to the keyboard data port. checks for success
// and returns TRUE if the data write succeeded
static inline boolean send_kb_data(ubyte data) {
ubyte result;
wait_kb_data_write();
outportb(KEYBRD_DATA_PORT, data);
wait_kb_data_read();
result = inportb(KEYBRD_DATA_PORT);
return (result == 0xFA);
}
// keyboard interrupt handler
void kb_int_handler(void) {
// read scan code of key that was just pressed
_key_scan = inportb(KEYBRD_DATA_PORT);
if (_key_scan & 0x80) {
// high bit set indicates key was released, clear high bit to get
// the actual key scan code
_key_scan &= 0x7f;
keys[(int)_key_scan] = 0;
} else {
keys[(int)_key_scan] = 1;
}
_key_last_scan = _key_scan;
// indicate key event was processed to keyboard controller
_key_scan = inportb(KEYBRD_CTRL_PORT) | 0x82;
outportb(KEYBRD_CTRL_PORT, _key_scan);
outportb(KEYBRD_CTRL_PORT, _key_scan & 0x7f);
outportb(PIC_CTRL_PORT, 0x20);
}
END_OF_FUNCTION(kb_int_handler)
static uword get_kb_flags(void) {
return *((uword*)(map_dos_memory(KEYBRD_FLAGS_ADDR)));
}
static void set_kb_flags(uword flags) {
*((uword*)(map_dos_memory(KEYBRD_FLAGS_ADDR))) = flags;
}
// updates the keyboard indicator LEDs from the num/caps/scroll lock flags
// set in the passed keyboard flags. returns FALSE if the LEDs could not
// be updated (if keyboard data write did not succeed)
static boolean update_kb_led(byte flags) {
ubyte led = 0;
if (flags & KEYBRD_FLAGS_SCROLLOCK)
led |= KEYBRD_LED_SCROLLOCK;
if (flags & KEYBRD_FLAGS_NUMLOCK)
led |= KEYBRD_LED_NUMLOCK;
if (flags & KEYBRD_FLAGS_CAPSLOCK)
led |= KEYBRD_LED_CAPSLOCK;
if (!send_kb_data(KEYBRD_CMD_SET_LED)) {
dgl_set_error(DGL_KEYBOARD_UPDATE_LED_FAILURE);
return FALSE;
}
if (!send_kb_data(led)) {
dgl_set_error(DGL_KEYBOARD_UPDATE_LED_FAILURE);
return FALSE;
}
return TRUE;
}
boolean keyboard_init(void) {
if (_installed) {
dgl_set_error(DGL_KEYBOARD_ALREADY_INITIALIZED);
return FALSE;
}
LOCK_MEMORY(keys, 128);
LOCK_VARIABLE(_key_scan);
LOCK_VARIABLE(_key_last_scan);
LOCK_FUNCTION(kb_int_handler);
// preserve old flags
_old_flags = get_kb_flags();
reset_key_states();
if (!_install_irq(9, kb_int_handler, &_new_handler, &_old_handler)) {
dgl_set_error(DGL_KEYBOARD_IRQ_INSTALL_FAILURE);
return FALSE;
}
// turn off keyboard LEDs since our interrupt handler does not currently
// respect the num/caps/scroll lock statuses
_disable_interrupts();
update_kb_led(0);
_enable_interrupts();
_installed = TRUE;
return TRUE;
}
boolean keyboard_shutdown(void) {
if (!_installed)
return TRUE; // don't care
// reset keyboard LEDs to previous state
_disable_interrupts();
update_kb_led(_old_flags);
_enable_interrupts();
if (!_restore_irq(9, &_new_handler, &_old_handler)) {
dgl_set_error(DGL_KEYBOARD_IRQ_RESTORE_FAILURE);
return FALSE;
}
reset_key_states();
// restore keyboard flags to previous state
set_kb_flags(_old_flags);
_installed = FALSE;
return TRUE;
}
boolean keyboard_is_initialized(void) {
return _installed;
}
KEY keyboard_read_key(void) {
_key_last_scan = 0;
while (_key_last_scan == 0) {
}
return _key_last_scan;
}
void keyboard_wait_for_key(KEY key) {
_key_last_scan = 0;
while (_key_last_scan != key) {
}
}

43
KEYBOARD.H Normal file
View file

@ -0,0 +1,43 @@
#ifndef DGL_KEYBOARD_H_INCLUDED
#define DGL_KEYBOARD_H_INCLUDED
#include "common.h"
#include "keys.h"
typedef byte KEY;
/*
* Current state of the keyboard.
*/
volatile extern ubyte keys[128];
/*
* Installs a custom keyboard interrupt handler.
* @return TRUE on success
*/
boolean keyboard_init(void);
/*
* Removes a previously installed keyboard interrupt handler.
* @return TRUE on success
*/
boolean keyboard_shutdown(void);
/*
* @return TRUE if the custom keyboard interrupt handler is installed.
*/
boolean keyboard_is_initialized(void);
/*
* Waits indefinitely until any key is pressed.
* @return The key that was pressed.
*/
KEY keyboard_read_key(void);
/*
* Waits indefinitely until the specified key is pressed.
*/
void keyboard_wait_for_key(KEY key);
#endif

89
KEYS.H Normal file
View file

@ -0,0 +1,89 @@
#ifndef DGL_KEYS_H_INCLUDED
#define DGL_KEYS_H_INCLUDED
#define KEY_ESC 0x01
#define KEY_1 0x02
#define KEY_2 0x03
#define KEY_3 0x04
#define KEY_4 0x05
#define KEY_5 0x06
#define KEY_6 0x07
#define KEY_7 0x08
#define KEY_8 0x09
#define KEY_9 0x0A
#define KEY_0 0x0B
#define KEY_MINUS 0x0C
#define KEY_EQUALS 0x0D
#define KEY_BACKSPACE 0x0E
#define KEY_TAB 0x0F
#define KEY_Q 0x10
#define KEY_W 0x11
#define KEY_E 0x12
#define KEY_R 0x13
#define KEY_T 0x14
#define KEY_Y 0x15
#define KEY_U 0x16
#define KEY_I 0x17
#define KEY_O 0x18
#define KEY_P 0x19
#define KEY_LEFTBRACKET 0x1A
#define KEY_RIGHTBRACKET 0x1B
#define KEY_ENTER 0x1C
#define KEY_CTRL 0x1D
#define KEY_A 0x1E
#define KEY_S 0x1F
#define KEY_D 0x20
#define KEY_F 0x21
#define KEY_G 0x22
#define KEY_H 0x23
#define KEY_J 0x24
#define KEY_K 0x25
#define KEY_L 0x26
#define KEY_SEMICOLON 0x27
#define KEY_APOSTROPHE 0x28
#define KEY_TILDE 0x29
#define KEY_LEFTSHIFT 0x2A
#define KEY_BACKSLASH 0x2B
#define KEY_Z 0x2C
#define KEY_X 0x2D
#define KEY_C 0x2E
#define KEY_V 0x2F
#define KEY_B 0x30
#define KEY_N 0x31
#define KEY_M 0x32
#define KEY_COMMA 0x33
#define KEY_PERIOD 0x34
#define KEY_FORWARDSLASH 0x35
#define KEY_RIGHTSHIFT 0x36
#define KEY_ASTERISK 0x37
#define KEY_ALT 0x38
#define KEY_SPACE 0x39
#define KEY_CAPSLOCK 0x3A
#define KEY_F1 0x3B
#define KEY_F2 0x3C
#define KEY_F3 0x3D
#define KEY_F4 0x3E
#define KEY_F5 0x3F
#define KEY_F6 0x40
#define KEY_F7 0x41
#define KEY_F8 0x42
#define KEY_F9 0x43
#define KEY_F10 0x44
#define KEY_NUMLOCK 0x45
#define KEY_SCROLLLOCK 0x46
#define KEY_HOME 0x47
#define KEY_UP 0x48
#define KEY_PAGEUP 0x49
#define KEY_NUM_MINUS 0x4A
#define KEY_LEFT 0x4B
#define KEY_NUM_5 0x4C
#define KEY_RIGHT 0x4D
#define KEY_NUM_PLUS 0x4E
#define KEY_END 0x4F
#define KEY_DOWN 0x50
#define KEY_PAGEDOWN 0x51
#define KEY_INSERT 0x52
#define KEY_DELETE 0x53
#endif

BIN
LIBDGL.GDT Normal file

Binary file not shown.

BIN
LIBDGL.GPR Normal file

Binary file not shown.

34
MATHEXT.C Normal file
View file

@ -0,0 +1,34 @@
#include "mathext.h"
#include <math.h>
float angle_between_i(int x1, int y1, int x2, int y2) {
int delta_x = x2 - x1;
int delta_y = y2 - y1;
if (delta_x == 0 && delta_y == 0)
return 0.0f;
else
return atan2(delta_y, delta_x);
}
float angle_between_f(float x1, float y1, float x2, float y2) {
float delta_x = x2 - x1;
float delta_y = y2 - y1;
if (close_enough(delta_x, 0.0f, TOLERANCE) && close_enough(delta_y, 0.0f, TOLERANCE))
return 0.0f;
else
return atan2(delta_y, delta_x);
}
int next_power_of_2(int n) {
int i = n & (~n + 1);
while (i < n) {
i <<= 1;
}
return i;
}
void point_on_circle(float radius, float radians, float *x, float *y) {
*x = radius * cos(radians);
*y = radius * sin(radians);
}

75
MATHEXT.H Normal file
View file

@ -0,0 +1,75 @@
#ifndef DGL_MATH_H_INCLUDED
#define DGL_MATH_H_INCLUDED
#include "common.h"
#include "vector2.h"
#include <math.h>
#define TOLERANCE 0.00001f
#define PI_OVER_180 (PI / 180.0f)
#define RADIANS_0 0.0f
#define RADIANS_45 (PI / 4.0f)
#define RADIANS_90 (PI / 2.0f)
#define RADIANS_135 ((3.0f * PI) / 4.0f)
#define RADIANS_180 PI
#define RADIANS_225 ((5.0f * PI) / 4.0f)
#define RADIANS_270 ((3.0f * PI) / 2.0f)
#define RADIANS_315 ((7.0f * PI) / 4.0f)
#define RADIANS_360 (PI * 2.0f)
#define DEG_TO_RAD(degrees) ((degrees) * PI_OVER_180)
#define RAD_TO_DEG(radians) ((radians) * (1.0f / PI_OVER_180))
#define CLAMP(value, low, high) (((value) < (low) ? (low) : ((value) > (high) ? (high) : (value))))
#define LERP(a, b, t) ((a) + ((b) - (a)) * (t))
#define INVERSE_LERP(a, b, lerped) (((lerped) - (a)) / ((b) - (a)))
#define SCALE_RANGE(value, from_min, from_max, to_min, to_max) \
(((value) / (((from_max) - (from_min)) / ((to_max) - (to_min)))) + (to_min))
float angle_between_i(int x1, int y1, int x2, int y2);
float angle_between_f(float x1, float y1, float x2, float y2);
int next_power_of_2(int n);
void point_on_circle(float radius, float radians, float *x, float *y);
static inline VECTOR2F direction_from_angle(float radians);
static inline float round(float value);
static inline float symmetrical_round(float value);
static inline boolean close_enough(float a, float b, float tolerance);
static inline boolean power_of_2(int n);
static inline float smooth_step(float low, float high, float t);
// --------------------------------------------------------------------------
static inline VECTOR2F direction_from_angle(float radians) {
VECTOR2F direction;
point_on_circle(1.0f, radians, &direction.x, &direction.y);
return direction;
}
static inline float round(float value) {
return ceil(value + 0.5f);
}
static inline float symmetrical_round(float value) {
if (value > 0.0f)
return floor(value + 0.5f);
else
return ceil(value - 0.5f);
}
static inline boolean close_enough(float a, float b, float tolerance) {
return fabs((a - b) / ((b == 0.0f) ? 1.0f : b)) < tolerance;
}
static inline boolean power_of_2(int n) {
return (n != 0) && !(n & (n - 1));
}
static inline float smooth_step(float low, float high, float t) {
float n = CLAMP(t, 0.0f, 1.0f);
return LERP(low, high, (n * n) * (3.0f - (2.0f * n)));
}
#endif

340
MATRIX33.H Normal file
View file

@ -0,0 +1,340 @@
#ifndef DGL_MATRIX33_H_INCLUDED
#define DGL_MATRIX33_H_INCLUDED
#include "common.h"
#include "mathext.h"
#include "vector2.h"
#include <math.h>
#define _M33_11 0
#define _M33_12 3
#define _M33_13 6
#define _M33_21 1
#define _M33_22 4
#define _M33_23 7
#define _M33_31 2
#define _M33_32 5
#define _M33_33 8
typedef struct {
float m[9];
} MATRIX33;
static inline MATRIX33 matrix33(float m11, float m12, float m13,
float m21, float m22, float m23,
float m31, float m32, float m33);
static inline void matrix33_set(MATRIX33 *m,
float m11, float m12, float m13,
float m21, float m22, float m23,
float m31, float m32, float m33);
static inline MATRIX33 matrix33_from_euler_angles(float x, float y, float z);
static inline MATRIX33 matrix33_rotation_x(float radians);
static inline MATRIX33 matrix33_rotation_y(float radians);
static inline MATRIX33 matrix33_rotation_z(float radians);
static inline MATRIX33 matrix33_add(MATRIX33 a, MATRIX33 b);
static inline MATRIX33 matrix33_sub(MATRIX33 a, MATRIX33 b);
static inline MATRIX33 matrix33_mul(MATRIX33 a, MATRIX33 b);
static inline MATRIX33 matrix33_scale(MATRIX33 m, float scale);
static inline float matrix33_determinant(MATRIX33 m);
static inline MATRIX33 matrix33_inverse(MATRIX33 m);
static inline MATRIX33 matrix33_transpose(MATRIX33 m);
static inline VECTOR2F matrix33_transform(MATRIX33 m, VECTOR2F v);
static inline MATRIX33 matrix33_translation_2d(float x, float y);
static inline MATRIX33 matrix33_scaling_2d(float x, float y);
static inline MATRIX33 matrix33_rotation_2d(float radians);
static inline VECTOR2F matrix33_transform_2d(MATRIX33 m, VECTOR2F v);
#define IDENTITY_MATRIX33 matrix33(1.0f, 0.0f, 0.0f, \
0.0f, 1.0f, 0.0f, \
0.0f, 0.0f, 1.0f)
// --------------------------------------------------------------------------
static inline MATRIX33 matrix33(float m11, float m12, float m13,
float m21, float m22, float m23,
float m31, float m32, float m33) {
MATRIX33 result;
result.m[_M33_11] = m11;
result.m[_M33_12] = m12;
result.m[_M33_13] = m13;
result.m[_M33_21] = m21;
result.m[_M33_22] = m22;
result.m[_M33_23] = m23;
result.m[_M33_31] = m31;
result.m[_M33_32] = m32;
result.m[_M33_33] = m33;
return result;
}
static inline void matrix33_set(MATRIX33 *m,
float m11, float m12, float m13,
float m21, float m22, float m23,
float m31, float m32, float m33) {
m->m[_M33_11] = m11;
m->m[_M33_12] = m12;
m->m[_M33_13] = m13;
m->m[_M33_21] = m21;
m->m[_M33_22] = m22;
m->m[_M33_23] = m23;
m->m[_M33_31] = m31;
m->m[_M33_32] = m32;
m->m[_M33_33] = m33;
}
static inline MATRIX33 matrix33_from_euler_angles(float x, float y, float z) {
MATRIX33 rx, ry, rz;
rx = matrix33_rotation_x(x);
ry = matrix33_rotation_y(y);
rz = matrix33_rotation_z(z);
return matrix33_mul(matrix33_mul(rz, ry), rx);
}
static inline MATRIX33 matrix33_rotation_x(float radians) {
MATRIX33 result;
float s, c;
s = sin(radians);
c = cos(radians);
result.m[_M33_11] = 1.0f;
result.m[_M33_12] = 0.0f;
result.m[_M33_13] = 0.0f;
result.m[_M33_21] = 0.0f;
result.m[_M33_22] = c;
result.m[_M33_23] = -s;
result.m[_M33_31] = 0.0f;
result.m[_M33_32] = s;
result.m[_M33_33] = c;
return result;
}
static inline MATRIX33 matrix33_rotation_y(float radians) {
MATRIX33 result;
float s, c;
s = sin(radians);
c = cos(radians);
result.m[_M33_11] = c;
result.m[_M33_12] = 0.0f;
result.m[_M33_13] = s;
result.m[_M33_21] = 0.0f;
result.m[_M33_22] = 1.0f;
result.m[_M33_23] = 0.0f;
result.m[_M33_31] = -s;
result.m[_M33_32] = 0.0f;
result.m[_M33_33] = c;
return result;
}
static inline MATRIX33 matrix33_rotation_z(float radians) {
MATRIX33 result;
float s, c;
s = sin(radians);
c = cos(radians);
result.m[_M33_11] = c;
result.m[_M33_12] = -s;
result.m[_M33_13] = 0.0f;
result.m[_M33_21] = s;
result.m[_M33_22] = c;
result.m[_M33_23] = 0.0f;
result.m[_M33_31] = 0.0f;
result.m[_M33_32] = 0.0f;
result.m[_M33_33] = 1.0f;
return result;
}
static inline MATRIX33 matrix33_add(MATRIX33 a, MATRIX33 b) {
MATRIX33 result;
result.m[_M33_11] = a.m[_M33_11] + b.m[_M33_11];
result.m[_M33_12] = a.m[_M33_12] + b.m[_M33_12];
result.m[_M33_13] = a.m[_M33_13] + b.m[_M33_13];
result.m[_M33_21] = a.m[_M33_21] + b.m[_M33_21];
result.m[_M33_22] = a.m[_M33_22] + b.m[_M33_22];
result.m[_M33_23] = a.m[_M33_23] + b.m[_M33_23];
result.m[_M33_31] = a.m[_M33_31] + b.m[_M33_31];
result.m[_M33_32] = a.m[_M33_32] + b.m[_M33_32];
result.m[_M33_33] = a.m[_M33_33] + b.m[_M33_33];
return result;
}
static inline MATRIX33 matrix33_sub(MATRIX33 a, MATRIX33 b) {
MATRIX33 result;
result.m[_M33_11] = a.m[_M33_11] - b.m[_M33_11];
result.m[_M33_12] = a.m[_M33_12] - b.m[_M33_12];
result.m[_M33_13] = a.m[_M33_13] - b.m[_M33_13];
result.m[_M33_21] = a.m[_M33_21] - b.m[_M33_21];
result.m[_M33_22] = a.m[_M33_22] - b.m[_M33_22];
result.m[_M33_23] = a.m[_M33_23] - b.m[_M33_23];
result.m[_M33_31] = a.m[_M33_31] - b.m[_M33_31];
result.m[_M33_32] = a.m[_M33_32] - b.m[_M33_32];
result.m[_M33_33] = a.m[_M33_33] - b.m[_M33_33];
return result;
}
static inline MATRIX33 matrix33_mul(MATRIX33 a, MATRIX33 b) {
MATRIX33 result;
result.m[_M33_11] = a.m[_M33_11] * b.m[_M33_11] + a.m[_M33_12] * b.m[_M33_21] + a.m[_M33_13] * b.m[_M33_31];
result.m[_M33_12] = a.m[_M33_11] * b.m[_M33_12] + a.m[_M33_12] * b.m[_M33_22] + a.m[_M33_13] * b.m[_M33_32];
result.m[_M33_13] = a.m[_M33_11] * b.m[_M33_13] + a.m[_M33_12] * b.m[_M33_23] + a.m[_M33_13] * b.m[_M33_33];
result.m[_M33_21] = a.m[_M33_21] * b.m[_M33_11] + a.m[_M33_22] * b.m[_M33_21] + a.m[_M33_23] * b.m[_M33_31];
result.m[_M33_22] = a.m[_M33_21] * b.m[_M33_12] + a.m[_M33_22] * b.m[_M33_22] + a.m[_M33_23] * b.m[_M33_32];
result.m[_M33_23] = a.m[_M33_21] * b.m[_M33_13] + a.m[_M33_22] * b.m[_M33_23] + a.m[_M33_23] * b.m[_M33_33];
result.m[_M33_31] = a.m[_M33_31] * b.m[_M33_11] + a.m[_M33_32] * b.m[_M33_21] + a.m[_M33_33] * b.m[_M33_31];
result.m[_M33_32] = a.m[_M33_31] * b.m[_M33_12] + a.m[_M33_32] * b.m[_M33_22] + a.m[_M33_33] * b.m[_M33_32];
result.m[_M33_33] = a.m[_M33_31] * b.m[_M33_13] + a.m[_M33_32] * b.m[_M33_23] + a.m[_M33_33] * b.m[_M33_33];
return result;
}
static inline MATRIX33 matrix33_scale(MATRIX33 m, float scale) {
MATRIX33 result;
result.m[_M33_11] = m.m[_M33_11] * scale;
result.m[_M33_12] = m.m[_M33_12] * scale;
result.m[_M33_13] = m.m[_M33_13] * scale;
result.m[_M33_21] = m.m[_M33_21] * scale;
result.m[_M33_22] = m.m[_M33_22] * scale;
result.m[_M33_23] = m.m[_M33_23] * scale;
result.m[_M33_31] = m.m[_M33_31] * scale;
result.m[_M33_32] = m.m[_M33_32] * scale;
result.m[_M33_33] = m.m[_M33_33] * scale;
return result;
}
static inline float matrix33_determinant(MATRIX33 m) {
return
m.m[_M33_11] * m.m[_M33_22] * m.m[_M33_33] +
m.m[_M33_12] * m.m[_M33_23] * m.m[_M33_31] +
m.m[_M33_13] * m.m[_M33_21] * m.m[_M33_32] -
m.m[_M33_11] * m.m[_M33_23] * m.m[_M33_32] -
m.m[_M33_12] * m.m[_M33_21] * m.m[_M33_33] -
m.m[_M33_13] * m.m[_M33_22] * m.m[_M33_31];
}
static inline MATRIX33 matrix33_inverse(MATRIX33 m) {
float d;
MATRIX33 result;
d = matrix33_determinant(m);
if (close_enough(d, 0.0f, TOLERANCE))
return IDENTITY_MATRIX33;
else {
d = 1.0f / d;
result.m[_M33_11] = d * (m.m[_M33_22] * m.m[_M33_33] - m.m[_M33_32] * m.m[_M33_23]);
result.m[_M33_21] = d * (m.m[_M33_31] * m.m[_M33_23] - m.m[_M33_21] * m.m[_M33_33]);
result.m[_M33_31] = d * (m.m[_M33_21] * m.m[_M33_32] - m.m[_M33_31] * m.m[_M33_22]);
result.m[_M33_21] = d * (m.m[_M33_32] * m.m[_M33_13] - m.m[_M33_12] * m.m[_M33_33]);
result.m[_M33_22] = d * (m.m[_M33_11] * m.m[_M33_33] - m.m[_M33_31] * m.m[_M33_13]);
result.m[_M33_23] = d * (m.m[_M33_31] * m.m[_M33_12] - m.m[_M33_11] * m.m[_M33_32]);
result.m[_M33_31] = d * (m.m[_M33_12] * m.m[_M33_23] - m.m[_M33_22] * m.m[_M33_13]);
result.m[_M33_32] = d * (m.m[_M33_21] * m.m[_M33_13] - m.m[_M33_11] * m.m[_M33_23]);
result.m[_M33_33] = d * (m.m[_M33_11] * m.m[_M33_22] - m.m[_M33_21] * m.m[_M33_12]);
return result;
}
}
static inline MATRIX33 matrix33_transpose(MATRIX33 m) {
MATRIX33 result;
result.m[_M33_11] = m.m[_M33_11];
result.m[_M33_12] = m.m[_M33_21];
result.m[_M33_13] = m.m[_M33_31];
result.m[_M33_21] = m.m[_M33_12];
result.m[_M33_22] = m.m[_M33_22];
result.m[_M33_23] = m.m[_M33_32];
result.m[_M33_31] = m.m[_M33_13];
result.m[_M33_32] = m.m[_M33_23];
result.m[_M33_33] = m.m[_M33_33];
return result;
}
static inline VECTOR2F matrix33_transform(MATRIX33 m, VECTOR2F v) {
VECTOR2F result;
result.x = v.x * m.m[_M33_11] + v.y * m.m[_M33_12] + m.m[_M33_13];
result.y = v.x * m.m[_M33_21] + v.y * m.m[_M33_22] + m.m[_M33_23];
return result;
}
static inline MATRIX33 matrix33_translation_2d(float x, float y) {
MATRIX33 result;
result.m[_M33_11] = 1.0f;
result.m[_M33_12] = 0.0f;
result.m[_M33_13] = 0.0f;
result.m[_M33_21] = 0.0f;
result.m[_M33_22] = 1.0f;
result.m[_M33_23] = 0.0f;
result.m[_M33_31] = x;
result.m[_M33_32] = y;
result.m[_M33_33] = 1.0f;
return result;
}
static inline MATRIX33 matrix33_scaling_2d(float x, float y) {
MATRIX33 result;
result.m[_M33_11] = x;
result.m[_M33_12] = 0.0f;
result.m[_M33_13] = 0.0f;
result.m[_M33_21] = 0.0f;
result.m[_M33_22] = y;
result.m[_M33_23] = 0.0f;
result.m[_M33_31] = 0.0f;
result.m[_M33_32] = 0.0f;
result.m[_M33_33] = 1.0f;
return result;
}
static inline MATRIX33 matrix33_rotation_2d(float radians) {
return matrix33_rotation_z(radians);
}
static inline VECTOR2F matrix33_transform_2d(MATRIX33 m, VECTOR2F v) {
VECTOR2F result;
result.x = v.x * m.m[_M33_11] + v.y * m.m[_M33_12] + m.m[_M33_13];
result.y = v.x * m.m[_M33_21] + v.y * m.m[_M33_22] + m.m[_M33_23];
result.x += m.m[_M33_31];
result.y += m.m[_M33_32];
return result;
}
#endif

188
MOUSE.C Normal file
View file

@ -0,0 +1,188 @@
#include "mouse.h"
#include "internal.h"
#include "error.h"
#include <string.h>
#include <go32.h>
static boolean _installed = FALSE;
static boolean _has_mouse = FALSE;
volatile int mouse_x;
volatile int mouse_y;
volatile int mouse_buttons;
volatile int mouse_delta_x;
volatile int mouse_delta_y;
__dpmi_regs _mouse_regs;
_go32_dpmi_seginfo _mouse_seg_info;
static void reset_mouse_state(void) {
mouse_x = 0;
mouse_y = 0;
mouse_buttons = 0;
mouse_delta_x = 0;
mouse_delta_y = 0;
}
static boolean init_mouse_driver(void) {
__dpmi_regs regs;
memset(&regs, 0, sizeof(__dpmi_regs));
regs.x.ax = 0x00;
__dpmi_int(0x33, &regs);
return (regs.x.ax != 0);
}
static void update_mouse_state(void) {
__dpmi_regs regs;
memset(&regs, 0, sizeof(__dpmi_regs));
regs.x.ax = 0x03;
__dpmi_int(0x33, &regs);
mouse_x = (regs.x.cx / 2);
mouse_y = regs.x.dx;
mouse_buttons = regs.x.bx;
mouse_delta_x = 0;
mouse_delta_y = 0;
}
void mouse_int_handler(__dpmi_regs* regs) {
mouse_delta_x = (regs->x.cx / 2) - mouse_x;
mouse_delta_y = regs->x.dx - mouse_y;
mouse_x = (regs->x.cx / 2);
mouse_y = regs->x.dx;
mouse_buttons = regs->x.bx;
}
END_OF_FUNCTION(mouse_int_handler)
boolean mouse_init(void) {
__dpmi_regs regs;
if (_installed) {
dgl_set_error(DGL_MOUSE_ALREADY_INITIALIZED);
return FALSE;
}
reset_mouse_state();
_has_mouse = init_mouse_driver();
if (!_has_mouse) {
_installed = TRUE;
return TRUE;
}
LOCK_FUNCTION(mouse_int_handler);
LOCK_VARIABLE(_mouse_regs);
LOCK_VARIABLE(_mouse_seg_info);
LOCK_VARIABLE(mouse_x);
LOCK_VARIABLE(mouse_y);
LOCK_VARIABLE(mouse_buttons);
LOCK_VARIABLE(mouse_delta_x);
LOCK_VARIABLE(mouse_delta_y);
memset(&_mouse_regs, 0, sizeof(__dpmi_regs));
memset(&_mouse_seg_info, 0, sizeof(_go32_dpmi_seginfo));
_mouse_seg_info.pm_offset = (int)mouse_int_handler;
_mouse_seg_info.pm_selector = _go32_my_cs();
if (_go32_dpmi_allocate_real_mode_callback_retf(&_mouse_seg_info, &_mouse_regs) != 0) {
dgl_set_error(DGL_MOUSE_ALLOCATE_CALLBACK_FAILURE);
return FALSE;
}
update_mouse_state();
memset(&regs, 0, sizeof(__dpmi_regs));
regs.x.ax = 0x0c;
regs.x.cx = 0x7f;
regs.x.dx = _mouse_seg_info.rm_offset;
regs.x.es = _mouse_seg_info.rm_segment;
if (__dpmi_int(0x33, &regs) != 0) {
dgl_set_error(DGL_MOUSE_INT_CALLBACK_SET_FAILURE);
return FALSE;
}
_installed = TRUE;
return TRUE;
}
boolean mouse_shutdown(void) {
__dpmi_regs regs;
if (!_installed)
return TRUE; // don't care
if (!_has_mouse) {
_installed = FALSE;
return TRUE;
}
memset(&regs, 0, sizeof(__dpmi_regs));
regs.x.ax = 0x0c;
regs.x.cx = 0;
regs.x.dx = 0;
regs.x.es = 0;
if (__dpmi_int(0x33, &regs) != 0) {
dgl_set_error(DGL_MOUSE_INT_CALLBACK_RESTORE_FAILURE);
return FALSE;
}
if (_go32_dpmi_free_real_mode_callback(&_mouse_seg_info) != 0)
dgl_set_error(DGL_MOUSE_FREE_CALLBACK_FAILURE);
reset_mouse_state();
_installed = FALSE;
return TRUE;
}
boolean mouse_is_initialized(void) {
return _installed;
}
boolean mouse_is_present(void) {
return _has_mouse;
}
void mouse_show(void) {
__dpmi_regs regs;
if (!_has_mouse)
return;
memset(&regs, 0, sizeof(__dpmi_regs));
regs.x.ax = 0x01;
__dpmi_int(0x33, &regs);
}
void mouse_hide(void) {
__dpmi_regs regs;
if (!_has_mouse)
return;
memset(&regs, 0, sizeof(__dpmi_regs));
regs.x.ax = 0x02;
__dpmi_int(0x33, &regs);
}
void mouse_set_bounds(int min_x, int min_y, int max_x, int max_y) {
__dpmi_regs regs;
if (!_has_mouse)
return;
memset(&regs, 0, sizeof(__dpmi_regs));
regs.x.ax = 0x07;
regs.x.cx = min_x;
regs.x.dx = max_x;
__dpmi_int(0x33, &regs);
regs.x.ax = 0x08;
regs.x.cx = min_y;
regs.x.dx = max_y;
__dpmi_int(0x33, &regs);
}

92
MOUSE.H Normal file
View file

@ -0,0 +1,92 @@
#ifndef DGL_MOUSE_H_INCLUDED
#define DGL_MOUSE_H_INCLUDED
#include "common.h"
#define MOUSE_LEFTBUTTON 0x01
#define MOUSE_RIGHTBUTTON 0x02
#define MOUSE_CENTERBUTTON 0x04
/*
* Current mouse cursor X position.
*/
volatile extern int mouse_x;
/*
* Current mouse cursor Y position.
*/
volatile extern int mouse_y;
/*
* Current state of mouse buttons.
*/
volatile extern int mouse_buttons;
/*
* Amount the cursor moved along the X-axis since the last update.
*/
volatile extern int mouse_delta_x;
/*
* Amount the cursor moved along the Y-axis since the last update.
*/
volatile extern int mouse_delta_y;
/*
* Installs a custom mouse handler.
* @return TRUE on success
*/
boolean mouse_init(void);
/*
* Removes a previously installed mouse handler.
* @return TRUE on success
*/
boolean mouse_shutdown(void);
/*
* @return TRUE if the custom mouse handler is installed.
*/
boolean mouse_is_initialized(void);
/*
* @return TRUE if the user's computer has a (recognized) mouse connected.
*/
boolean mouse_is_present(void);
/*
* Shows the mouse cursor. If the mouse cursor is currently shown, this does
* nothing.
*/
void mouse_show(void);
/*
* Hides the mouse cursor. If the mouse cursor is not currently shown, this
* does nothing.
*/
void mouse_hide(void);
/*
* Sets the pixel boundaries for the mouse cursor.
* @param min_x left coordinate
* @param max_x right coordinate
* @param min_y top coordinate
* @param max_y bottom coordinate
*/
void mouse_set_bounds(int min_x, int min_y, int max_x, int max_y);
/*
* Returns the current status of the specified button.
* @param button The button to check the status of.
* @return TRUE if the button is pressed.
*/
static inline boolean mouse_button(int button);
// --------------------------------------------------------------------------
static inline boolean mouse_button(int button) {
return (mouse_buttons & button) != 0;
}
#endif

223
PCX.C Normal file
View file

@ -0,0 +1,223 @@
#include "pcx.h"
#include "gfx.h"
#include "draw.h"
#include "error.h"
#include <stdio.h>
typedef struct {
byte manufacturer;
byte version;
byte encoding;
byte bpp;
word x;
word y;
word width;
word height;
word horizontal_dpi;
word vertical_dpi;
byte ega_palette[48];
byte reserved;
byte num_color_planes;
word bytes_per_line;
word palette_type;
word horizontal_size;
word vertical_size;
byte padding[54];
} PCX_HEADER;
SURFACE* pcx_load(const char *filename, byte *pcx_palette) {
FILE *fp;
PCX_HEADER header;
int i, n, count;
SURFACE *pcx;
ubyte data;
fp = fopen(filename, "rb");
if (!fp) {
dgl_set_error(DGL_IO_ERROR);
return NULL;
}
n = fread(&header, sizeof(PCX_HEADER), 1, fp);
if (n == -1) {
dgl_set_error(DGL_IO_ERROR);
fclose(fp);
return NULL;
}
if (header.manufacturer != 10 ||
header.version != 5 ||
header.encoding != 1 ||
header.bpp != 8) {
dgl_set_error(DGL_PCX_BAD_FORMAT);
fclose(fp);
return NULL;
}
pcx = surface_create(header.width + 1, header.height + 1);
// read pixel data
i = 0;
while (i < (header.width * header.height)) {
n = fread(&data, 1, 1, fp);
if (n == -1)
goto pcx_load_error;
if (data >= 192) {
count = data - 192;
n = fread(&data, 1, 1, fp);
if (n == -1)
goto pcx_load_error;
while (count > 0) {
pcx->pixels[i++] = data;
count--;
}
} else {
pcx->pixels[i++] = data;
}
}
// read palette (only if needed)
if (pcx_palette) {
fseek(fp, -768, SEEK_END);
n = fread(pcx_palette, 768, 1, fp);
if (n == -1)
goto pcx_load_error;
for (i = 0; i < 768; ++i)
pcx_palette[i] >>= 2;
}
fclose(fp);
return pcx;
pcx_load_error:
dgl_set_error(DGL_PCX_BAD_FORMAT);
surface_free(pcx);
fclose(fp);
return NULL;
}
static inline boolean write_pcx_data(FILE *fp, int run_count, byte pixel) {
int n;
if ((run_count > 1) || ((pixel & 0xc0) == 0xc0)) {
n = fputc(0xc0 | run_count, fp);
if (n == -1)
return FALSE;
}
n = fputc(pixel, fp);
if (n == -1)
return FALSE;
return TRUE;
}
boolean pcx_save(const char *filename, const SURFACE *src, const byte *palette) {
FILE *fp;
int i, n, x, y;
int run_count;
byte pixel, run_pixel;
byte r, g, b;
boolean result;
PCX_HEADER header;
fp = fopen(filename, "wb");
if (!fp) {
dgl_set_error(DGL_IO_ERROR);
return FALSE;
}
memset(&header, 0, sizeof(PCX_HEADER));
header.manufacturer = 10;
header.version = 5;
header.encoding = 1;
header.bpp = 8;
header.x = 0;
header.y = 0;
header.width = src->width - 1;
header.height = src->height - 1;
header.horizontal_dpi = 0;
header.vertical_dpi = 0;
header.num_color_planes = 1;
header.bytes_per_line = src->width;
header.palette_type = 1;
header.horizontal_size = 320;
header.vertical_size = 200;
n = fwrite(&header, sizeof(PCX_HEADER), 1, fp);
if (n == -1)
goto pcx_save_error;
// write image data
i = 0;
for (y = 0; y < src->height; ++y) {
// write one scanline at a time (breaking runs that could have
// continue across scanlines in the process... as per pcx standard)
run_count = 0;
run_pixel = 0;
for (x = 0; x < src->width; ++x) {
pixel = src->pixels[i];
++i;
if (run_count == 0) {
run_count = 1;
run_pixel = pixel;
} else {
if ((pixel != run_pixel) || (run_count >= 63)) {
result = write_pcx_data(fp, run_count, run_pixel);
if (!result)
goto pcx_save_error;
run_count = 1;
run_pixel = pixel;
} else {
++run_count;
}
}
}
// end the scanline, writing out whatever run we might have had going
result = write_pcx_data(fp, run_count, run_pixel);
if (!result)
goto pcx_save_error;
}
fputc(12, fp);
// use provided palette, otherwise use current vga palette
if (palette) {
for (i = 0; i < 768; ++i) {
n = fputc(palette[i] << 2, fp);
if (n == -1)
goto pcx_save_error;
}
} else {
for (i = 0; i < 256; ++i) {
video_get_color(i, &r, &g, &b);
n = fputc(r << 2, fp);
if (n == -1)
goto pcx_save_error;
n = fputc(g << 2, fp);
if (n == -1)
goto pcx_save_error;
n = fputc(b << 2, fp);
if (n == -1)
goto pcx_save_error;
}
}
fclose(fp);
return TRUE;
pcx_save_error:
dgl_set_error(DGL_IO_ERROR);
fclose(fp);
return FALSE;
}

11
PCX.H Normal file
View file

@ -0,0 +1,11 @@
#ifndef DGL_PCX_H_INCLUDED
#define DGL_PCX_H_INCLUDED
#include "common.h"
#include "gfx.h"
SURFACE* pcx_load(const char *filename, byte *pcx_palette);
boolean pcx_save(const char *filename, const SURFACE *src, const byte *palette);
#endif

58
README.md Normal file
View file

@ -0,0 +1,58 @@
# libDGL
libDGL is a "retro coding" C library aimed at MS-DOS [VGA Mode 13h](https://en.wikipedia.org/wiki/Mode_13h) game development. It is developed with DJGPP with 486 DX2 systems as a baseline target for performance.
### Why?
Because it's fun.
If you were looking for something for "retro" MS-DOS game development that is fully featured, really performant and bug-tested that's ready right now, have a look at Allegro 3.x or possibly 4.x depending on what hardware you're targetting.
### Status
This library is currently under early development and is lacking many things and probably chock-full of bugs.
**Done / Mostly Done**
* Primitive drawing support
* Text rendering
* Blitting
* Graphics clipping
* Keyboard input
* Mouse input
* PCX loading/saving
* Math library (general helpers, 2D vector, 3x3 matrix)
* Basic error handling / results
**TODO**
* Scaled/rotated blitting support
* Blending
* "Mode 7" like support
* Custom font loading (BIOS-like format?)
* Joystick / Gravis GamePad support
* PC speaker sounds
* Sound Blaster compatible sound/music
* Gravis Ultrasound compatible sound/music
* Fixed point math
* Sine/cosine lookup table optimizations
* BMP, LBM, GIF image loading (and saving?)
### DJGPP Toolchain
Along the same theme as this library itself, I am using an older version of DJGPP from the late 90's. I have not tested with any other versions of the DJGPP toolchain other than:
```
15 Jan 1998 bnu281b.zip
24 Oct 1997 csdpmi4b.zip
31 Oct 1996 djdev201.zip
18 Jan 1997 faq210b.zip
6 Jun 1998 gcc281b.zip
18 Oct 1996 gdb416b.zip
6 Jun 1998 gpp281b.zip
1 Mar 1998 mak3761b.zip
30 Sep 1997 rhide14b.zip
```
This is a pretty arbitrary selection that was based on a cut-off of about 1998 (which was when I first came across DJGPP when I was younger).

41
RECT.H Normal file
View file

@ -0,0 +1,41 @@
#ifndef DGL_RECT_H_INCLUDED
#define DGL_RECT_H_INCLUDED
typedef struct {
int x;
int y;
int width;
int height;
} RECT;
static inline RECT rect(int x, int y, int width, int height);
static inline int rect_right(const RECT *r);
static inline int rect_bottom(const RECT *r);
// --------------------------------------------------------------------------
static inline RECT rect(int x, int y, int width, int height) {
RECT result;
result.x = x;
result.y = y;
result.width = width;
result.height = height;
return result;
}
static inline int rect_right(const RECT *r) {
if (r->width)
return r->x + r->width - 1;
else
return r->x;
}
static inline int rect_bottom(const RECT *r) {
if (r->height)
return r->y + r->height - 1;
else
return r->y;
}
#endif

35
TEST.C Normal file
View file

@ -0,0 +1,35 @@
#include <stdio.h>
#include <time.h>
#include "dgl.h"
int main(void) {
SURFACE *backbuffer;
if (!dgl_init()) {
printf("Failed to initialize DGL: %s\n", dgl_last_error_message());
return 1;
}
backbuffer = surface_create(320, 200);
while (!keys[KEY_ESC]) {
surface_clear(backbuffer, 0);
surface_text(backbuffer, 100, 100, 15, "Hello, world!");
video_wait_vsync();
surface_copy(backbuffer, screen);
}
surface_free(backbuffer);
if (!dgl_shutdown()) {
printf("Failed to close DGL: %s\n", dgl_last_error_message());
return 1;
}
return 0;
}

37
UTIL.C Normal file
View file

@ -0,0 +1,37 @@
#include "util.h"
#include <stdlib.h>
#include <time.h>
#include <sys/nearptr.h>
#define SYS_CLOCKS_PER_SEC (1000.0f / 55.0f)
void* map_dos_memory(long physical_addr) {
return (void*)(__djgpp_conventional_base + physical_addr);
}
int sys_clock() {
//return *((int*)(map_dos_memory(0x046c)));
return (int)clock();
}
int sys_ticks() {
return (int)uclock();
}
float clock_ticks_to_seconds(int clocks) {
//return clocks / SYS_CLOCKS_PER_SEC;
return clocks / (float)CLOCKS_PER_SEC;
}
float ticks_to_seconds(int ticks) {
return (float)ticks / UCLOCKS_PER_SEC;
}
int rnd_int(int low, int high) {
return rand() % ((high - low) + 1) + low;
}
float rnd_float(float low, float high) {
return low + (rand() / (float)RAND_MAX) * (high - low);
}

26
UTIL.H Normal file
View file

@ -0,0 +1,26 @@
#ifndef DGL_UTIL_H_INCLUDED
#define DGL_UTIL_H_INCLUDED
#include "common.h"
#define SWAP(type, a, b) \
do { \
type __tmp = a; \
a = b; \
b = __tmp; \
} while (0)
#define SIGN(x) (((x) < 0) ? -1 : (((x) > 0) ? 1 : 0))
void* map_dos_memory(long physical_addr);
int sys_clock();
int sys_ticks();
float clock_ticks_to_seconds(int clocks);
float ticks_to_seconds(int ticks);
int rnd_int(int low, int high);
float rnd_float(float low, float high);
#endif

284
VECTOR2.H Normal file
View file

@ -0,0 +1,284 @@
#ifndef DGL_VECTOR2_H_INCLUDED
#define DGL_VECTOR2_H_INCLUDED
#include <math.h>
#include "common.h"
typedef struct {
int x;
int y;
} VECTOR2I;
static inline VECTOR2I vector2i(int x, int y);
static inline void vector2i_set(VECTOR2I *v, int x, int y);
static inline boolean vector2i_equals(VECTOR2I a, VECTOR2I b);
static inline VECTOR2I vector2i_add(VECTOR2I a, VECTOR2I b);
static inline VECTOR2I vector2i_sub(VECTOR2I a, VECTOR2I b);
static inline VECTOR2I vector2i_mul(VECTOR2I a, VECTOR2I b);
static inline VECTOR2I vector2i_muls(VECTOR2I v, int n);
static inline VECTOR2I vector2i_div(VECTOR2I a, VECTOR2I b);
static inline VECTOR2I vector2i_divs(VECTOR2I v, int n);
static inline int vector2i_distance(VECTOR2I a, VECTOR2I b);
static inline int vector2i_distancesq(VECTOR2I a, VECTOR2I b);
static inline int vector2i_dot(VECTOR2I a, VECTOR2I b);
static inline int vector2i_length(VECTOR2I v);
static inline int vector2i_lengthsq(VECTOR2I v);
static inline VECTOR2I vector2i_lerp(VECTOR2I a, VECTOR2I b, float lerp);
#define ZERO_VECTOR2I vector2i(0, 0)
#define UP_VECTOR2I vector2i(0, -1);
#define DOWN_VECTOR2I vector2i(0, 1);
#define LEFT_VECTOR2I vector2i(-1, 0);
#define RIGHT_VECTOR2I vector2i(1, 0);
#define UNIT_X_VECTOR2I vector2i(1, 0);
#define UNIT_Y_VECTOR2I vector2i(0, 1);
typedef struct {
float x;
float y;
} VECTOR2F;
static inline VECTOR2F vector2f(float x, float y);
static inline void vector2f_set(VECTOR2F *v, float x, float y);
static inline boolean vector2f_equals(VECTOR2F a, VECTOR2F b);
static inline VECTOR2F vector2f_add(VECTOR2F a, VECTOR2F b);
static inline VECTOR2F vector2f_sub(VECTOR2F a, VECTOR2F b);
static inline VECTOR2F vector2f_mul(VECTOR2F a, VECTOR2F b);
static inline VECTOR2F vector2f_muls(VECTOR2F v, float n);
static inline VECTOR2F vector2f_div(VECTOR2F a, VECTOR2F b);
static inline VECTOR2F vector2f_divs(VECTOR2F v, float n);
static inline float vector2f_distance(VECTOR2F a, VECTOR2F b);
static inline float vector2f_distancesq(VECTOR2F a, VECTOR2F b);
static inline float vector2f_dot(VECTOR2F a, VECTOR2F b);
static inline float vector2f_length(VECTOR2F v);
static inline float vector2f_lengthsq(VECTOR2F v);
static inline VECTOR2F vector2f_normalize(VECTOR2F v);
static inline VECTOR2F vector2f_set_length(VECTOR2F v, float length);
static inline VECTOR2F vector2f_lerp(VECTOR2F a, VECTOR2F b, float lerp);
#define ZERO_VECTOR2F vector2f(0.0f, 0.0f)
#define UP_VECTOR2F vector2f(0.0f, -1.0f);
#define DOWN_VECTOR2F vector2f(0.0f, 1.0f);
#define LEFT_VECTOR2F vector2f(-1.0f, 0.0f);
#define RIGHT_VECTOR2F vector2f(1.0f, 0.0f);
#define UNIT_X_VECTOR2F vector2f(1.0f, 0.0f);
#define UNIT_Y_VECTOR2F vector2f(0.0f, 1.0f);
// --------------------------------------------------------------------------
static inline VECTOR2I vector2i(int x, int y) {
VECTOR2I v;
v.x = x;
v.y = y;
return v;
}
static inline VECTOR2F vector2f(float x, float y) {
VECTOR2F v;
v.x = x;
v.y = y;
return v;
}
static inline void vector2i_set(VECTOR2I *v, int x, int y) {
v->x = x;
v->y = y;
}
static inline void vector2f_set(VECTOR2F *v, float x, float y) {
v->x = x;
v->y = y;
}
static inline boolean vector2i_equals(VECTOR2I a, VECTOR2I b) {
return (a.x == b.x && a.y == b.y);
}
static inline boolean vector2f_equals(VECTOR2F a, VECTOR2F b) {
return (a.x == b.x && a.y == b.y);
}
static inline VECTOR2I vector2i_add(VECTOR2I a, VECTOR2I b) {
VECTOR2I result;
result.x = a.x + b.x;
result.y = a.y + b.y;
return result;
}
static inline VECTOR2F vector2f_add(VECTOR2F a, VECTOR2F b) {
VECTOR2F result;
result.x = a.x + b.x;
result.y = a.y + b.y;
return result;
}
static inline VECTOR2I vector2i_sub(VECTOR2I a, VECTOR2I b) {
VECTOR2I result;
result.x = a.x - b.x;
result.y = a.y - b.y;
return result;
}
static inline VECTOR2F vector2f_sub(VECTOR2F a, VECTOR2F b) {
VECTOR2F result;
result.x = a.x - b.x;
result.y = a.y - b.y;
return result;
}
static inline VECTOR2I vector2i_mul(VECTOR2I a, VECTOR2I b) {
VECTOR2I result;
result.x = a.x * b.x;
result.y = a.y * b.y;
return result;
}
static inline VECTOR2F vector2f_mul(VECTOR2F a, VECTOR2F b) {
VECTOR2F result;
result.x = a.x * b.x;
result.y = a.y * b.y;
return result;
}
static inline VECTOR2I vector2i_muls(VECTOR2I v, int n) {
VECTOR2I result;
result.x = v.x * n;
result.y = v.y * n;
return result;
}
static inline VECTOR2F vector2f_muls(VECTOR2F v, float n) {
VECTOR2F result;
result.x = v.x * n;
result.y = v.y * n;
return result;
}
static inline VECTOR2I vector2i_div(VECTOR2I a, VECTOR2I b) {
VECTOR2I result;
result.x = a.x / b.x;
result.y = a.y / b.y;
return result;
}
static inline VECTOR2F vector2f_div(VECTOR2F a, VECTOR2F b) {
VECTOR2F result;
result.x = a.x / b.x;
result.y = a.y / b.y;
return result;
}
static inline VECTOR2I vector2i_divs(VECTOR2I v, int n) {
VECTOR2I result;
result.x = v.x / n;
result.y = v.y / n;
return result;
}
static inline VECTOR2F vector2f_divs(VECTOR2F v, float n) {
VECTOR2F result;
result.x = v.x / n;
result.y = v.y / n;
return result;
}
static inline int vector2i_distance(VECTOR2I a, VECTOR2I b) {
return (int)sqrt(
((b.x - a.x) * (b.x - a.x)) +
((b.y - a.y) * (b.y - a.y))
);
}
static inline float vector2f_distance(VECTOR2F a, VECTOR2F b) {
return (float)sqrt(
((b.x - a.x) * (b.x - a.x)) +
((b.y - a.y) * (b.y - a.y))
);
}
static inline int vector2i_distancesq(VECTOR2I a, VECTOR2I b) {
return
((b.x - a.x) * (b.x - a.x)) +
((b.y - a.y) * (b.y - a.y));
}
static inline float vector2f_distancesq(VECTOR2F a, VECTOR2F b) {
return
((b.x - a.x) * (b.x - a.x)) +
((b.y - a.y) * (b.y - a.y));
}
static inline int vector2i_dot(VECTOR2I a, VECTOR2I b) {
return
(a.x * b.x) +
(a.y * b.y);
}
static inline float vector2f_dot(VECTOR2F a, VECTOR2F b) {
return
(a.x * b.x) +
(a.y * b.y);
}
static inline int vector2i_length(VECTOR2I v) {
return sqrt(
(v.x * v.x) +
(v.y * v.y)
);
}
static inline float vector2f_length(VECTOR2F v) {
return (float)sqrt(
(v.x * v.x) +
(v.y * v.y)
);
}
static inline int vector2i_lengthsq(VECTOR2I v) {
return
(v.x * v.x) +
(v.y * v.y);
}
static inline float vector2f_lengthsq(VECTOR2F v) {
return
(v.x * v.x) +
(v.y * v.y);
}
static inline VECTOR2F vector2f_normalize(VECTOR2F v) {
float inverse_length;
VECTOR2F result;
inverse_length = 1.0f / vector2f_length(v);
result.x = v.x * inverse_length;
result.y = v.y * inverse_length;
return result;
}
static inline VECTOR2F vector2f_set_length(VECTOR2F v, float length) {
float scale_factor;
VECTOR2F result;
scale_factor = length / vector2f_length(v);
result.x = v.x * scale_factor;
result.y = v.y * scale_factor;
return result;
}
static inline VECTOR2I vector2i_lerp(VECTOR2I a, VECTOR2I b, float lerp) {
VECTOR2I result;
result.x = a.x + (b.x - a.x) * lerp;
result.y = a.y + (b.y - a.y) * lerp;
return result;
}
static inline VECTOR2F vector2f_lerp(VECTOR2F a, VECTOR2F b, float lerp) {
VECTOR2F result;
result.x = a.x + (b.x - a.x) * lerp;
result.y = a.y + (b.y - a.y) * lerp;
return result;
}
#endif