rayzor

changeset 0:2a5340a6eee4

rayzor first commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 05 Apr 2014 08:46:27 +0300
parents
children a826bf0fb169
files .hgignore Makefile src/camera.cc src/camera.h src/dpmi.c src/dpmi.h src/gfx.c src/gfx.h src/inttypes.h src/keyb.c src/keyb.h src/light.cc src/light.h src/logger.c src/logger.h src/m3dimpl.h src/main.cc src/min3d.c src/min3d.h src/mouse.c src/mouse.h src/object.cc src/object.h src/pit8254.h src/rend.cc src/rend.h src/scancode.h src/scene.cc src/scene.h src/timer.c src/timer.h src/vbe.c src/vbe.h src/vmath.cc src/vmath.h src/vmathmat.h
diffstat 36 files changed, 2199 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.hgignore	Sat Apr 05 08:46:27 2014 +0300
     1.3 @@ -0,0 +1,4 @@
     1.4 +\.o$
     1.5 +\.swp$
     1.6 +\.obj$
     1.7 +\.exe$
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/Makefile	Sat Apr 05 08:46:27 2014 +0300
     2.3 @@ -0,0 +1,29 @@
     2.4 +modelobj = main.obj min3d.obj logger.obj
     2.5 +rendobj = rend.obj vmath.obj
     2.6 +scnobj = scene.obj object.obj
     2.7 +sysobj = gfx.obj vbe.obj dpmi.obj timer.obj mouse.obj keyb.obj
     2.8 +obj = $(modelobj) $(rendobj) $(scnobj) $(sysobj)
     2.9 +bin = rayzor.exe
    2.10 +
    2.11 +CC = wcc386
    2.12 +CXX = wpp386
    2.13 +CFLAGS = -5 -fp5 -otexan -zq -bt=dos -Isrc\stl
    2.14 +CXXFLAGS = $(CFLAGS)
    2.15 +LD = wlink
    2.16 +
    2.17 +$(bin): $(obj)
    2.18 +	%write objects.lnk file { $(obj) }
    2.19 +	$(LD) name $@ @objects $(LDFLAGS)
    2.20 +
    2.21 +.c: src\
    2.22 +.cc: src\
    2.23 +
    2.24 +.c.obj: .autodepend
    2.25 +	$(CC) $(CFLAGS) $[*
    2.26 +
    2.27 +.cc.obj: .autodepend
    2.28 +	$(CXX) $(CXXFLAGS) $[*
    2.29 +
    2.30 +clean: .symbolic
    2.31 +	del *.obj
    2.32 +	del $(bin)
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/camera.cc	Sat Apr 05 08:46:27 2014 +0300
     3.3 @@ -0,0 +1,50 @@
     3.4 +#include "camera.h"
     3.5 +
     3.6 +Camera::Camera()
     3.7 +	: pos(0, 0, 10)
     3.8 +{
     3.9 +	fov = M_PI;
    3.10 +}
    3.11 +
    3.12 +void Camera::set_position(const Vector3 &pos)
    3.13 +{
    3.14 +	this->pos = pos;
    3.15 +}
    3.16 +
    3.17 +const Vector3 &Camera::get_position() const
    3.18 +{
    3.19 +	return pos;
    3.20 +}
    3.21 +
    3.22 +void Camera::set_target(const Vector3 &target)
    3.23 +{
    3.24 +	this->target = target;
    3.25 +}
    3.26 +
    3.27 +const Vector3 &Camera::get_target() const
    3.28 +{
    3.29 +	return target;
    3.30 +}
    3.31 +
    3.32 +void Camera::set_fov(float fov)
    3.33 +{
    3.34 +	this->fov = fov;
    3.35 +}
    3.36 +
    3.37 +float Camera::get_fov() const
    3.38 +{
    3.39 +	return fov;
    3.40 +}
    3.41 +
    3.42 +Matrix4x4 Camera::get_matrix() const
    3.43 +{
    3.44 +	Matrix4x4 res;
    3.45 +	res.lookat(pos, target, Vector3(0, 1, 0));
    3.46 +	return res;
    3.47 +}
    3.48 +
    3.49 +Matrix4x4 Camera::get_inv_matrix() const
    3.50 +{
    3.51 +	Matrix4x4 res;
    3.52 +	return res;	// TODO
    3.53 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/camera.h	Sat Apr 05 08:46:27 2014 +0300
     4.3 @@ -0,0 +1,28 @@
     4.4 +#ifndef CAMERA_H_
     4.5 +#define CAMERA_H_
     4.6 +
     4.7 +#include "vmath.h"
     4.8 +
     4.9 +class Camera {
    4.10 +private:
    4.11 +	Vector3 pos;
    4.12 +	Vector3 target;
    4.13 +	float fov;
    4.14 +
    4.15 +public:
    4.16 +	Camera();
    4.17 +
    4.18 +	void set_position(const Vector3 &pos);
    4.19 +	const Vector3 &get_position() const;
    4.20 +
    4.21 +	void set_target(const Vector3 &target);
    4.22 +	const Vector3 &get_target() const;
    4.23 +
    4.24 +	void set_fov(float fov);
    4.25 +	float get_fov() const;
    4.26 +
    4.27 +	Matrix4x4 get_matrix() const;
    4.28 +	Matrix4x4 get_inv_matrix() const;
    4.29 +};
    4.30 +
    4.31 +#endif	// CAMERA_H_
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/dpmi.c	Sat Apr 05 08:46:27 2014 +0300
     5.3 @@ -0,0 +1,55 @@
     5.4 +#include "dpmi.h"
     5.5 +
     5.6 +void dpmi_real_int(int inum, struct dpmi_real_regs *regs)
     5.7 +{
     5.8 +	unsigned char int_num = (unsigned char)inum;
     5.9 +	__asm {
    5.10 +		mov eax, 0x300
    5.11 +		mov edi, regs
    5.12 +		mov bl, int_num
    5.13 +		mov bh, 0
    5.14 +		xor ecx, ecx
    5.15 +		int 0x31
    5.16 +	}
    5.17 +}
    5.18 +
    5.19 +void *dpmi_mmap(uint32_t phys_addr, unsigned int size)
    5.20 +{
    5.21 +	uint16_t mem_high, mem_low;
    5.22 +	uint16_t phys_high = phys_addr >> 16;
    5.23 +	uint16_t phys_low = phys_addr & 0xffff;
    5.24 +	uint16_t size_high = size >> 16;
    5.25 +	uint16_t size_low = size & 0xffff;
    5.26 +	unsigned int err, res = 0;
    5.27 +
    5.28 +	__asm {
    5.29 +		mov eax, 0x800
    5.30 +		mov bx, phys_high
    5.31 +		mov cx, phys_low
    5.32 +		mov si, size_high
    5.33 +		mov di, size_low
    5.34 +		int 0x31
    5.35 +		add res, 1
    5.36 +		mov err, eax
    5.37 +		mov mem_high, bx
    5.38 +		mov mem_low, cx
    5.39 +	}
    5.40 +
    5.41 +	if(res == 2) {
    5.42 +		return 0;
    5.43 +	}
    5.44 +	return (void*)(((uint32_t)mem_high << 16) | ((uint32_t)mem_low));
    5.45 +}
    5.46 +
    5.47 +void dpmi_munmap(void *addr)
    5.48 +{
    5.49 +	uint16_t mem_high = (uint32_t)addr >> 16;
    5.50 +	uint16_t mem_low = (uint16_t)addr;
    5.51 +
    5.52 +	__asm {
    5.53 +		mov eax, 0x801
    5.54 +		mov bx, mem_high
    5.55 +		mov cx, mem_low
    5.56 +		int 0x31
    5.57 +	}
    5.58 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/dpmi.h	Sat Apr 05 08:46:27 2014 +0300
     6.3 @@ -0,0 +1,26 @@
     6.4 +#ifndef DPMI_H_
     6.5 +#define DPMI_H_
     6.6 +
     6.7 +#include "inttypes.h"
     6.8 +
     6.9 +struct dpmi_real_regs {
    6.10 +	uint32_t edi, esi, ebp;
    6.11 +	uint32_t reserved;
    6.12 +	uint32_t ebx, edx, ecx, eax;
    6.13 +	uint16_t flags;
    6.14 +	uint16_t es, ds, fs, gs;
    6.15 +	uint16_t ip, cs, sp, ss;
    6.16 +};
    6.17 +
    6.18 +unsigned short dpmi_alloc(unsigned int par);
    6.19 +#pragma aux dpmi_alloc = \
    6.20 +		"mov eax, 0x100" \
    6.21 +		"int 0x31" \
    6.22 +		value[ax] parm[ebx];
    6.23 +
    6.24 +void dpmi_real_int(int inum, struct dpmi_real_regs *regs);
    6.25 +
    6.26 +void *dpmi_mmap(uint32_t phys_addr, unsigned int size);
    6.27 +void dpmi_munmap(void *addr);
    6.28 +
    6.29 +#endif	/* DPMI_H_ */
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/gfx.c	Sat Apr 05 08:46:27 2014 +0300
     7.3 @@ -0,0 +1,152 @@
     7.4 +#ifndef GFX_H_
     7.5 +#define GFX_H_
     7.6 +
     7.7 +#include <stdio.h>
     7.8 +#include <stdlib.h>
     7.9 +#include <string.h>
    7.10 +#include "vbe.h"
    7.11 +
    7.12 +#define REALPTR(s, o)	(void*)(((uint32_t)(s) << 4) + (uint32_t)(o))
    7.13 +#define VBEPTR(x)		REALPTR(((x) & 0xffff0000) >> 16, (x) & 0xffff)
    7.14 +#define VBEPTR_SEG(x)	(((x) & 0xffff0000) >> 16)
    7.15 +#define VBEPTR_OFF(x)	((x) & 0xffff)
    7.16 +
    7.17 +#define SAME_BPP(a, b)	\
    7.18 +	((a) == (b) || (a) == 16 && (b) == 15 || (a) == 15 && (b) == 16 || (a) == 32 && (b) == 24 || (a) == 24 && (b) == 32)
    7.19 +
    7.20 +static unsigned int make_mask(int sz, int pos);
    7.21 +
    7.22 +static struct vbe_info *vbe_info;
    7.23 +static struct vbe_mode_info *mode_info;
    7.24 +static int pal_bits = 6;
    7.25 +
    7.26 +void *set_video_mode(int xsz, int ysz, int bpp)
    7.27 +{
    7.28 +	int i;
    7.29 +	uint16_t *modes, best = 0;
    7.30 +	unsigned int fbsize;
    7.31 +
    7.32 +	/* check for VBE2 support and output some info */
    7.33 +	if(!vbe_info) {
    7.34 +		if(!(vbe_info = vbe_get_info())) {
    7.35 +			fprintf(stderr, "VESA BIOS Extensions not available\n");
    7.36 +			return 0;
    7.37 +		}
    7.38 +
    7.39 +		printf("VBE Version: %x.%x\n", vbe_info->version >> 8, vbe_info->version & 0xff);
    7.40 +		if(vbe_info->version < 0x200) {
    7.41 +			fprintf(stderr, "This program requires VBE 2.0 or greater. Try running UniVBE\n");
    7.42 +			return 0;
    7.43 +		}
    7.44 +
    7.45 +		printf("Graphics adapter: %s, %s (%s)\n", VBEPTR(vbe_info->oem_vendor_name_ptr),
    7.46 +				VBEPTR(vbe_info->oem_product_name_ptr), VBEPTR(vbe_info->oem_product_rev_ptr));
    7.47 +		printf("Video memory: %dmb\n", vbe_info->total_mem << 6);
    7.48 +
    7.49 +		modes = VBEPTR(vbe_info->vid_mode_ptr);
    7.50 +	}
    7.51 +
    7.52 +	for(i=0; i<1024; i++) {	/* impose an upper limit to avoid inf-loops */
    7.53 +		if(modes[i] == 0xffff) {
    7.54 +			break;	/* reached the end */
    7.55 +		}
    7.56 +
    7.57 +		mode_info = vbe_get_mode_info(modes[i] | VBE_MODE_LFB);
    7.58 +		if(!mode_info || mode_info->xres != xsz || mode_info->yres != ysz) {
    7.59 +			continue;
    7.60 +		}
    7.61 +		if(SAME_BPP(mode_info->bpp, bpp)) {
    7.62 +			best = modes[i];
    7.63 +		}
    7.64 +	}
    7.65 +
    7.66 +	if(best) {
    7.67 +		mode_info = vbe_get_mode_info(best);
    7.68 +	} else {
    7.69 +		fprintf(stderr, "Requested video mode (%dx%d %dbpp) is unavailable\n", xsz, ysz, bpp);
    7.70 +		return 0;
    7.71 +	}
    7.72 +
    7.73 +	if(vbe_set_mode(best | VBE_MODE_LFB) == -1) {
    7.74 +		fprintf(stderr, "Failed to set video mode %dx%d %dbpp\n", mode_info->xres, mode_info->yres, mode_info->bpp);
    7.75 +		return 0;
    7.76 +	}
    7.77 +
    7.78 +	/* attempt to set 8 bits of color per component in palettized modes */
    7.79 +	if(bpp <= 8) {
    7.80 +		pal_bits = vbe_set_palette_bits(8);
    7.81 +		printf("palette bits per color primary: %d\n", pal_bits);
    7.82 +	}
    7.83 +
    7.84 +	fbsize = xsz * ysz * mode_info->num_img_pages * (bpp / CHAR_BIT);
    7.85 +	return (void*)dpmi_mmap(mode_info->fb_addr, fbsize);
    7.86 +}
    7.87 +
    7.88 +int set_text_mode(void)
    7.89 +{
    7.90 +	vbe_set_mode(0x3);
    7.91 +	return 0;
    7.92 +}
    7.93 +
    7.94 +int get_color_depth(void)
    7.95 +{
    7.96 +	if(!mode_info) {
    7.97 +		return -1;
    7.98 +	}
    7.99 +	return mode_info->bpp;
   7.100 +}
   7.101 +
   7.102 +int get_color_bits(int *rbits, int *gbits, int *bbits)
   7.103 +{
   7.104 +	if(!mode_info) {
   7.105 +		return -1;
   7.106 +	}
   7.107 +	*rbits = mode_info->rmask_size;
   7.108 +	*gbits = mode_info->gmask_size;
   7.109 +	*bbits = mode_info->bmask_size;
   7.110 +	return 0;
   7.111 +}
   7.112 +
   7.113 +int get_color_mask(unsigned int *rmask, unsigned int *gmask, unsigned int *bmask)
   7.114 +{
   7.115 +	if(!mode_info) {
   7.116 +		return -1;
   7.117 +	}
   7.118 +	*rmask = make_mask(mode_info->rmask_size, mode_info->rpos);
   7.119 +	*gmask = make_mask(mode_info->gmask_size, mode_info->gpos);
   7.120 +	*bmask = make_mask(mode_info->bmask_size, mode_info->bpos);
   7.121 +	return 0;
   7.122 +}
   7.123 +
   7.124 +int get_color_shift(int *rshift, int *gshift, int *bshift)
   7.125 +{
   7.126 +	if(!mode_info) {
   7.127 +		return -1;
   7.128 +	}
   7.129 +	*rshift = mode_info->rpos;
   7.130 +	*gshift = mode_info->gpos;
   7.131 +	*bshift = mode_info->bpos;
   7.132 +	return 0;
   7.133 +}
   7.134 +
   7.135 +void set_palette(int idx, int r, int g, int b)
   7.136 +{
   7.137 +	int col[3];
   7.138 +	col[0] = r;
   7.139 +	col[1] = g;
   7.140 +	col[2] = b;
   7.141 +	vbe_set_palette(idx, col, 1, pal_bits);
   7.142 +}
   7.143 +
   7.144 +static unsigned int make_mask(int sz, int pos)
   7.145 +{
   7.146 +	unsigned int i, mask = 0;
   7.147 +
   7.148 +	for(i=0; i<sz; i++) {
   7.149 +		mask |= 1 << i;
   7.150 +	}
   7.151 +	return mask << pos;
   7.152 +}
   7.153 +
   7.154 +
   7.155 +#endif	/* GFX_H_ */
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/gfx.h	Sat Apr 05 08:46:27 2014 +0300
     8.3 @@ -0,0 +1,22 @@
     8.4 +#ifndef GFX_H_
     8.5 +#define GFX_H_
     8.6 +
     8.7 +#ifdef __cplusplus
     8.8 +extern "C" {
     8.9 +#endif
    8.10 +
    8.11 +void *set_video_mode(int xsz, int ysz, int bpp);
    8.12 +int set_text_mode(void);
    8.13 +
    8.14 +int get_color_depth(void);
    8.15 +int get_color_bits(int *rbits, int *gbits, int *bbits);
    8.16 +int get_color_shift(int *rshift, int *gshift, int *bshift);
    8.17 +int get_color_mask(unsigned int *rmask, unsigned int *gmask, unsigned int *bmask);
    8.18 +
    8.19 +void set_palette(int idx, int r, int g, int b);
    8.20 +
    8.21 +#ifdef __cplusplus
    8.22 +}
    8.23 +#endif
    8.24 +
    8.25 +#endif	/* GFX_H_ */
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/src/inttypes.h	Sat Apr 05 08:46:27 2014 +0300
     9.3 @@ -0,0 +1,16 @@
     9.4 +#ifndef INT_TYPES_H_
     9.5 +#define INT_TYPES_H_
     9.6 +
     9.7 +#if defined(__DOS__) || defined(WIN32)
     9.8 +typedef char int8_t;
     9.9 +typedef short int16_t;
    9.10 +typedef long int32_t;
    9.11 +
    9.12 +typedef unsigned char uint8_t;
    9.13 +typedef unsigned short uint16_t;
    9.14 +typedef unsigned long uint32_t;
    9.15 +#else
    9.16 +#include <stdint.h>
    9.17 +#endif
    9.18 +
    9.19 +#endif	/* INT_TYPES_H_ */
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/src/keyb.c	Sat Apr 05 08:46:27 2014 +0300
    10.3 @@ -0,0 +1,194 @@
    10.4 +/*
    10.5 +DOS interrupt-based keyboard driver.
    10.6 +Copyright (C) 2013  John Tsiombikas <nuclear@member.fsf.org>
    10.7 +
    10.8 +This program is free software: you can redistribute it and/or modify
    10.9 +it under the terms of the GNU General Public License as published by
   10.10 +the Free Software Foundation, either version 3 of the License, or
   10.11 +(at your option) any later version.
   10.12 +
   10.13 +This program is distributed in the hope that it will be useful,
   10.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   10.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   10.16 +GNU General Public License  for more details.
   10.17 +
   10.18 +You should have received a copy of the GNU General Public License
   10.19 +along with the program. If not, see <http://www.gnu.org/licenses/>
   10.20 +*/
   10.21 +#define KEYB_C_
   10.22 +
   10.23 +#include <stdio.h>
   10.24 +#include <stdlib.h>
   10.25 +#include <string.h>
   10.26 +#include <conio.h>
   10.27 +#include <dos.h>
   10.28 +#include <i86.h>
   10.29 +#include "keyb.h"
   10.30 +#include "scancode.h"
   10.31 +
   10.32 +#define KB_INTR		0x9
   10.33 +#define KB_PORT		0x60
   10.34 +
   10.35 +#define PIC1_CMD_PORT	0x20
   10.36 +#define OCW2_EOI		(1 << 5)
   10.37 +
   10.38 +#define DONE_INIT	(prev_handler)
   10.39 +
   10.40 +static void __interrupt __far kbintr();
   10.41 +
   10.42 +static void (__interrupt __far *prev_handler)();
   10.43 +
   10.44 +static int *buffer;
   10.45 +static int buffer_size, buf_ridx, buf_widx;
   10.46 +static int last_key;
   10.47 +
   10.48 +static unsigned int num_pressed;
   10.49 +static unsigned char keystate[256];
   10.50 +
   10.51 +#define ADVANCE(x)	((x) = ((x) + 1) % buffer_size)
   10.52 +
   10.53 +int kb_init(int bufsz)
   10.54 +{
   10.55 +	if(DONE_INIT) {
   10.56 +		fprintf(stderr, "keyboard driver already initialized!\n");
   10.57 +		return 0;
   10.58 +	}
   10.59 +
   10.60 +	buffer_size = bufsz;
   10.61 +	if(buffer_size && !(buffer = malloc(buffer_size * sizeof *buffer))) {
   10.62 +		fprintf(stderr, "failed to allocate input buffer, continuing without\n");
   10.63 +		buffer_size = 0;
   10.64 +	}
   10.65 +	buf_ridx = buf_widx = 0;
   10.66 +	last_key = -1;
   10.67 +
   10.68 +	memset(keystate, 0, sizeof keystate);
   10.69 +	num_pressed = 0;
   10.70 +
   10.71 +	/* set our interrupt handler */
   10.72 +	_disable();
   10.73 +	prev_handler = _dos_getvect(KB_INTR);
   10.74 +	_dos_setvect(KB_INTR, kbintr);
   10.75 +	_enable();
   10.76 +
   10.77 +	return 0;
   10.78 +}
   10.79 +
   10.80 +void kb_shutdown(void)
   10.81 +{
   10.82 +	if(!DONE_INIT) {
   10.83 +		return;
   10.84 +	}
   10.85 +
   10.86 +	/* restore the original interrupt handler */
   10.87 +	_disable();
   10.88 +	_dos_setvect(KB_INTR, prev_handler);
   10.89 +	_enable();
   10.90 +
   10.91 +	free(buffer);
   10.92 +}
   10.93 +
   10.94 +int kb_isdown(int key)
   10.95 +{
   10.96 +	if(key == KB_ANY) {
   10.97 +		return num_pressed;
   10.98 +	}
   10.99 +	return (int)keystate[key];
  10.100 +}
  10.101 +
  10.102 +void kb_wait(void)
  10.103 +{
  10.104 +	int key;
  10.105 +	while((key = kb_getkey()) == -1) {
  10.106 +		/* put the processor to sleep while waiting for keypresses, but first
  10.107 +		 * make sure interrupts are enabled, or we'll sleep forever
  10.108 +		 */
  10.109 +		__asm {
  10.110 +			sti
  10.111 +			hlt
  10.112 +		}
  10.113 +	}
  10.114 +	kb_putback(key);
  10.115 +}
  10.116 +
  10.117 +int kb_getkey(void)
  10.118 +{
  10.119 +	int res;
  10.120 +
  10.121 +	if(buffer) {
  10.122 +		if(buf_ridx == buf_widx) {
  10.123 +			return -1;
  10.124 +		}
  10.125 +		res = buffer[buf_ridx];
  10.126 +		ADVANCE(buf_ridx);
  10.127 +	} else {
  10.128 +		res = last_key;
  10.129 +		last_key = -1;
  10.130 +	}
  10.131 +	return res;
  10.132 +}
  10.133 +
  10.134 +void kb_putback(int key)
  10.135 +{
  10.136 +	if(buffer) {
  10.137 +		/* go back a place */
  10.138 +		if(--buf_ridx < 0) {
  10.139 +			buf_ridx += buffer_size;
  10.140 +		}
  10.141 +
  10.142 +		/* if the write end hasn't caught up with us, go back one place
  10.143 +		 * and put it there, otherwise just overwrite the oldest key which
  10.144 +		 * is right where we were.
  10.145 +		 */
  10.146 +		if(buf_ridx == buf_widx) {
  10.147 +			ADVANCE(buf_ridx);
  10.148 +		}
  10.149 +
  10.150 +		buffer[buf_ridx] = key;
  10.151 +	} else {
  10.152 +		last_key = key;
  10.153 +	}
  10.154 +}
  10.155 +
  10.156 +static void __interrupt __far kbintr()
  10.157 +{
  10.158 +	unsigned char code;
  10.159 +	int key, press;
  10.160 +
  10.161 +	code = inp(KB_PORT);
  10.162 +
  10.163 +	if(code >= 128) {
  10.164 +		press = 0;
  10.165 +		code -= 128;
  10.166 +
  10.167 +		if(num_pressed > 0) {
  10.168 +			num_pressed--;
  10.169 +		}
  10.170 +	} else {
  10.171 +		press = 1;
  10.172 +
  10.173 +		num_pressed++;
  10.174 +	}
  10.175 +
  10.176 +	key = scantbl[code];
  10.177 +
  10.178 +	if(press) {
  10.179 +		/* append to buffer */
  10.180 +		last_key = key;
  10.181 +		if(buffer_size > 0) {
  10.182 +			buffer[buf_widx] = key;
  10.183 +			ADVANCE(buf_widx);
  10.184 +			/* if the write end overtook the read end, advance the read end
  10.185 +			 * too, to discard the oldest keypress from the buffer
  10.186 +			 */
  10.187 +			if(buf_widx == buf_ridx) {
  10.188 +				ADVANCE(buf_ridx);
  10.189 +			}
  10.190 +		}
  10.191 +	}
  10.192 +
  10.193 +	/* and update keystate table */
  10.194 +	keystate[key] = press;
  10.195 +
  10.196 +	outp(PIC1_CMD_PORT, OCW2_EOI);	/* send end-of-interrupt */
  10.197 +}
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/src/keyb.h	Sat Apr 05 08:46:27 2014 +0300
    11.3 @@ -0,0 +1,48 @@
    11.4 +/*
    11.5 +DOS interrupt-based keyboard driver.
    11.6 +Copyright (C) 2013  John Tsiombikas <nuclear@member.fsf.org>
    11.7 +
    11.8 +This program is free software: you can redistribute it and/or modify
    11.9 +it under the terms of the GNU General Public License as published by
   11.10 +the Free Software Foundation, either version 3 of the License, or
   11.11 +(at your option) any later version.
   11.12 +
   11.13 +This program is distributed in the hope that it will be useful,
   11.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   11.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   11.16 +GNU General Public License  for more details.
   11.17 +
   11.18 +You should have received a copy of the GNU General Public License
   11.19 +along with the program. If not, see <http://www.gnu.org/licenses/>
   11.20 +*/
   11.21 +#ifndef KEYB_H_
   11.22 +#define KEYB_H_
   11.23 +
   11.24 +#define KB_ANY	(-1)
   11.25 +
   11.26 +#ifdef __cplusplus
   11.27 +extern "C" {
   11.28 +#endif
   11.29 +
   11.30 +int kb_init(int bufsz);	/* bufsz can be 0 for no buffered keys */
   11.31 +void kb_shutdown(void); /* don't forget to call this at the end! */
   11.32 +
   11.33 +/* Boolean predicate for testing the current state of a particular key.
   11.34 + * You may also pass KB_ANY to test if any key is held down.
   11.35 + */
   11.36 +int kb_isdown(int key);
   11.37 +
   11.38 +/* waits for any keypress */
   11.39 +void kb_wait(void);
   11.40 +
   11.41 +/* removes and returns a single key from the input buffer.
   11.42 + * If buffering is disabled (initialized with kb_init(0)), then it always
   11.43 + * returns the last key pressed.
   11.44 + */
   11.45 +int kb_getkey(void);
   11.46 +
   11.47 +#ifdef __cplusplus
   11.48 +}
   11.49 +#endif
   11.50 +
   11.51 +#endif	/* KEYB_H_ */
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/src/light.cc	Sat Apr 05 08:46:27 2014 +0300
    12.3 @@ -0,0 +1,41 @@
    12.4 +#include "light.h"
    12.5 +
    12.6 +Light::Light()
    12.7 +{
    12.8 +	color.x = color.y = color.z = 1.0;
    12.9 +	atten.x = 1.0;
   12.10 +	atten.y = 0.0;
   12.11 +	atten.z = 0.0;
   12.12 +}
   12.13 +
   12.14 +void Light::set_position(const Vector3 &pos)
   12.15 +{
   12.16 +	this->pos = pos;
   12.17 +}
   12.18 +
   12.19 +const Vector3 &Light::get_position() const
   12.20 +{
   12.21 +	return pos;
   12.22 +}
   12.23 +
   12.24 +
   12.25 +void Light::set_color(const Vector3 &color)
   12.26 +{
   12.27 +	this->color = color;
   12.28 +}
   12.29 +
   12.30 +const Vector3 &Light::get_color() const
   12.31 +{
   12.32 +	return color;
   12.33 +}
   12.34 +
   12.35 +
   12.36 +void Light::set_attenuation(const Vector3 &atten)
   12.37 +{
   12.38 +	this->atten = atten;
   12.39 +}
   12.40 +
   12.41 +const Vector3 &Light::get_attenuation() const
   12.42 +{
   12.43 +	return atten;
   12.44 +}
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/src/light.h	Sat Apr 05 08:46:27 2014 +0300
    13.3 @@ -0,0 +1,25 @@
    13.4 +#ifndef LIGHT_H_
    13.5 +#define LIGHT_H_
    13.6 +
    13.7 +#include "vmath.h"
    13.8 +
    13.9 +class Light {
   13.10 +private:
   13.11 +	Vector3 pos;
   13.12 +	Vector3 color;
   13.13 +	Vector3 atten;
   13.14 +
   13.15 +public:
   13.16 +	Light();
   13.17 +
   13.18 +	void set_position(const Vector3 &pos);
   13.19 +	const Vector3 &get_position() const;
   13.20 +
   13.21 +	void set_color(const Vector3 &color);
   13.22 +	const Vector3 &get_color() const;
   13.23 +
   13.24 +	void set_attenuation(const Vector3 &atten);
   13.25 +	const Vector3 &get_attenuation() const;
   13.26 +};
   13.27 +
   13.28 +#endif	// LIGHT_H_
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/src/logger.c	Sat Apr 05 08:46:27 2014 +0300
    14.3 @@ -0,0 +1,23 @@
    14.4 +#include <stdio.h>
    14.5 +#include <stdarg.h>
    14.6 +#include "logger.h"
    14.7 +
    14.8 +#define LOGFNAME	"rayzor.log"
    14.9 +
   14.10 +static FILE *logfile;
   14.11 +
   14.12 +void printlog(const char *fmt, ...)
   14.13 +{
   14.14 +	va_list ap;
   14.15 +
   14.16 +	if(!logfile) {
   14.17 +		if(!(logfile = fopen(LOGFNAME, "w"))) {
   14.18 +			return;
   14.19 +		}
   14.20 +		setvbuf(logfile, 0, _IOLBF, 0);
   14.21 +	}
   14.22 +
   14.23 +	va_start(ap, fmt);
   14.24 +	vfprintf(logfile, fmt, ap);
   14.25 +	va_end(ap);
   14.26 +}
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/src/logger.h	Sat Apr 05 08:46:27 2014 +0300
    15.3 @@ -0,0 +1,14 @@
    15.4 +#ifndef LOGGER_H_
    15.5 +#define LOGGER_H_
    15.6 +
    15.7 +#ifdef __cplusplus
    15.8 +extern "C" {
    15.9 +#endif
   15.10 +
   15.11 +void printlog(const char *fmt, ...);
   15.12 +
   15.13 +#ifdef __cplusplus
   15.14 +}
   15.15 +#endif
   15.16 +
   15.17 +#endif	/* LOGGER_H_ */
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/src/m3dimpl.h	Sat Apr 05 08:46:27 2014 +0300
    16.3 @@ -0,0 +1,23 @@
    16.4 +#ifndef M3DIMPL_H_
    16.5 +#define M3DIMPL_H_
    16.6 +
    16.7 +#include "min3d.h"
    16.8 +
    16.9 +#define MSTACK_SIZE		16
   16.10 +
   16.11 +struct min3d_mstack {
   16.12 +	float m[MSTACK_SIZE][16];
   16.13 +	int top;
   16.14 +};
   16.15 +
   16.16 +struct min3d_context {
   16.17 +	struct m3d_image *cbuf;
   16.18 +	uint16_t *zbuf;
   16.19 +
   16.20 +	unsigned long state;
   16.21 +
   16.22 +	int mmode;	/* matrix mode */
   16.23 +	struct min3d_mstack mstack[2];
   16.24 +} *m3dctx;
   16.25 +
   16.26 +#endif	/* M3DIMPL_H_ */
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/src/main.cc	Sat Apr 05 08:46:27 2014 +0300
    17.3 @@ -0,0 +1,212 @@
    17.4 +#include <stdio.h>
    17.5 +#include <stdlib.h>
    17.6 +#include <string.h>
    17.7 +#include <math.h>
    17.8 +#include "inttypes.h"
    17.9 +#include "gfx.h"
   17.10 +#include "keyb.h"
   17.11 +#include "mouse.h"
   17.12 +#include "logger.h"
   17.13 +
   17.14 +static void display();
   17.15 +static void swap_buffers();
   17.16 +static void handle_keyboard();
   17.17 +static void handle_mouse();
   17.18 +static bool parse_args(int argc, char **argv);
   17.19 +
   17.20 +static int xsz = 800;
   17.21 +static int ysz = 600;
   17.22 +static int bpp = 16;
   17.23 +static int bytespp;
   17.24 +static unsigned char *fb;
   17.25 +static unsigned char *backbuf;
   17.26 +static int rbits, gbits, bbits;
   17.27 +static int rshift, gshift, bshift;
   17.28 +static unsigned int rmask, gmask, bmask;
   17.29 +
   17.30 +static bool quit;
   17.31 +
   17.32 +int main(int argc, char **argv)
   17.33 +{
   17.34 +	if(!parse_args(argc, argv)) {
   17.35 +		return 1;
   17.36 +	}
   17.37 +	if(kb_init(32) == -1) {
   17.38 +		fprintf(stderr, "failed to initialize keyboard driver\n");
   17.39 +		return 1;
   17.40 +	}
   17.41 +	if(!(fb = (unsigned char*)set_video_mode(xsz, ysz, bpp))) {
   17.42 +		set_text_mode();
   17.43 +		fprintf(stderr, "failed to set video mode: %dx%d %dbpp\n", xsz, ysz, bpp);
   17.44 +		return 1;
   17.45 +	}
   17.46 +	bpp = get_color_depth();
   17.47 +	get_color_bits(&rbits, &gbits, &bbits);
   17.48 +	get_color_shift(&rshift, &gshift, &bshift);
   17.49 +	get_color_mask(&rmask, &gmask, &bmask);
   17.50 +	bytespp = (int)ceil(bpp / 8.0);
   17.51 +
   17.52 +	printlog("bpp: %d (%d %d %d)\n", bpp, rbits, gbits, bbits);
   17.53 +	printlog("shift: %d %d %d\n", rshift, gshift, bshift);
   17.54 +	printlog("mask: %x %x %x\n", rmask, gmask, bmask);
   17.55 +
   17.56 +	backbuf = new unsigned char[xsz * ysz * 3];
   17.57 +
   17.58 +	// main loop
   17.59 +	for(;;) {
   17.60 +		handle_keyboard();
   17.61 +		handle_mouse();
   17.62 +		if(quit) break;
   17.63 +
   17.64 +		display();
   17.65 +	}
   17.66 +
   17.67 +	delete [] backbuf;
   17.68 +
   17.69 +	set_text_mode();
   17.70 +	kb_shutdown();
   17.71 +
   17.72 +	printf("Thank you for using Rayzor!\n");
   17.73 +	return 0;
   17.74 +}
   17.75 +
   17.76 +static void display()
   17.77 +{
   17.78 +	unsigned char *fbptr = backbuf;
   17.79 +
   17.80 +	for(int i=0; i<ysz; i++) {
   17.81 +		for(int j=0; j<xsz; j++) {
   17.82 +			bool chess = ((i / 16) & 1) == ((j / 16) & 1);
   17.83 +			fbptr[chess ? 0 : 2] = 255;
   17.84 +			fbptr[1] = 128;
   17.85 +			fbptr[chess ? 2 : 0] = 32;
   17.86 +			fbptr += 3;
   17.87 +		}
   17.88 +	}
   17.89 +
   17.90 +	swap_buffers();
   17.91 +}
   17.92 +
   17.93 +#define PACK_RGB(r, g, b) \
   17.94 +	((((r) << rshift) & rmask) | \
   17.95 +	 (((g) << gshift) & gmask) | \
   17.96 +	 (((b) << bshift) & bmask))
   17.97 +
   17.98 +static void swap_buffers()
   17.99 +{
  17.100 +	unsigned char *src = backbuf;
  17.101 +	int num_pixels = xsz * ysz;
  17.102 +
  17.103 +	switch(bpp) {
  17.104 +	case 32:
  17.105 +		{
  17.106 +			uint32_t *dest = (uint32_t*)fb;
  17.107 +			for(int i=0; i<num_pixels; i++) {
  17.108 +				*dest++ = PACK_RGB(src[0], src[1], src[2]);
  17.109 +				src += 3;
  17.110 +			}
  17.111 +		}
  17.112 +		break;
  17.113 +
  17.114 +	case 24:
  17.115 +		memcpy(fb, backbuf, num_pixels * 3);
  17.116 +		break;
  17.117 +
  17.118 +	case 16:
  17.119 +	case 15:
  17.120 +		{
  17.121 +			int srs = 8 - rbits;
  17.122 +			int sgs = 8 - gbits;
  17.123 +			int sbs = 8 - bbits;
  17.124 +			uint16_t *dest = (uint16_t*)fb;
  17.125 +			for(int i=0; i<num_pixels; i++) {
  17.126 +				*dest++ = PACK_RGB(src[0] >> srs, src[1] >> sgs, src[2] >> sbs);
  17.127 +				src += 3;
  17.128 +			}
  17.129 +		}
  17.130 +		break;
  17.131 +
  17.132 +	default:
  17.133 +		break;
  17.134 +	}
  17.135 +}
  17.136 +
  17.137 +static void handle_keyboard()
  17.138 +{
  17.139 +	if(!kb_isdown(KB_ANY))
  17.140 +		return;
  17.141 +
  17.142 +	int c = kb_getkey();
  17.143 +	switch(c) {
  17.144 +	case 27:
  17.145 +		quit = true;
  17.146 +		return;
  17.147 +	}
  17.148 +}
  17.149 +
  17.150 +static void handle_mouse()
  17.151 +{
  17.152 +}
  17.153 +
  17.154 +static struct {
  17.155 +	int opt;
  17.156 +	const char *lopt;
  17.157 +	const char *desc;
  17.158 +} options[] = {
  17.159 +	{'s', "size", "resolution <xres>x<yres>[:bpp]"},
  17.160 +	{'h', "help", "print usage information and exit"},
  17.161 +	{-1, 0, 0}
  17.162 +};
  17.163 +
  17.164 +static void print_usage(const char *argv0)
  17.165 +{
  17.166 +	printf("%s usage\n", argv0);
  17.167 +	for(int i=0; options[i].opt != -1; i++) {
  17.168 +		printf("  -%c, -%s: %s\n", options[i].opt, options[i].lopt, options[i].desc);
  17.169 +	}
  17.170 +	exit(0);
  17.171 +}
  17.172 +
  17.173 +static bool parse_args(int argc, char **argv)
  17.174 +{
  17.175 +	for(int i=1; i<argc; i++) {
  17.176 +		if(argv[i][0] == '-') {
  17.177 +			int opt = -1;
  17.178 +
  17.179 +			for(int j=0; options[j].opt != -1; j++) {
  17.180 +				if(argv[i][2] == 0) {
  17.181 +					if(argv[i][1] == options[j].opt) {
  17.182 +						opt = options[j].opt;
  17.183 +						break;
  17.184 +					}
  17.185 +				} else {
  17.186 +					if(strcmp(argv[i] + 1, options[j].lopt) == 0) {
  17.187 +						opt = options[j].opt;
  17.188 +						break;
  17.189 +					}
  17.190 +				}
  17.191 +			}
  17.192 +
  17.193 +			switch(opt) {
  17.194 +			case 's':
  17.195 +				if(sscanf(argv[++i], "%dx%d:%d", &xsz, &ysz, &bpp) < 2) {
  17.196 +					fprintf(stderr, "%s must be followed by a resolution: WxH\n", argv[i - 1]);
  17.197 +					return false;
  17.198 +				}
  17.199 +				break;
  17.200 +
  17.201 +			case 'h':
  17.202 +				print_usage(argv[0]);	// doesn't return
  17.203 +				break;
  17.204 +
  17.205 +			default:
  17.206 +				fprintf(stderr, "unknown option: %s\n", argv[i]);
  17.207 +				return false;
  17.208 +			}
  17.209 +		} else {
  17.210 +			fprintf(stderr, "unexpected argument: %s\n", argv[i]);
  17.211 +			return false;
  17.212 +		}
  17.213 +	}
  17.214 +	return true;
  17.215 +}
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/src/min3d.c	Sat Apr 05 08:46:27 2014 +0300
    18.3 @@ -0,0 +1,178 @@
    18.4 +#include <stdlib.h>
    18.5 +#include "min3d.h"
    18.6 +#include "m3dimpl.h"
    18.7 +
    18.8 +#ifndef M_PI
    18.9 +#define M_PI	3.141592653
   18.10 +#endif
   18.11 +
   18.12 +int m3d_init(void)
   18.13 +{
   18.14 +	if(!(m3dctx = malloc(sizeof *m3dctx))) {
   18.15 +		return -1;
   18.16 +	}
   18.17 +	memset(m3dctx, 0, sizeof *m3dctx);
   18.18 +
   18.19 +	m3d_matrix_mode(M3D_PROJECTION);
   18.20 +	m3d_load_identity();
   18.21 +	m3d_matrix_mode(M3D_MODELVIEW);
   18.22 +	m3d_load_identity();
   18.23 +	return 0;
   18.24 +}
   18.25 +
   18.26 +void m3d_shutdown(void)
   18.27 +{
   18.28 +	free(m3dctx);
   18.29 +}
   18.30 +
   18.31 +void m3d_set_buffers(struct m3d_image *cbuf, uint16_t *zbuf)
   18.32 +{
   18.33 +	m3dctx->cbuf = cbuf;
   18.34 +	m3dctx->zbuf = zbuf;
   18.35 +}
   18.36 +
   18.37 +void m3d_clear(unsigned int bmask)
   18.38 +{
   18.39 +	int num_pixels = m3dctx->cbuf->xsz * m3dctx->cbuf->ysz;
   18.40 +	if(bmask & M3D_COLOR_BUFFER_BIT) {
   18.41 +		memset(m3dctx->cbuf->pixels, 0, num_pixels * 3);
   18.42 +	}
   18.43 +	if(bmask & M3D_DEPTH_BUFFER_BIT) {
   18.44 +		memset(m3dctx->zbuf, 0xff, num_pixels * sizeof *m3dctx->zbuf);
   18.45 +	}
   18.46 +}
   18.47 +
   18.48 +
   18.49 +void m3d_enable(int bit)
   18.50 +{
   18.51 +	m3dctx->state |= (1 << bit);
   18.52 +}
   18.53 +
   18.54 +void m3d_disable(int bit)
   18.55 +{
   18.56 +	m3dctx->state &= ~(1 << bit);
   18.57 +}
   18.58 +
   18.59 +
   18.60 +/* matrix stack */
   18.61 +void m3d_matrix_mode(int mode)
   18.62 +{
   18.63 +	m3dctx->mmode = mode;
   18.64 +}
   18.65 +
   18.66 +void m3d_load_identity(void)
   18.67 +{
   18.68 +	static const float mid[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
   18.69 +	m3d_load_matrix(mid);
   18.70 +}
   18.71 +
   18.72 +void m3d_load_matrix(const float *m)
   18.73 +{
   18.74 +	int top = m3dctx->mstack[m3dctx->mmode].top;
   18.75 +	memcpy(m3dctx->mstack[m3dctx->mmode].m[top], m, 16 * sizeof *m);
   18.76 +}
   18.77 +
   18.78 +#define M(i,j)	(((i) << 2) + (j))
   18.79 +void m3d_mult_matrix(const float *m2)
   18.80 +{
   18.81 +	int i, j, top = m3dctx->mstack[m3dctx->mmode].top;
   18.82 +	float m1[16];
   18.83 +	float *dest = m3dctx->mstack[m3dctx->mmode].m[top];
   18.84 +
   18.85 +	memcpy(m1, dest, sizeof m1);
   18.86 +
   18.87 +	for(i=0; i<4; i++) {
   18.88 +		for(j=0; j<4; j++) {
   18.89 +			dest[M(i,j)] = m1[M(0,j)] * m2[M(i,0)] +
   18.90 +				m1[M(1,j)] * m2[M(i,1)] +
   18.91 +				m1[M(2,j)] * m2[M(i,2)] +
   18.92 +				m1[M(3,j)] * m2[M(i,3)];
   18.93 +		}
   18.94 +	}
   18.95 +}
   18.96 +
   18.97 +void m3d_translate(float x, float y, float z)
   18.98 +{
   18.99 +	float m[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
  18.100 +	m[12] = x;
  18.101 +	m[13] = y;
  18.102 +	m[14] = z;
  18.103 +	m3d_mult_matrix(m);
  18.104 +}
  18.105 +
  18.106 +void m3d_rotate(float deg, float x, float y, float z)
  18.107 +{
  18.108 +	float xform[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
  18.109 +
  18.110 +	float angle = M_PI * deg / 180.0f;
  18.111 +	float sina = sin(angle);
  18.112 +	float cosa = cos(angle);
  18.113 +	float one_minus_cosa = 1.0f - cosa;
  18.114 +	float nxsq = x * x;
  18.115 +	float nysq = y * y;
  18.116 +	float nzsq = z * z;
  18.117 +
  18.118 +	xform[0] = nxsq + (1.0f - nxsq) * cosa;
  18.119 +	xform[4] = x * y * one_minus_cosa - z * sina;
  18.120 +	xform[8] = x * z * one_minus_cosa + y * sina;
  18.121 +	xform[1] = x * y * one_minus_cosa + z * sina;
  18.122 +	xform[5] = nysq + (1.0 - nysq) * cosa;
  18.123 +	xform[9] = y * z * one_minus_cosa - x * sina;
  18.124 +	xform[2] = x * z * one_minus_cosa - y * sina;
  18.125 +	xform[6] = y * z * one_minus_cosa + x * sina;
  18.126 +	xform[10] = nzsq + (1.0 - nzsq) * cosa;
  18.127 +
  18.128 +	m3d_mult_matrix(xform);
  18.129 +}
  18.130 +
  18.131 +void m3d_scale(float x, float y, float z)
  18.132 +{
  18.133 +	static float m[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
  18.134 +	m[0] = x;
  18.135 +	m[5] = y;
  18.136 +	m[10] = z;
  18.137 +	m3d_mult_matrix(m);
  18.138 +}
  18.139 +
  18.140 +void m3d_frustum(float left, float right, float bottom, float top, float nr, float fr)
  18.141 +{
  18.142 +	float xform[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
  18.143 +
  18.144 +	float dx = right - left;
  18.145 +	float dy = top - bottom;
  18.146 +	float dz = fr - nr;
  18.147 +
  18.148 +	float a = (right + left) / dx;
  18.149 +	float b = (top + bottom) / dy;
  18.150 +	float c = -(fr + nr) / dz;
  18.151 +	float d = -2.0 * fr * nr / dz;
  18.152 +
  18.153 +	xform[0] = 2.0 * nr / dx;
  18.154 +	xform[5] = 2.0 * nr / dy;
  18.155 +	xform[8] = a;
  18.156 +	xform[9] = b;
  18.157 +	xform[10] = c;
  18.158 +	xform[11] = -1.0f;
  18.159 +	xform[14] = d;
  18.160 +
  18.161 +	m3d_mult_matrix(xform);
  18.162 +}
  18.163 +
  18.164 +void m3d_perspective(float vfov, float aspect, float nr, float fr)
  18.165 +{
  18.166 +	float vfov_rad = M_PI * vfov / 180.0;
  18.167 +	float x = nr * tan(vfov_rad / 2.0);
  18.168 +	m3d_frustum(-aspect * x, aspect * x, -x, x, nr, fr);
  18.169 +}
  18.170 +
  18.171 +/* drawing */
  18.172 +void m3d_draw(int prim, const float *varr, int vcount)
  18.173 +{
  18.174 +	/* TODO */
  18.175 +}
  18.176 +
  18.177 +void m3d_draw_indexed(int prim, const float *varr, const int *idxarr, int icount)
  18.178 +{
  18.179 +	/* TODO */
  18.180 +}
  18.181 +
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/src/min3d.h	Sat Apr 05 08:46:27 2014 +0300
    19.3 @@ -0,0 +1,73 @@
    19.4 +#ifndef MIN3D_H_
    19.5 +#define MIN3D_H_
    19.6 +
    19.7 +#include "inttypes.h"
    19.8 +
    19.9 +/* state toggles */
   19.10 +enum {
   19.11 +	M3D_DEPTH_TEST,
   19.12 +	M3D_CULL_FACE,
   19.13 +	M3D_LIGHTING,
   19.14 +	M3D_LIGHT0,
   19.15 +	M3D_LIGHT1,
   19.16 +	M3D_LIGHT2,
   19.17 +	M3D_LIGHT3
   19.18 +};
   19.19 +
   19.20 +/* buffer bits */
   19.21 +enum {
   19.22 +	M3D_COLOR_BUFFER_BIT	= 1,
   19.23 +	M3D_DEPTH_BUFFER_BIT	= 2
   19.24 +};
   19.25 +
   19.26 +/* primitives */
   19.27 +enum {
   19.28 +	M3D_POINTS = 1,
   19.29 +	M3D_LINES = 2,
   19.30 +	M3D_TRIANGLES = 3,
   19.31 +	M3D_QUADS = 4
   19.32 +};
   19.33 +
   19.34 +/* matrix mode */
   19.35 +enum {
   19.36 +	M3D_MODELVIEW,
   19.37 +	M3D_PROJECTION
   19.38 +};
   19.39 +
   19.40 +struct m3d_image {
   19.41 +	int xsz, ysz;
   19.42 +	unsigned char *pixels;
   19.43 +};
   19.44 +
   19.45 +#ifdef __cplusplus
   19.46 +extern "C" {
   19.47 +#endif
   19.48 +
   19.49 +void m3d_set_buffers(struct m3d_image *cbuf, uint16_t *zbuf);
   19.50 +void m3d_clear(unsigned int bmask);
   19.51 +
   19.52 +void m3d_enable(int bit);
   19.53 +void m3d_disable(int bit);
   19.54 +
   19.55 +/* matrix stack */
   19.56 +void m3d_matrix_mode(int mode);
   19.57 +void m3d_load_identity(void);
   19.58 +void m3d_load_matrix(const float *m);
   19.59 +void m3d_mult_matrix(const float *m);
   19.60 +void m3d_translate(float x, float y, float z);
   19.61 +void m3d_rotate(float angle, float x, float y, float z);
   19.62 +void m3d_scale(float x, float y, float z);
   19.63 +void m3d_frustum(float left, float right, float bottom, float top, float nr, float fr);
   19.64 +void m3d_perspective(float vfov, float aspect, float znear, float zfar);
   19.65 +
   19.66 +/* drawing */
   19.67 +void m3d_draw(int prim, const float *varr, int vcount);
   19.68 +void m3d_draw_indexed(int prim, const float *varr, const int *idxarr, int icount);
   19.69 +
   19.70 +/* TODO immediate mode */
   19.71 +
   19.72 +#ifdef __cplusplus
   19.73 +}
   19.74 +#endif
   19.75 +
   19.76 +#endif	/* MIN3D_H_ */
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/src/mouse.c	Sat Apr 05 08:46:27 2014 +0300
    20.3 @@ -0,0 +1,72 @@
    20.4 +/* TODO: try NOT using the v8086 interrupts to avoid the overhead */
    20.5 +#include "mouse.h"
    20.6 +#include "inttypes.h"
    20.7 +#include "dpmi.h"
    20.8 +
    20.9 +#define INTR	0x33
   20.10 +
   20.11 +#define QUERY	0
   20.12 +#define SHOW	1
   20.13 +#define HIDE	2
   20.14 +#define READ	3
   20.15 +#define WRITE	4
   20.16 +
   20.17 +#define XLIM	7
   20.18 +#define YLIM	8
   20.19 +
   20.20 +int have_mouse(void)
   20.21 +{
   20.22 +	struct dpmi_real_regs regs;
   20.23 +	memset(&regs, 0, sizeof regs);
   20.24 +	regs.eax = QUERY;
   20.25 +	dpmi_real_int(INTR, &regs);
   20.26 +	return regs.eax & 0xffff;
   20.27 +}
   20.28 +
   20.29 +void show_mouse(int show)
   20.30 +{
   20.31 +	struct dpmi_real_regs regs;
   20.32 +	memset(&regs, 0, sizeof regs);
   20.33 +	regs.eax = show ? SHOW : HIDE;
   20.34 +	dpmi_real_int(INTR, &regs);
   20.35 +}
   20.36 +
   20.37 +int read_mouse(int *xp, int *yp)
   20.38 +{
   20.39 +	struct dpmi_real_regs regs;
   20.40 +	memset(&regs, 0, sizeof regs);
   20.41 +
   20.42 +	regs.eax = READ;
   20.43 +	dpmi_real_int(INTR, &regs);
   20.44 +
   20.45 +	if(xp) *xp = regs.ecx & 0xffff;
   20.46 +	if(yp) *yp = regs.edx & 0xffff;
   20.47 +	return regs.ebx & 0xffff;
   20.48 +}
   20.49 +
   20.50 +void set_mouse(int x, int y)
   20.51 +{
   20.52 +	struct dpmi_real_regs regs;
   20.53 +	memset(&regs, 0, sizeof regs);
   20.54 +
   20.55 +	regs.eax = WRITE;
   20.56 +	regs.ecx = x;
   20.57 +	regs.edx = y;
   20.58 +	dpmi_real_int(INTR, &regs);
   20.59 +}
   20.60 +
   20.61 +void set_mouse_limits(int xmin, int ymin, int xmax, int ymax)
   20.62 +{
   20.63 +	struct dpmi_real_regs regs;
   20.64 +	memset(&regs, 0, sizeof regs);
   20.65 +	regs.eax = XLIM;
   20.66 +	regs.ecx = xmin;
   20.67 +	regs.edx = xmax;
   20.68 +	dpmi_real_int(INTR, &regs);
   20.69 +
   20.70 +	memset(&regs, 0, sizeof regs);
   20.71 +	regs.eax = YLIM;
   20.72 +	regs.ecx = ymin;
   20.73 +	regs.edx = ymax;
   20.74 +	dpmi_real_int(INTR, &regs);
   20.75 +}
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/src/mouse.h	Sat Apr 05 08:46:27 2014 +0300
    21.3 @@ -0,0 +1,22 @@
    21.4 +#ifndef MOUSE_H_
    21.5 +#define MOUSE_H_
    21.6 +
    21.7 +#define MOUSE_LEFT		1
    21.8 +#define MOUSE_RIGHT		2
    21.9 +#define MOUSE_MIDDLE	4
   21.10 +
   21.11 +#ifdef __cplusplus
   21.12 +extern "C" {
   21.13 +#endif
   21.14 +
   21.15 +int have_mouse(void);
   21.16 +void show_mouse(int show);
   21.17 +int read_mouse(int *xp, int *yp);
   21.18 +void set_mouse(int x, int y);
   21.19 +void set_mouse_limits(int xmin, int ymin, int xmax, int ymax);
   21.20 +
   21.21 +#ifdef __cplusplus
   21.22 +}
   21.23 +#endif
   21.24 +
   21.25 +#endif	/* MOUSE_H_ */
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/src/object.cc	Sat Apr 05 08:46:27 2014 +0300
    22.3 @@ -0,0 +1,53 @@
    22.4 +#include "object.h"
    22.5 +#include "vmath.h"
    22.6 +#include "min3d.h"
    22.7 +
    22.8 +Object::Object()
    22.9 +{
   22.10 +}
   22.11 +
   22.12 +Object::~Object()
   22.13 +{
   22.14 +}
   22.15 +
   22.16 +// ---- sphere ----
   22.17 +Sphere::Sphere()
   22.18 +{
   22.19 +}
   22.20 +
   22.21 +Sphere::~Sphere()
   22.22 +{
   22.23 +}
   22.24 +
   22.25 +#define USUB	16
   22.26 +#define VSUB	8
   22.27 +
   22.28 +void Sphere::draw() const
   22.29 +{
   22.30 +	static Vector3 *varr;
   22.31 +	static int num_verts;
   22.32 +	if(!varr) {
   22.33 +		int uverts = USUB;
   22.34 +		int vverts = VSUB + 1;
   22.35 +		num_verts = uverts * vverts;
   22.36 +		varr = new Vector3[num_verts];
   22.37 +
   22.38 +		Vector3 *vptr = varr;
   22.39 +		for(int i=0; i<uverts; i++) {
   22.40 +			float u = (float)i / (float)USUB;
   22.41 +			float theta = u * M_PI * 2.0;
   22.42 +			for(int j=0; j<vverts; j++) {
   22.43 +				float v = (float)j / (float)VSUB;
   22.44 +				float phi = (v - 0.5) * M_PI;
   22.45 +
   22.46 +				float x = sin(theta) * cos(phi);
   22.47 +				float y = sin(phi);
   22.48 +				float z = cos(theta) * cos(phi);
   22.49 +
   22.50 +				*vptr++ = Vector3(x, y, z);
   22.51 +			}
   22.52 +		}
   22.53 +	}
   22.54 +
   22.55 +	m3d_draw(M3D_POINTS, &varr->x, num_verts);
   22.56 +}
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/src/object.h	Sat Apr 05 08:46:27 2014 +0300
    23.3 @@ -0,0 +1,20 @@
    23.4 +#ifndef OBJECT_H_
    23.5 +#define OBJECT_H_
    23.6 +
    23.7 +class Object {
    23.8 +public:
    23.9 +	Object();
   23.10 +	virtual ~Object();
   23.11 +
   23.12 +	virtual void draw() const = 0;
   23.13 +};
   23.14 +
   23.15 +class Sphere {
   23.16 +public:
   23.17 +	Sphere();
   23.18 +	~Sphere();
   23.19 +
   23.20 +	void draw() const;
   23.21 +};
   23.22 +
   23.23 +#endif	// OBJECT_H_
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/src/pit8254.h	Sat Apr 05 08:46:27 2014 +0300
    24.3 @@ -0,0 +1,34 @@
    24.4 +#ifndef PIT8254_H_
    24.5 +#define PIT8254_H_
    24.6 +
    24.7 +/* frequency of the oscillator driving the 8254 timer */
    24.8 +#define OSC_FREQ_HZ		1193182
    24.9 +
   24.10 +/* I/O ports connected to the 8254 */
   24.11 +#define PORT_DATA0	0x40
   24.12 +#define PORT_DATA1	0x41
   24.13 +#define PORT_DATA2	0x42
   24.14 +#define PORT_CMD	0x43
   24.15 +
   24.16 +/* command bits */
   24.17 +#define CMD_CHAN0			0
   24.18 +#define CMD_CHAN1			(1 << 6)
   24.19 +#define CMD_CHAN2			(2 << 6)
   24.20 +#define CMD_RDBACK			(3 << 6)
   24.21 +
   24.22 +#define CMD_LATCH			0
   24.23 +#define CMD_ACCESS_LOW		(1 << 4)
   24.24 +#define CMD_ACCESS_HIGH		(2 << 4)
   24.25 +#define CMD_ACCESS_BOTH		(3 << 4)
   24.26 +
   24.27 +#define CMD_OP_INT_TERM		0
   24.28 +#define CMD_OP_ONESHOT		(1 << 1)
   24.29 +#define CMD_OP_RATE			(2 << 1)
   24.30 +#define CMD_OP_SQWAVE		(3 << 1)
   24.31 +#define CMD_OP_SW_STROBE	(4 << 1)
   24.32 +#define CMD_OP_HW_STROBE	(5 << 1)
   24.33 +
   24.34 +#define CMD_MODE_BIN		0
   24.35 +#define CMD_MODE_BCD		1
   24.36 +
   24.37 +#endif	/* PIT8254_H_ */
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/src/rend.cc	Sat Apr 05 08:46:27 2014 +0300
    25.3 @@ -0,0 +1,10 @@
    25.4 +#include "rend.h"
    25.5 +
    25.6 +bool rend_init()
    25.7 +{
    25.8 +	return false;
    25.9 +}
   25.10 +
   25.11 +void rend_shutdown()
   25.12 +{
   25.13 +}
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/src/rend.h	Sat Apr 05 08:46:27 2014 +0300
    26.3 @@ -0,0 +1,7 @@
    26.4 +#ifndef REND_H_
    26.5 +#define REND_H_
    26.6 +
    26.7 +bool rend_init();
    26.8 +void rend_shutdown();
    26.9 +
   26.10 +#endif	// REND_H_
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/src/scancode.h	Sat Apr 05 08:46:27 2014 +0300
    27.3 @@ -0,0 +1,31 @@
    27.4 +#ifndef KEYB_C_
    27.5 +#error "do not include scancode.h anywhere..."
    27.6 +#endif
    27.7 +
    27.8 +/* special keys */
    27.9 +enum {
   27.10 +	LALT, RALT,
   27.11 +	LCTRL, RCTRL,
   27.12 +	LSHIFT, RSHIFT,
   27.13 +	F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
   27.14 +	CAPSLK, NUMLK, SCRLK, SYSRQ,
   27.15 +	ESC		= 27,
   27.16 +	INSERT, DEL, HOME, END, PGUP, PGDN, LEFT, RIGHT, UP, DOWN,
   27.17 +	NUM_DOT, NUM_ENTER, NUM_PLUS, NUM_MINUS, NUM_MUL, NUM_DIV,
   27.18 +	NUM_0, NUM_1, NUM_2, NUM_3, NUM_4, NUM_5, NUM_6, NUM_7, NUM_8, NUM_9,
   27.19 +	BACKSP	= 127
   27.20 +};
   27.21 +
   27.22 +/* table with rough translations from set 1 scancodes to ASCII-ish */
   27.23 +static int scantbl[] = {
   27.24 +	0, ESC, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',		/* 0 - e */
   27.25 +	'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',			/* f - 1c */
   27.26 +	LCTRL, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',				/* 1d - 29 */
   27.27 +	LSHIFT, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', RSHIFT,			/* 2a - 36 */
   27.28 +	NUM_MUL, LALT, ' ', CAPSLK, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10,			/* 37 - 44 */
   27.29 +	NUMLK, SCRLK, NUM_7, NUM_8, NUM_9, NUM_MINUS, NUM_4, NUM_5, NUM_6, NUM_PLUS,	/* 45 - 4e */
   27.30 +	NUM_1, NUM_2, NUM_3, NUM_0, NUM_DOT, SYSRQ, 0, 0, F11, F12,						/* 4d - 58 */
   27.31 +	0, 0, 0, 0, 0, 0, 0,															/* 59 - 5f */
   27.32 +	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,									/* 60 - 6f */
   27.33 +	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0									/* 70 - 7f */
   27.34 +};
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/src/scene.cc	Sat Apr 05 08:46:27 2014 +0300
    28.3 @@ -0,0 +1,43 @@
    28.4 +#include "scene.h"
    28.5 +
    28.6 +Scene::Scene()
    28.7 +{
    28.8 +	name = 0;
    28.9 +}
   28.10 +
   28.11 +Scene::~Scene()
   28.12 +{
   28.13 +	clear();
   28.14 +}
   28.15 +
   28.16 +void Scene::clear()
   28.17 +{
   28.18 +	delete [] name;
   28.19 +
   28.20 +	size_t i;
   28.21 +	for(i=0; i<objects.size(); i++) {
   28.22 +		delete objects[i];
   28.23 +	}
   28.24 +	for(i=0; i<lights.size(); i++) {
   28.25 +		delete lights[i];
   28.26 +	}
   28.27 +	for(i=0; i<cameras.size(); i++) {
   28.28 +		delete cameras[i];
   28.29 +	}
   28.30 +}
   28.31 +
   28.32 +void Scene::set_name(const char *name)
   28.33 +{
   28.34 +	delete [] this->name;
   28.35 +	this->name = new char[strlen(name) + 1];
   28.36 +	strcpy(this->name, name);
   28.37 +}
   28.38 +
   28.39 +const char *Scene::get_name() const
   28.40 +{
   28.41 +	return name ? name : "<unknown>";
   28.42 +}
   28.43 +
   28.44 +void Scene::draw() const
   28.45 +{
   28.46 +}
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/src/scene.h	Sat Apr 05 08:46:27 2014 +0300
    29.3 @@ -0,0 +1,29 @@
    29.4 +#ifndef SCENE_H_
    29.5 +#define SCENE_H_
    29.6 +
    29.7 +#include <string>
    29.8 +#include <vector.h>
    29.9 +#include "object.h"
   29.10 +#include "light.h"
   29.11 +#include "camera.h"
   29.12 +
   29.13 +class Scene {
   29.14 +private:
   29.15 +	char *name;
   29.16 +	vector<Object*> objects;
   29.17 +	vector<Light*> lights;
   29.18 +	vector<Camera*> cameras;
   29.19 +
   29.20 +public:
   29.21 +	Scene();
   29.22 +	~Scene();
   29.23 +
   29.24 +	void clear();
   29.25 +
   29.26 +	void set_name(const char *name);
   29.27 +	const char *get_name() const;
   29.28 +
   29.29 +	void draw() const;
   29.30 +};
   29.31 +
   29.32 +#endif	// SCENE_H_
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/src/timer.c	Sat Apr 05 08:46:27 2014 +0300
    30.3 @@ -0,0 +1,131 @@
    30.4 +/*
    30.5 +256-color 3D graphics hack for real-mode DOS.
    30.6 +Copyright (C) 2011  John Tsiombikas <nuclear@member.fsf.org>
    30.7 +
    30.8 +This program is free software: you can redistribute it and/or modify
    30.9 +it under the terms of the GNU General Public License as published by
   30.10 +the Free Software Foundation, either version 3 of the License, or
   30.11 +(at your option) any later version.
   30.12 +
   30.13 +This program is distributed in the hope that it will be useful,
   30.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   30.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   30.16 +GNU General Public License for more details.
   30.17 +
   30.18 +You should have received a copy of the GNU General Public License
   30.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
   30.20 +*/
   30.21 +#include <stdio.h>
   30.22 +#include <stdlib.h>
   30.23 +#include <conio.h>
   30.24 +#include <dos.h>
   30.25 +#include <i86.h>
   30.26 +#include "pit8254.h"
   30.27 +
   30.28 +#define PIT_TIMER_INTR	8
   30.29 +#define DOS_TIMER_INTR	0x1c
   30.30 +
   30.31 +/* macro to divide and round to the nearest integer */
   30.32 +#define DIV_ROUND(a, b) \
   30.33 +	((a) / (b) + ((a) % (b)) / ((b) / 2))
   30.34 +
   30.35 +static void set_timer_reload(int reload_val);
   30.36 +static void cleanup(void);
   30.37 +static void __interrupt __far timer_irq();
   30.38 +static void __interrupt __far dos_timer_intr();
   30.39 +
   30.40 +static void (__interrupt __far *prev_timer_intr)();
   30.41 +
   30.42 +static unsigned long ticks;
   30.43 +static unsigned long tick_interval, ticks_per_dos_intr;
   30.44 +static int inum;
   30.45 +
   30.46 +void init_timer(int res_hz)
   30.47 +{
   30.48 +	_disable();
   30.49 +
   30.50 +	if(res_hz > 0) {
   30.51 +		int reload_val = DIV_ROUND(OSC_FREQ_HZ, res_hz);
   30.52 +		set_timer_reload(reload_val);
   30.53 +
   30.54 +		tick_interval = DIV_ROUND(1000, res_hz);
   30.55 +		ticks_per_dos_intr = DIV_ROUND(65535L, reload_val);
   30.56 +
   30.57 +		inum = PIT_TIMER_INTR;
   30.58 +		prev_timer_intr = _dos_getvect(inum);
   30.59 +		_dos_setvect(inum, timer_irq);
   30.60 +	} else {
   30.61 +		tick_interval = 55;
   30.62 +
   30.63 +		inum = DOS_TIMER_INTR;
   30.64 +		prev_timer_intr = _dos_getvect(inum);
   30.65 +		_dos_setvect(inum, dos_timer_intr);
   30.66 +	}
   30.67 +	_enable();
   30.68 +
   30.69 +	atexit(cleanup);
   30.70 +}
   30.71 +
   30.72 +static void cleanup(void)
   30.73 +{
   30.74 +	if(!prev_timer_intr) {
   30.75 +		return; /* init hasn't ran, there's nothing to cleanup */
   30.76 +	}
   30.77 +
   30.78 +	_disable();
   30.79 +	if(inum == PIT_TIMER_INTR) {
   30.80 +		/* restore the original timer frequency */
   30.81 +		set_timer_reload(65535);
   30.82 +	}
   30.83 +
   30.84 +	/* restore the original interrupt handler */
   30.85 +	_dos_setvect(inum, prev_timer_intr);
   30.86 +	_enable();
   30.87 +}
   30.88 +
   30.89 +void reset_timer(void)
   30.90 +{
   30.91 +	ticks = 0;
   30.92 +}
   30.93 +
   30.94 +unsigned long get_msec(void)
   30.95 +{
   30.96 +	return ticks * tick_interval;
   30.97 +}
   30.98 +
   30.99 +static void set_timer_reload(int reload_val)
  30.100 +{
  30.101 +	outp(PORT_CMD, CMD_CHAN0 | CMD_ACCESS_BOTH | CMD_OP_SQWAVE);
  30.102 +	outp(PORT_DATA0, reload_val & 0xff);
  30.103 +	outp(PORT_DATA0, (reload_val >> 8) & 0xff);
  30.104 +}
  30.105 +
  30.106 +static void __interrupt __far dos_timer_intr()
  30.107 +{
  30.108 +	ticks++;
  30.109 +	_chain_intr(prev_timer_intr);	/* DOES NOT RETURN */
  30.110 +}
  30.111 +
  30.112 +/* first PIC command port */
  30.113 +#define PIC1_CMD	0x20
  30.114 +/* end of interrupt control word */
  30.115 +#define OCW2_EOI	(1 << 5)
  30.116 +
  30.117 +static void __interrupt __far timer_irq()
  30.118 +{
  30.119 +	static unsigned long dos_ticks;
  30.120 +
  30.121 +	ticks++;
  30.122 +
  30.123 +	if(++dos_ticks >= ticks_per_dos_intr) {
  30.124 +		/* I suppose the dos irq handler does the EOI so I shouldn't
  30.125 +		 * do it if I am to call the previous function
  30.126 +		 */
  30.127 +		dos_ticks = 0;
  30.128 +		_chain_intr(prev_timer_intr);	/* XXX DOES NOT RETURN */
  30.129 +		return;	/* just for clarity */
  30.130 +	}
  30.131 +
  30.132 +	/* send EOI to the PIC */
  30.133 +	outp(PIC1_CMD, OCW2_EOI);
  30.134 +}
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/src/timer.h	Sat Apr 05 08:46:27 2014 +0300
    31.3 @@ -0,0 +1,29 @@
    31.4 +/*
    31.5 +256-color 3D graphics hack for real-mode DOS.
    31.6 +Copyright (C) 2011  John Tsiombikas <nuclear@member.fsf.org>
    31.7 +
    31.8 +This program is free software: you can redistribute it and/or modify
    31.9 +it under the terms of the GNU General Public License as published by
   31.10 +the Free Software Foundation, either version 3 of the License, or
   31.11 +(at your option) any later version.
   31.12 +
   31.13 +This program is distributed in the hope that it will be useful,
   31.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   31.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   31.16 +GNU General Public License for more details.
   31.17 +
   31.18 +You should have received a copy of the GNU General Public License
   31.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
   31.20 +*/
   31.21 +#ifndef TIMER_H_
   31.22 +#define TIMER_H_
   31.23 +
   31.24 +/* expects the required timer resolution in hertz
   31.25 + * if res_hz is 0, the current resolution is retained
   31.26 + */
   31.27 +void init_timer(int res_hz);
   31.28 +
   31.29 +void reset_timer(void);
   31.30 +unsigned long get_msec(void);
   31.31 +
   31.32 +#endif	/* TIMER_H_ */
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/src/vbe.c	Sat Apr 05 08:46:27 2014 +0300
    32.3 @@ -0,0 +1,153 @@
    32.4 +#include <stdio.h>
    32.5 +#include <string.h>
    32.6 +#include "vbe.h"
    32.7 +#include "dpmi.h"
    32.8 +
    32.9 +/* VGA DAC registers used for palette setting in 8bpp modes */
   32.10 +#define VGA_DAC_STATE		0x3c7
   32.11 +#define VGA_DAC_ADDR_RD		0x3c7
   32.12 +#define VGA_DAC_ADDR_WR		0x3c8
   32.13 +#define VGA_DAC_DATA		0x3c9
   32.14 +
   32.15 +#define MODE_LFB	(1 << 14)
   32.16 +
   32.17 +
   32.18 +struct vbe_info *vbe_get_info(void)
   32.19 +{
   32.20 +	static unsigned short info_block_seg;
   32.21 +	static struct vbe_info *info;
   32.22 +	struct dpmi_real_regs regs;
   32.23 +
   32.24 +	if(!info) {
   32.25 +		/* allocate 32 paragraphs (512 bytes) */
   32.26 +		info_block_seg = dpmi_alloc(32);
   32.27 +		info = (struct vbe_info*)(info_block_seg << 4);
   32.28 +	}
   32.29 +
   32.30 +	memcpy(info->sig, "VBE2", 4);
   32.31 +
   32.32 +	memset(&regs, 0, sizeof regs);
   32.33 +	regs.es = info_block_seg;
   32.34 +	regs.eax = 0x4f00;
   32.35 +
   32.36 +	dpmi_real_int(0x10, &regs);
   32.37 +
   32.38 +	return info;
   32.39 +}
   32.40 +
   32.41 +struct vbe_mode_info *vbe_get_mode_info(int mode)
   32.42 +{
   32.43 +	static unsigned short mode_info_seg;
   32.44 +	static struct vbe_mode_info *mi;
   32.45 +	struct dpmi_real_regs regs;
   32.46 +
   32.47 +	if(!mi) {
   32.48 +		/* allocate 16 paragraphs (256 bytes) */
   32.49 +		mode_info_seg = dpmi_alloc(16);
   32.50 +		mi = (struct vbe_mode_info*)(mode_info_seg << 4);
   32.51 +	}
   32.52 +
   32.53 +	memset(&regs, 0, sizeof regs);
   32.54 +	regs.es = mode_info_seg;
   32.55 +	regs.eax = 0x4f01;
   32.56 +	regs.ecx = mode;
   32.57 +	regs.es = mode_info_seg;
   32.58 +
   32.59 +	dpmi_real_int(0x10, &regs);
   32.60 +	if(regs.eax & 0xff00) {
   32.61 +		return 0;
   32.62 +	}
   32.63 +
   32.64 +	return mi;
   32.65 +}
   32.66 +
   32.67 +int vbe_set_mode(int mode)
   32.68 +{
   32.69 +	struct dpmi_real_regs regs;
   32.70 +
   32.71 +	memset(&regs, 0, sizeof regs);
   32.72 +	regs.eax = 0x4f02;
   32.73 +	regs.ebx = mode;
   32.74 +	dpmi_real_int(0x10, &regs);
   32.75 +
   32.76 +	if(regs.eax == 0x100) {
   32.77 +		return -1;
   32.78 +	}
   32.79 +	return 0;
   32.80 +}
   32.81 +
   32.82 +int vbe_set_palette_bits(int bits)
   32.83 +{
   32.84 +	struct dpmi_real_regs regs;
   32.85 +
   32.86 +	memset(&regs, 0, sizeof regs);
   32.87 +	regs.eax = 0x4f08;
   32.88 +	regs.ebx = bits << 8;	/* bits in bh */
   32.89 +	dpmi_real_int(0x10, &regs);
   32.90 +
   32.91 +	if((regs.eax >> 8) & 0xff == 3) {
   32.92 +		return -1;
   32.93 +	}
   32.94 +	return regs.ebx >> 8 & 0xff;	/* new color bits in bh */
   32.95 +}
   32.96 +
   32.97 +/* TODO: implement palette setting through the VBE2 interface for
   32.98 + * non-VGA displays (actually don't).
   32.99 + */
  32.100 +void vbe_set_palette(int idx, int *col, int count, int bits)
  32.101 +{
  32.102 +	int i, shift = 8 - bits;
  32.103 +
  32.104 +	__asm {
  32.105 +		mov dx, VGA_DAC_ADDR_WR
  32.106 +		mov eax, idx
  32.107 +		out dx, al
  32.108 +	}
  32.109 +
  32.110 +	for(i=0; i<count; i++) {
  32.111 +		unsigned char r = *col++;
  32.112 +		unsigned char g = *col++;
  32.113 +		unsigned char b = *col++;
  32.114 +
  32.115 +		if(shift) {
  32.116 +			r >>= shift;
  32.117 +			g >>= shift;
  32.118 +			b >>= shift;
  32.119 +		}
  32.120 +
  32.121 +		__asm {
  32.122 +			mov dx, VGA_DAC_DATA
  32.123 +			mov al, r
  32.124 +			out dx, al
  32.125 +			mov al, g
  32.126 +			out dx, al
  32.127 +			mov al, b
  32.128 +			out dx, al
  32.129 +		}
  32.130 +	}
  32.131 +}
  32.132 +
  32.133 +static unsigned int get_mask(int sz, int pos)
  32.134 +{
  32.135 +	unsigned int i, mask = 0;
  32.136 +
  32.137 +	for(i=0; i<sz; i++) {
  32.138 +		mask |= 1 << i;
  32.139 +	}
  32.140 +	return mask << pos;
  32.141 +}
  32.142 +
  32.143 +void print_mode_info(FILE *fp, struct vbe_mode_info *mi)
  32.144 +{
  32.145 +	fprintf(fp, "resolution: %dx%d\n", mi->xres, mi->yres);
  32.146 +	fprintf(fp, "color depth: %d\n", mi->bpp);
  32.147 +	fprintf(fp, "mode attributes: %x\n", mi->mode_attr);
  32.148 +	fprintf(fp, "bytes per scanline: %d\n", mi->scanline_bytes);
  32.149 +	fprintf(fp, "number of planes: %d\n", (int)mi->num_planes);
  32.150 +	fprintf(fp, "number of banks: %d\n", (int)mi->num_banks);
  32.151 +	fprintf(fp, "mem model: %d\n", (int)mi->mem_model);
  32.152 +	fprintf(fp, "red bits: %d (mask: %x)\n", (int)mi->rmask_size, get_mask(mi->rmask_size, mi->rpos));
  32.153 +	fprintf(fp, "green bits: %d (mask: %x)\n", (int)mi->gmask_size, get_mask(mi->gmask_size, mi->gpos));
  32.154 +	fprintf(fp, "blue bits: %d (mask: %x)\n", (int)mi->bmask_size, get_mask(mi->bmask_size, mi->bpos));
  32.155 +	fprintf(fp, "framebuffer address: %x\n", mi->fb_addr);
  32.156 +}
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/src/vbe.h	Sat Apr 05 08:46:27 2014 +0300
    33.3 @@ -0,0 +1,70 @@
    33.4 +#ifndef VBE_H_
    33.5 +#define VBE_H_
    33.6 +
    33.7 +#include "inttypes.h"
    33.8 +
    33.9 +#define VBE_ATTR_LFB	(1 << 7)
   33.10 +#define VBE_MODE_LFB	(1 << 14)
   33.11 +
   33.12 +#pragma pack (push, 0)
   33.13 +struct vbe_info {
   33.14 +	uint8_t sig[4];
   33.15 +	uint16_t version;
   33.16 +	uint32_t oem_str_ptr;
   33.17 +	uint8_t caps[4];			/* capabilities */
   33.18 +	uint32_t vid_mode_ptr;		/* vbefarptr to video mode list */
   33.19 +	uint16_t total_mem;			/* num of 64k mem blocks */
   33.20 +	uint16_t oem_sw_rev;		/* VBE implementation software revision */
   33.21 +	uint32_t oem_vendor_name_ptr;
   33.22 +	uint32_t oem_product_name_ptr;
   33.23 +	uint32_t oem_product_rev_ptr;
   33.24 +	uint8_t reserved[222];
   33.25 +	uint8_t oem_data[256];
   33.26 +};
   33.27 +
   33.28 +struct vbe_mode_info {
   33.29 +	uint16_t mode_attr;
   33.30 +	uint8_t wina_attr, winb_attr;
   33.31 +	uint16_t win_gran, win_size;
   33.32 +	uint16_t wina_seg, winb_seg;
   33.33 +	uint32_t win_func;
   33.34 +	uint16_t scanline_bytes;
   33.35 +
   33.36 +	/* VBE 1.2 and above */
   33.37 +	uint16_t xres, yres;
   33.38 +	uint8_t xcharsz, ycharsz;
   33.39 +	uint8_t num_planes;
   33.40 +	uint8_t bpp;
   33.41 +	uint8_t num_banks;
   33.42 +	uint8_t mem_model;
   33.43 +	uint8_t bank_size;		/* bank size in KB */
   33.44 +	uint8_t num_img_pages;
   33.45 +	uint8_t reserved1;
   33.46 +
   33.47 +	/* direct color fields */
   33.48 +	uint8_t rmask_size, rpos;
   33.49 +	uint8_t gmask_size, gpos;
   33.50 +	uint8_t bmask_size, bpos;
   33.51 +	uint8_t xmask_size, xpos;
   33.52 +	uint8_t cmode_info;		/* direct color mode attributes */
   33.53 +
   33.54 +	/* VBE 2.0 and above */
   33.55 +	uint32_t fb_addr;		/* physical address of the linear framebuffer */
   33.56 +	uint32_t reserved2;
   33.57 +	uint16_t reserved3;
   33.58 +
   33.59 +	uint8_t reserved4[206];
   33.60 +};
   33.61 +#pragma pack (pop)
   33.62 +
   33.63 +struct vbe_info *vbe_get_info(void);
   33.64 +struct vbe_mode_info *vbe_get_mode_info(unsigned int mode);
   33.65 +
   33.66 +int vbe_set_mode(unsigned int mode);
   33.67 +
   33.68 +int vbe_set_palette_bits(int bits);
   33.69 +void vbe_set_palette(int idx, int *col, int count, int bits);
   33.70 +
   33.71 +void print_mode_info(FILE *fp, struct vbe_mode_info *modei);
   33.72 +
   33.73 +#endif	/* VBE_H_ */
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/src/vmath.cc	Sat Apr 05 08:46:27 2014 +0300
    34.3 @@ -0,0 +1,18 @@
    34.4 +#include "vmathmat.h"
    34.5 +#include "vmath.h"
    34.6 +
    34.7 +void Matrix4x4::lookat(const Vector3 &pos, const Vector3 &targ, const Vector3 &up)
    34.8 +{
    34.9 +	Vector3 vk = normalize(targ - pos);
   34.10 +	Vector3 vj = normalize(up);
   34.11 +	Vector3 vi = normalize(cross(vk, vj));
   34.12 +	vj = cross(vi, vk);
   34.13 +
   34.14 +	Matrix4x4 m(
   34.15 +			vi.x, vi.y, vi.z, 0,
   34.16 +			vj.x, vj.y, vj.z, 0,
   34.17 +			-vk.x, -vk.y, -vk.z, 0,
   34.18 +			0, 0, 0, 1);
   34.19 +	translate(-pos.x, -pos.y, -pos.z);
   34.20 +	*this = *this * m;
   34.21 +}
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/src/vmath.h	Sat Apr 05 08:46:27 2014 +0300
    35.3 @@ -0,0 +1,148 @@
    35.4 +#ifndef VMATH_H_
    35.5 +#define VMATH_H_
    35.6 +
    35.7 +#include <math.h>
    35.8 +#include "vmathmat.h"
    35.9 +
   35.10 +class Vector3 {
   35.11 +public:
   35.12 +	float x, y, z;
   35.13 +
   35.14 +	Vector3() : x(0), y(0), z(0) {}
   35.15 +	Vector3(float xx, float yy, float zz) : x(xx), y(yy), z(zz) {}
   35.16 +
   35.17 +	float length_sq() const { return x * x + y * y + z * z; }
   35.18 +	float length() const { return sqrt(x * x + y * y + z * z); }
   35.19 +
   35.20 +	void normalize()
   35.21 +	{
   35.22 +		float len = length();
   35.23 +		if(len != 0.0) {
   35.24 +			x /= len;
   35.25 +			y /= len;
   35.26 +			z /= len;
   35.27 +		}
   35.28 +	}
   35.29 +
   35.30 +	float &operator [](int idx) { return idx == 2 ? z : (idx == 1 ? y : x); }
   35.31 +	const float &operator [](int idx) const { return idx == 2 ? z : (idx == 1 ? y : x); }
   35.32 +};
   35.33 +
   35.34 +inline Vector3 normalize(const Vector3 &v)
   35.35 +{
   35.36 +	float len = v.length();
   35.37 +	if(len != 0.0) {
   35.38 +		return Vector3(v.x / len, v.y / len, v.z / len);
   35.39 +	}
   35.40 +	return v;
   35.41 +}
   35.42 +
   35.43 +inline Vector3 operator +(const Vector3 &a, const Vector3 &b)
   35.44 +{
   35.45 +	return Vector3(a.x + b.x, a.y + b.y, a.z + b.z);
   35.46 +}
   35.47 +
   35.48 +inline Vector3 operator -(const Vector3 &a, const Vector3 &b)
   35.49 +{
   35.50 +	return Vector3(a.x - b.x, a.y - b.y, a.z - b.z);
   35.51 +}
   35.52 +
   35.53 +inline Vector3 operator *(const Vector3 &v, float s)
   35.54 +{
   35.55 +	return Vector3(v.x * s, v.y * s, v.z * s);
   35.56 +}
   35.57 +
   35.58 +inline Vector3 operator /(const Vector3 &v, float s)
   35.59 +{
   35.60 +	return Vector3(v.x / s, v.y / s, v.z / s);
   35.61 +}
   35.62 +
   35.63 +inline float dot(const Vector3 &a, const Vector3 &b)
   35.64 +{
   35.65 +	return a.x * b.x + a.y * b.y + a.z * b.z;
   35.66 +}
   35.67 +
   35.68 +inline Vector3 cross(const Vector3 &a, const Vector3 &b)
   35.69 +{
   35.70 +	return Vector3(a.y * b.z - a.z * b.y,
   35.71 +			a.z * b.z - a.x * b.z,
   35.72 +			a.x * b.y - a.y * b.x);
   35.73 +}
   35.74 +
   35.75 +inline Vector3 transform(const Matrix4x4 &m, const Vector3 &v)
   35.76 +{
   35.77 +	float x = m.m[0][0] * v.x + m.m[0][1] * v.y + m.m[0][2] * v.z + m.m[0][3];
   35.78 +	float y = m.m[1][0] * v.x + m.m[1][1] * v.y + m.m[1][2] * v.z + m.m[1][3];
   35.79 +	float z = m.m[2][0] * v.x + m.m[2][1] * v.y + m.m[2][2] * v.z + m.m[2][3];
   35.80 +	return Vector3(x, y, z);
   35.81 +}
   35.82 +
   35.83 +// ---- Vector4 ----
   35.84 +
   35.85 +class Vector4 {
   35.86 +public:
   35.87 +	float x, y, z, w;
   35.88 +
   35.89 +	Vector4() : x(0), y(0), z(0), w(1.0) {}
   35.90 +	Vector4(const Vector3 &v) : x(v.x), y(v.y), z(v.z), w(1.0) {}
   35.91 +	Vector4(float xx, float yy, float zz, float ww) : x(xx), y(yy), z(zz), w(ww) {}
   35.92 +
   35.93 +	float length_sq() const { return x * x + y * y + z * z + w * w; }
   35.94 +	float length() const { return sqrt(x * x + y * y + z * z + w * w); }
   35.95 +
   35.96 +	void normalize()
   35.97 +	{
   35.98 +		float len = length();
   35.99 +		if(len != 0.0) {
  35.100 +			x /= len;
  35.101 +			y /= len;
  35.102 +			z /= len;
  35.103 +			w /= len;
  35.104 +		}
  35.105 +	}
  35.106 +
  35.107 +	float &operator [](int idx)
  35.108 +	{
  35.109 +		return idx == 3 ? w : (idx == 2 ? z : (idx == 1 ? y : x));
  35.110 +	}
  35.111 +	const float &operator [](int idx) const
  35.112 +	{
  35.113 +		return idx == 3 ? w : (idx == 2 ? z : (idx == 1 ? y : x));
  35.114 +	}
  35.115 +};
  35.116 +
  35.117 +inline Vector4 operator +(const Vector4 &a, const Vector4 &b)
  35.118 +{
  35.119 +	return Vector4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
  35.120 +}
  35.121 +
  35.122 +inline Vector4 operator -(const Vector4 &a, const Vector4 &b)
  35.123 +{
  35.124 +	return Vector4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
  35.125 +}
  35.126 +
  35.127 +inline Vector4 operator *(const Vector4 &v, float s)
  35.128 +{
  35.129 +	return Vector4(v.x * s, v.y * s, v.z * s, v.w * s);
  35.130 +}
  35.131 +
  35.132 +inline Vector4 operator /(const Vector4 &v, float s)
  35.133 +{
  35.134 +	return Vector4(v.x / s, v.y / s, v.z / s, v.w / s);
  35.135 +}
  35.136 +
  35.137 +inline float dot(const Vector4 &a, const Vector4 &b)
  35.138 +{
  35.139 +	return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
  35.140 +}
  35.141 +
  35.142 +inline Vector4 transform(const Matrix4x4 &m, const Vector4 &v)
  35.143 +{
  35.144 +	float x = m.m[0][0] * v.x + m.m[0][1] * v.y + m.m[0][2] * v.z + m.m[0][3] * v.w;
  35.145 +	float y = m.m[1][0] * v.x + m.m[1][1] * v.y + m.m[1][2] * v.z + m.m[1][3] * v.w;
  35.146 +	float z = m.m[2][0] * v.x + m.m[2][1] * v.y + m.m[2][2] * v.z + m.m[2][3] * v.w;
  35.147 +	float w = m.m[3][0] * v.x + m.m[3][1] * v.y + m.m[3][2] * v.z + m.m[3][3] * v.w;
  35.148 +	return Vector4(x, y, z, w);
  35.149 +}
  35.150 +
  35.151 +#endif	// VMATH_H_
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/src/vmathmat.h	Sat Apr 05 08:46:27 2014 +0300
    36.3 @@ -0,0 +1,116 @@
    36.4 +#ifndef VMATH_MATRIX_H_
    36.5 +#define VMATH_MATRIX_H_
    36.6 +
    36.7 +#include <math.h>
    36.8 +
    36.9 +#ifndef M_PI
   36.10 +#define M_PI	3.141592653
   36.11 +#endif
   36.12 +
   36.13 +class Vector3;
   36.14 +
   36.15 +class Matrix4x4 {
   36.16 +public:
   36.17 +	float m[4][4];
   36.18 +
   36.19 +	Matrix4x4()
   36.20 +	{
   36.21 +		set_identity();
   36.22 +	}
   36.23 +
   36.24 +	Matrix4x4(float m00, float m01, float m02, float m03,
   36.25 +			float m10, float m11, float m12, float m13,
   36.26 +			float m20, float m21, float m22, float m23,
   36.27 +			float m30, float m31, float m32, float m33)
   36.28 +	{
   36.29 +		m[0][0] = m00; m[0][1] = m01; m[0][2] = m02; m[0][3] = m03;
   36.30 +		m[1][0] = m10; m[1][1] = m11; m[1][2] = m12; m[1][3] = m13;
   36.31 +		m[2][0] = m20; m[2][1] = m21; m[2][2] = m22; m[2][3] = m23;
   36.32 +		m[3][0] = m30; m[3][1] = m31; m[3][2] = m32; m[3][3] = m33;
   36.33 +	}
   36.34 +
   36.35 +	inline void set_identity();
   36.36 +	inline void translate(float x, float y, float z);
   36.37 +	inline void rotate(float angle, float x, float y, float z);
   36.38 +	inline void scale(float x, float y, float z);
   36.39 +	inline void perspective(float vfov, float aspect, float znear, float zfar);
   36.40 +	inline void lookat(const Vector3 &pos, const Vector3 &targ, const Vector3 &up);
   36.41 +
   36.42 +	float *operator [](int idx) { return m[idx]; }
   36.43 +	const float *operator [](int idx) const { return m[idx]; }
   36.44 +};
   36.45 +
   36.46 +inline Matrix4x4 operator *(const Matrix4x4 &a, const Matrix4x4 &b)
   36.47 +{
   36.48 +	Matrix4x4 res;
   36.49 +	for(int i=0; i<4; i++) {
   36.50 +		for(int j=0; j<4; j++) {
   36.51 +			res[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j] +
   36.52 +				a[i][2] * b[2][j] + a[i][3] * b[3][j];
   36.53 +		}
   36.54 +	}
   36.55 +	return res;
   36.56 +}
   36.57 +
   36.58 +inline void Matrix4x4::set_identity()
   36.59 +{
   36.60 +	m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0;
   36.61 +	m[0][1] = m[0][2] = m[0][3] = m[1][2] = m[1][3] = m[2][3] = 0.0;
   36.62 +	m[1][0] = m[2][0] = m[3][0] = m[2][1] = m[3][1] = m[3][2] = 0.0;
   36.63 +}
   36.64 +
   36.65 +inline void Matrix4x4::translate(float x, float y, float z)
   36.66 +{
   36.67 +	Matrix4x4 m(1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, z, 0, 0, 0, 1);
   36.68 +	*this = *this * m;
   36.69 +}
   36.70 +
   36.71 +inline void Matrix4x4::rotate(float angle, float x, float y, float z)
   36.72 +{
   36.73 +	float sina = (float)sin(angle);
   36.74 +	float cosa = (float)cos(angle);
   36.75 +	float rcosa = 1.0f - cosa;
   36.76 +	float nxsq = x * x;
   36.77 +	float nysq = y * y;
   36.78 +	float nzsq = z * z;
   36.79 +
   36.80 +	Matrix4x4 m;
   36.81 +	m[0][0] = nxsq + (1.0f - nxsq) * cosa;
   36.82 +	m[0][1] = x * y * rcosa - z * sina;
   36.83 +	m[0][2] = x * z * rcosa + y * sina;
   36.84 +
   36.85 +	m[1][0] = x * y * rcosa + z * sina;
   36.86 +	m[1][1] = nysq + (1.0f - nysq) * cosa;
   36.87 +	m[1][2] = y * z * rcosa - x * sina;
   36.88 +
   36.89 +	m[2][0] = x * z * rcosa - y * sina;
   36.90 +	m[2][1] = y * z * rcosa + x * sina;
   36.91 +	m[2][2] = nzsq + (1.0f - nzsq) * cosa;
   36.92 +
   36.93 +	*this = *this * m;
   36.94 +}
   36.95 +
   36.96 +inline void Matrix4x4::scale(float x, float y, float z)
   36.97 +{
   36.98 +	Matrix4x4 m(x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1);
   36.99 +	*this = *this * m;
  36.100 +}
  36.101 +
  36.102 +inline void Matrix4x4::perspective(float vfov, float aspect, float znear, float zfar)
  36.103 +{
  36.104 +	float f = 1.0f / tan(vfov * 0.5f);
  36.105 +	float dz = znear - zfar;
  36.106 +
  36.107 +	Matrix4x4 m;
  36.108 +	m[0][0] = f / aspect;
  36.109 +	m[1][1] = f;
  36.110 +	m[2][2] = (zfar + znear) / dz;
  36.111 +	m[3][2] = -1.0f;
  36.112 +	m[2][3] = 2.0f * zfar * znear / dz;
  36.113 +	m[3][3] = 0.0f;
  36.114 +
  36.115 +	*this = *this * m;
  36.116 +}
  36.117 +
  36.118 +
  36.119 +#endif	// VMATH_MATRIX_H_