initial commit
This commit is contained in:
commit
e5415c977c
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
.DS_Store
|
||||||
|
*.exe
|
||||||
|
*.a
|
||||||
|
*.o
|
||||||
|
/dgl_test.gdt
|
||||||
|
/dgl_test.gpr
|
204
BLIT.C
Normal file
204
BLIT.C
Normal 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
67
BLIT.H
Normal 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
111
CLIPPING.C
Normal 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
39
CLIPPING.H
Normal 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
36
COMMON.H
Normal 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
106
DGL.C
Normal 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
24
DGL.H
Normal 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
365
DRAW.C
Normal 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
68
DRAW.H
Normal 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
31
ERROR.H
Normal 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
151
GFX.C
Normal 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(®s, 0, sizeof(__dpmi_regs));
|
||||||
|
regs.h.ah = 0x00;
|
||||||
|
regs.h.al = 0x13;
|
||||||
|
if (__dpmi_int(0x10, ®s)) {
|
||||||
|
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(®s, 0, sizeof(__dpmi_regs));
|
||||||
|
regs.h.ah = 0x00;
|
||||||
|
regs.h.al = 0x03;
|
||||||
|
if (__dpmi_int(0x10, ®s)) {
|
||||||
|
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
47
GFX.H
Normal 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
36
INTERNAL.C
Normal 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
60
INTERNAL.H
Normal 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
194
KEYBOARD.C
Normal 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
43
KEYBOARD.H
Normal 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
89
KEYS.H
Normal 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
BIN
LIBDGL.GDT
Normal file
Binary file not shown.
BIN
LIBDGL.GPR
Normal file
BIN
LIBDGL.GPR
Normal file
Binary file not shown.
34
MATHEXT.C
Normal file
34
MATHEXT.C
Normal 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
75
MATHEXT.H
Normal 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
340
MATRIX33.H
Normal 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
188
MOUSE.C
Normal 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(®s, 0, sizeof(__dpmi_regs));
|
||||||
|
regs.x.ax = 0x00;
|
||||||
|
__dpmi_int(0x33, ®s);
|
||||||
|
|
||||||
|
return (regs.x.ax != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_mouse_state(void) {
|
||||||
|
__dpmi_regs regs;
|
||||||
|
|
||||||
|
memset(®s, 0, sizeof(__dpmi_regs));
|
||||||
|
regs.x.ax = 0x03;
|
||||||
|
__dpmi_int(0x33, ®s);
|
||||||
|
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(®s, 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, ®s) != 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(®s, 0, sizeof(__dpmi_regs));
|
||||||
|
regs.x.ax = 0x0c;
|
||||||
|
regs.x.cx = 0;
|
||||||
|
regs.x.dx = 0;
|
||||||
|
regs.x.es = 0;
|
||||||
|
if (__dpmi_int(0x33, ®s) != 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(®s, 0, sizeof(__dpmi_regs));
|
||||||
|
regs.x.ax = 0x01;
|
||||||
|
__dpmi_int(0x33, ®s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mouse_hide(void) {
|
||||||
|
__dpmi_regs regs;
|
||||||
|
|
||||||
|
if (!_has_mouse)
|
||||||
|
return;
|
||||||
|
|
||||||
|
memset(®s, 0, sizeof(__dpmi_regs));
|
||||||
|
regs.x.ax = 0x02;
|
||||||
|
__dpmi_int(0x33, ®s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mouse_set_bounds(int min_x, int min_y, int max_x, int max_y) {
|
||||||
|
__dpmi_regs regs;
|
||||||
|
|
||||||
|
if (!_has_mouse)
|
||||||
|
return;
|
||||||
|
|
||||||
|
memset(®s, 0, sizeof(__dpmi_regs));
|
||||||
|
|
||||||
|
regs.x.ax = 0x07;
|
||||||
|
regs.x.cx = min_x;
|
||||||
|
regs.x.dx = max_x;
|
||||||
|
__dpmi_int(0x33, ®s);
|
||||||
|
|
||||||
|
regs.x.ax = 0x08;
|
||||||
|
regs.x.cx = min_y;
|
||||||
|
regs.x.dx = max_y;
|
||||||
|
__dpmi_int(0x33, ®s);
|
||||||
|
}
|
||||||
|
|
92
MOUSE.H
Normal file
92
MOUSE.H
Normal 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
223
PCX.C
Normal 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
11
PCX.H
Normal 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
58
README.md
Normal 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
41
RECT.H
Normal 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
35
TEST.C
Normal 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
37
UTIL.C
Normal 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
26
UTIL.H
Normal 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
284
VECTOR2.H
Normal 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
|
||||||
|
|
Loading…
Reference in a new issue