Cleanup
This commit is contained in:
parent
5250505d3e
commit
40ca67447f
32 changed files with 1 additions and 18325 deletions
151
asm_draw.h
151
asm_draw.h
|
@ -1,151 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
//
|
||||
// asm_draw.h
|
||||
//
|
||||
// Include file for asm drawing routines.
|
||||
//
|
||||
|
||||
//
|
||||
// !!! note that this file must match the corresponding C structures at all
|
||||
// times !!!
|
||||
//
|
||||
|
||||
// !!! if this is changed, it must be changed in r_local.h too !!!
|
||||
#define NEAR_CLIP 0.01
|
||||
|
||||
// !!! if this is changed, it must be changed in r_local.h too !!!
|
||||
#define CYCLE 128
|
||||
|
||||
// espan_t structure
|
||||
// !!! if this is changed, it must be changed in r_shared.h too !!!
|
||||
#define espan_t_u 0
|
||||
#define espan_t_v 4
|
||||
#define espan_t_count 8
|
||||
#define espan_t_pnext 12
|
||||
#define espan_t_size 16
|
||||
|
||||
// sspan_t structure
|
||||
// !!! if this is changed, it must be changed in d_local.h too !!!
|
||||
#define sspan_t_u 0
|
||||
#define sspan_t_v 4
|
||||
#define sspan_t_count 8
|
||||
#define sspan_t_size 12
|
||||
|
||||
// spanpackage_t structure
|
||||
// !!! if this is changed, it must be changed in d_polyset.c too !!!
|
||||
#define spanpackage_t_pdest 0
|
||||
#define spanpackage_t_pz 4
|
||||
#define spanpackage_t_count 8
|
||||
#define spanpackage_t_ptex 12
|
||||
#define spanpackage_t_sfrac 16
|
||||
#define spanpackage_t_tfrac 20
|
||||
#define spanpackage_t_light 24
|
||||
#define spanpackage_t_zi 28
|
||||
#define spanpackage_t_size 32
|
||||
|
||||
// edge_t structure
|
||||
// !!! if this is changed, it must be changed in r_shared.h too !!!
|
||||
#define et_u 0
|
||||
#define et_u_step 4
|
||||
#define et_prev 8
|
||||
#define et_next 12
|
||||
#define et_surfs 16
|
||||
#define et_nextremove 20
|
||||
#define et_nearzi 24
|
||||
#define et_owner 28
|
||||
#define et_size 32
|
||||
|
||||
// surf_t structure
|
||||
// !!! if this is changed, it must be changed in r_shared.h too !!!
|
||||
#define SURF_T_SHIFT 6
|
||||
#define st_next 0
|
||||
#define st_prev 4
|
||||
#define st_spans 8
|
||||
#define st_key 12
|
||||
#define st_last_u 16
|
||||
#define st_spanstate 20
|
||||
#define st_flags 24
|
||||
#define st_data 28
|
||||
#define st_entity 32
|
||||
#define st_nearzi 36
|
||||
#define st_insubmodel 40
|
||||
#define st_d_ziorigin 44
|
||||
#define st_d_zistepu 48
|
||||
#define st_d_zistepv 52
|
||||
#define st_pad 56
|
||||
#define st_size 64
|
||||
|
||||
// clipplane_t structure
|
||||
// !!! if this is changed, it must be changed in r_local.h too !!!
|
||||
#define cp_normal 0
|
||||
#define cp_dist 12
|
||||
#define cp_next 16
|
||||
#define cp_leftedge 20
|
||||
#define cp_rightedge 21
|
||||
#define cp_reserved 22
|
||||
#define cp_size 24
|
||||
|
||||
// medge_t structure
|
||||
// !!! if this is changed, it must be changed in model.h too !!!
|
||||
#define me_v 0
|
||||
#define me_cachededgeoffset 4
|
||||
#define me_size 8
|
||||
|
||||
// mvertex_t structure
|
||||
// !!! if this is changed, it must be changed in model.h too !!!
|
||||
#define mv_position 0
|
||||
#define mv_size 12
|
||||
|
||||
// refdef_t structure
|
||||
// !!! if this is changed, it must be changed in render.h too !!!
|
||||
#define rd_vrect 0
|
||||
#define rd_aliasvrect 20
|
||||
#define rd_vrectright 40
|
||||
#define rd_vrectbottom 44
|
||||
#define rd_aliasvrectright 48
|
||||
#define rd_aliasvrectbottom 52
|
||||
#define rd_vrectrightedge 56
|
||||
#define rd_fvrectx 60
|
||||
#define rd_fvrecty 64
|
||||
#define rd_fvrectx_adj 68
|
||||
#define rd_fvrecty_adj 72
|
||||
#define rd_vrect_x_adj_shift20 76
|
||||
#define rd_vrectright_adj_shift20 80
|
||||
#define rd_fvrectright_adj 84
|
||||
#define rd_fvrectbottom_adj 88
|
||||
#define rd_fvrectright 92
|
||||
#define rd_fvrectbottom 96
|
||||
#define rd_horizontalFieldOfView 100
|
||||
#define rd_xOrigin 104
|
||||
#define rd_yOrigin 108
|
||||
#define rd_vieworg 112
|
||||
#define rd_viewangles 124
|
||||
#define rd_ambientlight 136
|
||||
#define rd_size 140
|
||||
|
||||
// mtriangle_t structure
|
||||
// !!! if this is changed, it must be changed in model.h too !!!
|
||||
#define mtri_facesfront 0
|
||||
#define mtri_vertindex 4
|
||||
#define mtri_size 16 // !!! if this changes, array indexing in !!!
|
||||
// !!! d_polysa.s must be changed to match !!!
|
||||
#define mtri_shift 4
|
||||
|
886
cd_audio.c
886
cd_audio.c
|
@ -1,886 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All
|
||||
// rights reserved.
|
||||
|
||||
#include <dpmi.h>
|
||||
#include "quakedef.h"
|
||||
#include "dosisms.h"
|
||||
|
||||
extern cvar_t bgmvolume;
|
||||
|
||||
#define ADDRESS_MODE_HSG 0
|
||||
#define ADDRESS_MODE_RED_BOOK 1
|
||||
|
||||
#define STATUS_ERROR_BIT 0x8000
|
||||
#define STATUS_BUSY_BIT 0x0200
|
||||
#define STATUS_DONE_BIT 0x0100
|
||||
#define STATUS_ERROR_MASK 0x00ff
|
||||
|
||||
#define ERROR_WRITE_PROTECT 0
|
||||
#define ERROR_UNKNOWN_UNIT 1
|
||||
#define ERROR_DRIVE_NOT_READY 2
|
||||
#define ERROR_UNKNOWN_COMMAND 3
|
||||
#define ERROR_CRC_ERROR 4
|
||||
#define ERROR_BAD_REQUEST_LEN 5
|
||||
#define ERROR_SEEK_ERROR 6
|
||||
#define ERROR_UNKNOWN_MEDIA 7
|
||||
#define ERROR_SECTOR_NOT_FOUND 8
|
||||
#define ERROR_OUT_OF_PAPER 9
|
||||
#define ERROR_WRITE_FAULT 10
|
||||
#define ERROR_READ_FAULT 11
|
||||
#define ERROR_GENERAL_FAILURE 12
|
||||
#define ERROR_RESERVED_13 13
|
||||
#define ERROR_RESERVED_14 14
|
||||
#define ERROR_BAD_DISK_CHANGE 15
|
||||
|
||||
#define COMMAND_READ 3
|
||||
#define COMMAND_WRITE 12
|
||||
#define COMMAND_PLAY_AUDIO 132
|
||||
#define COMMAND_STOP_AUDIO 133
|
||||
#define COMMAND_RESUME_AUDIO 136
|
||||
|
||||
#define READ_REQUEST_AUDIO_CHANNEL_INFO 4
|
||||
#define READ_REQUEST_DEVICE_STATUS 6
|
||||
#define READ_REQUEST_MEDIA_CHANGE 9
|
||||
#define READ_REQUEST_AUDIO_DISK_INFO 10
|
||||
#define READ_REQUEST_AUDIO_TRACK_INFO 11
|
||||
#define READ_REQUEST_AUDIO_STATUS 15
|
||||
|
||||
#define WRITE_REQUEST_EJECT 0
|
||||
#define WRITE_REQUEST_RESET 2
|
||||
#define WRITE_REQUEST_AUDIO_CHANNEL_INFO 3
|
||||
|
||||
#define STATUS_DOOR_OPEN 0x00000001
|
||||
#define STATUS_DOOR_UNLOCKED 0x00000002
|
||||
#define STATUS_RAW_SUPPORT 0x00000004
|
||||
#define STATUS_READ_WRITE 0x00000008
|
||||
#define STATUS_AUDIO_SUPPORT 0x00000010
|
||||
#define STATUS_INTERLEAVE_SUPPORT 0x00000020
|
||||
#define STATUS_BIT_6_RESERVED 0x00000040
|
||||
#define STATUS_PREFETCH_SUPPORT 0x00000080
|
||||
#define STATUS_AUDIO_MANIPLUATION_SUPPORT 0x00000100
|
||||
#define STATUS_RED_BOOK_ADDRESS_SUPPORT 0x00000200
|
||||
|
||||
#define MEDIA_NOT_CHANGED 1
|
||||
#define MEDIA_STATUS_UNKNOWN 0
|
||||
#define MEDIA_CHANGED -1
|
||||
|
||||
#define AUDIO_CONTROL_MASK 0xd0
|
||||
#define AUDIO_CONTROL_DATA_TRACK 0x40
|
||||
#define AUDIO_CONTROL_AUDIO_2_TRACK 0x00
|
||||
#define AUDIO_CONTROL_AUDIO_2P_TRACK 0x10
|
||||
#define AUDIO_CONTROL_AUDIO_4_TRACK 0x80
|
||||
#define AUDIO_CONTROL_AUDIO_4P_TRACK 0x90
|
||||
|
||||
#define AUDIO_STATUS_PAUSED 0x0001
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
struct playAudioRequest
|
||||
{
|
||||
char addressingMode;
|
||||
int startLocation;
|
||||
int sectors;
|
||||
};
|
||||
|
||||
struct readRequest
|
||||
{
|
||||
char mediaDescriptor;
|
||||
short bufferOffset;
|
||||
short bufferSegment;
|
||||
short length;
|
||||
short startSector;
|
||||
int volumeID;
|
||||
};
|
||||
|
||||
struct writeRequest
|
||||
{
|
||||
char mediaDescriptor;
|
||||
short bufferOffset;
|
||||
short bufferSegment;
|
||||
short length;
|
||||
short startSector;
|
||||
int volumeID;
|
||||
};
|
||||
|
||||
struct cd_request
|
||||
{
|
||||
char headerLength;
|
||||
char unit;
|
||||
char command;
|
||||
short status;
|
||||
char reserved[8];
|
||||
union
|
||||
{
|
||||
struct playAudioRequest playAudio;
|
||||
struct readRequest read;
|
||||
struct writeRequest write;
|
||||
} x;
|
||||
};
|
||||
|
||||
|
||||
struct audioChannelInfo_s
|
||||
{
|
||||
char code;
|
||||
char channel0input;
|
||||
char channel0volume;
|
||||
char channel1input;
|
||||
char channel1volume;
|
||||
char channel2input;
|
||||
char channel2volume;
|
||||
char channel3input;
|
||||
char channel3volume;
|
||||
};
|
||||
|
||||
struct deviceStatus_s
|
||||
{
|
||||
char code;
|
||||
int status;
|
||||
};
|
||||
|
||||
struct mediaChange_s
|
||||
{
|
||||
char code;
|
||||
char status;
|
||||
};
|
||||
|
||||
struct audioDiskInfo_s
|
||||
{
|
||||
char code;
|
||||
char lowTrack;
|
||||
char highTrack;
|
||||
int leadOutStart;
|
||||
};
|
||||
|
||||
struct audioTrackInfo_s
|
||||
{
|
||||
char code;
|
||||
char track;
|
||||
int start;
|
||||
char control;
|
||||
};
|
||||
|
||||
struct audioStatus_s
|
||||
{
|
||||
char code;
|
||||
short status;
|
||||
int PRstartLocation;
|
||||
int PRendLocation;
|
||||
};
|
||||
|
||||
struct reset_s
|
||||
{
|
||||
char code;
|
||||
};
|
||||
|
||||
union readInfo_u
|
||||
{
|
||||
struct audioChannelInfo_s audioChannelInfo;
|
||||
struct deviceStatus_s deviceStatus;
|
||||
struct mediaChange_s mediaChange;
|
||||
struct audioDiskInfo_s audioDiskInfo;
|
||||
struct audioTrackInfo_s audioTrackInfo;
|
||||
struct audioStatus_s audioStatus;
|
||||
struct reset_s reset;
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
#define MAXIMUM_TRACKS 100
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int start;
|
||||
int length;
|
||||
qboolean isData;
|
||||
} track_info;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
qboolean valid;
|
||||
int leadOutAddress;
|
||||
track_info track[MAXIMUM_TRACKS];
|
||||
byte lowTrack;
|
||||
byte highTrack;
|
||||
} cd_info;
|
||||
|
||||
static struct cd_request *cdRequest;
|
||||
static union readInfo_u *readInfo;
|
||||
static cd_info cd;
|
||||
|
||||
static qboolean playing = false;
|
||||
static qboolean wasPlaying = false;
|
||||
static qboolean mediaCheck = false;
|
||||
static qboolean initialized = false;
|
||||
static qboolean enabled = true;
|
||||
static qboolean playLooping = false;
|
||||
static short cdRequestSegment;
|
||||
static short cdRequestOffset;
|
||||
static short readInfoSegment;
|
||||
static short readInfoOffset;
|
||||
static byte remap[256];
|
||||
static byte cdrom;
|
||||
static byte playTrack;
|
||||
static byte cdvolume;
|
||||
|
||||
|
||||
static int RedBookToSector(int rb)
|
||||
{
|
||||
byte minute;
|
||||
byte second;
|
||||
byte frame;
|
||||
|
||||
minute = (rb >> 16) & 0xff;
|
||||
second = (rb >> 8) & 0xff;
|
||||
frame = rb & 0xff;
|
||||
return minute * 60 * 75 + second * 75 + frame;
|
||||
}
|
||||
|
||||
|
||||
static void CDAudio_Reset(void)
|
||||
{
|
||||
cdRequest->headerLength = 13;
|
||||
cdRequest->unit = 0;
|
||||
cdRequest->command = COMMAND_WRITE;
|
||||
cdRequest->status = 0;
|
||||
|
||||
cdRequest->x.write.mediaDescriptor = 0;
|
||||
cdRequest->x.write.bufferOffset = readInfoOffset;
|
||||
cdRequest->x.write.bufferSegment = readInfoSegment;
|
||||
cdRequest->x.write.length = sizeof(struct reset_s);
|
||||
cdRequest->x.write.startSector = 0;
|
||||
cdRequest->x.write.volumeID = 0;
|
||||
|
||||
readInfo->reset.code = WRITE_REQUEST_RESET;
|
||||
|
||||
regs.x.ax = 0x1510;
|
||||
regs.x.cx = cdrom;
|
||||
regs.x.es = cdRequestSegment;
|
||||
regs.x.bx = cdRequestOffset;
|
||||
dos_int86 (0x2f);
|
||||
}
|
||||
|
||||
|
||||
static void CDAudio_Eject(void)
|
||||
{
|
||||
cdRequest->headerLength = 13;
|
||||
cdRequest->unit = 0;
|
||||
cdRequest->command = COMMAND_WRITE;
|
||||
cdRequest->status = 0;
|
||||
|
||||
cdRequest->x.write.mediaDescriptor = 0;
|
||||
cdRequest->x.write.bufferOffset = readInfoOffset;
|
||||
cdRequest->x.write.bufferSegment = readInfoSegment;
|
||||
cdRequest->x.write.length = sizeof(struct reset_s);
|
||||
cdRequest->x.write.startSector = 0;
|
||||
cdRequest->x.write.volumeID = 0;
|
||||
|
||||
readInfo->reset.code = WRITE_REQUEST_EJECT;
|
||||
|
||||
regs.x.ax = 0x1510;
|
||||
regs.x.cx = cdrom;
|
||||
regs.x.es = cdRequestSegment;
|
||||
regs.x.bx = cdRequestOffset;
|
||||
dos_int86 (0x2f);
|
||||
}
|
||||
|
||||
|
||||
static int CDAudio_GetAudioTrackInfo(byte track, int *start)
|
||||
{
|
||||
byte control;
|
||||
|
||||
cdRequest->headerLength = 13;
|
||||
cdRequest->unit = 0;
|
||||
cdRequest->command = COMMAND_READ;
|
||||
cdRequest->status = 0;
|
||||
|
||||
cdRequest->x.read.mediaDescriptor = 0;
|
||||
cdRequest->x.read.bufferOffset = readInfoOffset;
|
||||
cdRequest->x.read.bufferSegment = readInfoSegment;
|
||||
cdRequest->x.read.length = sizeof(struct audioTrackInfo_s);
|
||||
cdRequest->x.read.startSector = 0;
|
||||
cdRequest->x.read.volumeID = 0;
|
||||
|
||||
readInfo->audioTrackInfo.code = READ_REQUEST_AUDIO_TRACK_INFO;
|
||||
readInfo->audioTrackInfo.track = track;
|
||||
|
||||
regs.x.ax = 0x1510;
|
||||
regs.x.cx = cdrom;
|
||||
regs.x.es = cdRequestSegment;
|
||||
regs.x.bx = cdRequestOffset;
|
||||
dos_int86 (0x2f);
|
||||
|
||||
if (cdRequest->status & STATUS_ERROR_BIT)
|
||||
{
|
||||
Con_DPrintf("CDAudio_GetAudioTrackInfo %04x\n", cdRequest->status & 0xffff);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*start = readInfo->audioTrackInfo.start;
|
||||
control = readInfo->audioTrackInfo.control & AUDIO_CONTROL_MASK;
|
||||
return (control & AUDIO_CONTROL_DATA_TRACK);
|
||||
}
|
||||
|
||||
|
||||
static int CDAudio_GetAudioDiskInfo(void)
|
||||
{
|
||||
int n;
|
||||
|
||||
cdRequest->headerLength = 13;
|
||||
cdRequest->unit = 0;
|
||||
cdRequest->command = COMMAND_READ;
|
||||
cdRequest->status = 0;
|
||||
|
||||
cdRequest->x.read.mediaDescriptor = 0;
|
||||
cdRequest->x.read.bufferOffset = readInfoOffset;
|
||||
cdRequest->x.read.bufferSegment = readInfoSegment;
|
||||
cdRequest->x.read.length = sizeof(struct audioDiskInfo_s);
|
||||
cdRequest->x.read.startSector = 0;
|
||||
cdRequest->x.read.volumeID = 0;
|
||||
|
||||
readInfo->audioDiskInfo.code = READ_REQUEST_AUDIO_DISK_INFO;
|
||||
|
||||
regs.x.ax = 0x1510;
|
||||
regs.x.cx = cdrom;
|
||||
regs.x.es = cdRequestSegment;
|
||||
regs.x.bx = cdRequestOffset;
|
||||
dos_int86 (0x2f);
|
||||
|
||||
if (cdRequest->status & STATUS_ERROR_BIT)
|
||||
{
|
||||
Con_DPrintf("CDAudio_GetAudioDiskInfo %04x\n", cdRequest->status & 0xffff);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cd.valid = true;
|
||||
cd.lowTrack = readInfo->audioDiskInfo.lowTrack;
|
||||
cd.highTrack = readInfo->audioDiskInfo.highTrack;
|
||||
cd.leadOutAddress = readInfo->audioDiskInfo.leadOutStart;
|
||||
|
||||
for (n = cd.lowTrack; n <= cd.highTrack; n++)
|
||||
{
|
||||
cd.track[n].isData = CDAudio_GetAudioTrackInfo (n, &cd.track[n].start);
|
||||
if (n > cd.lowTrack)
|
||||
{
|
||||
cd.track[n-1].length = RedBookToSector(cd.track[n].start) - RedBookToSector(cd.track[n-1].start);
|
||||
if (n == cd.highTrack)
|
||||
cd.track[n].length = RedBookToSector(cd.leadOutAddress) - RedBookToSector(cd.track[n].start);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int CDAudio_GetAudioStatus(void)
|
||||
{
|
||||
cdRequest->headerLength = 13;
|
||||
cdRequest->unit = 0;
|
||||
cdRequest->command = COMMAND_READ;
|
||||
cdRequest->status = 0;
|
||||
|
||||
cdRequest->x.read.mediaDescriptor = 0;
|
||||
cdRequest->x.read.bufferOffset = readInfoOffset;
|
||||
cdRequest->x.read.bufferSegment = readInfoSegment;
|
||||
cdRequest->x.read.length = sizeof(struct audioStatus_s);
|
||||
cdRequest->x.read.startSector = 0;
|
||||
cdRequest->x.read.volumeID = 0;
|
||||
|
||||
readInfo->audioDiskInfo.code = READ_REQUEST_AUDIO_STATUS;
|
||||
|
||||
regs.x.ax = 0x1510;
|
||||
regs.x.cx = cdrom;
|
||||
regs.x.es = cdRequestSegment;
|
||||
regs.x.bx = cdRequestOffset;
|
||||
dos_int86 (0x2f);
|
||||
|
||||
if (cdRequest->status & STATUS_ERROR_BIT)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int CDAudio_MediaChange(void)
|
||||
{
|
||||
cdRequest->headerLength = 13;
|
||||
cdRequest->unit = 0;
|
||||
cdRequest->command = COMMAND_READ;
|
||||
cdRequest->status = 0;
|
||||
|
||||
cdRequest->x.read.mediaDescriptor = 0;
|
||||
cdRequest->x.read.bufferOffset = readInfoOffset;
|
||||
cdRequest->x.read.bufferSegment = readInfoSegment;
|
||||
cdRequest->x.read.length = sizeof(struct mediaChange_s);
|
||||
cdRequest->x.read.startSector = 0;
|
||||
cdRequest->x.read.volumeID = 0;
|
||||
|
||||
readInfo->mediaChange.code = READ_REQUEST_MEDIA_CHANGE;
|
||||
|
||||
regs.x.ax = 0x1510;
|
||||
regs.x.cx = cdrom;
|
||||
regs.x.es = cdRequestSegment;
|
||||
regs.x.bx = cdRequestOffset;
|
||||
dos_int86 (0x2f);
|
||||
|
||||
return readInfo->mediaChange.status;
|
||||
}
|
||||
|
||||
|
||||
// we set the volume to 0 first and then to the desired volume
|
||||
// some cd-rom drivers seem to need it done this way
|
||||
void CDAudio_SetVolume (byte volume)
|
||||
{
|
||||
if (!initialized || !enabled)
|
||||
return;
|
||||
|
||||
cdRequest->headerLength = 13;
|
||||
cdRequest->unit = 0;
|
||||
cdRequest->command = COMMAND_WRITE;
|
||||
cdRequest->status = 0;
|
||||
|
||||
cdRequest->x.read.mediaDescriptor = 0;
|
||||
cdRequest->x.read.bufferOffset = readInfoOffset;
|
||||
cdRequest->x.read.bufferSegment = readInfoSegment;
|
||||
cdRequest->x.read.length = sizeof(struct audioChannelInfo_s);
|
||||
cdRequest->x.read.startSector = 0;
|
||||
cdRequest->x.read.volumeID = 0;
|
||||
|
||||
readInfo->audioChannelInfo.code = WRITE_REQUEST_AUDIO_CHANNEL_INFO;
|
||||
readInfo->audioChannelInfo.channel0input = 0;
|
||||
readInfo->audioChannelInfo.channel0volume = 0;
|
||||
readInfo->audioChannelInfo.channel1input = 1;
|
||||
readInfo->audioChannelInfo.channel1volume = 0;
|
||||
readInfo->audioChannelInfo.channel2input = 2;
|
||||
readInfo->audioChannelInfo.channel2volume = 0;
|
||||
readInfo->audioChannelInfo.channel3input = 3;
|
||||
readInfo->audioChannelInfo.channel3volume = 0;
|
||||
|
||||
regs.x.ax = 0x1510;
|
||||
regs.x.cx = cdrom;
|
||||
regs.x.es = cdRequestSegment;
|
||||
regs.x.bx = cdRequestOffset;
|
||||
dos_int86 (0x2f);
|
||||
|
||||
readInfo->audioChannelInfo.channel0volume = volume;
|
||||
readInfo->audioChannelInfo.channel1volume = volume;
|
||||
|
||||
regs.x.ax = 0x1510;
|
||||
regs.x.cx = cdrom;
|
||||
regs.x.es = cdRequestSegment;
|
||||
regs.x.bx = cdRequestOffset;
|
||||
dos_int86 (0x2f);
|
||||
|
||||
cdvolume = volume;
|
||||
}
|
||||
|
||||
|
||||
void CDAudio_Play(byte track, qboolean looping)
|
||||
{
|
||||
int volume;
|
||||
|
||||
if (!initialized || !enabled)
|
||||
return;
|
||||
|
||||
if (!cd.valid)
|
||||
return;
|
||||
|
||||
track = remap[track];
|
||||
|
||||
if (playing)
|
||||
{
|
||||
if (playTrack == track)
|
||||
return;
|
||||
CDAudio_Stop();
|
||||
}
|
||||
|
||||
playLooping = looping;
|
||||
|
||||
if (track < cd.lowTrack || track > cd.highTrack)
|
||||
{
|
||||
Con_DPrintf("CDAudio_Play: Bad track number %u.\n", track);
|
||||
return;
|
||||
}
|
||||
|
||||
playTrack = track;
|
||||
|
||||
if (cd.track[track].isData)
|
||||
{
|
||||
Con_DPrintf("CDAudio_Play: Can not play data.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
volume = (int)(bgmvolume.value * 255.0);
|
||||
if (volume < 0)
|
||||
{
|
||||
Cvar_SetValue ("bgmvolume", 0.0);
|
||||
volume = 0;
|
||||
}
|
||||
else if (volume > 255)
|
||||
{
|
||||
Cvar_SetValue ("bgmvolume", 1.0);
|
||||
volume = 255;
|
||||
}
|
||||
CDAudio_SetVolume (volume);
|
||||
|
||||
cdRequest->headerLength = 13;
|
||||
cdRequest->unit = 0;
|
||||
cdRequest->command = COMMAND_PLAY_AUDIO;
|
||||
cdRequest->status = 0;
|
||||
|
||||
cdRequest->x.playAudio.addressingMode = ADDRESS_MODE_RED_BOOK;
|
||||
cdRequest->x.playAudio.startLocation = cd.track[track].start;
|
||||
cdRequest->x.playAudio.sectors = cd.track[track].length;
|
||||
|
||||
regs.x.ax = 0x1510;
|
||||
regs.x.cx = cdrom;
|
||||
regs.x.es = cdRequestSegment;
|
||||
regs.x.bx = cdRequestOffset;
|
||||
dos_int86 (0x2f);
|
||||
|
||||
if (cdRequest->status & STATUS_ERROR_BIT)
|
||||
{
|
||||
Con_DPrintf("CDAudio_Play: track %u failed\n", track);
|
||||
cd.valid = false;
|
||||
playing = false;
|
||||
return;
|
||||
}
|
||||
|
||||
playing = true;
|
||||
}
|
||||
|
||||
|
||||
void CDAudio_Stop(void)
|
||||
{
|
||||
if (!initialized || !enabled)
|
||||
return;
|
||||
|
||||
cdRequest->headerLength = 13;
|
||||
cdRequest->unit = 0;
|
||||
cdRequest->command = COMMAND_STOP_AUDIO;
|
||||
cdRequest->status = 0;
|
||||
|
||||
regs.x.ax = 0x1510;
|
||||
regs.x.cx = cdrom;
|
||||
regs.x.es = cdRequestSegment;
|
||||
regs.x.bx = cdRequestOffset;
|
||||
dos_int86 (0x2f);
|
||||
|
||||
wasPlaying = playing;
|
||||
playing = false;
|
||||
}
|
||||
|
||||
|
||||
void CDAudio_Pause(void)
|
||||
{
|
||||
CDAudio_Stop();
|
||||
}
|
||||
|
||||
|
||||
void CDAudio_Resume(void)
|
||||
{
|
||||
if (!initialized || !enabled)
|
||||
return;
|
||||
|
||||
if (!cd.valid)
|
||||
return;
|
||||
|
||||
if (!wasPlaying)
|
||||
return;
|
||||
|
||||
cdRequest->headerLength = 13;
|
||||
cdRequest->unit = 0;
|
||||
cdRequest->command = COMMAND_RESUME_AUDIO;
|
||||
cdRequest->status = 0;
|
||||
|
||||
regs.x.ax = 0x1510;
|
||||
regs.x.cx = cdrom;
|
||||
regs.x.es = cdRequestSegment;
|
||||
regs.x.bx = cdRequestOffset;
|
||||
dos_int86 (0x2f);
|
||||
|
||||
playing = true;
|
||||
}
|
||||
|
||||
|
||||
static void CD_f (void)
|
||||
{
|
||||
char *command;
|
||||
int ret;
|
||||
int n;
|
||||
int startAddress;
|
||||
|
||||
if (Cmd_Argc() < 2)
|
||||
return;
|
||||
|
||||
command = Cmd_Argv (1);
|
||||
|
||||
if (Q_strcasecmp(command, "on") == 0)
|
||||
{
|
||||
enabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "off") == 0)
|
||||
{
|
||||
if (playing)
|
||||
CDAudio_Stop();
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "reset") == 0)
|
||||
{
|
||||
enabled = true;
|
||||
if (playing)
|
||||
CDAudio_Stop();
|
||||
for (n = 0; n < 256; n++)
|
||||
remap[n] = n;
|
||||
CDAudio_Reset();
|
||||
CDAudio_GetAudioDiskInfo();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "remap") == 0)
|
||||
{
|
||||
ret = Cmd_Argc() - 2;
|
||||
if (ret <= 0)
|
||||
{
|
||||
for (n = 1; n < 256; n++)
|
||||
if (remap[n] != n)
|
||||
Con_Printf(" %u -> %u\n", n, remap[n]);
|
||||
return;
|
||||
}
|
||||
for (n = 1; n <= ret; n++)
|
||||
remap[n] = Q_atoi(Cmd_Argv (n+1));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cd.valid)
|
||||
{
|
||||
Con_Printf("No CD in player.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "play") == 0)
|
||||
{
|
||||
CDAudio_Play(Q_atoi(Cmd_Argv (2)), false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "loop") == 0)
|
||||
{
|
||||
CDAudio_Play(Q_atoi(Cmd_Argv (2)), true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "stop") == 0)
|
||||
{
|
||||
CDAudio_Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "pause") == 0)
|
||||
{
|
||||
CDAudio_Pause();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "resume") == 0)
|
||||
{
|
||||
CDAudio_Resume();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "eject") == 0)
|
||||
{
|
||||
if (playing)
|
||||
CDAudio_Stop();
|
||||
CDAudio_Eject();
|
||||
cd.valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "info") == 0)
|
||||
{
|
||||
Con_Printf("%u tracks\n", cd.highTrack - cd.lowTrack + 1);
|
||||
for (n = cd.lowTrack; n <= cd.highTrack; n++)
|
||||
{
|
||||
ret = CDAudio_GetAudioTrackInfo (n, &startAddress);
|
||||
Con_Printf("Track %2u: %s at %2u:%02u\n", n, ret ? "data " : "music", (startAddress >> 16) & 0xff, (startAddress >> 8) & 0xff);
|
||||
}
|
||||
if (playing)
|
||||
Con_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack);
|
||||
Con_Printf("Volume is %u\n", cdvolume);
|
||||
CDAudio_MediaChange();
|
||||
Con_Printf("Status %04x\n", cdRequest->status & 0xffff);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CDAudio_Update(void)
|
||||
{
|
||||
int ret;
|
||||
int newVolume;
|
||||
static double lastUpdate;
|
||||
|
||||
if (!initialized || !enabled)
|
||||
return;
|
||||
|
||||
if ((realtime - lastUpdate) < 0.25)
|
||||
return;
|
||||
lastUpdate = realtime;
|
||||
|
||||
if (mediaCheck)
|
||||
{
|
||||
static double lastCheck;
|
||||
|
||||
if ((realtime - lastCheck) < 5.0)
|
||||
return;
|
||||
lastCheck = realtime;
|
||||
|
||||
ret = CDAudio_MediaChange();
|
||||
if (ret == MEDIA_CHANGED)
|
||||
{
|
||||
Con_DPrintf("CDAudio: media changed\n");
|
||||
playing = false;
|
||||
wasPlaying = false;
|
||||
cd.valid = false;
|
||||
CDAudio_GetAudioDiskInfo();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
newVolume = (int)(bgmvolume.value * 255.0);
|
||||
if (newVolume != cdvolume)
|
||||
{
|
||||
if (newVolume < 0)
|
||||
{
|
||||
Cvar_SetValue ("bgmvolume", 0.0);
|
||||
newVolume = 0;
|
||||
}
|
||||
else if (newVolume > 255)
|
||||
{
|
||||
Cvar_SetValue ("bgmvolume", 1.0);
|
||||
newVolume = 255;
|
||||
}
|
||||
CDAudio_SetVolume (newVolume);
|
||||
}
|
||||
|
||||
if (playing)
|
||||
{
|
||||
CDAudio_GetAudioStatus();
|
||||
if ((cdRequest->status & STATUS_BUSY_BIT) == 0)
|
||||
{
|
||||
playing = false;
|
||||
if (playLooping)
|
||||
CDAudio_Play(playTrack, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int CDAudio_Init(void)
|
||||
{
|
||||
char *memory;
|
||||
int n;
|
||||
|
||||
if (cls.state == ca_dedicated)
|
||||
return -1;
|
||||
|
||||
if (COM_CheckParm("-nocdaudio"))
|
||||
return -1;
|
||||
|
||||
if (COM_CheckParm("-cdmediacheck"))
|
||||
mediaCheck = true;
|
||||
|
||||
regs.x.ax = 0x1500;
|
||||
regs.x.bx = 0;
|
||||
dos_int86 (0x2f);
|
||||
if (regs.x.bx == 0)
|
||||
{
|
||||
Con_NotifyBox (
|
||||
"MSCDEX not loaded, music is\n"
|
||||
"disabled. Use \"-nocdaudio\" if you\n"
|
||||
"wish to avoid this message in the\n"
|
||||
"future. See README.TXT for help.\n"
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
if (regs.x.bx > 1)
|
||||
Con_DPrintf("CDAudio_Init: First CD-ROM drive will be used\n");
|
||||
cdrom = regs.x.cx;
|
||||
|
||||
regs.x.ax = 0x150c;
|
||||
regs.x.bx = 0;
|
||||
dos_int86 (0x2f);
|
||||
if (regs.x.bx == 0)
|
||||
{
|
||||
Con_NotifyBox (
|
||||
"MSCDEX version 2.00 or later\n"
|
||||
"required for music. See README.TXT\n"
|
||||
"for help.\n"
|
||||
);
|
||||
Con_DPrintf("CDAudio_Init: MSCDEX version 2.00 or later required.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memory = dos_getmemory(sizeof(struct cd_request
|
||||
) + sizeof(union readInfo_u));
|
||||
if (memory == NULL)
|
||||
{
|
||||
Con_DPrintf("CDAudio_Init: Unable to allocate low memory.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cdRequest = (struct cd_request *)memory;
|
||||
cdRequestSegment = ptr2real(cdRequest) >> 4;
|
||||
cdRequestOffset = ptr2real(cdRequest) & 0xf;
|
||||
|
||||
readInfo = (union readInfo_u *)(memory + sizeof(struct cd_request));
|
||||
readInfoSegment = ptr2real(readInfo) >> 4;
|
||||
readInfoOffset = ptr2real(readInfo) & 0xf;
|
||||
|
||||
for (n = 0; n < 256; n++)
|
||||
remap[n] = n;
|
||||
initialized = true;
|
||||
|
||||
CDAudio_SetVolume (255);
|
||||
if (CDAudio_GetAudioDiskInfo())
|
||||
{
|
||||
Con_Printf("CDAudio_Init: No CD in player.\n");
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
Cmd_AddCommand ("cd", CD_f);
|
||||
|
||||
Con_Printf("CD Audio Initialized\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void CDAudio_Shutdown(void)
|
||||
{
|
||||
if (!initialized)
|
||||
return;
|
||||
CDAudio_Stop();
|
||||
}
|
77
dosasm.s
77
dosasm.s
|
@ -1,77 +0,0 @@
|
|||
#include "asm_i386.h"
|
||||
|
||||
.data
|
||||
fpenv: .long 0, 0, 0, 0, 0, 0, 0, 0
|
||||
|
||||
.text
|
||||
.globl C(StartMSRInterval)
|
||||
C(StartMSRInterval):
|
||||
movl $0x11,%ecx // read the CESR
|
||||
.byte 0x0F
|
||||
.byte 0x32 // RDMSR
|
||||
|
||||
andl $0xFE3FFE3F,%eax // stop both counters
|
||||
.byte 0x0F
|
||||
.byte 0x30 // WRMSR
|
||||
|
||||
movl 4(%esp),%eax // point counter 0 to desired event, with counters
|
||||
andl $0x3F,%eax // still stopped
|
||||
movl $0x11,%ecx
|
||||
.byte 0x0F
|
||||
.byte 0x30 // WRMSR
|
||||
|
||||
movl $0x12,%ecx // set counter 0 to the value 0
|
||||
subl %eax,%eax
|
||||
subl %edx,%edx
|
||||
.byte 0x0F
|
||||
.byte 0x30 // WRMSR
|
||||
|
||||
movl 4(%esp),%eax // restart counter 0 with selected event
|
||||
andl $0x3F,%eax
|
||||
subl %edx,%edx
|
||||
orl $0xC0,%eax
|
||||
movl $0x11,%ecx // control and event select
|
||||
.byte 0x0F
|
||||
.byte 0x30 // WRMSR
|
||||
|
||||
ret
|
||||
|
||||
.globl C(EndMSRInterval)
|
||||
C(EndMSRInterval):
|
||||
movl $0x12,%ecx // counter 0
|
||||
.byte 0x0F
|
||||
.byte 0x32 // RDMSR
|
||||
|
||||
ret // lower 32 bits of count in %eax
|
||||
|
||||
#if 0
|
||||
.data
|
||||
Lxxx: .long 0
|
||||
|
||||
.text
|
||||
|
||||
.globl C(setstackcheck)
|
||||
C(setstackcheck):
|
||||
|
||||
movl %esp,%eax
|
||||
subl $0x38000,%eax
|
||||
movl $0x5A5A5A5A,(%eax)
|
||||
movl %eax,Lxxx
|
||||
|
||||
ret
|
||||
|
||||
|
||||
.globl C(dostackcheck)
|
||||
C(dostackcheck):
|
||||
|
||||
movl Lxxx,%edx
|
||||
movl $0,%eax
|
||||
|
||||
cmpl $0x5A5A5A5A,(%edx)
|
||||
jz qqq
|
||||
incl %eax
|
||||
qqq:
|
||||
|
||||
ret
|
||||
#endif
|
||||
|
100
dosisms.h
100
dosisms.h
|
@ -1,100 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
//
|
||||
// dosisms.h: I'd call it dos.h, but the name's taken
|
||||
//
|
||||
|
||||
#ifndef _DOSISMS_H_
|
||||
#define _DOSISMS_H_
|
||||
|
||||
int dos_lockmem(void *addr, int size);
|
||||
int dos_unlockmem(void *addr, int size);
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
unsigned long edi;
|
||||
unsigned long esi;
|
||||
unsigned long ebp;
|
||||
unsigned long res;
|
||||
unsigned long ebx;
|
||||
unsigned long edx;
|
||||
unsigned long ecx;
|
||||
unsigned long eax;
|
||||
} d;
|
||||
struct {
|
||||
unsigned short di, di_hi;
|
||||
unsigned short si, si_hi;
|
||||
unsigned short bp, bp_hi;
|
||||
unsigned short res, res_hi;
|
||||
unsigned short bx, bx_hi;
|
||||
unsigned short dx, dx_hi;
|
||||
unsigned short cx, cx_hi;
|
||||
unsigned short ax, ax_hi;
|
||||
unsigned short flags;
|
||||
unsigned short es;
|
||||
unsigned short ds;
|
||||
unsigned short fs;
|
||||
unsigned short gs;
|
||||
unsigned short ip;
|
||||
unsigned short cs;
|
||||
unsigned short sp;
|
||||
unsigned short ss;
|
||||
} x;
|
||||
struct {
|
||||
unsigned char edi[4];
|
||||
unsigned char esi[4];
|
||||
unsigned char ebp[4];
|
||||
unsigned char res[4];
|
||||
unsigned char bl, bh, ebx_b2, ebx_b3;
|
||||
unsigned char dl, dh, edx_b2, edx_b3;
|
||||
unsigned char cl, ch, ecx_b2, ecx_b3;
|
||||
unsigned char al, ah, eax_b2, eax_b3;
|
||||
} h;
|
||||
} regs_t;
|
||||
|
||||
unsigned int ptr2real(void *ptr);
|
||||
void *real2ptr(unsigned int real);
|
||||
void *far2ptr(unsigned int farptr);
|
||||
unsigned int ptr2far(void *ptr);
|
||||
|
||||
int dos_inportb(int port);
|
||||
int dos_inportw(int port);
|
||||
void dos_outportb(int port, int val);
|
||||
void dos_outportw(int port, int val);
|
||||
|
||||
void dos_irqenable(void);
|
||||
void dos_irqdisable(void);
|
||||
void dos_registerintr(int intr, void (*handler)(void));
|
||||
void dos_restoreintr(int intr);
|
||||
|
||||
int dos_int86(int vec);
|
||||
|
||||
void *dos_getmemory(int size);
|
||||
void dos_freememory(void *ptr);
|
||||
|
||||
void dos_usleep(int usecs);
|
||||
|
||||
int dos_getheapsize(void);
|
||||
|
||||
extern regs_t regs;
|
||||
|
||||
#endif // _DOSISMS_H_
|
||||
|
902
draw.c
902
draw.c
|
@ -1,902 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
// draw.c -- this is the only file outside the refresh that touches the
|
||||
// vid buffer
|
||||
|
||||
#include "quakedef.h"
|
||||
|
||||
typedef struct {
|
||||
vrect_t rect;
|
||||
int width;
|
||||
int height;
|
||||
byte *ptexbytes;
|
||||
int rowbytes;
|
||||
} rectdesc_t;
|
||||
|
||||
static rectdesc_t r_rectdesc;
|
||||
|
||||
byte *draw_chars; // 8*8 graphic characters
|
||||
qpic_t *draw_disc;
|
||||
qpic_t *draw_backtile;
|
||||
|
||||
//=============================================================================
|
||||
/* Support Routines */
|
||||
|
||||
typedef struct cachepic_s
|
||||
{
|
||||
char name[MAX_QPATH];
|
||||
cache_user_t cache;
|
||||
} cachepic_t;
|
||||
|
||||
#define MAX_CACHED_PICS 128
|
||||
cachepic_t menu_cachepics[MAX_CACHED_PICS];
|
||||
int menu_numcachepics;
|
||||
|
||||
|
||||
qpic_t *Draw_PicFromWad (char *name)
|
||||
{
|
||||
return W_GetLumpName (name);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Draw_CachePic
|
||||
================
|
||||
*/
|
||||
qpic_t *Draw_CachePic (char *path)
|
||||
{
|
||||
cachepic_t *pic;
|
||||
int i;
|
||||
qpic_t *dat;
|
||||
|
||||
for (pic=menu_cachepics, i=0 ; i<menu_numcachepics ; pic++, i++)
|
||||
if (!strcmp (path, pic->name))
|
||||
break;
|
||||
|
||||
if (i == menu_numcachepics)
|
||||
{
|
||||
if (menu_numcachepics == MAX_CACHED_PICS)
|
||||
Sys_Error ("menu_numcachepics == MAX_CACHED_PICS");
|
||||
menu_numcachepics++;
|
||||
strcpy (pic->name, path);
|
||||
}
|
||||
|
||||
dat = Cache_Check (&pic->cache);
|
||||
|
||||
if (dat)
|
||||
return dat;
|
||||
|
||||
//
|
||||
// load the pic from disk
|
||||
//
|
||||
COM_LoadCacheFile (path, &pic->cache);
|
||||
|
||||
dat = (qpic_t *)pic->cache.data;
|
||||
if (!dat)
|
||||
{
|
||||
Sys_Error ("Draw_CachePic: failed to load %s", path);
|
||||
}
|
||||
|
||||
SwapPic (dat);
|
||||
|
||||
return dat;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
Draw_Init
|
||||
===============
|
||||
*/
|
||||
void Draw_Init (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
draw_chars = W_GetLumpName ("conchars");
|
||||
draw_disc = W_GetLumpName ("disc");
|
||||
draw_backtile = W_GetLumpName ("backtile");
|
||||
|
||||
r_rectdesc.width = draw_backtile->width;
|
||||
r_rectdesc.height = draw_backtile->height;
|
||||
r_rectdesc.ptexbytes = draw_backtile->data;
|
||||
r_rectdesc.rowbytes = draw_backtile->width;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Draw_Character
|
||||
|
||||
Draws one 8*8 graphics character with 0 being transparent.
|
||||
It can be clipped to the top of the screen to allow the console to be
|
||||
smoothly scrolled off.
|
||||
================
|
||||
*/
|
||||
void Draw_Character (int x, int y, int num)
|
||||
{
|
||||
byte *dest;
|
||||
byte *source;
|
||||
unsigned short *pusdest;
|
||||
int drawline;
|
||||
int row, col;
|
||||
|
||||
num &= 255;
|
||||
|
||||
if (y <= -8)
|
||||
return; // totally off screen
|
||||
|
||||
#ifdef PARANOID
|
||||
if (y > vid.height - 8 || x < 0 || x > vid.width - 8)
|
||||
Sys_Error ("Con_DrawCharacter: (%i, %i)", x, y);
|
||||
if (num < 0 || num > 255)
|
||||
Sys_Error ("Con_DrawCharacter: char %i", num);
|
||||
#endif
|
||||
|
||||
row = num>>4;
|
||||
col = num&15;
|
||||
source = draw_chars + (row<<10) + (col<<3);
|
||||
|
||||
if (y < 0)
|
||||
{ // clipped
|
||||
drawline = 8 + y;
|
||||
source -= 128*y;
|
||||
y = 0;
|
||||
}
|
||||
else
|
||||
drawline = 8;
|
||||
|
||||
|
||||
if (r_pixbytes == 1)
|
||||
{
|
||||
dest = vid.conbuffer + y*vid.conrowbytes + x;
|
||||
|
||||
while (drawline--)
|
||||
{
|
||||
if (source[0])
|
||||
dest[0] = source[0];
|
||||
if (source[1])
|
||||
dest[1] = source[1];
|
||||
if (source[2])
|
||||
dest[2] = source[2];
|
||||
if (source[3])
|
||||
dest[3] = source[3];
|
||||
if (source[4])
|
||||
dest[4] = source[4];
|
||||
if (source[5])
|
||||
dest[5] = source[5];
|
||||
if (source[6])
|
||||
dest[6] = source[6];
|
||||
if (source[7])
|
||||
dest[7] = source[7];
|
||||
source += 128;
|
||||
dest += vid.conrowbytes;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: pre-expand to native format?
|
||||
pusdest = (unsigned short *)
|
||||
((byte *)vid.conbuffer + y*vid.conrowbytes + (x<<1));
|
||||
|
||||
while (drawline--)
|
||||
{
|
||||
if (source[0])
|
||||
pusdest[0] = d_8to16table[source[0]];
|
||||
if (source[1])
|
||||
pusdest[1] = d_8to16table[source[1]];
|
||||
if (source[2])
|
||||
pusdest[2] = d_8to16table[source[2]];
|
||||
if (source[3])
|
||||
pusdest[3] = d_8to16table[source[3]];
|
||||
if (source[4])
|
||||
pusdest[4] = d_8to16table[source[4]];
|
||||
if (source[5])
|
||||
pusdest[5] = d_8to16table[source[5]];
|
||||
if (source[6])
|
||||
pusdest[6] = d_8to16table[source[6]];
|
||||
if (source[7])
|
||||
pusdest[7] = d_8to16table[source[7]];
|
||||
|
||||
source += 128;
|
||||
pusdest += (vid.conrowbytes >> 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Draw_String
|
||||
================
|
||||
*/
|
||||
void Draw_String (int x, int y, char *str)
|
||||
{
|
||||
while (*str)
|
||||
{
|
||||
Draw_Character (x, y, *str);
|
||||
str++;
|
||||
x += 8;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Draw_DebugChar
|
||||
|
||||
Draws a single character directly to the upper right corner of the screen.
|
||||
This is for debugging lockups by drawing different chars in different parts
|
||||
of the code.
|
||||
================
|
||||
*/
|
||||
void Draw_DebugChar (char num)
|
||||
{
|
||||
byte *dest;
|
||||
byte *source;
|
||||
int drawline;
|
||||
extern byte *draw_chars;
|
||||
int row, col;
|
||||
|
||||
if (!vid.direct)
|
||||
return; // don't have direct FB access, so no debugchars...
|
||||
|
||||
drawline = 8;
|
||||
|
||||
row = num>>4;
|
||||
col = num&15;
|
||||
source = draw_chars + (row<<10) + (col<<3);
|
||||
|
||||
dest = vid.direct + 312;
|
||||
|
||||
while (drawline--)
|
||||
{
|
||||
dest[0] = source[0];
|
||||
dest[1] = source[1];
|
||||
dest[2] = source[2];
|
||||
dest[3] = source[3];
|
||||
dest[4] = source[4];
|
||||
dest[5] = source[5];
|
||||
dest[6] = source[6];
|
||||
dest[7] = source[7];
|
||||
source += 128;
|
||||
dest += 320;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
Draw_Pic
|
||||
=============
|
||||
*/
|
||||
void Draw_Pic (int x, int y, qpic_t *pic)
|
||||
{
|
||||
byte *dest, *source;
|
||||
unsigned short *pusdest;
|
||||
int v, u;
|
||||
|
||||
if ((x < 0) ||
|
||||
(x + pic->width > vid.width) ||
|
||||
(y < 0) ||
|
||||
(y + pic->height > vid.height))
|
||||
{
|
||||
Sys_Error ("Draw_Pic: bad coordinates");
|
||||
}
|
||||
|
||||
source = pic->data;
|
||||
|
||||
if (r_pixbytes == 1)
|
||||
{
|
||||
dest = vid.buffer + y * vid.rowbytes + x;
|
||||
|
||||
for (v=0 ; v<pic->height ; v++)
|
||||
{
|
||||
Q_memcpy (dest, source, pic->width);
|
||||
dest += vid.rowbytes;
|
||||
source += pic->width;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: pretranslate at load time?
|
||||
pusdest = (unsigned short *)vid.buffer + y * (vid.rowbytes >> 1) + x;
|
||||
|
||||
for (v=0 ; v<pic->height ; v++)
|
||||
{
|
||||
for (u=0 ; u<pic->width ; u++)
|
||||
{
|
||||
pusdest[u] = d_8to16table[source[u]];
|
||||
}
|
||||
|
||||
pusdest += vid.rowbytes >> 1;
|
||||
source += pic->width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
Draw_TransPic
|
||||
=============
|
||||
*/
|
||||
void Draw_TransPic (int x, int y, qpic_t *pic)
|
||||
{
|
||||
byte *dest, *source, tbyte;
|
||||
unsigned short *pusdest;
|
||||
int v, u;
|
||||
|
||||
if (x < 0 || (unsigned)(x + pic->width) > vid.width || y < 0 ||
|
||||
(unsigned)(y + pic->height) > vid.height)
|
||||
{
|
||||
Sys_Error ("Draw_TransPic: bad coordinates");
|
||||
}
|
||||
|
||||
source = pic->data;
|
||||
|
||||
if (r_pixbytes == 1)
|
||||
{
|
||||
dest = vid.buffer + y * vid.rowbytes + x;
|
||||
|
||||
if (pic->width & 7)
|
||||
{ // general
|
||||
for (v=0 ; v<pic->height ; v++)
|
||||
{
|
||||
for (u=0 ; u<pic->width ; u++)
|
||||
if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
|
||||
dest[u] = tbyte;
|
||||
|
||||
dest += vid.rowbytes;
|
||||
source += pic->width;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // unwound
|
||||
for (v=0 ; v<pic->height ; v++)
|
||||
{
|
||||
for (u=0 ; u<pic->width ; u+=8)
|
||||
{
|
||||
if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
|
||||
dest[u] = tbyte;
|
||||
if ( (tbyte=source[u+1]) != TRANSPARENT_COLOR)
|
||||
dest[u+1] = tbyte;
|
||||
if ( (tbyte=source[u+2]) != TRANSPARENT_COLOR)
|
||||
dest[u+2] = tbyte;
|
||||
if ( (tbyte=source[u+3]) != TRANSPARENT_COLOR)
|
||||
dest[u+3] = tbyte;
|
||||
if ( (tbyte=source[u+4]) != TRANSPARENT_COLOR)
|
||||
dest[u+4] = tbyte;
|
||||
if ( (tbyte=source[u+5]) != TRANSPARENT_COLOR)
|
||||
dest[u+5] = tbyte;
|
||||
if ( (tbyte=source[u+6]) != TRANSPARENT_COLOR)
|
||||
dest[u+6] = tbyte;
|
||||
if ( (tbyte=source[u+7]) != TRANSPARENT_COLOR)
|
||||
dest[u+7] = tbyte;
|
||||
}
|
||||
dest += vid.rowbytes;
|
||||
source += pic->width;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: pretranslate at load time?
|
||||
pusdest = (unsigned short *)vid.buffer + y * (vid.rowbytes >> 1) + x;
|
||||
|
||||
for (v=0 ; v<pic->height ; v++)
|
||||
{
|
||||
for (u=0 ; u<pic->width ; u++)
|
||||
{
|
||||
tbyte = source[u];
|
||||
|
||||
if (tbyte != TRANSPARENT_COLOR)
|
||||
{
|
||||
pusdest[u] = d_8to16table[tbyte];
|
||||
}
|
||||
}
|
||||
|
||||
pusdest += vid.rowbytes >> 1;
|
||||
source += pic->width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
Draw_TransPicTranslate
|
||||
=============
|
||||
*/
|
||||
void Draw_TransPicTranslate (int x, int y, qpic_t *pic, byte *translation)
|
||||
{
|
||||
byte *dest, *source, tbyte;
|
||||
unsigned short *pusdest;
|
||||
int v, u;
|
||||
|
||||
if (x < 0 || (unsigned)(x + pic->width) > vid.width || y < 0 ||
|
||||
(unsigned)(y + pic->height) > vid.height)
|
||||
{
|
||||
Sys_Error ("Draw_TransPic: bad coordinates");
|
||||
}
|
||||
|
||||
source = pic->data;
|
||||
|
||||
if (r_pixbytes == 1)
|
||||
{
|
||||
dest = vid.buffer + y * vid.rowbytes + x;
|
||||
|
||||
if (pic->width & 7)
|
||||
{ // general
|
||||
for (v=0 ; v<pic->height ; v++)
|
||||
{
|
||||
for (u=0 ; u<pic->width ; u++)
|
||||
if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
|
||||
dest[u] = translation[tbyte];
|
||||
|
||||
dest += vid.rowbytes;
|
||||
source += pic->width;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // unwound
|
||||
for (v=0 ; v<pic->height ; v++)
|
||||
{
|
||||
for (u=0 ; u<pic->width ; u+=8)
|
||||
{
|
||||
if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
|
||||
dest[u] = translation[tbyte];
|
||||
if ( (tbyte=source[u+1]) != TRANSPARENT_COLOR)
|
||||
dest[u+1] = translation[tbyte];
|
||||
if ( (tbyte=source[u+2]) != TRANSPARENT_COLOR)
|
||||
dest[u+2] = translation[tbyte];
|
||||
if ( (tbyte=source[u+3]) != TRANSPARENT_COLOR)
|
||||
dest[u+3] = translation[tbyte];
|
||||
if ( (tbyte=source[u+4]) != TRANSPARENT_COLOR)
|
||||
dest[u+4] = translation[tbyte];
|
||||
if ( (tbyte=source[u+5]) != TRANSPARENT_COLOR)
|
||||
dest[u+5] = translation[tbyte];
|
||||
if ( (tbyte=source[u+6]) != TRANSPARENT_COLOR)
|
||||
dest[u+6] = translation[tbyte];
|
||||
if ( (tbyte=source[u+7]) != TRANSPARENT_COLOR)
|
||||
dest[u+7] = translation[tbyte];
|
||||
}
|
||||
dest += vid.rowbytes;
|
||||
source += pic->width;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: pretranslate at load time?
|
||||
pusdest = (unsigned short *)vid.buffer + y * (vid.rowbytes >> 1) + x;
|
||||
|
||||
for (v=0 ; v<pic->height ; v++)
|
||||
{
|
||||
for (u=0 ; u<pic->width ; u++)
|
||||
{
|
||||
tbyte = source[u];
|
||||
|
||||
if (tbyte != TRANSPARENT_COLOR)
|
||||
{
|
||||
pusdest[u] = d_8to16table[tbyte];
|
||||
}
|
||||
}
|
||||
|
||||
pusdest += vid.rowbytes >> 1;
|
||||
source += pic->width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Draw_CharToConback (int num, byte *dest)
|
||||
{
|
||||
int row, col;
|
||||
byte *source;
|
||||
int drawline;
|
||||
int x;
|
||||
|
||||
row = num>>4;
|
||||
col = num&15;
|
||||
source = draw_chars + (row<<10) + (col<<3);
|
||||
|
||||
drawline = 8;
|
||||
|
||||
while (drawline--)
|
||||
{
|
||||
for (x=0 ; x<8 ; x++)
|
||||
if (source[x])
|
||||
dest[x] = 0x60 + source[x];
|
||||
source += 128;
|
||||
dest += 320;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Draw_ConsoleBackground
|
||||
|
||||
================
|
||||
*/
|
||||
void Draw_ConsoleBackground (int lines)
|
||||
{
|
||||
int x, y, v;
|
||||
byte *src, *dest;
|
||||
unsigned short *pusdest;
|
||||
int f, fstep;
|
||||
qpic_t *conback;
|
||||
char ver[100];
|
||||
|
||||
conback = Draw_CachePic ("gfx/conback.lmp");
|
||||
|
||||
// hack the version number directly into the pic
|
||||
#ifdef _WIN32
|
||||
sprintf (ver, "(WinQuake) %4.2f", (float)VERSION);
|
||||
dest = conback->data + 320*186 + 320 - 11 - 8*strlen(ver);
|
||||
#elif defined(X11)
|
||||
sprintf (ver, "(X11 Quake %2.2f) %4.2f", (float)X11_VERSION, (float)VERSION);
|
||||
dest = conback->data + 320*186 + 320 - 11 - 8*strlen(ver);
|
||||
#elif defined(__linux__)
|
||||
sprintf (ver, "(Linux Quake %2.2f) %4.2f", (float)LINUX_VERSION, (float)VERSION);
|
||||
dest = conback->data + 320*186 + 320 - 11 - 8*strlen(ver);
|
||||
#else
|
||||
dest = conback->data + 320 - 43 + 320*186;
|
||||
sprintf (ver, "%4.2f", VERSION);
|
||||
#endif
|
||||
|
||||
for (x=0 ; x<strlen(ver) ; x++)
|
||||
Draw_CharToConback (ver[x], dest+(x<<3));
|
||||
|
||||
// draw the pic
|
||||
if (r_pixbytes == 1)
|
||||
{
|
||||
dest = vid.conbuffer;
|
||||
|
||||
for (y=0 ; y<lines ; y++, dest += vid.conrowbytes)
|
||||
{
|
||||
v = (vid.conheight - lines + y)*200/vid.conheight;
|
||||
src = conback->data + v*320;
|
||||
if (vid.conwidth == 320)
|
||||
memcpy (dest, src, vid.conwidth);
|
||||
else
|
||||
{
|
||||
f = 0;
|
||||
fstep = 320*0x10000/vid.conwidth;
|
||||
for (x=0 ; x<vid.conwidth ; x+=4)
|
||||
{
|
||||
dest[x] = src[f>>16];
|
||||
f += fstep;
|
||||
dest[x+1] = src[f>>16];
|
||||
f += fstep;
|
||||
dest[x+2] = src[f>>16];
|
||||
f += fstep;
|
||||
dest[x+3] = src[f>>16];
|
||||
f += fstep;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pusdest = (unsigned short *)vid.conbuffer;
|
||||
|
||||
for (y=0 ; y<lines ; y++, pusdest += (vid.conrowbytes >> 1))
|
||||
{
|
||||
// FIXME: pre-expand to native format?
|
||||
// FIXME: does the endian switching go away in production?
|
||||
v = (vid.conheight - lines + y)*200/vid.conheight;
|
||||
src = conback->data + v*320;
|
||||
f = 0;
|
||||
fstep = 320*0x10000/vid.conwidth;
|
||||
for (x=0 ; x<vid.conwidth ; x+=4)
|
||||
{
|
||||
pusdest[x] = d_8to16table[src[f>>16]];
|
||||
f += fstep;
|
||||
pusdest[x+1] = d_8to16table[src[f>>16]];
|
||||
f += fstep;
|
||||
pusdest[x+2] = d_8to16table[src[f>>16]];
|
||||
f += fstep;
|
||||
pusdest[x+3] = d_8to16table[src[f>>16]];
|
||||
f += fstep;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
R_DrawRect8
|
||||
==============
|
||||
*/
|
||||
void R_DrawRect8 (vrect_t *prect, int rowbytes, byte *psrc,
|
||||
int transparent)
|
||||
{
|
||||
byte t;
|
||||
int i, j, srcdelta, destdelta;
|
||||
byte *pdest;
|
||||
|
||||
pdest = vid.buffer + (prect->y * vid.rowbytes) + prect->x;
|
||||
|
||||
srcdelta = rowbytes - prect->width;
|
||||
destdelta = vid.rowbytes - prect->width;
|
||||
|
||||
if (transparent)
|
||||
{
|
||||
for (i=0 ; i<prect->height ; i++)
|
||||
{
|
||||
for (j=0 ; j<prect->width ; j++)
|
||||
{
|
||||
t = *psrc;
|
||||
if (t != TRANSPARENT_COLOR)
|
||||
{
|
||||
*pdest = t;
|
||||
}
|
||||
|
||||
psrc++;
|
||||
pdest++;
|
||||
}
|
||||
|
||||
psrc += srcdelta;
|
||||
pdest += destdelta;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=0 ; i<prect->height ; i++)
|
||||
{
|
||||
memcpy (pdest, psrc, prect->width);
|
||||
psrc += rowbytes;
|
||||
pdest += vid.rowbytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
R_DrawRect16
|
||||
==============
|
||||
*/
|
||||
void R_DrawRect16 (vrect_t *prect, int rowbytes, byte *psrc,
|
||||
int transparent)
|
||||
{
|
||||
byte t;
|
||||
int i, j, srcdelta, destdelta;
|
||||
unsigned short *pdest;
|
||||
|
||||
// FIXME: would it be better to pre-expand native-format versions?
|
||||
|
||||
pdest = (unsigned short *)vid.buffer +
|
||||
(prect->y * (vid.rowbytes >> 1)) + prect->x;
|
||||
|
||||
srcdelta = rowbytes - prect->width;
|
||||
destdelta = (vid.rowbytes >> 1) - prect->width;
|
||||
|
||||
if (transparent)
|
||||
{
|
||||
for (i=0 ; i<prect->height ; i++)
|
||||
{
|
||||
for (j=0 ; j<prect->width ; j++)
|
||||
{
|
||||
t = *psrc;
|
||||
if (t != TRANSPARENT_COLOR)
|
||||
{
|
||||
*pdest = d_8to16table[t];
|
||||
}
|
||||
|
||||
psrc++;
|
||||
pdest++;
|
||||
}
|
||||
|
||||
psrc += srcdelta;
|
||||
pdest += destdelta;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=0 ; i<prect->height ; i++)
|
||||
{
|
||||
for (j=0 ; j<prect->width ; j++)
|
||||
{
|
||||
*pdest = d_8to16table[*psrc];
|
||||
psrc++;
|
||||
pdest++;
|
||||
}
|
||||
|
||||
psrc += srcdelta;
|
||||
pdest += destdelta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
Draw_TileClear
|
||||
|
||||
This repeats a 64*64 tile graphic to fill the screen around a sized down
|
||||
refresh window.
|
||||
=============
|
||||
*/
|
||||
void Draw_TileClear (int x, int y, int w, int h)
|
||||
{
|
||||
int width, height, tileoffsetx, tileoffsety;
|
||||
byte *psrc;
|
||||
vrect_t vr;
|
||||
|
||||
r_rectdesc.rect.x = x;
|
||||
r_rectdesc.rect.y = y;
|
||||
r_rectdesc.rect.width = w;
|
||||
r_rectdesc.rect.height = h;
|
||||
|
||||
vr.y = r_rectdesc.rect.y;
|
||||
height = r_rectdesc.rect.height;
|
||||
|
||||
tileoffsety = vr.y % r_rectdesc.height;
|
||||
|
||||
while (height > 0)
|
||||
{
|
||||
vr.x = r_rectdesc.rect.x;
|
||||
width = r_rectdesc.rect.width;
|
||||
|
||||
if (tileoffsety != 0)
|
||||
vr.height = r_rectdesc.height - tileoffsety;
|
||||
else
|
||||
vr.height = r_rectdesc.height;
|
||||
|
||||
if (vr.height > height)
|
||||
vr.height = height;
|
||||
|
||||
tileoffsetx = vr.x % r_rectdesc.width;
|
||||
|
||||
while (width > 0)
|
||||
{
|
||||
if (tileoffsetx != 0)
|
||||
vr.width = r_rectdesc.width - tileoffsetx;
|
||||
else
|
||||
vr.width = r_rectdesc.width;
|
||||
|
||||
if (vr.width > width)
|
||||
vr.width = width;
|
||||
|
||||
psrc = r_rectdesc.ptexbytes +
|
||||
(tileoffsety * r_rectdesc.rowbytes) + tileoffsetx;
|
||||
|
||||
if (r_pixbytes == 1)
|
||||
{
|
||||
R_DrawRect8 (&vr, r_rectdesc.rowbytes, psrc, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
R_DrawRect16 (&vr, r_rectdesc.rowbytes, psrc, 0);
|
||||
}
|
||||
|
||||
vr.x += vr.width;
|
||||
width -= vr.width;
|
||||
tileoffsetx = 0; // only the left tile can be left-clipped
|
||||
}
|
||||
|
||||
vr.y += vr.height;
|
||||
height -= vr.height;
|
||||
tileoffsety = 0; // only the top tile can be top-clipped
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
Draw_Fill
|
||||
|
||||
Fills a box of pixels with a single color
|
||||
=============
|
||||
*/
|
||||
void Draw_Fill (int x, int y, int w, int h, int c)
|
||||
{
|
||||
byte *dest;
|
||||
unsigned short *pusdest;
|
||||
unsigned uc;
|
||||
int u, v;
|
||||
|
||||
if (r_pixbytes == 1)
|
||||
{
|
||||
dest = vid.buffer + y*vid.rowbytes + x;
|
||||
for (v=0 ; v<h ; v++, dest += vid.rowbytes)
|
||||
for (u=0 ; u<w ; u++)
|
||||
dest[u] = c;
|
||||
}
|
||||
else
|
||||
{
|
||||
uc = d_8to16table[c];
|
||||
|
||||
pusdest = (unsigned short *)vid.buffer + y * (vid.rowbytes >> 1) + x;
|
||||
for (v=0 ; v<h ; v++, pusdest += (vid.rowbytes >> 1))
|
||||
for (u=0 ; u<w ; u++)
|
||||
pusdest[u] = uc;
|
||||
}
|
||||
}
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
================
|
||||
Draw_FadeScreen
|
||||
|
||||
================
|
||||
*/
|
||||
void Draw_FadeScreen (void)
|
||||
{
|
||||
int x,y;
|
||||
byte *pbuf;
|
||||
|
||||
VID_UnlockBuffer ();
|
||||
S_ExtraUpdate ();
|
||||
VID_LockBuffer ();
|
||||
|
||||
for (y=0 ; y<vid.height ; y++)
|
||||
{
|
||||
int t;
|
||||
|
||||
pbuf = (byte *)(vid.buffer + vid.rowbytes*y);
|
||||
t = (y & 1) << 1;
|
||||
|
||||
for (x=0 ; x<vid.width ; x++)
|
||||
{
|
||||
if ((x & 3) != t)
|
||||
pbuf[x] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
VID_UnlockBuffer ();
|
||||
S_ExtraUpdate ();
|
||||
VID_LockBuffer ();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
================
|
||||
Draw_BeginDisc
|
||||
|
||||
Draws the little blue disc in the corner of the screen.
|
||||
Call before beginning any disc IO.
|
||||
================
|
||||
*/
|
||||
void Draw_BeginDisc (void)
|
||||
{
|
||||
|
||||
D_BeginDirectRect (vid.width - 24, 0, draw_disc->data, 24, 24);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Draw_EndDisc
|
||||
|
||||
Erases the disc icon.
|
||||
Call after completing any disc IO
|
||||
================
|
||||
*/
|
||||
void Draw_EndDisc (void)
|
||||
{
|
||||
|
||||
D_EndDirectRect (vid.width - 24, 0, 24, 24);
|
||||
}
|
||||
|
615
in_dos.c
615
in_dos.c
|
@ -1,615 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// in_mouse.c -- dos mouse code
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "dosisms.h"
|
||||
|
||||
#define AUX_FLAG_FREELOOK 0x00000001
|
||||
|
||||
typedef struct
|
||||
{
|
||||
long interruptVector;
|
||||
char deviceName[16];
|
||||
long numAxes;
|
||||
long numButtons;
|
||||
long flags;
|
||||
|
||||
vec3_t viewangles;
|
||||
|
||||
// intended velocities
|
||||
float forwardmove;
|
||||
float sidemove;
|
||||
float upmove;
|
||||
|
||||
long buttons;
|
||||
} externControl_t;
|
||||
|
||||
/*
|
||||
#define AUX_FLAG_FORCEFREELOOK 0x00000001 // r/o
|
||||
#define AUX_FLAG_EXTENDED 0x00000002 // r/o
|
||||
#define AUX_FLAG_RUN 0x00000004 // w/o
|
||||
#define AUX_FLAG_STRAFE 0x00000008 // w/o
|
||||
#define AUX_FLAG_FREELOOK 0x00000010 // w/o
|
||||
|
||||
#define AUX_MAP_UNDEFINED 0
|
||||
#define AUX_MAP_PITCH 1
|
||||
#define AUX_MAP_YAW 2
|
||||
#define AUX_MAP_ROLL 3
|
||||
#define AUX_MAP_FORWARD 4
|
||||
#define AUX_MAP_SIDE 5
|
||||
#define AUX_MAP_UP 6
|
||||
|
||||
typedef struct
|
||||
{
|
||||
long interruptVector;
|
||||
// r/o
|
||||
char deviceName[16];
|
||||
// r/o
|
||||
long numAxes;
|
||||
// r/o 1-6
|
||||
long numButtons; // r/o 0-32
|
||||
long flags; // see above
|
||||
byte axisMapping[6]; // w/o default = p,y,r,f,s,u
|
||||
float axisValue[6]; // r/w
|
||||
float sensitivity[6]; // w/o default = 1.0
|
||||
long buttons; // r/o
|
||||
float last_frame_time; // w/o
|
||||
} externControl_t;
|
||||
*/
|
||||
|
||||
cvar_t m_filter = {"m_filter","1"};
|
||||
|
||||
qboolean mouse_avail;
|
||||
int mouse_buttons;
|
||||
int mouse_oldbuttonstate;
|
||||
int mouse_buttonstate;
|
||||
float mouse_x, mouse_y;
|
||||
float old_mouse_x, old_mouse_y;
|
||||
|
||||
|
||||
cvar_t in_joystick = {"joy_enabled","1"};
|
||||
cvar_t joy_numbuttons = {"joy_buttons","4", true};
|
||||
|
||||
qboolean joy_avail;
|
||||
int joy_oldbuttonstate;
|
||||
int joy_buttonstate;
|
||||
|
||||
int joyxl, joyxh, joyyl, joyyh;
|
||||
int joystickx, joysticky;
|
||||
|
||||
qboolean need_center;
|
||||
|
||||
qboolean extern_avail;
|
||||
int extern_buttons;
|
||||
int extern_oldbuttonstate;
|
||||
int extern_buttonstate;
|
||||
cvar_t aux_look = {"auxlook","1", true};
|
||||
externControl_t *extern_control;
|
||||
void IN_StartupExternal (void);
|
||||
void IN_ExternalMove (usercmd_t *cmd);
|
||||
|
||||
void IN_StartupJoystick (void);
|
||||
qboolean IN_ReadJoystick (void);
|
||||
|
||||
|
||||
void Toggle_AuxLook_f (void)
|
||||
{
|
||||
if (aux_look.value)
|
||||
Cvar_Set ("auxlook","0");
|
||||
else
|
||||
Cvar_Set ("auxlook","1");
|
||||
}
|
||||
|
||||
|
||||
void Force_CenterView_f (void)
|
||||
{
|
||||
cl.viewangles[PITCH] = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_StartupMouse
|
||||
===========
|
||||
*/
|
||||
void IN_StartupMouse (void)
|
||||
{
|
||||
if ( COM_CheckParm ("-nomouse") )
|
||||
return;
|
||||
|
||||
// check for mouse
|
||||
regs.x.ax = 0;
|
||||
dos_int86(0x33);
|
||||
mouse_avail = regs.x.ax;
|
||||
if (!mouse_avail)
|
||||
{
|
||||
Con_Printf ("No mouse found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mouse_buttons = regs.x.bx;
|
||||
if (mouse_buttons > 3)
|
||||
mouse_buttons = 3;
|
||||
Con_Printf("%d-button mouse available\n", mouse_buttons);
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_Init
|
||||
===========
|
||||
*/
|
||||
void IN_Init (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
Cvar_RegisterVariable (&m_filter);
|
||||
Cvar_RegisterVariable (&in_joystick);
|
||||
Cvar_RegisterVariable (&joy_numbuttons);
|
||||
Cvar_RegisterVariable (&aux_look);
|
||||
Cmd_AddCommand ("toggle_auxlook", Toggle_AuxLook_f);
|
||||
Cmd_AddCommand ("force_centerview", Force_CenterView_f);
|
||||
|
||||
IN_StartupMouse ();
|
||||
IN_StartupJoystick ();
|
||||
|
||||
i = COM_CheckParm ("-control");
|
||||
if (i)
|
||||
{
|
||||
extern_control = real2ptr(Q_atoi (com_argv[i+1]));
|
||||
IN_StartupExternal ();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_Shutdown
|
||||
===========
|
||||
*/
|
||||
void IN_Shutdown (void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_Commands
|
||||
===========
|
||||
*/
|
||||
void IN_Commands (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (mouse_avail)
|
||||
{
|
||||
regs.x.ax = 3; // read buttons
|
||||
dos_int86(0x33);
|
||||
mouse_buttonstate = regs.x.bx;
|
||||
|
||||
// perform button actions
|
||||
for (i=0 ; i<mouse_buttons ; i++)
|
||||
{
|
||||
if ( (mouse_buttonstate & (1<<i)) &&
|
||||
!(mouse_oldbuttonstate & (1<<i)) )
|
||||
{
|
||||
Key_Event (K_MOUSE1 + i, true);
|
||||
}
|
||||
if ( !(mouse_buttonstate & (1<<i)) &&
|
||||
(mouse_oldbuttonstate & (1<<i)) )
|
||||
{
|
||||
Key_Event (K_MOUSE1 + i, false);
|
||||
}
|
||||
}
|
||||
|
||||
mouse_oldbuttonstate = mouse_buttonstate;
|
||||
}
|
||||
|
||||
if (joy_avail)
|
||||
{
|
||||
joy_buttonstate = ((dos_inportb(0x201) >> 4)&15)^15;
|
||||
// perform button actions
|
||||
for (i=0 ; i<joy_numbuttons.value ; i++)
|
||||
{
|
||||
if ( (joy_buttonstate & (1<<i)) &&
|
||||
!(joy_oldbuttonstate & (1<<i)) )
|
||||
{
|
||||
Key_Event (K_JOY1 + i, true);
|
||||
}
|
||||
if ( !(joy_buttonstate & (1<<i)) &&
|
||||
(joy_oldbuttonstate & (1<<i)) )
|
||||
{
|
||||
Key_Event (K_JOY1 + i, false);
|
||||
}
|
||||
}
|
||||
|
||||
joy_oldbuttonstate = joy_buttonstate;
|
||||
}
|
||||
|
||||
if (extern_avail)
|
||||
{
|
||||
extern_buttonstate = extern_control->buttons;
|
||||
|
||||
// perform button actions
|
||||
for (i=0 ; i<extern_buttons ; i++)
|
||||
{
|
||||
if ( (extern_buttonstate & (1<<i)) &&
|
||||
!(extern_oldbuttonstate & (1<<i)) )
|
||||
{
|
||||
Key_Event (K_AUX1 + i, true);
|
||||
}
|
||||
if ( !(extern_buttonstate & (1<<i)) &&
|
||||
(extern_oldbuttonstate & (1<<i)) )
|
||||
{
|
||||
Key_Event (K_AUX1 + i, false);
|
||||
}
|
||||
}
|
||||
|
||||
extern_oldbuttonstate = extern_buttonstate;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_Move
|
||||
===========
|
||||
*/
|
||||
void IN_MouseMove (usercmd_t *cmd)
|
||||
{
|
||||
int mx, my;
|
||||
|
||||
if (!mouse_avail)
|
||||
return;
|
||||
|
||||
regs.x.ax = 11; // read move
|
||||
dos_int86(0x33);
|
||||
mx = (short)regs.x.cx;
|
||||
my = (short)regs.x.dx;
|
||||
|
||||
if (m_filter.value)
|
||||
{
|
||||
mouse_x = (mx + old_mouse_x) * 0.5;
|
||||
mouse_y = (my + old_mouse_y) * 0.5;
|
||||
}
|
||||
else
|
||||
{
|
||||
mouse_x = mx;
|
||||
mouse_y = my;
|
||||
}
|
||||
old_mouse_x = mx;
|
||||
old_mouse_y = my;
|
||||
|
||||
mouse_x *= sensitivity.value;
|
||||
mouse_y *= sensitivity.value;
|
||||
|
||||
// add mouse X/Y movement to cmd
|
||||
if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) ))
|
||||
cmd->sidemove += m_side.value * mouse_x;
|
||||
else
|
||||
cl.viewangles[YAW] -= m_yaw.value * mouse_x;
|
||||
|
||||
if (in_mlook.state & 1)
|
||||
V_StopPitchDrift ();
|
||||
|
||||
if ( (in_mlook.state & 1) && !(in_strafe.state & 1))
|
||||
{
|
||||
cl.viewangles[PITCH] += m_pitch.value * mouse_y;
|
||||
if (cl.viewangles[PITCH] > 80)
|
||||
cl.viewangles[PITCH] = 80;
|
||||
if (cl.viewangles[PITCH] < -70)
|
||||
cl.viewangles[PITCH] = -70;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((in_strafe.state & 1) && noclip_anglehack)
|
||||
cmd->upmove -= m_forward.value * mouse_y;
|
||||
else
|
||||
cmd->forwardmove -= m_forward.value * mouse_y;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_JoyMove
|
||||
===========
|
||||
*/
|
||||
void IN_JoyMove (usercmd_t *cmd)
|
||||
{
|
||||
float speed, aspeed;
|
||||
|
||||
if (!joy_avail || !in_joystick.value)
|
||||
return;
|
||||
|
||||
IN_ReadJoystick ();
|
||||
if (joysticky > joyyh*2 || joystickx > joyxh*2)
|
||||
return; // assume something jumped in and messed up the joystick
|
||||
// reading time (win 95)
|
||||
|
||||
if (in_speed.state & 1)
|
||||
speed = cl_movespeedkey.value;
|
||||
else
|
||||
speed = 1;
|
||||
aspeed = speed*host_frametime;
|
||||
|
||||
if (in_strafe.state & 1)
|
||||
{
|
||||
if (joystickx < joyxl)
|
||||
cmd->sidemove -= speed*cl_sidespeed.value;
|
||||
else if (joystickx > joyxh)
|
||||
cmd->sidemove += speed*cl_sidespeed.value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (joystickx < joyxl)
|
||||
cl.viewangles[YAW] += aspeed*cl_yawspeed.value;
|
||||
else if (joystickx > joyxh)
|
||||
cl.viewangles[YAW] -= aspeed*cl_yawspeed.value;
|
||||
cl.viewangles[YAW] = anglemod(cl.viewangles[YAW]);
|
||||
}
|
||||
|
||||
if (in_mlook.state & 1)
|
||||
{
|
||||
if (m_pitch.value < 0)
|
||||
speed *= -1;
|
||||
|
||||
if (joysticky < joyyl)
|
||||
cl.viewangles[PITCH] += aspeed*cl_pitchspeed.value;
|
||||
else if (joysticky > joyyh)
|
||||
cl.viewangles[PITCH] -= aspeed*cl_pitchspeed.value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (joysticky < joyyl)
|
||||
cmd->forwardmove += speed*cl_forwardspeed.value;
|
||||
else if (joysticky > joyyh)
|
||||
cmd->forwardmove -= speed*cl_backspeed.value;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_Move
|
||||
===========
|
||||
*/
|
||||
void IN_Move (usercmd_t *cmd)
|
||||
{
|
||||
IN_MouseMove (cmd);
|
||||
IN_JoyMove (cmd);
|
||||
IN_ExternalMove (cmd);
|
||||
}
|
||||
|
||||
/*
|
||||
============================================================================
|
||||
|
||||
JOYSTICK
|
||||
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
|
||||
|
||||
qboolean IN_ReadJoystick (void)
|
||||
{
|
||||
int b;
|
||||
int count;
|
||||
|
||||
joystickx = 0;
|
||||
joysticky = 0;
|
||||
|
||||
count = 0;
|
||||
|
||||
b = dos_inportb(0x201);
|
||||
dos_outportb(0x201, b);
|
||||
|
||||
// clear counters
|
||||
while (++count < 10000)
|
||||
{
|
||||
b = dos_inportb(0x201);
|
||||
|
||||
joystickx += b&1;
|
||||
joysticky += (b&2)>>1;
|
||||
if ( !(b&3) )
|
||||
return true;
|
||||
}
|
||||
|
||||
Con_Printf ("IN_ReadJoystick: no response\n");
|
||||
joy_avail = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
WaitJoyButton
|
||||
=============
|
||||
*/
|
||||
qboolean WaitJoyButton (void)
|
||||
{
|
||||
int oldbuttons, buttons;
|
||||
|
||||
oldbuttons = 0;
|
||||
do
|
||||
{
|
||||
key_count = -1;
|
||||
Sys_SendKeyEvents ();
|
||||
key_count = 0;
|
||||
if (key_lastpress == K_ESCAPE)
|
||||
{
|
||||
Con_Printf ("aborted.\n");
|
||||
return false;
|
||||
}
|
||||
key_lastpress = 0;
|
||||
SCR_UpdateScreen ();
|
||||
buttons = ((dos_inportb(0x201) >> 4)&1)^1;
|
||||
if (buttons != oldbuttons)
|
||||
{
|
||||
oldbuttons = buttons;
|
||||
continue;
|
||||
}
|
||||
} while ( !buttons);
|
||||
|
||||
do
|
||||
{
|
||||
key_count = -1;
|
||||
Sys_SendKeyEvents ();
|
||||
key_count = 0;
|
||||
if (key_lastpress == K_ESCAPE)
|
||||
{
|
||||
Con_Printf ("aborted.\n");
|
||||
return false;
|
||||
}
|
||||
key_lastpress = 0;
|
||||
SCR_UpdateScreen ();
|
||||
buttons = ((dos_inportb(0x201) >> 4)&1)^1;
|
||||
if (buttons != oldbuttons)
|
||||
{
|
||||
oldbuttons = buttons;
|
||||
continue;
|
||||
}
|
||||
} while ( buttons);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
IN_StartupJoystick
|
||||
===============
|
||||
*/
|
||||
void IN_StartupJoystick (void)
|
||||
{
|
||||
int centerx, centery;
|
||||
|
||||
Con_Printf ("\n");
|
||||
|
||||
joy_avail = false;
|
||||
if ( COM_CheckParm ("-nojoy") )
|
||||
return;
|
||||
|
||||
if (!IN_ReadJoystick ())
|
||||
{
|
||||
joy_avail = false;
|
||||
Con_Printf ("joystick not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Con_Printf ("joystick found\n");
|
||||
|
||||
Con_Printf ("CENTER the joystick\nand press button 1 (ESC to skip):\n");
|
||||
if (!WaitJoyButton ())
|
||||
return;
|
||||
IN_ReadJoystick ();
|
||||
centerx = joystickx;
|
||||
centery = joysticky;
|
||||
|
||||
Con_Printf ("Push the joystick to the UPPER LEFT\nand press button 1 (ESC to skip):\n");
|
||||
if (!WaitJoyButton ())
|
||||
return;
|
||||
IN_ReadJoystick ();
|
||||
joyxl = (centerx + joystickx)/2;
|
||||
joyyl = (centerx + joysticky)/2;
|
||||
|
||||
Con_Printf ("Push the joystick to the LOWER RIGHT\nand press button 1 (ESC to skip):\n");
|
||||
if (!WaitJoyButton ())
|
||||
return;
|
||||
IN_ReadJoystick ();
|
||||
joyxh = (centerx + joystickx)/2;
|
||||
joyyh = (centery + joysticky)/2;
|
||||
|
||||
joy_avail = true;
|
||||
Con_Printf ("joystick configured.\n");
|
||||
|
||||
Con_Printf ("\n");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============================================================================
|
||||
|
||||
EXTERNAL
|
||||
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
IN_StartupExternal
|
||||
===============
|
||||
*/
|
||||
void IN_StartupExternal (void)
|
||||
{
|
||||
if (extern_control->numButtons > 32)
|
||||
extern_control->numButtons = 32;
|
||||
|
||||
Con_Printf("%s Initialized\n", extern_control->deviceName);
|
||||
Con_Printf(" %u axes %u buttons\n", extern_control->numAxes, extern_control->numButtons);
|
||||
|
||||
extern_avail = true;
|
||||
extern_buttons = extern_control->numButtons;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_ExternalMove
|
||||
===========
|
||||
*/
|
||||
void IN_ExternalMove (usercmd_t *cmd)
|
||||
{
|
||||
qboolean freelook;
|
||||
|
||||
if (! extern_avail)
|
||||
return;
|
||||
|
||||
extern_control->viewangles[YAW] = cl.viewangles[YAW];
|
||||
extern_control->viewangles[PITCH] = cl.viewangles[PITCH];
|
||||
extern_control->viewangles[ROLL] = cl.viewangles[ROLL];
|
||||
extern_control->forwardmove = cmd->forwardmove;
|
||||
extern_control->sidemove = cmd->sidemove;
|
||||
extern_control->upmove = cmd->upmove;
|
||||
|
||||
Con_DPrintf("IN: y:%f p:%f r:%f f:%f s:%f u:%f\n", extern_control->viewangles[YAW], extern_control->viewangles[PITCH], extern_control->viewangles[ROLL], extern_control->forwardmove, extern_control->sidemove, extern_control->upmove);
|
||||
|
||||
dos_int86(extern_control->interruptVector);
|
||||
|
||||
Con_DPrintf("OUT: y:%f p:%f r:%f f:%f s:%f u:%f\n", extern_control->viewangles[YAW], extern_control->viewangles[PITCH], extern_control->viewangles[ROLL], extern_control->forwardmove, extern_control->sidemove, extern_control->upmove);
|
||||
|
||||
cl.viewangles[YAW] = extern_control->viewangles[YAW];
|
||||
cl.viewangles[PITCH] = extern_control->viewangles[PITCH];
|
||||
cl.viewangles[ROLL] = extern_control->viewangles[ROLL];
|
||||
cmd->forwardmove = extern_control->forwardmove;
|
||||
cmd->sidemove = extern_control->sidemove;
|
||||
cmd->upmove = extern_control->upmove;
|
||||
|
||||
if (cl.viewangles[PITCH] > 80)
|
||||
cl.viewangles[PITCH] = 80;
|
||||
if (cl.viewangles[PITCH] < -70)
|
||||
cl.viewangles[PITCH] = -70;
|
||||
|
||||
freelook = (extern_control->flags & AUX_FLAG_FREELOOK || aux_look.value || in_mlook.state & 1);
|
||||
|
||||
if (freelook)
|
||||
V_StopPitchDrift ();
|
||||
}
|
||||
|
2
in_win.c
2
in_win.c
|
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include <dinput.h>
|
||||
#include "quakedef.h"
|
||||
#include "winquake.h"
|
||||
#include "dosisms.h"
|
||||
//#include "dosisms.h"
|
||||
|
||||
#define DINPUT_BUFFERSIZE 16
|
||||
#define iDirectInputCreate(a,b,c,d) pDirectInputCreate(a,b,c,d)
|
||||
|
|
222
mplib.c
222
mplib.c
|
@ -1,222 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
#include <dpmi.h>
|
||||
|
||||
//#include "types.h"
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned short WORD;
|
||||
typedef unsigned long DWORD;
|
||||
|
||||
//#include "mgenord.h"
|
||||
#define MGENVXD_REGISTER_ORD 1
|
||||
#define MGENVXD_GETMEM_ORD 2
|
||||
#define MGENVXD_DEREGISTER_ORD 3
|
||||
#define MGENVXD_WAKEUP_ORD 4
|
||||
#define MGENVXD_MAKEDQS_ORD 5
|
||||
|
||||
|
||||
// Virtual 8086 API Ordinals
|
||||
#define V86API_GETSELECTOR16_ORD (1)
|
||||
#define V86API_GETSELECTOR32_ORD (2)
|
||||
#define V86API_GETFLAT32_ORD (3)
|
||||
#define V86API_MOVERP_ORD (6)
|
||||
#define V86API_MOVEPR_ORD (7)
|
||||
#define V86API_POST_ORD (8)
|
||||
#define V86API_INIT_ORD (9)
|
||||
#define V86API_UNINIT_ORD (10)
|
||||
#define V86API_INSERTKEY_ORD (11)
|
||||
#define V86API_REMOVEHOTKEY_ORD (12)
|
||||
#define V86API_INSTALLHOTKEY_ORD (13)
|
||||
#define V86API_HOOKINT48_ORD (14)
|
||||
#define V86API_WAKEUPDLL_ORD (15)
|
||||
|
||||
#define DPMIAPI_GETFLAT32_ORD (1)
|
||||
#define DPMIAPI_POST_WINDOWS_ORD (2)
|
||||
// these are DPMI functions. Make sure they don't clash with the
|
||||
// other MGENVXD_XXXX functions above, or the DPMI functions!
|
||||
#define MGENVXD_GETQUEUECTR_ORD 6
|
||||
#define MGENVXD_MOVENODE_ORD 7
|
||||
#define MGENVXD_GETNODE_ORD 8
|
||||
#define MGENVXD_FLUSHNODE_ORD 9
|
||||
#define MGENVXD_MCOUNT_ORD 10
|
||||
#define MGENVXD_MASTERNODE_ORD 11
|
||||
#define MGENVXD_SANITYCHECK_ORD 12
|
||||
#define MGENVXD_WAKEUPDLL_ORD 13
|
||||
#define MGENVXD_WAIT_ORD 14
|
||||
|
||||
//
|
||||
#define HWND_OFFSET (0)
|
||||
#define UMSG_OFFSET (1)
|
||||
#define SIZEREQUEST_OFFSET (2)
|
||||
#define HVXD_OFFSET (3)
|
||||
#define DATUM_OFFSET (4)
|
||||
#define SLOT_OFFSET (5)
|
||||
#define SIZEGIVEN_OFFSET (6)
|
||||
#define SELECTOR32_OFFSET (7)
|
||||
#define SELECTOR16_OFFSET (8)
|
||||
|
||||
//#include "magic.h"
|
||||
#define MGENVXD_DEVICE_ID 0x18AA
|
||||
|
||||
//#include "rtq.h"
|
||||
#define RTQ_NODE struct rtq_node
|
||||
|
||||
RTQ_NODE
|
||||
{
|
||||
RTQ_NODE *self; // Ring zero address of this node
|
||||
RTQ_NODE *left; // Ring zero address of preceding node
|
||||
RTQ_NODE *right; // Ring zero address of succeding node
|
||||
BYTE * rtqDatum; // Ring 3 Datum of Buffer (start of preface)
|
||||
BYTE * rtqInsert; // Ring 3 insertion position
|
||||
WORD rtqLen; // Length of buffer, excluding preface
|
||||
WORD rtqUpCtr; // Up Counter of bytes used so far
|
||||
WORD rtqQCtr; // number of nodes attached
|
||||
WORD padding; // DWORD alignment
|
||||
};
|
||||
|
||||
#define RTQ_PARAM_MOVENODE struct rtq_param_movenode
|
||||
RTQ_PARAM_MOVENODE
|
||||
{
|
||||
WORD rtqFromDQ;
|
||||
WORD rtqToDQ;
|
||||
};
|
||||
|
||||
RTQ_NODE* rtq_fetch(RTQ_NODE*, RTQ_NODE*); // To, From
|
||||
|
||||
int _int86(int vector, __dpmi_regs *iregs, __dpmi_regs *oregs);
|
||||
|
||||
#define CHUNNEL_INT 0x48
|
||||
|
||||
#define int386 _int86
|
||||
#define REGISTERS __dpmi_regs
|
||||
|
||||
void
|
||||
Yield(void)
|
||||
{
|
||||
__dpmi_yield();
|
||||
}
|
||||
|
||||
void
|
||||
PostWindowsMessage(void)
|
||||
{
|
||||
REGISTERS regs;
|
||||
|
||||
regs.d.eax = DPMIAPI_POST_WINDOWS_ORD << 16 | MGENVXD_DEVICE_ID;
|
||||
regs.d.ebx = 0;
|
||||
regs.d.ecx = 0;
|
||||
int386(CHUNNEL_INT, ®s, ®s);
|
||||
}
|
||||
|
||||
int
|
||||
MGenWait(void)
|
||||
{
|
||||
REGISTERS regs;
|
||||
|
||||
regs.d.eax = MGENVXD_WAIT_ORD << 16 | MGENVXD_DEVICE_ID;
|
||||
int386(CHUNNEL_INT, ®s, ®s);
|
||||
return regs.d.eax;
|
||||
}
|
||||
|
||||
int MGenGetQueueCtr(int qNo)
|
||||
{
|
||||
REGISTERS regs;
|
||||
|
||||
regs.d.eax = MGENVXD_GETQUEUECTR_ORD << 16 | MGENVXD_DEVICE_ID;
|
||||
regs.d.ebx = qNo;
|
||||
int386(CHUNNEL_INT, ®s, ®s);
|
||||
|
||||
return regs.d.eax;
|
||||
}
|
||||
|
||||
RTQ_NODE *MGenMoveTo(int qFrom, int qTo)
|
||||
{
|
||||
REGISTERS regs;
|
||||
|
||||
regs.d.eax = MGENVXD_MOVENODE_ORD << 16 | MGENVXD_DEVICE_ID;
|
||||
regs.d.ebx = qFrom;
|
||||
regs.d.ecx = qTo;
|
||||
int386(CHUNNEL_INT, ®s, ®s);
|
||||
|
||||
return (RTQ_NODE *) regs.d.eax;
|
||||
}
|
||||
|
||||
RTQ_NODE *MGenGetNode(int q)
|
||||
{
|
||||
REGISTERS regs;
|
||||
|
||||
regs.d.eax = MGENVXD_GETNODE_ORD << 16 | MGENVXD_DEVICE_ID;
|
||||
regs.d.ebx = q;
|
||||
int386(CHUNNEL_INT, ®s, ®s);
|
||||
|
||||
return (RTQ_NODE *) regs.d.eax;
|
||||
}
|
||||
|
||||
RTQ_NODE *MGenGetMasterNode(unsigned *size)
|
||||
{
|
||||
REGISTERS regs;
|
||||
|
||||
regs.d.eax = MGENVXD_MASTERNODE_ORD << 16 | MGENVXD_DEVICE_ID;
|
||||
int386(CHUNNEL_INT, ®s, ®s);
|
||||
*size = regs.d.ecx;
|
||||
|
||||
return (RTQ_NODE *) regs.d.eax;
|
||||
}
|
||||
|
||||
RTQ_NODE *MGenFlushNodes(int qFrom, int qTo)
|
||||
{
|
||||
REGISTERS regs;
|
||||
|
||||
regs.d.eax = MGENVXD_FLUSHNODE_ORD << 16 | MGENVXD_DEVICE_ID;
|
||||
regs.d.ebx = qFrom;
|
||||
regs.d.ecx = qTo;
|
||||
int386(CHUNNEL_INT, ®s, ®s);
|
||||
|
||||
return (RTQ_NODE *) regs.d.eax;
|
||||
}
|
||||
|
||||
int MGenMCount(unsigned lowerOrderBits, unsigned upperOrderBits)
|
||||
{
|
||||
REGISTERS regs;
|
||||
|
||||
regs.d.eax = MGENVXD_MCOUNT_ORD << 16 | MGENVXD_DEVICE_ID;
|
||||
regs.d.ebx = lowerOrderBits;
|
||||
regs.d.ecx = upperOrderBits;
|
||||
int386(CHUNNEL_INT, ®s, ®s);
|
||||
|
||||
return regs.d.eax;
|
||||
}
|
||||
|
||||
int MGenSanityCheck(void)
|
||||
{
|
||||
REGISTERS regs;
|
||||
|
||||
regs.d.eax = MGENVXD_SANITYCHECK_ORD << 16 | MGENVXD_DEVICE_ID;
|
||||
int386(CHUNNEL_INT, ®s, ®s);
|
||||
|
||||
return regs.d.eax;
|
||||
}
|
||||
|
||||
void MGenWakeupDll(void)
|
||||
{
|
||||
REGISTERS regs;
|
||||
|
||||
regs.d.eax = MGENVXD_WAKEUPDLL_ORD << 16 | MGENVXD_DEVICE_ID;
|
||||
int386(CHUNNEL_INT, ®s, ®s);
|
||||
}
|
763
net_bw.c
763
net_bw.c
|
@ -1,763 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// net_bw.c
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <dpmi.h>
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "dosisms.h"
|
||||
|
||||
|
||||
// this section is general Unix stuff that we need
|
||||
|
||||
#define EIO 5 /* I/O error */
|
||||
#define EBADS 9
|
||||
#define EWOULDBLOCK 35 /* function would block */
|
||||
#define EMSGSIZE 40 /* message to big for buffers */
|
||||
#define EPROTONOSUPPORT 43 /* Protocol not supported */
|
||||
#define ESOCKTNOSUPPORT 44 /* Socket type not supported */
|
||||
#define EPFNOSUPPORT 46 /* Protocol family not supported */
|
||||
#define EAFNOSUPPORT 47 /* Address family not supported */
|
||||
#define ECONNABORTED 53 /* User requested hangup */
|
||||
#define ENOBUFS 55 /* No buffers available */
|
||||
#define EISCONN 56 /* Socket has closed */
|
||||
#define ENOTCONN 57 /* Socket is not connected */
|
||||
#define ESHUTDOWN 58 /* Socket is closed */
|
||||
#define ETOOMANYREFS 59 /* Too many sockets open */
|
||||
#define ETIMEDOUT 60 /* Connection timed out */
|
||||
#define ECONNREFUSED 61 /* Connection refused */
|
||||
|
||||
#define AF_INET 2 /* internet */
|
||||
|
||||
#define PF_INET AF_INET
|
||||
|
||||
#define SOCK_STREAM 1 /* stream */
|
||||
#define SOCK_DGRAM 2 /* datagram */
|
||||
|
||||
#define IPPROTO_TCP 6
|
||||
#define IPPROTO_UDP 17
|
||||
|
||||
#define INADDR_ANY 0
|
||||
|
||||
#define SIOCDONE 0x7300
|
||||
#define FIONREAD 0x667f
|
||||
#define FIONBIO 0x667e
|
||||
#define FIONWIN 0x1000
|
||||
#define FIONTIN 0x2000
|
||||
|
||||
#define BRDINIT 0
|
||||
#define BRDADDR 10
|
||||
|
||||
#define MAXHOSTNAMELEN 256
|
||||
|
||||
#define SOL_SOCKET 0xffff /* options for socket level */
|
||||
|
||||
/*
|
||||
* Option flags per-socket.
|
||||
*/
|
||||
#define SO_DEBUG 0x0001 /* turn on debugging info recording */
|
||||
#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */
|
||||
#define SO_REUSEADDR 0x0004 /* allow local address reuse */
|
||||
#define SO_KEEPALIVE 0x0008 /* keep connections alive */
|
||||
#define SO_DONTROUTE 0x0010 /* just use interface addresses */
|
||||
#define SO_BROADCAST 0x0020 /* permit sending of broadcast msgs */
|
||||
#define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */
|
||||
#define SO_LINGER 0x0080 /* linger on close if data present */
|
||||
#define SO_OOBINLINE 0x0100 /* leave received OOB data in line */
|
||||
#define SO_USEPRIV 0x4000 /* allocate from privileged port area */
|
||||
#define SO_CANTSIG 0x8000 /* prevent SIGPIPE on SS_CANTSENDMORE */
|
||||
|
||||
/*
|
||||
* Additional options, not kept in so_options.
|
||||
*/
|
||||
#define SO_SNDBUF 0x1001 /* send buffer size */
|
||||
#define SO_RCVBUF 0x1002 /* receive buffer size */
|
||||
#define SO_SNDLOWAT 0x1003 /* send low-water mark */
|
||||
#define SO_RCVLOWAT 0x1004 /* receive low-water mark */
|
||||
#define SO_SNDTIMEO 0x1005 /* send timeout */
|
||||
#define SO_RCVTIMEO 0x1006 /* receive timeout */
|
||||
#define SO_ERROR 0x1007 /* get error status and clear */
|
||||
#define SO_TYPE 0x1008 /* get socket type */
|
||||
|
||||
|
||||
struct in_addr
|
||||
{
|
||||
union
|
||||
{
|
||||
struct { unsigned char s_b1,s_b2,s_b3,s_b4; } S_un_b;
|
||||
struct { unsigned short s_w1,s_w2; } S_un_w;
|
||||
unsigned long S_addr;
|
||||
} S_un;
|
||||
};
|
||||
#define s_addr S_un.S_addr /* can be used for most tcp & ip code */
|
||||
#define s_host S_un.S_un_b.s_b2 /* host on imp */
|
||||
#define s_net S_un.S_un_b.s_b1 /* network */
|
||||
#define s_imp S_un.S_un_w.s_w2 /* imp */
|
||||
#define s_impno S_un.S_un_b.s_b4 /* imp # */
|
||||
#define s_lh S_un.S_un_b.s_b3 /* logical host */
|
||||
|
||||
struct sockaddr_in
|
||||
{
|
||||
short sin_family;
|
||||
unsigned short sin_port;
|
||||
struct in_addr sin_addr;
|
||||
char sin_zero[8];
|
||||
};
|
||||
|
||||
struct hostent {
|
||||
char *h_name; /* official name of host */
|
||||
char **h_aliases; /* alias list */
|
||||
int h_addrtype; /* host address type */
|
||||
int h_length; /* length of address */
|
||||
char **h_addr_list; /* list of addresses from name server */
|
||||
#define h_addr h_addr_list[0] /* address, for backward compatiblity */
|
||||
};
|
||||
|
||||
char *inet_ntoa(struct in_addr in);
|
||||
|
||||
|
||||
// this section is B&W specific constants & structures
|
||||
|
||||
#define BW_IOCTL_BIND 0
|
||||
#define BW_IOCTL_CLEAROPTIONS 5
|
||||
#define BW_IOCTL_SETOPTIONS 6
|
||||
#define BW_IOCTL_PEEK 7
|
||||
#define BW_IOCTL_SETWINMASK 8
|
||||
|
||||
#define BW_OPTION_BLOCKING 0x01
|
||||
#define BW_OPTION_REUSEBUFFERS 0x80
|
||||
|
||||
#define BW_ERR_USR_HANGUP 50
|
||||
#define BW_ERR_HANGUP 51
|
||||
#define BW_ERR_NET_ERR 52
|
||||
#define BW_ERR_IS_CLOSED 53
|
||||
#define BW_ERR_TIME_OUT 54
|
||||
#define BW_ERR_RESET 55
|
||||
#define BW_ERR_FULL 56
|
||||
#define BW_ERR_BLOCK 57
|
||||
#define BW_ERR_SHUTDOWN 58
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char state; // always 1
|
||||
short localPort;
|
||||
struct in_addr localAddr;
|
||||
char reason; // always 0
|
||||
char options;
|
||||
short dataAvailable;
|
||||
} BW_UDPinfo_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char reserved1 [6];
|
||||
unsigned short info2Offset;
|
||||
char reserved2 [18];
|
||||
struct in_addr remoteAddr;
|
||||
} BW_UDPreadInfo1_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
short remotePort;
|
||||
char reserved1 [2];
|
||||
unsigned short dataLenPlus8;
|
||||
char reserved2 [2];
|
||||
char data[1]; // actual size is <dataLenPlus8> - 8
|
||||
} BW_UDPreadInfo2_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char reserved1 [2];
|
||||
short remotePort;
|
||||
unsigned short dataLen;
|
||||
struct in_addr remoteAddr;
|
||||
char reserved2 [42];
|
||||
char data[1]; // actual size is <datalen>
|
||||
} BW_writeInfo_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
short ioport;
|
||||
byte dma;
|
||||
byte vector;
|
||||
byte irq;
|
||||
short bufferSize;
|
||||
short maxWindow;
|
||||
short timeZone;
|
||||
byte myType;
|
||||
int inetAddr;
|
||||
short value;
|
||||
byte subnetMask;
|
||||
short etherPointer;
|
||||
short logserverPointer;
|
||||
short nameserverPointer;
|
||||
short printserverPointer;
|
||||
short timeserverPointer;
|
||||
short gatewayPointer;
|
||||
short driverSegment;
|
||||
byte transferSize;
|
||||
char cardName [9];
|
||||
} BW_ethdevinfo_t;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
#define LOWMEM_SIZE 4096
|
||||
|
||||
static unsigned char *lowmem_buffer;
|
||||
static int lowmem_bufseg;
|
||||
static int lowmem_bufoff;
|
||||
static BW_ethdevinfo_t ethdevinfo;
|
||||
static int netmask;
|
||||
static struct in_addr bcastaddr;
|
||||
|
||||
extern regs_t regs;
|
||||
|
||||
static int net_acceptsocket = -1; // socket for fielding new connections
|
||||
static int net_controlsocket = 0;
|
||||
|
||||
#include "net_bw.h"
|
||||
|
||||
//=============================================================================
|
||||
|
||||
static int BW_ioctl(int s, char *msg, int msglen)
|
||||
{
|
||||
Q_memcpy(lowmem_buffer, msg, msglen);
|
||||
|
||||
regs.x.ax = 0x4403;
|
||||
regs.x.bx = s;
|
||||
regs.x.cx = msglen;
|
||||
regs.x.dx = lowmem_bufoff;
|
||||
regs.x.ds = lowmem_bufseg;
|
||||
if (dos_int86(0x21))
|
||||
return regs.x.ax;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
static int BW_TranslateError(int error)
|
||||
{
|
||||
switch(error)
|
||||
{
|
||||
case BW_ERR_USR_HANGUP: return ECONNABORTED;
|
||||
case BW_ERR_HANGUP: return EISCONN;
|
||||
case BW_ERR_NET_ERR: return ENOTCONN;
|
||||
case BW_ERR_IS_CLOSED: return ENOTCONN;
|
||||
case BW_ERR_TIME_OUT: return ETIMEDOUT;
|
||||
case BW_ERR_RESET: return ECONNREFUSED;
|
||||
case BW_ERR_FULL: return ETOOMANYREFS;
|
||||
case BW_ERR_BLOCK: return EWOULDBLOCK;
|
||||
case BW_ERR_SHUTDOWN: return ESHUTDOWN;
|
||||
}
|
||||
return EIO;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
static int GetEthdevinfo(void)
|
||||
{
|
||||
int fd;
|
||||
|
||||
Q_strcpy((char *)lowmem_buffer, "ETHDEV27");
|
||||
regs.x.ax = 0x3d42;
|
||||
regs.x.ds = lowmem_bufseg;
|
||||
regs.x.dx = lowmem_bufoff;
|
||||
if (dos_int86(0x21))
|
||||
return -1;
|
||||
fd = regs.x.ax;
|
||||
|
||||
regs.x.ax = 0x4401;
|
||||
regs.x.bx = fd;
|
||||
regs.x.dx = 0x60;
|
||||
dos_int86(0x21);
|
||||
|
||||
regs.h.ah = 0x3f;
|
||||
regs.x.cx = sizeof(ethdevinfo);
|
||||
regs.x.es = regs.x.ds = lowmem_bufseg;
|
||||
regs.x.dx = lowmem_bufoff;
|
||||
regs.x.bx = fd;
|
||||
if (dos_int86(0x21))
|
||||
return -1;
|
||||
Q_memcpy(ðdevinfo, lowmem_buffer, regs.x.ax);
|
||||
|
||||
regs.h.ah = 0x3e;
|
||||
regs.x.bx = fd;
|
||||
dos_int86(0x21);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int BW_Init(void)
|
||||
{
|
||||
struct qsockaddr addr;
|
||||
char *colon;
|
||||
|
||||
if (COM_CheckParm ("-noudp"))
|
||||
return -1;
|
||||
|
||||
lowmem_buffer = dos_getmemory(LOWMEM_SIZE);
|
||||
if (!lowmem_buffer)
|
||||
Sys_Error("not enough low memory\n");
|
||||
lowmem_bufoff = ptr2real(lowmem_buffer) & 0xf;
|
||||
lowmem_bufseg = ptr2real(lowmem_buffer) >> 4;
|
||||
|
||||
if (GetEthdevinfo())
|
||||
{
|
||||
Con_DPrintf("Beame & Whiteside TCP/IP not detected\n");
|
||||
dos_freememory(lowmem_buffer);
|
||||
return -1;
|
||||
}
|
||||
netmask = 0xffffffff >> (32 - ethdevinfo.subnetMask);
|
||||
bcastaddr.s_addr = (ethdevinfo.inetAddr & netmask) | (~netmask);
|
||||
|
||||
if ((net_controlsocket = BW_OpenSocket (0)) == -1)
|
||||
{
|
||||
dos_freememory(lowmem_buffer);
|
||||
Con_DPrintf ("BW_Init unable to open control socket; disabled\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
BW_GetSocketAddr (net_controlsocket, &addr);
|
||||
Q_strcpy(my_tcpip_address, BW_AddrToString (&addr));
|
||||
colon = Q_strrchr (my_tcpip_address, ':');
|
||||
if (colon)
|
||||
*colon = 0;
|
||||
|
||||
Con_Printf("BW_Init: UDP initialized\n");
|
||||
tcpipAvailable = true;
|
||||
|
||||
return net_controlsocket;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
void BW_Shutdown(void)
|
||||
{
|
||||
BW_Listen (false);
|
||||
BW_CloseSocket (net_controlsocket);
|
||||
dos_freememory(lowmem_buffer);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
void BW_Listen (qboolean state)
|
||||
{
|
||||
// enable listening
|
||||
if (state)
|
||||
{
|
||||
if (net_acceptsocket != -1)
|
||||
return;
|
||||
if ((net_acceptsocket = BW_OpenSocket (net_hostport)) == -1)
|
||||
Sys_Error ("BW_Listen: Unable to open accept socket\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// disable listening
|
||||
if (net_acceptsocket == -1)
|
||||
return;
|
||||
BW_CloseSocket (net_acceptsocket);
|
||||
net_acceptsocket = -1;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
OpenSocket returns a handle to a network socket that has been opened,
|
||||
set to nonblocking, and bound to <port>. Additional socket options
|
||||
should be set here if they are needed. -1 is returned on failure.
|
||||
*/
|
||||
|
||||
int BW_OpenSocket(int port)
|
||||
{
|
||||
int s;
|
||||
int ret;
|
||||
int deadman = 3 * 1024;
|
||||
static int dynamic = 1024;
|
||||
static char reuse_msg[2] = {BW_IOCTL_SETOPTIONS, BW_OPTION_REUSEBUFFERS};
|
||||
static char bind_msg[3] = {BW_IOCTL_BIND, 0, 0};
|
||||
static char nonblock_msg[2] = {BW_IOCTL_CLEAROPTIONS, BW_OPTION_BLOCKING};
|
||||
|
||||
// allocate a UDP socket
|
||||
Q_strcpy((char *)lowmem_buffer, "UDP-IP10");
|
||||
regs.x.ax = 0x3d42;
|
||||
regs.x.ds = lowmem_bufseg;
|
||||
regs.x.dx = lowmem_bufoff;
|
||||
if (dos_int86(0x21))
|
||||
{
|
||||
Con_Printf("BW_OpenSocket failed: %u\n", BW_TranslateError(regs.x.ax));
|
||||
return -1;
|
||||
}
|
||||
s = regs.x.ax;
|
||||
|
||||
// set file descriptor to raw mode
|
||||
regs.x.ax = 0x4401;
|
||||
regs.x.bx = s;
|
||||
regs.x.dx = 0x60;
|
||||
dos_int86(0x21);
|
||||
|
||||
if (BW_ioctl(s, reuse_msg, 2))
|
||||
{
|
||||
Con_Printf("BW_OpenSocket ioctl(reuse) failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (BW_ioctl(s, nonblock_msg, 2))
|
||||
{
|
||||
Con_Printf("BW_OpenSocket ioctl(nonblocking) failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// if a socket was specified, bind to it and return
|
||||
if (port)
|
||||
{
|
||||
*(short *)&bind_msg[1] = port;
|
||||
if (BW_ioctl(s, bind_msg, 3))
|
||||
{
|
||||
BW_CloseSocket(s);
|
||||
return -1;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
// B&W does NOT do dynamic allocation, so if port == 0 we must fake it
|
||||
do
|
||||
{
|
||||
port = dynamic++;
|
||||
if (dynamic == 4096)
|
||||
dynamic = 1024;
|
||||
deadman--;
|
||||
*(short *)&bind_msg[1] = port;
|
||||
ret = BW_ioctl(s, bind_msg, 3);
|
||||
}
|
||||
while (ret && deadman);
|
||||
if (ret)
|
||||
return -1;
|
||||
return s;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int BW_CloseSocket(int socket)
|
||||
{
|
||||
regs.h.ah = 0x3e;
|
||||
regs.x.bx = socket;
|
||||
if(dos_int86(0x21))
|
||||
{
|
||||
Con_Printf("BW_CloseSocket %u failed: %u\n", socket, BW_TranslateError(regs.x.ax));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int BW_Connect (int socket, struct qsockaddr *hostaddr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int BW_CheckNewConnections(void)
|
||||
{
|
||||
if (net_acceptsocket == 0)
|
||||
return -1;
|
||||
|
||||
// see if there's anything waiting
|
||||
regs.x.ax = 0x4406;
|
||||
regs.x.bx = net_acceptsocket;
|
||||
dos_int86(0x21);
|
||||
if (regs.x.ax == 0)
|
||||
return -1;
|
||||
return net_acceptsocket;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int BW_Read(int s, byte *buf, int len, struct qsockaddr *from)
|
||||
{
|
||||
BW_UDPreadInfo1_t *info1;
|
||||
BW_UDPreadInfo2_t *info2;
|
||||
|
||||
// ask if there's anything waiting
|
||||
regs.x.ax = 0x4406;
|
||||
regs.x.bx = s;
|
||||
dos_int86(0x21);
|
||||
if (regs.x.ax == 0)
|
||||
return 0;
|
||||
|
||||
// there was, so let's get it
|
||||
regs.h.ah = 0x3f;
|
||||
regs.x.cx = /* len + 53 */ LOWMEM_SIZE;
|
||||
regs.x.es = regs.x.ds = lowmem_bufseg;
|
||||
regs.x.dx = lowmem_bufoff;
|
||||
regs.x.bx = s;
|
||||
if (dos_int86(0x21))
|
||||
{
|
||||
Con_Printf("BW UDP read error: %u\n", BW_TranslateError(regs.x.ax));
|
||||
return -1;
|
||||
}
|
||||
|
||||
info1 = (BW_UDPreadInfo1_t *)lowmem_buffer;
|
||||
info2 = (BW_UDPreadInfo2_t *)(lowmem_buffer + info1->info2Offset);
|
||||
|
||||
if (from)
|
||||
{
|
||||
from->sa_family = AF_INET;
|
||||
((struct sockaddr_in *)from)->sin_addr = info1->remoteAddr;
|
||||
((struct sockaddr_in *)from)->sin_port = htons(info2->remotePort);
|
||||
}
|
||||
|
||||
len = info2->dataLenPlus8 - 8;
|
||||
if (len > NET_DATAGRAMSIZE)
|
||||
{
|
||||
Con_Printf("BW UDP read packet too large: %u\n", len);
|
||||
return -1;
|
||||
}
|
||||
Q_memcpy(buf, info2->data, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int BW_Broadcast(int s, byte *msg, int len)
|
||||
{
|
||||
BW_writeInfo_t *writeInfo;
|
||||
|
||||
// ask if we're clear to send
|
||||
regs.x.ax = 0x4407;
|
||||
regs.x.bx = s;
|
||||
dos_int86(0x21);
|
||||
if (regs.x.ax == 0)
|
||||
return 0;
|
||||
|
||||
// yes, let's do it
|
||||
writeInfo = (BW_writeInfo_t *)lowmem_buffer;
|
||||
writeInfo->remoteAddr = bcastaddr;
|
||||
writeInfo->remotePort = net_hostport;
|
||||
writeInfo->dataLen = len;
|
||||
if (len > NET_DATAGRAMSIZE)
|
||||
Sys_Error("BW UDP write packet too large: %u\n", len);
|
||||
Q_memcpy(writeInfo->data, msg, len);
|
||||
writeInfo->data[len] = 0;
|
||||
regs.h.ah = 0x40;
|
||||
regs.x.bx = s;
|
||||
regs.x.cx = len + sizeof(BW_writeInfo_t);
|
||||
regs.x.es = regs.x.ds = lowmem_bufseg;
|
||||
regs.x.dx = lowmem_bufoff;
|
||||
if (dos_int86(0x21))
|
||||
{
|
||||
Con_Printf("BW_Broadcast failed: %u\n", BW_TranslateError(regs.x.ax));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int BW_Write(int s, byte *msg, int len, struct qsockaddr *to)
|
||||
{
|
||||
BW_writeInfo_t *writeInfo;
|
||||
|
||||
// ask if we're clear to send
|
||||
regs.x.ax = 0x4407;
|
||||
regs.x.bx = s;
|
||||
dos_int86(0x21);
|
||||
if (regs.x.ax == 0)
|
||||
return 0;
|
||||
|
||||
// yes, let's do it
|
||||
writeInfo = (BW_writeInfo_t *)lowmem_buffer;
|
||||
writeInfo->remoteAddr = ((struct sockaddr_in *)to)->sin_addr;
|
||||
writeInfo->remotePort = ntohs(((struct sockaddr_in *)to)->sin_port);
|
||||
writeInfo->dataLen = len;
|
||||
if (len > NET_DATAGRAMSIZE)
|
||||
Sys_Error("BW UDP write packet too large: %u\n", len);
|
||||
Q_memcpy(writeInfo->data, msg, len);
|
||||
writeInfo->data[len] = 0;
|
||||
regs.h.ah = 0x40;
|
||||
regs.x.bx = s;
|
||||
regs.x.cx = len + sizeof(BW_writeInfo_t);
|
||||
regs.x.es = regs.x.ds = lowmem_bufseg;
|
||||
regs.x.dx = lowmem_bufoff;
|
||||
if (dos_int86(0x21))
|
||||
{
|
||||
Con_Printf("BW_Write failed: %u\n", BW_TranslateError(regs.x.ax));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
|
||||
char *BW_AddrToString (struct qsockaddr *addr)
|
||||
{
|
||||
static char buffer[22];
|
||||
|
||||
sprintf(buffer, "%d.%d.%d.%d:%d",
|
||||
((struct sockaddr_in *)addr)->sin_addr.s_net,
|
||||
((struct sockaddr_in *)addr)->sin_addr.s_host,
|
||||
((struct sockaddr_in *)addr)->sin_addr.s_lh,
|
||||
((struct sockaddr_in *)addr)->sin_addr.s_impno,
|
||||
ntohs(((struct sockaddr_in *)addr)->sin_port)
|
||||
);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int BW_StringToAddr (char *string, struct qsockaddr *addr)
|
||||
{
|
||||
int ha1, ha2, ha3, ha4, hp;
|
||||
int ipaddr;
|
||||
|
||||
sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp);
|
||||
ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4;
|
||||
|
||||
addr->sa_family = AF_INET;
|
||||
((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr);
|
||||
((struct sockaddr_in *)addr)->sin_port = htons((short)hp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int BW_GetSocketAddr (int socket, struct qsockaddr *addr)
|
||||
{
|
||||
regs.x.ax = 0x4402;
|
||||
regs.x.bx = socket;
|
||||
regs.x.cx = sizeof(BW_UDPinfo_t);
|
||||
regs.x.dx = lowmem_bufoff;
|
||||
regs.x.ds = lowmem_bufseg;
|
||||
dos_int86(0x21);
|
||||
|
||||
addr->sa_family = AF_INET;
|
||||
((struct sockaddr_in *)addr)->sin_addr.s_addr = ((BW_UDPinfo_t *)lowmem_buffer)->localAddr.s_addr;
|
||||
((struct sockaddr_in *)addr)->sin_port = htons(((BW_UDPinfo_t *)lowmem_buffer)->localPort);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int BW_GetNameFromAddr (struct qsockaddr *addr, char *name)
|
||||
{
|
||||
Q_strcpy(name, BW_AddrToString(addr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
///=============================================================================
|
||||
|
||||
int BW_GetAddrFromName (char *name, struct qsockaddr *hostaddr)
|
||||
{
|
||||
char buff[MAXHOSTNAMELEN];
|
||||
char *b;
|
||||
int addr;
|
||||
int num;
|
||||
int mask;
|
||||
int run;
|
||||
int port;
|
||||
|
||||
if (name[0] < '0' || name[0] > '9')
|
||||
return -1;
|
||||
|
||||
buff[0] = '.';
|
||||
b = buff;
|
||||
Q_strcpy(buff+1, name);
|
||||
if (buff[1] == '.')
|
||||
b++;
|
||||
|
||||
addr = 0;
|
||||
mask = -1;
|
||||
while (*b == '.')
|
||||
{
|
||||
b++;
|
||||
num = 0;
|
||||
run = 0;
|
||||
while (!( *b < '0' || *b > '9'))
|
||||
{
|
||||
num = num*10 + *b++ - '0';
|
||||
if (++run > 3)
|
||||
return -1;
|
||||
}
|
||||
if ((*b < '0' || *b > '9') && *b != '.' && *b != ':' && *b != 0)
|
||||
return -1;
|
||||
if (num < 0 || num > 255)
|
||||
return -1;
|
||||
mask<<=8;
|
||||
addr = (addr<<8) + num;
|
||||
}
|
||||
addr = htonl(addr);
|
||||
mask = htonl(mask);
|
||||
|
||||
if (*b++ == ':')
|
||||
port = Q_atoi(b);
|
||||
else
|
||||
port = net_hostport;
|
||||
|
||||
hostaddr->sa_family = AF_INET;
|
||||
((struct sockaddr_in *)hostaddr)->sin_port = htons((short)port);
|
||||
((struct sockaddr_in *)hostaddr)->sin_addr.s_addr =
|
||||
((ethdevinfo.inetAddr & mask) | addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int BW_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2)
|
||||
{
|
||||
if (addr1->sa_family != addr2->sa_family)
|
||||
return -1;
|
||||
|
||||
if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr)
|
||||
return -1;
|
||||
|
||||
if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int BW_GetSocketPort (struct qsockaddr *addr)
|
||||
{
|
||||
return ntohs(((struct sockaddr_in *)addr)->sin_port);
|
||||
}
|
||||
|
||||
|
||||
int BW_SetSocketPort (struct qsockaddr *addr, int port)
|
||||
{
|
||||
((struct sockaddr_in *)addr)->sin_port = htons(port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
39
net_bw.h
39
net_bw.h
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// net_bw.h
|
||||
|
||||
int BW_Init (void);
|
||||
void BW_Shutdown (void);
|
||||
void BW_Listen (qboolean state);
|
||||
int BW_OpenSocket (int port);
|
||||
int BW_CloseSocket (int socket);
|
||||
int BW_Connect (int socket, struct qsockaddr *addr);
|
||||
int BW_CheckNewConnections (void);
|
||||
int BW_Read (int socket, byte *buf, int len, struct qsockaddr *addr);
|
||||
int BW_Write (int socket, byte *buf, int len, struct qsockaddr *addr);
|
||||
int BW_Broadcast (int socket, byte *buf, int len);
|
||||
char *BW_AddrToString (struct qsockaddr *addr);
|
||||
int BW_StringToAddr (char *string, struct qsockaddr *addr);
|
||||
int BW_GetSocketAddr (int socket, struct qsockaddr *addr);
|
||||
int BW_GetNameFromAddr (struct qsockaddr *addr, char *name);
|
||||
int BW_GetAddrFromName (char *name, struct qsockaddr *addr);
|
||||
int BW_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2);
|
||||
int BW_GetSocketPort (struct qsockaddr *addr);
|
||||
int BW_SetSocketPort (struct qsockaddr *addr, int port);
|
1285
net_comx.c
1285
net_comx.c
File diff suppressed because it is too large
Load diff
162
net_dos.c
162
net_dos.c
|
@ -1,162 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
#include "quakedef.h"
|
||||
|
||||
#include "net_loop.h"
|
||||
#include "net_dgrm.h"
|
||||
#include "net_ser.h"
|
||||
|
||||
net_driver_t net_drivers[MAX_NET_DRIVERS] =
|
||||
{
|
||||
{
|
||||
"Loopback",
|
||||
false,
|
||||
Loop_Init,
|
||||
Loop_Listen,
|
||||
Loop_SearchForHosts,
|
||||
Loop_Connect,
|
||||
Loop_CheckNewConnections,
|
||||
Loop_GetMessage,
|
||||
Loop_SendMessage,
|
||||
Loop_SendUnreliableMessage,
|
||||
Loop_CanSendMessage,
|
||||
Loop_CanSendUnreliableMessage,
|
||||
Loop_Close,
|
||||
Loop_Shutdown
|
||||
}
|
||||
,
|
||||
{
|
||||
"Datagram",
|
||||
false,
|
||||
Datagram_Init,
|
||||
Datagram_Listen,
|
||||
Datagram_SearchForHosts,
|
||||
Datagram_Connect,
|
||||
Datagram_CheckNewConnections,
|
||||
Datagram_GetMessage,
|
||||
Datagram_SendMessage,
|
||||
Datagram_SendUnreliableMessage,
|
||||
Datagram_CanSendMessage,
|
||||
Datagram_CanSendUnreliableMessage,
|
||||
Datagram_Close,
|
||||
Datagram_Shutdown
|
||||
}
|
||||
,
|
||||
{
|
||||
"Serial",
|
||||
false,
|
||||
Serial_Init,
|
||||
Serial_Listen,
|
||||
Serial_SearchForHosts,
|
||||
Serial_Connect,
|
||||
Serial_CheckNewConnections,
|
||||
Serial_GetMessage,
|
||||
Serial_SendMessage,
|
||||
Serial_SendUnreliableMessage,
|
||||
Serial_CanSendMessage,
|
||||
Serial_CanSendUnreliableMessage,
|
||||
Serial_Close,
|
||||
Serial_Shutdown
|
||||
}
|
||||
};
|
||||
|
||||
int net_numdrivers = 3;
|
||||
|
||||
|
||||
#include "net_bw.h"
|
||||
#include "net_ipx.h"
|
||||
#include "net_mp.h"
|
||||
|
||||
net_landriver_t net_landrivers[MAX_NET_DRIVERS] =
|
||||
{
|
||||
{
|
||||
"Beame & Whiteside TCP/IP",
|
||||
false,
|
||||
0,
|
||||
BW_Init,
|
||||
BW_Shutdown,
|
||||
BW_Listen,
|
||||
BW_OpenSocket,
|
||||
BW_CloseSocket,
|
||||
BW_Connect,
|
||||
BW_CheckNewConnections,
|
||||
BW_Read,
|
||||
BW_Write,
|
||||
BW_Broadcast,
|
||||
BW_AddrToString,
|
||||
BW_StringToAddr,
|
||||
BW_GetSocketAddr,
|
||||
BW_GetNameFromAddr,
|
||||
BW_GetAddrFromName,
|
||||
BW_AddrCompare,
|
||||
BW_GetSocketPort,
|
||||
BW_SetSocketPort
|
||||
}
|
||||
,
|
||||
{
|
||||
"IPX",
|
||||
false,
|
||||
0,
|
||||
IPX_Init,
|
||||
IPX_Shutdown,
|
||||
IPX_Listen,
|
||||
IPX_OpenSocket,
|
||||
IPX_CloseSocket,
|
||||
IPX_Connect,
|
||||
IPX_CheckNewConnections,
|
||||
IPX_Read,
|
||||
IPX_Write,
|
||||
IPX_Broadcast,
|
||||
IPX_AddrToString,
|
||||
IPX_StringToAddr,
|
||||
IPX_GetSocketAddr,
|
||||
IPX_GetNameFromAddr,
|
||||
IPX_GetAddrFromName,
|
||||
IPX_AddrCompare,
|
||||
IPX_GetSocketPort,
|
||||
IPX_SetSocketPort
|
||||
}
|
||||
,
|
||||
{
|
||||
"Win95 TCP/IP",
|
||||
false,
|
||||
0,
|
||||
MPATH_Init,
|
||||
MPATH_Shutdown,
|
||||
MPATH_Listen,
|
||||
MPATH_OpenSocket,
|
||||
MPATH_CloseSocket,
|
||||
MPATH_Connect,
|
||||
MPATH_CheckNewConnections,
|
||||
MPATH_Read,
|
||||
MPATH_Write,
|
||||
MPATH_Broadcast,
|
||||
MPATH_AddrToString,
|
||||
MPATH_StringToAddr,
|
||||
MPATH_GetSocketAddr,
|
||||
MPATH_GetNameFromAddr,
|
||||
MPATH_GetAddrFromName,
|
||||
MPATH_AddrCompare,
|
||||
MPATH_GetSocketPort,
|
||||
MPATH_SetSocketPort
|
||||
}
|
||||
};
|
||||
|
||||
int net_numlandrivers = 3;
|
706
net_ipx.c
706
net_ipx.c
|
@ -1,706 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// net_ipx.c
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <dpmi.h>
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "dosisms.h"
|
||||
#include "net_ipx.h"
|
||||
|
||||
#define EIO 5 /* I/O error */
|
||||
|
||||
#define AF_NETWARE 64
|
||||
|
||||
#define IPX_OPEN 0
|
||||
#define IPX_CLOSE 1
|
||||
#define IPX_GETROUTE 2
|
||||
#define IPX_SEND 3
|
||||
#define IPX_LISTEN 4
|
||||
#define IPX_SCHEDULEEVENT 5
|
||||
#define IPX_CANCEL 6
|
||||
#define IPX_SCHEDULESPECIALEVENT 7
|
||||
#define IPX_GETINTERVALMARKER 8
|
||||
#define IPX_GETADDRESS 9
|
||||
#define IPX_RELINQUISH 10
|
||||
|
||||
#define PTYPE_UNKNOWN 0
|
||||
#define PTYPE_RIP 1
|
||||
#define PTYPE_ECHO 2
|
||||
#define PTYPE_ERROR 3
|
||||
#define PTYPE_IPX 4
|
||||
#define PTYPE_SPX 5
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
byte network[4];
|
||||
byte node[6];
|
||||
short socket;
|
||||
} IPXaddr;
|
||||
|
||||
struct sockaddr_ipx
|
||||
{
|
||||
short sipx_family;
|
||||
IPXaddr sipx_addr;
|
||||
char sipx_zero[2];
|
||||
};
|
||||
#define sipx_port sipx_addr.socket
|
||||
|
||||
typedef struct
|
||||
{
|
||||
short checkSum;
|
||||
short length;
|
||||
byte transportControl;
|
||||
byte type;
|
||||
IPXaddr destination;
|
||||
IPXaddr source;
|
||||
} IPXheader;
|
||||
|
||||
typedef struct ECBStructure
|
||||
{
|
||||
struct ECBStructure *link;
|
||||
unsigned short ESR_off;
|
||||
unsigned short ESR_seg;
|
||||
byte inUse;
|
||||
byte completionCode;
|
||||
short socket;
|
||||
byte IPXWorkspace[4];
|
||||
byte driverWorkspace[12];
|
||||
byte immediateAddress[6];
|
||||
short fragCount;
|
||||
short fragOff;
|
||||
short fragSeg;
|
||||
short fragSize;
|
||||
} ECB;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ECB ecb;
|
||||
IPXheader header;
|
||||
int sequence;
|
||||
char data[NET_DATAGRAMSIZE];
|
||||
} ipx_lowmem_buffer_t;
|
||||
|
||||
#define LOWMEMSIZE (100 * 1024)
|
||||
#define LOWMEMSAVE 256
|
||||
#define IPXBUFFERS ((LOWMEMSIZE - LOWMEMSAVE)/ sizeof(ipx_lowmem_buffer_t))
|
||||
#define IPXSOCKBUFFERS 5
|
||||
#define IPXSOCKETS (IPXBUFFERS / IPXSOCKBUFFERS)
|
||||
|
||||
// each socket's socketbuffer 0 is used for sending, the others for listening
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char reserved[LOWMEMSAVE];
|
||||
ipx_lowmem_buffer_t socketbuffer[IPXSOCKETS][IPXSOCKBUFFERS];
|
||||
} ipx_lowmem_area_t;
|
||||
|
||||
|
||||
static int ipxsocket[IPXSOCKETS];
|
||||
static ECB *readlist[IPXSOCKETS];
|
||||
static int sequence[IPXSOCKETS];
|
||||
static int handlesInUse;
|
||||
static ipx_lowmem_area_t *lma;
|
||||
static char *lowmem_buffer;
|
||||
static int lowmem_bufseg;
|
||||
static int lowmem_bufoff;
|
||||
static unsigned short ipx_cs;
|
||||
static unsigned short ipx_ip;
|
||||
static int net_acceptsocket = -1;
|
||||
static int net_controlsocket;
|
||||
|
||||
static void IPX_PollProcedure(void);
|
||||
static PollProcedure pollProcedure = {NULL, 0.0, IPX_PollProcedure};
|
||||
|
||||
//=============================================================================
|
||||
|
||||
static void IPX_GetLocalAddress(IPXaddr *addr)
|
||||
{
|
||||
regs.x.cs = ipx_cs;
|
||||
regs.x.ip = ipx_ip;
|
||||
regs.x.bx = IPX_GETADDRESS;
|
||||
regs.x.es = lowmem_bufseg;
|
||||
regs.x.si = lowmem_bufoff;
|
||||
__dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
|
||||
Q_memcpy(addr, lowmem_buffer, 10);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
static int IPX_GetLocalTarget(IPXaddr *addr, byte *localTarget)
|
||||
{
|
||||
regs.x.cs = ipx_cs;
|
||||
regs.x.ip = ipx_ip;
|
||||
regs.x.bx = IPX_GETROUTE;
|
||||
regs.x.es = lowmem_bufseg;
|
||||
regs.x.si = lowmem_bufoff;
|
||||
regs.x.di = lowmem_bufoff + sizeof(IPXaddr);
|
||||
Q_memcpy(lowmem_buffer, addr, sizeof(IPXaddr));
|
||||
__dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
|
||||
if (regs.h.al)
|
||||
return -1;
|
||||
Q_memcpy(localTarget, lowmem_buffer + sizeof(IPXaddr), 6);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
static void IPX_ListenForPacket(ECB *ecb)
|
||||
{
|
||||
regs.x.cs = ipx_cs;
|
||||
regs.x.ip = ipx_ip;
|
||||
regs.x.bx = IPX_LISTEN;
|
||||
regs.x.es = ptr2real(ecb) >> 4;
|
||||
regs.x.si = ptr2real(ecb) & 0xf;
|
||||
__dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
static void IPX_RelinquishControl(void)
|
||||
{
|
||||
regs.x.cs = ipx_cs;
|
||||
regs.x.ip = ipx_ip;
|
||||
regs.x.bx = IPX_RELINQUISH;
|
||||
__dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
|
||||
}
|
||||
|
||||
|
||||
void IPX_PollProcedure(void)
|
||||
{
|
||||
IPX_RelinquishControl();
|
||||
SchedulePollProcedure(&pollProcedure, 0.01);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
static void ProcessReadyList(int s)
|
||||
{
|
||||
int n;
|
||||
ECB *ecb;
|
||||
ECB *prev;
|
||||
|
||||
for (n = 1; n < IPXSOCKBUFFERS; n++)
|
||||
{
|
||||
if (lma->socketbuffer[s][n].ecb.inUse == 0)
|
||||
{
|
||||
for (ecb = readlist[s], prev = NULL; ecb; ecb = ecb->link)
|
||||
{
|
||||
if (lma->socketbuffer[s][n].sequence < ((ipx_lowmem_buffer_t *) ecb)->sequence)
|
||||
break;
|
||||
prev = ecb;
|
||||
}
|
||||
if (ecb)
|
||||
lma->socketbuffer[s][n].ecb.link = ecb;
|
||||
else
|
||||
lma->socketbuffer[s][n].ecb.link = NULL;
|
||||
if (prev)
|
||||
prev->link = &lma->socketbuffer[s][n].ecb;
|
||||
else
|
||||
readlist[s] = &lma->socketbuffer[s][n].ecb;
|
||||
lma->socketbuffer[s][n].ecb.inUse = 0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int IPX_Init(void)
|
||||
{
|
||||
int s;
|
||||
int n;
|
||||
struct qsockaddr addr;
|
||||
char *colon;
|
||||
|
||||
if (COM_CheckParm ("-noipx"))
|
||||
return -1;
|
||||
|
||||
// find the IPX far call entry point
|
||||
regs.x.ax = 0x7a00;
|
||||
__dpmi_simulate_real_mode_interrupt (0x2f, (__dpmi_regs *)®s);
|
||||
if (regs.h.al != 0xff)
|
||||
{
|
||||
Con_Printf("IPX not detected\n");
|
||||
return -1;
|
||||
}
|
||||
ipx_cs = regs.x.es;
|
||||
ipx_ip = regs.x.di;
|
||||
|
||||
// grab a chunk of memory down in DOS land
|
||||
lowmem_buffer = dos_getmemory(LOWMEMSIZE);
|
||||
if (!lowmem_buffer)
|
||||
{
|
||||
Con_Printf("IPX_Init: Not enough low memory\n");
|
||||
return -1;
|
||||
}
|
||||
lowmem_bufoff = ptr2real(lowmem_buffer) & 0xf;
|
||||
lowmem_bufseg = ptr2real(lowmem_buffer) >> 4;
|
||||
|
||||
// init socket handles & buffers
|
||||
handlesInUse = 0;
|
||||
lma = (ipx_lowmem_area_t *)lowmem_buffer;
|
||||
for (s = 0; s < IPXSOCKETS; s++)
|
||||
{
|
||||
ipxsocket[s] = 0;
|
||||
for (n = 0; n < IPXSOCKBUFFERS; n++)
|
||||
{
|
||||
lma->socketbuffer[s][n].ecb.link = NULL;
|
||||
lma->socketbuffer[s][n].ecb.ESR_off = 0;
|
||||
lma->socketbuffer[s][n].ecb.ESR_seg = 0;
|
||||
lma->socketbuffer[s][n].ecb.socket = 0;
|
||||
lma->socketbuffer[s][n].ecb.inUse = 0xff;
|
||||
lma->socketbuffer[s][n].ecb.completionCode = 0;
|
||||
lma->socketbuffer[s][n].ecb.fragCount = 1;
|
||||
lma->socketbuffer[s][n].ecb.fragOff = ptr2real(&lma->socketbuffer[s][n].header) & 0xf;
|
||||
lma->socketbuffer[s][n].ecb.fragSeg = ptr2real(&lma->socketbuffer[s][n].header) >> 4;
|
||||
lma->socketbuffer[s][n].ecb.fragSize = sizeof(IPXheader) + sizeof(int) + NET_DATAGRAMSIZE;
|
||||
}
|
||||
}
|
||||
|
||||
if ((net_controlsocket = IPX_OpenSocket (0)) == -1)
|
||||
{
|
||||
dos_freememory(lowmem_buffer);
|
||||
Con_DPrintf ("IPX_Init: Unable to open control socket\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
SchedulePollProcedure(&pollProcedure, 0.01);
|
||||
|
||||
IPX_GetSocketAddr (net_controlsocket, &addr);
|
||||
Q_strcpy(my_ipx_address, IPX_AddrToString (&addr));
|
||||
colon = Q_strrchr (my_ipx_address, ':');
|
||||
if (colon)
|
||||
*colon = 0;
|
||||
|
||||
Con_Printf("IPX initialized\n");
|
||||
ipxAvailable = true;
|
||||
return net_controlsocket;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
void IPX_Shutdown(void)
|
||||
{
|
||||
IPX_Listen (false);
|
||||
IPX_CloseSocket (net_controlsocket);
|
||||
dos_freememory(lowmem_buffer);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
void IPX_Listen (qboolean state)
|
||||
{
|
||||
// enable listening
|
||||
if (state)
|
||||
{
|
||||
if (net_acceptsocket != -1)
|
||||
return;
|
||||
if ((net_acceptsocket = IPX_OpenSocket (net_hostport)) == -1)
|
||||
Sys_Error ("IPX_Listen: Unable to open accept socket\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// disable listening
|
||||
if (net_acceptsocket == -1)
|
||||
return;
|
||||
IPX_CloseSocket (net_acceptsocket);
|
||||
net_acceptsocket = -1;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int IPX_OpenSocket(int port)
|
||||
{
|
||||
int handle;
|
||||
int n;
|
||||
unsigned short socket;
|
||||
|
||||
if (handlesInUse == IPXSOCKETS)
|
||||
return -1;
|
||||
|
||||
// open the IPX socket
|
||||
regs.x.cs = ipx_cs;
|
||||
regs.x.ip = ipx_ip;
|
||||
regs.x.bx = IPX_OPEN;
|
||||
regs.h.al = 0;
|
||||
regs.x.dx = htons(port);
|
||||
__dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
|
||||
if (regs.h.al == 0xfe)
|
||||
{
|
||||
Con_DPrintf("IPX_OpenSocket: all sockets in use\n");
|
||||
return -1;
|
||||
}
|
||||
if (regs.h.al == 0xff)
|
||||
{
|
||||
Con_DPrintf("IPX_OpenSocket: socket already open\n");
|
||||
return -1;
|
||||
}
|
||||
if (regs.h.al != 0)
|
||||
{
|
||||
Con_DPrintf("IPX_OpenSocket: error %02x\n", regs.h.al);
|
||||
return -1;
|
||||
}
|
||||
socket = regs.x.dx;
|
||||
|
||||
// grab a handle; fill in the ECBs, and get them listening
|
||||
for (handle = 0; handle < IPXSOCKETS; handle++)
|
||||
{
|
||||
if (ipxsocket[handle] == 0)
|
||||
{
|
||||
ipxsocket[handle] = socket;
|
||||
readlist[handle] = NULL;
|
||||
sequence[handle] = 0;
|
||||
for (n = 0; n < IPXSOCKBUFFERS; n ++)
|
||||
{
|
||||
lma->socketbuffer[handle][n].ecb.socket = socket;
|
||||
lma->socketbuffer[handle][n].ecb.inUse = 0;
|
||||
if (n)
|
||||
IPX_ListenForPacket(&lma->socketbuffer[handle][n].ecb);
|
||||
}
|
||||
handlesInUse++;
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
|
||||
// "this will NEVER happen"
|
||||
Sys_Error("IPX_OpenSocket: handle allocation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int IPX_CloseSocket(int handle)
|
||||
{
|
||||
// if there's a send in progress, give it one last chance
|
||||
if (lma->socketbuffer[handle][0].ecb.inUse != 0)
|
||||
IPX_RelinquishControl();
|
||||
|
||||
// close the socket (all pending sends/received are cancelled)
|
||||
regs.x.cs = ipx_cs;
|
||||
regs.x.ip = ipx_ip;
|
||||
regs.x.bx = IPX_CLOSE;
|
||||
regs.x.dx = ipxsocket[handle];
|
||||
__dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
|
||||
|
||||
ipxsocket[handle] = 0;
|
||||
handlesInUse--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int IPX_Connect (int handle, struct qsockaddr *addr)
|
||||
{
|
||||
IPXaddr ipxaddr;
|
||||
|
||||
Q_memcpy(&ipxaddr, &((struct sockaddr_ipx *)addr)->sipx_addr, sizeof(IPXaddr));
|
||||
if (IPX_GetLocalTarget(&ipxaddr, lma->socketbuffer[handle][0].ecb.immediateAddress) != 0)
|
||||
{
|
||||
Con_Printf("Get Local Target failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int IPX_CheckNewConnections (void)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (net_acceptsocket == -1)
|
||||
return -1;
|
||||
|
||||
for (n = 1; n < IPXSOCKBUFFERS; n ++)
|
||||
if (lma->socketbuffer[net_acceptsocket][n].ecb.inUse == 0)
|
||||
return net_acceptsocket;
|
||||
return -1;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int IPX_Read (int handle, byte *buf, int len, struct qsockaddr *addr)
|
||||
{
|
||||
ECB *ecb;
|
||||
ipx_lowmem_buffer_t *rcvbuf;
|
||||
int copylen;
|
||||
|
||||
ProcessReadyList(handle);
|
||||
tryagain:
|
||||
if (readlist[handle] == NULL)
|
||||
return 0;
|
||||
ecb = readlist[handle];
|
||||
readlist[handle] = ecb->link;
|
||||
|
||||
if (ecb->completionCode != 0)
|
||||
{
|
||||
Con_Printf("Warning: IPX_Read error %02x\n", ecb->completionCode);
|
||||
ecb->fragSize = sizeof(IPXheader) + sizeof(int) + NET_DATAGRAMSIZE;
|
||||
IPX_ListenForPacket(ecb);
|
||||
goto tryagain;
|
||||
}
|
||||
|
||||
rcvbuf = (ipx_lowmem_buffer_t *)ecb;
|
||||
|
||||
// copy the data up to the buffer
|
||||
copylen = ntohs(rcvbuf->header.length) - (sizeof(int) + sizeof(IPXheader));
|
||||
if (len < copylen)
|
||||
Sys_Error("IPX_Read: buffer too small (%d vs %d)\n", len, copylen);
|
||||
Q_memcpy(buf, rcvbuf->data, copylen);
|
||||
|
||||
// fill in the addr if they want it
|
||||
if (addr)
|
||||
{
|
||||
((struct sockaddr_ipx *)addr)->sipx_family = AF_NETWARE;
|
||||
Q_memcpy(&((struct sockaddr_ipx *)addr)->sipx_addr, rcvbuf->header.source.network, sizeof(IPXaddr));
|
||||
((struct sockaddr_ipx *)addr)->sipx_zero[0] = 0;
|
||||
((struct sockaddr_ipx *)addr)->sipx_zero[1] = 0;
|
||||
}
|
||||
|
||||
// update the send ecb's immediate address
|
||||
Q_memcpy(lma->socketbuffer[handle][0].ecb.immediateAddress, rcvbuf->ecb.immediateAddress, 6);
|
||||
|
||||
// get this ecb listening again
|
||||
rcvbuf->ecb.fragSize = sizeof(IPXheader) + sizeof(int) + NET_DATAGRAMSIZE;
|
||||
IPX_ListenForPacket(&rcvbuf->ecb);
|
||||
return copylen;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int IPX_Broadcast (int handle, byte *buf, int len)
|
||||
{
|
||||
struct sockaddr_ipx addr;
|
||||
int ret;
|
||||
|
||||
Q_memset(addr.sipx_addr.network, 0x00, 4);
|
||||
Q_memset(addr.sipx_addr.node, 0xff, 6);
|
||||
addr.sipx_port = htons(net_hostport);
|
||||
Q_memset(lma->socketbuffer[handle][0].ecb.immediateAddress, 0xff, 6);
|
||||
ret = IPX_Write (handle, buf, len, (struct qsockaddr *)&addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int IPX_Write (int handle, byte *buf, int len, struct qsockaddr *addr)
|
||||
{
|
||||
// has the previous send completed?
|
||||
while (lma->socketbuffer[handle][0].ecb.inUse != 0)
|
||||
IPX_RelinquishControl();
|
||||
|
||||
switch (lma->socketbuffer[handle][0].ecb.completionCode)
|
||||
{
|
||||
case 0x00: // success
|
||||
case 0xfc: // request cancelled
|
||||
break;
|
||||
|
||||
case 0xfd: // malformed packet
|
||||
default:
|
||||
Con_Printf("IPX driver send failure: %02x\n", lma->socketbuffer[handle][0].ecb.completionCode);
|
||||
break;
|
||||
|
||||
case 0xfe: // packet undeliverable
|
||||
case 0xff: // unable to send packet
|
||||
Con_Printf("IPX lost route, trying to re-establish\n");
|
||||
|
||||
// look for a new route
|
||||
if (IPX_GetLocalTarget (&lma->socketbuffer[handle][0].header.destination, lma->socketbuffer[handle][0].ecb.immediateAddress) != 0)
|
||||
return -1;
|
||||
|
||||
// re-send the one that failed
|
||||
regs.x.cs = ipx_cs;
|
||||
regs.x.ip = ipx_ip;
|
||||
regs.x.bx = IPX_SEND;
|
||||
regs.x.es = ptr2real(&lma->socketbuffer[handle][0].ecb) >> 4;
|
||||
regs.x.si = ptr2real(&lma->socketbuffer[handle][0].ecb) & 0xf;
|
||||
__dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
|
||||
|
||||
// report that we did not send the current one
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ecb : length
|
||||
lma->socketbuffer[handle][0].ecb.fragSize = sizeof(IPXheader) + sizeof(int) + len;
|
||||
|
||||
// ipx header : type
|
||||
lma->socketbuffer[handle][0].header.type = PTYPE_IPX;
|
||||
|
||||
// ipx header : destination
|
||||
Q_memcpy(&lma->socketbuffer[handle][0].header.destination, &((struct sockaddr_ipx *)addr)->sipx_addr, sizeof(IPXaddr));
|
||||
|
||||
// sequence number
|
||||
lma->socketbuffer[handle][0].sequence = sequence[handle];
|
||||
sequence[handle]++;
|
||||
|
||||
// copy down the data
|
||||
Q_memcpy(lma->socketbuffer[handle][0].data, buf, len);
|
||||
|
||||
regs.x.cs = ipx_cs;
|
||||
regs.x.ip = ipx_ip;
|
||||
regs.x.bx = IPX_SEND;
|
||||
regs.x.es = ptr2real(&lma->socketbuffer[handle][0].ecb) >> 4;
|
||||
regs.x.si = ptr2real(&lma->socketbuffer[handle][0].ecb) & 0xf;
|
||||
__dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
char *IPX_AddrToString (struct qsockaddr *addr)
|
||||
{
|
||||
static char buf[28];
|
||||
|
||||
sprintf(buf, "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%u",
|
||||
((struct sockaddr_ipx *)addr)->sipx_addr.network[0],
|
||||
((struct sockaddr_ipx *)addr)->sipx_addr.network[1],
|
||||
((struct sockaddr_ipx *)addr)->sipx_addr.network[2],
|
||||
((struct sockaddr_ipx *)addr)->sipx_addr.network[3],
|
||||
((struct sockaddr_ipx *)addr)->sipx_addr.node[0],
|
||||
((struct sockaddr_ipx *)addr)->sipx_addr.node[1],
|
||||
((struct sockaddr_ipx *)addr)->sipx_addr.node[2],
|
||||
((struct sockaddr_ipx *)addr)->sipx_addr.node[3],
|
||||
((struct sockaddr_ipx *)addr)->sipx_addr.node[4],
|
||||
((struct sockaddr_ipx *)addr)->sipx_addr.node[5],
|
||||
ntohs(((struct sockaddr_ipx *)addr)->sipx_port)
|
||||
);
|
||||
return buf;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int IPX_StringToAddr (char *string, struct qsockaddr *addr)
|
||||
{
|
||||
int val;
|
||||
char buf[3];
|
||||
|
||||
buf[2] = 0;
|
||||
Q_memset(addr, 0, sizeof(struct qsockaddr));
|
||||
addr->sa_family = AF_NETWARE;
|
||||
|
||||
#define DO(src,dest) \
|
||||
buf[0] = string[src]; \
|
||||
buf[1] = string[src + 1]; \
|
||||
if (sscanf (buf, "%x", &val) != 1) \
|
||||
return -1; \
|
||||
((struct sockaddr_ipx *)addr)->sipx_addr.dest = val
|
||||
|
||||
DO(0, network[0]);
|
||||
DO(2, network[1]);
|
||||
DO(4, network[2]);
|
||||
DO(6, network[3]);
|
||||
DO(9, node[0]);
|
||||
DO(11, node[1]);
|
||||
DO(13, node[2]);
|
||||
DO(15, node[3]);
|
||||
DO(17, node[4]);
|
||||
DO(19, node[5]);
|
||||
#undef DO
|
||||
|
||||
sscanf (&string[22], "%u", &val);
|
||||
((struct sockaddr_ipx *)addr)->sipx_port = htons(val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int IPX_GetSocketAddr (int handle, struct qsockaddr *addr)
|
||||
{
|
||||
Q_memset(addr, 0, sizeof(struct qsockaddr));
|
||||
addr->sa_family = AF_NETWARE;
|
||||
IPX_GetLocalAddress(&((struct sockaddr_ipx *)addr)->sipx_addr);
|
||||
((struct sockaddr_ipx *)addr)->sipx_port = ipxsocket[handle];
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int IPX_GetNameFromAddr (struct qsockaddr *addr, char *name)
|
||||
{
|
||||
Q_strcpy(name, IPX_AddrToString(addr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int IPX_GetAddrFromName (char *name, struct qsockaddr *addr)
|
||||
{
|
||||
int n;
|
||||
char buf[32];
|
||||
|
||||
n = Q_strlen(name);
|
||||
|
||||
if (n == 12)
|
||||
{
|
||||
sprintf(buf, "00000000:%s:%u", name, net_hostport);
|
||||
return IPX_StringToAddr (buf, addr);
|
||||
}
|
||||
if (n == 21)
|
||||
{
|
||||
sprintf(buf, "%s:%u", name, net_hostport);
|
||||
return IPX_StringToAddr (buf, addr);
|
||||
}
|
||||
if (n > 21 && n <= 27)
|
||||
return IPX_StringToAddr (name, addr);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int IPX_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2)
|
||||
{
|
||||
if (addr1->sa_family != addr2->sa_family)
|
||||
return -1;
|
||||
|
||||
if(Q_memcmp(&((struct sockaddr_ipx *)addr1)->sipx_addr, &((struct sockaddr_ipx *)addr2)->sipx_addr, 10))
|
||||
return -1;
|
||||
|
||||
if (((struct sockaddr_ipx *)addr1)->sipx_port != ((struct sockaddr_ipx *)addr2)->sipx_port)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int IPX_GetSocketPort (struct qsockaddr *addr)
|
||||
{
|
||||
return ntohs(((struct sockaddr_ipx *)addr)->sipx_port);
|
||||
}
|
||||
|
||||
|
||||
int IPX_SetSocketPort (struct qsockaddr *addr, int port)
|
||||
{
|
||||
((struct sockaddr_ipx *)addr)->sipx_port = htons(port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
39
net_ipx.h
39
net_ipx.h
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// net_ipx.h
|
||||
|
||||
int IPX_Init (void);
|
||||
void IPX_Shutdown (void);
|
||||
void IPX_Listen (qboolean state);
|
||||
int IPX_OpenSocket (int port);
|
||||
int IPX_CloseSocket (int socket);
|
||||
int IPX_Connect (int socket, struct qsockaddr *addr);
|
||||
int IPX_CheckNewConnections (void);
|
||||
int IPX_Read (int socket, byte *buf, int len, struct qsockaddr *addr);
|
||||
int IPX_Write (int socket, byte *buf, int len, struct qsockaddr *addr);
|
||||
int IPX_Broadcast (int socket, byte *buf, int len);
|
||||
char *IPX_AddrToString (struct qsockaddr *addr);
|
||||
int IPX_StringToAddr (char *string, struct qsockaddr *addr);
|
||||
int IPX_GetSocketAddr (int socket, struct qsockaddr *addr);
|
||||
int IPX_GetNameFromAddr (struct qsockaddr *addr, char *name);
|
||||
int IPX_GetAddrFromName (char *name, struct qsockaddr *addr);
|
||||
int IPX_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2);
|
||||
int IPX_GetSocketPort (struct qsockaddr *addr);
|
||||
int IPX_SetSocketPort (struct qsockaddr *addr, int port);
|
443
net_mp.c
443
net_mp.c
|
@ -1,443 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// net_mpath.c
|
||||
|
||||
#include <dpmi.h>
|
||||
#include "quakedef.h"
|
||||
#include "mpdosock.h"
|
||||
|
||||
short flat_selector;
|
||||
|
||||
int WSAGetLastError(void);
|
||||
void sockets_flush(void);
|
||||
|
||||
extern cvar_t hostname;
|
||||
|
||||
#define MAXHOSTNAMELEN 256
|
||||
|
||||
static int net_acceptsocket = -1; // socket for fielding new connections
|
||||
static int net_controlsocket;
|
||||
static int net_broadcastsocket = 0;
|
||||
//static qboolean ifbcastinit = false;
|
||||
static struct qsockaddr broadcastaddr;
|
||||
|
||||
static unsigned long myAddr;
|
||||
|
||||
#include "net_mp.h"
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int MPATH_Init (void)
|
||||
{
|
||||
int i;
|
||||
struct hostent *local = NULL;
|
||||
char buff[MAXHOSTNAMELEN];
|
||||
struct qsockaddr addr;
|
||||
char *p;
|
||||
|
||||
if (COM_CheckParm ("-mpath") == 0)
|
||||
return -1;
|
||||
|
||||
flat_selector = __dpmi_allocate_ldt_descriptors(1);
|
||||
if (flat_selector == -1) {
|
||||
Con_Printf("MPATH_Init: Can't get flat selector\n");
|
||||
return -1;
|
||||
}
|
||||
if (__dpmi_set_segment_base_address(flat_selector, 0) == -1) {
|
||||
Con_Printf("MPATH_Init: Can't seg flat base!\n");
|
||||
return -1;
|
||||
}
|
||||
if (__dpmi_set_segment_limit(flat_selector, 0xffffffff) == -1) {
|
||||
Con_Printf("MPATH_Init: Can't set segment limit\n");
|
||||
return -1;
|
||||
}
|
||||
// determine my name & address
|
||||
if (gethostname(buff, MAXHOSTNAMELEN) == 0)
|
||||
local = gethostbyname(buff);
|
||||
if (local)
|
||||
{
|
||||
myAddr = *(int *)local->h_addr_list[0];
|
||||
|
||||
// if the quake hostname isn't set, set it to the machine name
|
||||
if (Q_strcmp(hostname.string, "UNNAMED") == 0)
|
||||
{
|
||||
// see if it's a text IP address (well, close enough)
|
||||
for (p = buff; *p; p++)
|
||||
if ((*p < '0' || *p > '9') && *p != '.')
|
||||
break;
|
||||
|
||||
// if it is a real name, strip off the domain; we only want the host
|
||||
if (*p)
|
||||
{
|
||||
for (i = 0; i < 15; i++)
|
||||
if (buff[i] == '.')
|
||||
break;
|
||||
buff[i] = 0;
|
||||
}
|
||||
Cvar_Set ("hostname", buff);
|
||||
}
|
||||
}
|
||||
|
||||
if ((net_controlsocket = MPATH_OpenSocket (0)) == -1)
|
||||
Sys_Error("MPATH_Init: Unable to open control socket\n");
|
||||
|
||||
((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET;
|
||||
((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST;
|
||||
((struct sockaddr_in *)&broadcastaddr)->sin_port = htons(net_hostport);
|
||||
|
||||
MPATH_GetSocketAddr (net_controlsocket, &addr);
|
||||
Q_strcpy(my_tcpip_address, MPATH_AddrToString (&addr));
|
||||
p = Q_strrchr (my_tcpip_address, ':');
|
||||
if (p)
|
||||
*p = 0;
|
||||
|
||||
Con_Printf("MPath Initialized\n");
|
||||
tcpipAvailable = true;
|
||||
|
||||
return net_controlsocket;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
void MPATH_Shutdown (void)
|
||||
{
|
||||
MPATH_Listen (false);
|
||||
MPATH_CloseSocket (net_controlsocket);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
void MPATH_Listen (qboolean state)
|
||||
{
|
||||
// enable listening
|
||||
if (state)
|
||||
{
|
||||
if (net_acceptsocket != -1)
|
||||
return;
|
||||
if ((net_acceptsocket = MPATH_OpenSocket (net_hostport)) == -1)
|
||||
Sys_Error ("MPATH_Listen: Unable to open accept socket\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// disable listening
|
||||
if (net_acceptsocket == -1)
|
||||
return;
|
||||
MPATH_CloseSocket (net_acceptsocket);
|
||||
net_acceptsocket = -1;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int MPATH_OpenSocket (int port)
|
||||
{
|
||||
int newsocket;
|
||||
struct sockaddr_in address;
|
||||
u_long _true = 1;
|
||||
|
||||
if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
|
||||
return -1;
|
||||
|
||||
if (ioctlsocket (newsocket, FIONBIO, &_true) == -1)
|
||||
goto ErrorReturn;
|
||||
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_addr.s_addr = INADDR_ANY;
|
||||
address.sin_port = htons(port);
|
||||
if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
|
||||
goto ErrorReturn;
|
||||
|
||||
return newsocket;
|
||||
|
||||
ErrorReturn:
|
||||
closesocket (newsocket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int MPATH_CloseSocket (int socket)
|
||||
{
|
||||
if (socket == net_broadcastsocket)
|
||||
net_broadcastsocket = 0;
|
||||
return closesocket (socket);
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
/*
|
||||
============
|
||||
PartialIPAddress
|
||||
|
||||
this lets you type only as much of the net address as required, using
|
||||
the local network components to fill in the rest
|
||||
============
|
||||
*/
|
||||
static int PartialIPAddress (char *in, struct qsockaddr *hostaddr)
|
||||
{
|
||||
char buff[256];
|
||||
char *b;
|
||||
int addr;
|
||||
int num;
|
||||
int mask;
|
||||
int run;
|
||||
int port;
|
||||
|
||||
buff[0] = '.';
|
||||
b = buff;
|
||||
strcpy(buff+1, in);
|
||||
if (buff[1] == '.')
|
||||
b++;
|
||||
|
||||
addr = 0;
|
||||
mask=-1;
|
||||
while (*b == '.')
|
||||
{
|
||||
b++;
|
||||
num = 0;
|
||||
run = 0;
|
||||
while (!( *b < '0' || *b > '9'))
|
||||
{
|
||||
num = num*10 + *b++ - '0';
|
||||
if (++run > 3)
|
||||
return -1;
|
||||
}
|
||||
if ((*b < '0' || *b > '9') && *b != '.' && *b != ':' && *b != 0)
|
||||
return -1;
|
||||
if (num < 0 || num > 255)
|
||||
return -1;
|
||||
mask<<=8;
|
||||
addr = (addr<<8) + num;
|
||||
}
|
||||
|
||||
if (*b++ == ':')
|
||||
port = Q_atoi(b);
|
||||
else
|
||||
port = net_hostport;
|
||||
|
||||
hostaddr->sa_family = AF_INET;
|
||||
((struct sockaddr_in *)hostaddr)->sin_port = htons((short)port);
|
||||
((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
//=============================================================================
|
||||
|
||||
int MPATH_Connect (int socket, struct qsockaddr *addr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int MPATH_CheckNewConnections (void)
|
||||
{
|
||||
char buf[4];
|
||||
|
||||
if (net_acceptsocket == -1)
|
||||
return -1;
|
||||
|
||||
if (recvfrom (net_acceptsocket, buf, 4, MSG_PEEK, NULL, NULL) > 0)
|
||||
return net_acceptsocket;
|
||||
return -1;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int MPATH_Read (int socket, byte *buf, int len, struct qsockaddr *addr)
|
||||
{
|
||||
int addrlen = sizeof (struct qsockaddr);
|
||||
int ret;
|
||||
|
||||
ret = recvfrom (socket, buf, len, 0, (struct sockaddr *)addr, &addrlen);
|
||||
if (ret == -1)
|
||||
{
|
||||
int errno = WSAGetLastError();
|
||||
|
||||
if (errno == WSAEWOULDBLOCK || errno == WSAECONNREFUSED)
|
||||
return 0;
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int MPATH_MakeSocketBroadcastCapable (int socket)
|
||||
{
|
||||
int i = 1;
|
||||
|
||||
// make this socket broadcast capable
|
||||
if (setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0)
|
||||
return -1;
|
||||
net_broadcastsocket = socket;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int MPATH_Broadcast (int socket, byte *buf, int len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (socket != net_broadcastsocket)
|
||||
{
|
||||
if (net_broadcastsocket != 0)
|
||||
Sys_Error("Attempted to use multiple broadcasts sockets\n");
|
||||
ret = MPATH_MakeSocketBroadcastCapable (socket);
|
||||
if (ret == -1)
|
||||
{
|
||||
Con_Printf("Unable to make socket broadcast capable\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return MPATH_Write (socket, buf, len, &broadcastaddr);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int MPATH_Write (int socket, byte *buf, int len, struct qsockaddr *addr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = sendto (socket, buf, len, 0, (struct sockaddr *)addr, sizeof(struct qsockaddr));
|
||||
if (ret == -1)
|
||||
if (WSAGetLastError() == WSAEWOULDBLOCK)
|
||||
return 0;
|
||||
|
||||
sockets_flush();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
char *MPATH_AddrToString (struct qsockaddr *addr)
|
||||
{
|
||||
static char buffer[22];
|
||||
int haddr;
|
||||
|
||||
haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
|
||||
sprintf(buffer, "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff, (haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff, ntohs(((struct sockaddr_in *)addr)->sin_port));
|
||||
return buffer;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int MPATH_StringToAddr (char *string, struct qsockaddr *addr)
|
||||
{
|
||||
int ha1, ha2, ha3, ha4, hp;
|
||||
int ipaddr;
|
||||
|
||||
sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp);
|
||||
ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4;
|
||||
|
||||
addr->sa_family = AF_INET;
|
||||
((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr);
|
||||
((struct sockaddr_in *)addr)->sin_port = htons(hp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int MPATH_GetSocketAddr (int socket, struct qsockaddr *addr)
|
||||
{
|
||||
int addrlen = sizeof(struct qsockaddr);
|
||||
unsigned int a;
|
||||
|
||||
Q_memset(addr, 0, sizeof(struct qsockaddr));
|
||||
getsockname(socket, (struct sockaddr *)addr, &addrlen);
|
||||
a = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
|
||||
if (a == 0 || a == inet_addr("127.0.0.1"))
|
||||
((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int MPATH_GetNameFromAddr (struct qsockaddr *addr, char *name)
|
||||
{
|
||||
struct hostent *hostentry;
|
||||
|
||||
hostentry = gethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr), AF_INET);
|
||||
if (hostentry)
|
||||
{
|
||||
Q_strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Q_strcpy (name, MPATH_AddrToString (addr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int MPATH_GetAddrFromName(char *name, struct qsockaddr *addr)
|
||||
{
|
||||
struct hostent *hostentry;
|
||||
|
||||
if (name[0] >= '0' && name[0] <= '9')
|
||||
return PartialIPAddress (name, addr);
|
||||
|
||||
hostentry = gethostbyname (name);
|
||||
if (!hostentry)
|
||||
return -1;
|
||||
|
||||
addr->sa_family = AF_INET;
|
||||
((struct sockaddr_in *)addr)->sin_port = htons(net_hostport);
|
||||
((struct sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int MPATH_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2)
|
||||
{
|
||||
if (addr1->sa_family != addr2->sa_family)
|
||||
return -1;
|
||||
|
||||
if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr)
|
||||
return -1;
|
||||
|
||||
if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int MPATH_GetSocketPort (struct qsockaddr *addr)
|
||||
{
|
||||
return ntohs(((struct sockaddr_in *)addr)->sin_port);
|
||||
}
|
||||
|
||||
|
||||
int MPATH_SetSocketPort (struct qsockaddr *addr, int port)
|
||||
{
|
||||
((struct sockaddr_in *)addr)->sin_port = htons(port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
39
net_mp.h
39
net_mp.h
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// net_mpath.h
|
||||
|
||||
int MPATH_Init (void);
|
||||
void MPATH_Shutdown (void);
|
||||
void MPATH_Listen (qboolean state);
|
||||
int MPATH_OpenSocket (int port);
|
||||
int MPATH_CloseSocket (int socket);
|
||||
int MPATH_Connect (int socket, struct qsockaddr *addr);
|
||||
int MPATH_CheckNewConnections (void);
|
||||
int MPATH_Read (int socket, byte *buf, int len, struct qsockaddr *addr);
|
||||
int MPATH_Write (int socket, byte *buf, int len, struct qsockaddr *addr);
|
||||
int MPATH_Broadcast (int socket, byte *buf, int len);
|
||||
char *MPATH_AddrToString (struct qsockaddr *addr);
|
||||
int MPATH_StringToAddr (char *string, struct qsockaddr *addr);
|
||||
int MPATH_GetSocketAddr (int socket, struct qsockaddr *addr);
|
||||
int MPATH_GetNameFromAddr (struct qsockaddr *addr, char *name);
|
||||
int MPATH_GetAddrFromName (char *name, struct qsockaddr *addr);
|
||||
int MPATH_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2);
|
||||
int MPATH_GetSocketPort (struct qsockaddr *addr);
|
||||
int MPATH_SetSocketPort (struct qsockaddr *addr, int port);
|
64
nonintel.c
64
nonintel.c
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
//
|
||||
// nonintel.c: code for non-Intel processors only
|
||||
//
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "r_local.h"
|
||||
#include "d_local.h"
|
||||
|
||||
#if !id386
|
||||
|
||||
/*
|
||||
================
|
||||
R_Surf8Patch
|
||||
================
|
||||
*/
|
||||
void R_Surf8Patch ()
|
||||
{
|
||||
// we only patch code on Intel
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_Surf16Patch
|
||||
================
|
||||
*/
|
||||
void R_Surf16Patch ()
|
||||
{
|
||||
// we only patch code on Intel
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_SurfacePatch
|
||||
================
|
||||
*/
|
||||
void R_SurfacePatch (void)
|
||||
{
|
||||
// we only patch code on Intel
|
||||
}
|
||||
|
||||
|
||||
#endif // !id386
|
||||
|
653
snd_dos.c
653
snd_dos.c
|
@ -1,653 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "dosisms.h"
|
||||
|
||||
int BLASTER_GetDMAPos(void);
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
GUS SUPPORT
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
qboolean GUS_Init (void);
|
||||
int GUS_GetDMAPos (void);
|
||||
void GUS_Shutdown (void);
|
||||
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
BLASTER SUPPORT
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
short *dma_buffer=0;
|
||||
static int dma_size;
|
||||
static int dma;
|
||||
|
||||
static int dsp_port;
|
||||
static int irq;
|
||||
static int low_dma;
|
||||
static int high_dma;
|
||||
static int mixer_port;
|
||||
static int mpu401_port;
|
||||
|
||||
int dsp_version;
|
||||
int dsp_minor_version;
|
||||
|
||||
int timeconstant=-1;
|
||||
|
||||
|
||||
void PrintBits (byte b)
|
||||
{
|
||||
int i;
|
||||
char str[9];
|
||||
|
||||
for (i=0 ; i<8 ; i++)
|
||||
str[i] = '0' + ((b & (1<<(7-i))) > 0);
|
||||
|
||||
str[8] = 0;
|
||||
Con_Printf ("%s (%i)", str, b);
|
||||
}
|
||||
|
||||
void SB_Info_f(void)
|
||||
{
|
||||
Con_Printf ("BLASTER=%s\n", getenv("BLASTER"));
|
||||
Con_Printf("dsp version=%d.%d\n", dsp_version, dsp_minor_version);
|
||||
Con_Printf("dma=%d\n", dma);
|
||||
if (timeconstant != -1)
|
||||
Con_Printf("timeconstant=%d\n", timeconstant);
|
||||
Con_Printf("dma position:%i\n", BLASTER_GetDMAPos ());
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// Interprets BLASTER variable
|
||||
// =======================================================================
|
||||
|
||||
int GetBLASTER(void)
|
||||
{
|
||||
char *BLASTER;
|
||||
char *param;
|
||||
|
||||
BLASTER = getenv("BLASTER");
|
||||
if (!BLASTER)
|
||||
return 0;
|
||||
|
||||
param = strchr(BLASTER, 'A');
|
||||
if (!param)
|
||||
param = strchr(BLASTER, 'a');
|
||||
if (!param)
|
||||
return 0;
|
||||
sscanf(param+1, "%x", &dsp_port);
|
||||
|
||||
param = strchr(BLASTER, 'I');
|
||||
if (!param)
|
||||
param = strchr(BLASTER, 'i');
|
||||
if (!param)
|
||||
return 0;
|
||||
sscanf(param+1, "%d", &irq);
|
||||
|
||||
param = strchr(BLASTER, 'D');
|
||||
if (!param)
|
||||
param = strchr(BLASTER, 'd');
|
||||
if (!param)
|
||||
return 0;
|
||||
sscanf(param+1, "%d", &low_dma);
|
||||
|
||||
param = strchr(BLASTER, 'H');
|
||||
if (!param)
|
||||
param = strchr(BLASTER, 'h');
|
||||
if (param)
|
||||
sscanf(param+1, "%d", &high_dma);
|
||||
|
||||
param = strchr(BLASTER, 'M');
|
||||
if (!param)
|
||||
param = strchr(BLASTER, 'm');
|
||||
if (param)
|
||||
sscanf(param+1, "%x", &mixer_port);
|
||||
else
|
||||
mixer_port = dsp_port;
|
||||
|
||||
param = strchr(BLASTER, 'P');
|
||||
if (!param)
|
||||
param = strchr(BLASTER, 'p');
|
||||
if (param)
|
||||
sscanf(param+1, "%x", &mpu401_port);
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
// ==================================================================
|
||||
// Resets DSP. Returns 0 on success.
|
||||
// ==================================================================
|
||||
|
||||
int ResetDSP(void)
|
||||
{
|
||||
volatile int i;
|
||||
|
||||
dos_outportb(dsp_port + 6, 1);
|
||||
for (i=65536 ; i ; i--) ;
|
||||
dos_outportb(dsp_port + 6, 0);
|
||||
for (i=65536 ; i ; i--)
|
||||
{
|
||||
if (!(dos_inportb(dsp_port + 0xe) & 0x80)) continue;
|
||||
if (dos_inportb(dsp_port + 0xa) == 0xaa) break;
|
||||
}
|
||||
if (i) return 0;
|
||||
else return 1;
|
||||
|
||||
}
|
||||
|
||||
int ReadDSP(void)
|
||||
{
|
||||
while (!(dos_inportb(dsp_port+0xe)&0x80)) ;
|
||||
return dos_inportb(dsp_port+0xa);
|
||||
}
|
||||
|
||||
void WriteDSP(int val)
|
||||
{
|
||||
while ((dos_inportb(dsp_port+0xc)&0x80)) ;
|
||||
dos_outportb(dsp_port+0xc, val);
|
||||
}
|
||||
|
||||
int ReadMixer(int addr)
|
||||
{
|
||||
dos_outportb(mixer_port+4, addr);
|
||||
return dos_inportb(mixer_port+5);
|
||||
}
|
||||
|
||||
void WriteMixer(int addr, int val)
|
||||
{
|
||||
dos_outportb(mixer_port+4, addr);
|
||||
dos_outportb(mixer_port+5, val);
|
||||
}
|
||||
|
||||
int oldmixervalue;
|
||||
|
||||
/*
|
||||
================
|
||||
StartSB
|
||||
|
||||
================
|
||||
*/
|
||||
void StartSB(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
// version 4.xx startup code
|
||||
if (dsp_version >= 4)
|
||||
{
|
||||
Con_Printf("Version 4 SB startup\n");
|
||||
WriteDSP(0xd1); // turn on speaker
|
||||
|
||||
WriteDSP(0x41);
|
||||
|
||||
WriteDSP(shm->speed>>8);
|
||||
WriteDSP(shm->speed&0xff);
|
||||
|
||||
WriteDSP(0xb6); // 16-bit output
|
||||
WriteDSP(0x30); // stereo
|
||||
WriteDSP((shm->samples-1) & 0xff); // # of samples - 1
|
||||
WriteDSP((shm->samples-1) >> 8);
|
||||
}
|
||||
// version 3.xx startup code
|
||||
else if (dsp_version == 3)
|
||||
{
|
||||
Con_Printf("Version 3 SB startup\n");
|
||||
WriteDSP(0xd1); // turn on speaker
|
||||
|
||||
oldmixervalue = ReadMixer (0xe);
|
||||
WriteMixer (0xe, oldmixervalue | 0x2);// turn on stereo
|
||||
|
||||
WriteDSP(0x14); // send one byte
|
||||
WriteDSP(0x0);
|
||||
WriteDSP(0x0);
|
||||
|
||||
for (i=0 ; i<0x10000 ; i++)
|
||||
dos_inportb(dsp_port+0xe); // ack the dsp
|
||||
|
||||
timeconstant = 65536-(256000000/(shm->channels*shm->speed));
|
||||
WriteDSP(0x40);
|
||||
WriteDSP(timeconstant>>8);
|
||||
|
||||
WriteMixer (0xe, ReadMixer(0xe) | 0x20);// turn off filter
|
||||
|
||||
WriteDSP(0x48);
|
||||
WriteDSP((shm->samples-1) & 0xff); // # of samples - 1
|
||||
WriteDSP((shm->samples-1) >> 8);
|
||||
|
||||
WriteDSP(0x90); // high speed 8 bit stereo
|
||||
}
|
||||
// normal speed mono
|
||||
else
|
||||
{
|
||||
Con_Printf("Version 2 SB startup\n");
|
||||
WriteDSP(0xd1); // turn on speaker
|
||||
|
||||
timeconstant = 65536-(256000000/(shm->channels*shm->speed));
|
||||
WriteDSP(0x40);
|
||||
WriteDSP(timeconstant>>8);
|
||||
|
||||
WriteDSP(0x48);
|
||||
WriteDSP((shm->samples-1) & 0xff); // # of samples - 1
|
||||
WriteDSP((shm->samples-1) >> 8);
|
||||
|
||||
WriteDSP(0x1c); // normal speed 8 bit mono
|
||||
}
|
||||
}
|
||||
|
||||
static int page_reg[] = { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };
|
||||
static int addr_reg[] = { 0, 2, 4, 6, 0xc0, 0xc4, 0xc8, 0xcc };
|
||||
static int count_reg[] = { 1, 3, 5, 7, 0xc2, 0xc6, 0xca, 0xce };
|
||||
|
||||
static int mode_reg;
|
||||
static int flipflop_reg;
|
||||
static int disable_reg;
|
||||
static int clear_reg;
|
||||
|
||||
/*
|
||||
================
|
||||
StartDMA
|
||||
|
||||
================
|
||||
*/
|
||||
void StartDMA(void)
|
||||
{
|
||||
int mode;
|
||||
int realaddr;
|
||||
|
||||
realaddr = ptr2real(dma_buffer);
|
||||
|
||||
// use a high dma channel if specified
|
||||
if (high_dma && dsp_version >= 4) // 8 bit snd can never use 16 bit dma
|
||||
dma = high_dma;
|
||||
else
|
||||
dma = low_dma;
|
||||
|
||||
Con_Printf ("Using DMA channel %i\n", dma);
|
||||
|
||||
if (dma > 3)
|
||||
{
|
||||
mode_reg = 0xd6;
|
||||
flipflop_reg = 0xd8;
|
||||
disable_reg = 0xd4;
|
||||
clear_reg = 0xdc;
|
||||
}
|
||||
else
|
||||
{
|
||||
mode_reg = 0xb;
|
||||
flipflop_reg = 0xc;
|
||||
disable_reg = 0xa;
|
||||
clear_reg = 0xe;
|
||||
}
|
||||
|
||||
dos_outportb(disable_reg, dma|4); // disable channel
|
||||
// set mode- see "undocumented pc", p.876
|
||||
mode = (1<<6) // single-cycle
|
||||
+(0<<5) // address increment
|
||||
+(1<<4) // auto-init dma
|
||||
+(2<<2) // read
|
||||
+(dma&3); // channel #
|
||||
dos_outportb(mode_reg, mode);
|
||||
|
||||
// set address
|
||||
// set page
|
||||
dos_outportb(page_reg[dma], realaddr >> 16);
|
||||
|
||||
if (dma > 3)
|
||||
{ // address is in words
|
||||
dos_outportb(flipflop_reg, 0); // prepare to send 16-bit value
|
||||
dos_outportb(addr_reg[dma], (realaddr>>1) & 0xff);
|
||||
dos_outportb(addr_reg[dma], (realaddr>>9) & 0xff);
|
||||
|
||||
dos_outportb(flipflop_reg, 0); // prepare to send 16-bit value
|
||||
dos_outportb(count_reg[dma], ((dma_size>>1)-1) & 0xff);
|
||||
dos_outportb(count_reg[dma], ((dma_size>>1)-1) >> 8);
|
||||
}
|
||||
else
|
||||
{ // address is in bytes
|
||||
dos_outportb(flipflop_reg, 0); // prepare to send 16-bit value
|
||||
dos_outportb(addr_reg[dma], realaddr & 0xff);
|
||||
dos_outportb(addr_reg[dma], (realaddr>>8) & 0xff);
|
||||
|
||||
dos_outportb(flipflop_reg, 0); // prepare to send 16-bit value
|
||||
dos_outportb(count_reg[dma], (dma_size-1) & 0xff);
|
||||
dos_outportb(count_reg[dma], (dma_size-1) >> 8);
|
||||
}
|
||||
|
||||
dos_outportb(clear_reg, 0); // clear write mask
|
||||
dos_outportb(disable_reg, dma&~4);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
BLASTER_Init
|
||||
|
||||
Returns false if nothing is found.
|
||||
==================
|
||||
*/
|
||||
qboolean BLASTER_Init(void)
|
||||
{
|
||||
int size;
|
||||
int realaddr;
|
||||
int rc;
|
||||
int p;
|
||||
|
||||
shm = 0;
|
||||
rc = 0;
|
||||
|
||||
//
|
||||
// must have a blaster variable set
|
||||
//
|
||||
if (!GetBLASTER())
|
||||
{
|
||||
Con_NotifyBox (
|
||||
"The BLASTER environment variable\n"
|
||||
"is not set, sound effects are\n"
|
||||
"disabled. See README.TXT for help.\n"
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ResetDSP())
|
||||
{
|
||||
Con_Printf("Could not reset SB");
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// get dsp version
|
||||
//
|
||||
WriteDSP(0xe1);
|
||||
dsp_version = ReadDSP();
|
||||
dsp_minor_version = ReadDSP();
|
||||
|
||||
// we need at least v2 for auto-init dma
|
||||
if (dsp_version < 2)
|
||||
{
|
||||
Con_Printf ("Sound blaster must be at least v2.0\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// allow command line parm to set quality down
|
||||
p = COM_CheckParm ("-dsp");
|
||||
if (p && p < com_argc - 1)
|
||||
{
|
||||
p = Q_atoi (com_argv[p+1]);
|
||||
if (p < 2 || p > 4)
|
||||
Con_Printf ("-dsp parameter can only be 2, 3, or 4\n");
|
||||
else if (p > dsp_version)
|
||||
Con_Printf ("Can't -dsp %i on v%i hardware\n", p, dsp_version);
|
||||
else
|
||||
dsp_version = p;
|
||||
}
|
||||
|
||||
|
||||
// everyone does 11khz sampling rate unless told otherwise
|
||||
shm = &sn;
|
||||
shm->speed = 11025;
|
||||
rc = COM_CheckParm("-sspeed");
|
||||
if (rc)
|
||||
shm->speed = Q_atoi(com_argv[rc+1]);
|
||||
|
||||
// version 4 cards (sb 16) do 16 bit stereo
|
||||
if (dsp_version >= 4)
|
||||
{
|
||||
shm->channels = 2;
|
||||
shm->samplebits = 16;
|
||||
}
|
||||
// version 3 cards (sb pro) do 8 bit stereo
|
||||
else if (dsp_version == 3)
|
||||
{
|
||||
shm->channels = 2;
|
||||
shm->samplebits = 8;
|
||||
}
|
||||
// v2 cards do 8 bit mono
|
||||
else
|
||||
{
|
||||
shm->channels = 1;
|
||||
shm->samplebits = 8;
|
||||
}
|
||||
|
||||
|
||||
Cmd_AddCommand("sbinfo", SB_Info_f);
|
||||
size = 4096;
|
||||
|
||||
// allocate 8k and get a 4k-aligned buffer from it
|
||||
dma_buffer = dos_getmemory(size*2);
|
||||
if (!dma_buffer)
|
||||
{
|
||||
Con_Printf("Couldn't allocate sound dma buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
realaddr = ptr2real(dma_buffer);
|
||||
realaddr = (realaddr + size) & ~(size-1);
|
||||
dma_buffer = (short *) real2ptr(realaddr);
|
||||
dma_size = size;
|
||||
|
||||
memset(dma_buffer, 0, dma_size);
|
||||
|
||||
shm->soundalive = true;
|
||||
shm->splitbuffer = false;
|
||||
|
||||
shm->samples = size/(shm->samplebits/8);
|
||||
shm->samplepos = 0;
|
||||
shm->submission_chunk = 1;
|
||||
shm->buffer = (unsigned char *) dma_buffer;
|
||||
shm->samples = size/(shm->samplebits/8);
|
||||
|
||||
StartDMA();
|
||||
StartSB();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
BLASTER_GetDMAPos
|
||||
|
||||
return the current sample position (in mono samples read)
|
||||
inside the recirculating dma buffer, so the mixing code will know
|
||||
how many sample are required to fill it up.
|
||||
===============
|
||||
*/
|
||||
int BLASTER_GetDMAPos(void)
|
||||
{
|
||||
int count;
|
||||
|
||||
// this function is called often. acknowledge the transfer completions
|
||||
// all the time so that it loops
|
||||
if (dsp_version >= 4)
|
||||
dos_inportb(dsp_port+0xf); // 16 bit audio
|
||||
else
|
||||
dos_inportb(dsp_port+0xe); // 8 bit audio
|
||||
|
||||
// clear 16-bit reg flip-flop
|
||||
// load the current dma count register
|
||||
if (dma < 4)
|
||||
{
|
||||
dos_outportb(0xc, 0);
|
||||
count = dos_inportb(dma*2+1);
|
||||
count += dos_inportb(dma*2+1) << 8;
|
||||
if (shm->samplebits == 16)
|
||||
count /= 2;
|
||||
count = shm->samples - (count+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
dos_outportb(0xd8, 0);
|
||||
count = dos_inportb(0xc0+(dma-4)*4+2);
|
||||
count += dos_inportb(0xc0+(dma-4)*4+2) << 8;
|
||||
if (shm->samplebits == 8)
|
||||
count *= 2;
|
||||
count = shm->samples - (count+1);
|
||||
}
|
||||
|
||||
// Con_Printf("DMA pos = 0x%x\n", count);
|
||||
|
||||
shm->samplepos = count & (shm->samples-1);
|
||||
return shm->samplepos;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
BLASTER_Shutdown
|
||||
|
||||
Reset the sound device for exiting
|
||||
===============
|
||||
*/
|
||||
void BLASTER_Shutdown(void)
|
||||
{
|
||||
if (dsp_version >= 4)
|
||||
{
|
||||
}
|
||||
else if (dsp_version == 3)
|
||||
{
|
||||
ResetDSP (); // stop high speed mode
|
||||
WriteMixer (0xe, oldmixervalue); // turn stereo off and filter on
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
WriteDSP(0xd3); // turn off speaker
|
||||
ResetDSP ();
|
||||
|
||||
dos_outportb(disable_reg, dma|4); // disable dma channel
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
INTERFACE
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
dma_none,
|
||||
dma_blaster,
|
||||
dma_gus
|
||||
} dmacard_t;
|
||||
|
||||
dmacard_t dmacard;
|
||||
|
||||
/*
|
||||
==================
|
||||
SNDDM_Init
|
||||
|
||||
Try to find a sound device to mix for.
|
||||
Returns false if nothing is found.
|
||||
Returns true and fills in the "shm" structure with information for the mixer.
|
||||
==================
|
||||
*/
|
||||
qboolean SNDDMA_Init(void)
|
||||
{
|
||||
if (GUS_Init ())
|
||||
{
|
||||
dmacard = dma_gus;
|
||||
return true;
|
||||
}
|
||||
if (BLASTER_Init ())
|
||||
{
|
||||
dmacard = dma_blaster;
|
||||
return true;
|
||||
}
|
||||
|
||||
dmacard = dma_none;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
SNDDMA_GetDMAPos
|
||||
|
||||
return the current sample position (in mono samples, not stereo)
|
||||
inside the recirculating dma buffer, so the mixing code will know
|
||||
how many sample are required to fill it up.
|
||||
===============
|
||||
*/
|
||||
int SNDDMA_GetDMAPos(void)
|
||||
{
|
||||
switch (dmacard)
|
||||
{
|
||||
case dma_blaster:
|
||||
return BLASTER_GetDMAPos ();
|
||||
case dma_gus:
|
||||
return GUS_GetDMAPos ();
|
||||
case dma_none:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
SNDDMA_Shutdown
|
||||
|
||||
Reset the sound device for exiting
|
||||
===============
|
||||
*/
|
||||
void SNDDMA_Shutdown(void)
|
||||
{
|
||||
switch (dmacard)
|
||||
{
|
||||
case dma_blaster:
|
||||
BLASTER_Shutdown ();
|
||||
break;
|
||||
case dma_gus:
|
||||
GUS_Shutdown ();
|
||||
break;
|
||||
case dma_none:
|
||||
break;
|
||||
}
|
||||
|
||||
dmacard = dma_none;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
SNDDMA_Submit
|
||||
|
||||
Send sound to device if buffer isn't really the dma buffer
|
||||
===============
|
||||
*/
|
||||
void SNDDMA_Submit(void)
|
||||
{
|
||||
}
|
||||
|
172
surf16.s
172
surf16.s
|
@ -1,172 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
//
|
||||
// surf16.s
|
||||
// x86 assembly-language 16 bpp surface block drawing code.
|
||||
//
|
||||
|
||||
#include "asm_i386.h"
|
||||
#include "quakeasm.h"
|
||||
#include "asm_draw.h"
|
||||
|
||||
#if id386
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Surface block drawer
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
.data
|
||||
|
||||
k: .long 0
|
||||
loopentry: .long 0
|
||||
|
||||
.align 4
|
||||
blockjumptable16:
|
||||
.long LEnter2_16
|
||||
.long LEnter4_16
|
||||
.long 0, LEnter8_16
|
||||
.long 0, 0, 0, LEnter16_16
|
||||
|
||||
|
||||
.text
|
||||
|
||||
.align 4
|
||||
.globl C(R_Surf16Start)
|
||||
C(R_Surf16Start):
|
||||
|
||||
.align 4
|
||||
.globl C(R_DrawSurfaceBlock16)
|
||||
C(R_DrawSurfaceBlock16):
|
||||
pushl %ebp // preserve caller's stack frame
|
||||
pushl %edi
|
||||
pushl %esi // preserve register variables
|
||||
pushl %ebx
|
||||
|
||||
movl C(blocksize),%eax
|
||||
movl C(prowdestbase),%edi
|
||||
movl C(pbasesource),%esi
|
||||
movl C(sourcesstep),%ebx
|
||||
movl blockjumptable16-4(,%eax,2),%ecx
|
||||
movl %eax,k
|
||||
movl %ecx,loopentry
|
||||
movl C(lightleft),%edx
|
||||
movl C(lightright),%ebp
|
||||
|
||||
Lblockloop16:
|
||||
|
||||
subl %edx,%ebp
|
||||
movb C(blockdivshift),%cl
|
||||
sarl %cl,%ebp
|
||||
jns Lp1_16
|
||||
testl C(blockdivmask),%ebp
|
||||
jz Lp1_16
|
||||
incl %ebp
|
||||
Lp1_16:
|
||||
|
||||
subl %eax,%eax
|
||||
subl %ecx,%ecx // high words must be 0 in loop for addressing
|
||||
|
||||
jmp *loopentry
|
||||
|
||||
.align 4
|
||||
|
||||
#include "block16.h"
|
||||
|
||||
movl C(pbasesource),%esi
|
||||
movl C(lightleft),%edx
|
||||
movl C(lightright),%ebp
|
||||
movl C(sourcetstep),%eax
|
||||
movl C(lightrightstep),%ecx
|
||||
movl C(prowdestbase),%edi
|
||||
|
||||
addl %eax,%esi
|
||||
addl %ecx,%ebp
|
||||
|
||||
movl C(lightleftstep),%eax
|
||||
movl C(surfrowbytes),%ecx
|
||||
|
||||
addl %eax,%edx
|
||||
addl %ecx,%edi
|
||||
|
||||
movl %esi,C(pbasesource)
|
||||
movl %ebp,C(lightright)
|
||||
movl k,%eax
|
||||
movl %edx,C(lightleft)
|
||||
decl %eax
|
||||
movl %edi,C(prowdestbase)
|
||||
movl %eax,k
|
||||
jnz Lblockloop16
|
||||
|
||||
popl %ebx // restore register variables
|
||||
popl %esi
|
||||
popl %edi
|
||||
popl %ebp // restore the caller's stack frame
|
||||
ret
|
||||
|
||||
.globl C(R_Surf16End)
|
||||
C(R_Surf16End):
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Code patching routines
|
||||
//----------------------------------------------------------------------
|
||||
.data
|
||||
|
||||
.align 4
|
||||
LPatchTable16:
|
||||
.long LBPatch0-4
|
||||
.long LBPatch1-4
|
||||
.long LBPatch2-4
|
||||
.long LBPatch3-4
|
||||
.long LBPatch4-4
|
||||
.long LBPatch5-4
|
||||
.long LBPatch6-4
|
||||
.long LBPatch7-4
|
||||
.long LBPatch8-4
|
||||
.long LBPatch9-4
|
||||
.long LBPatch10-4
|
||||
.long LBPatch11-4
|
||||
.long LBPatch12-4
|
||||
.long LBPatch13-4
|
||||
.long LBPatch14-4
|
||||
.long LBPatch15-4
|
||||
|
||||
.text
|
||||
|
||||
.align 4
|
||||
.globl C(R_Surf16Patch)
|
||||
C(R_Surf16Patch):
|
||||
pushl %ebx
|
||||
|
||||
movl C(colormap),%eax
|
||||
movl $LPatchTable16,%ebx
|
||||
movl $16,%ecx
|
||||
LPatchLoop16:
|
||||
movl (%ebx),%edx
|
||||
addl $4,%ebx
|
||||
movl %eax,(%edx)
|
||||
decl %ecx
|
||||
jnz LPatchLoop16
|
||||
|
||||
popl %ebx
|
||||
|
||||
ret
|
||||
|
||||
|
||||
#endif // id386
|
783
surf8.s
783
surf8.s
|
@ -1,783 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
//
|
||||
// surf8.s
|
||||
// x86 assembly-language 8 bpp surface block drawing code.
|
||||
//
|
||||
|
||||
#include "asm_i386.h"
|
||||
#include "quakeasm.h"
|
||||
#include "asm_draw.h"
|
||||
|
||||
#if id386
|
||||
|
||||
.data
|
||||
|
||||
sb_v: .long 0
|
||||
|
||||
.text
|
||||
|
||||
.align 4
|
||||
.globl C(R_Surf8Start)
|
||||
C(R_Surf8Start):
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Surface block drawer for mip level 0
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
.align 4
|
||||
.globl C(R_DrawSurfaceBlock8_mip0)
|
||||
C(R_DrawSurfaceBlock8_mip0):
|
||||
pushl %ebp // preserve caller's stack frame
|
||||
pushl %edi
|
||||
pushl %esi // preserve register variables
|
||||
pushl %ebx
|
||||
|
||||
// for (v=0 ; v<numvblocks ; v++)
|
||||
// {
|
||||
movl C(r_lightptr),%ebx
|
||||
movl C(r_numvblocks),%eax
|
||||
|
||||
movl %eax,sb_v
|
||||
movl C(prowdestbase),%edi
|
||||
|
||||
movl C(pbasesource),%esi
|
||||
|
||||
Lv_loop_mip0:
|
||||
|
||||
// lightleft = lightptr[0];
|
||||
// lightright = lightptr[1];
|
||||
// lightdelta = (lightleft - lightright) & 0xFFFFF;
|
||||
movl (%ebx),%eax // lightleft
|
||||
movl 4(%ebx),%edx // lightright
|
||||
|
||||
movl %eax,%ebp
|
||||
movl C(r_lightwidth),%ecx
|
||||
|
||||
movl %edx,C(lightright)
|
||||
subl %edx,%ebp
|
||||
|
||||
andl $0xFFFFF,%ebp
|
||||
leal (%ebx,%ecx,4),%ebx
|
||||
|
||||
// lightptr += lightwidth;
|
||||
movl %ebx,C(r_lightptr)
|
||||
|
||||
// lightleftstep = (lightptr[0] - lightleft) >> blockdivshift;
|
||||
// lightrightstep = (lightptr[1] - lightright) >> blockdivshift;
|
||||
// lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) |
|
||||
// 0xF0000000;
|
||||
movl 4(%ebx),%ecx // lightptr[1]
|
||||
movl (%ebx),%ebx // lightptr[0]
|
||||
|
||||
subl %eax,%ebx
|
||||
subl %edx,%ecx
|
||||
|
||||
sarl $4,%ecx
|
||||
orl $0xF0000000,%ebp
|
||||
|
||||
sarl $4,%ebx
|
||||
movl %ecx,C(lightrightstep)
|
||||
|
||||
subl %ecx,%ebx
|
||||
andl $0xFFFFF,%ebx
|
||||
|
||||
orl $0xF0000000,%ebx
|
||||
subl %ecx,%ecx // high word must be 0 in loop for addressing
|
||||
|
||||
movl %ebx,C(lightdeltastep)
|
||||
subl %ebx,%ebx // high word must be 0 in loop for addressing
|
||||
|
||||
Lblockloop8_mip0:
|
||||
movl %ebp,C(lightdelta)
|
||||
movb 14(%esi),%cl
|
||||
|
||||
sarl $4,%ebp
|
||||
movb %dh,%bh
|
||||
|
||||
movb 15(%esi),%bl
|
||||
addl %ebp,%edx
|
||||
|
||||
movb %dh,%ch
|
||||
addl %ebp,%edx
|
||||
|
||||
movb 0x12345678(%ebx),%ah
|
||||
LBPatch0:
|
||||
movb 13(%esi),%bl
|
||||
|
||||
movb 0x12345678(%ecx),%al
|
||||
LBPatch1:
|
||||
movb 12(%esi),%cl
|
||||
|
||||
movb %dh,%bh
|
||||
addl %ebp,%edx
|
||||
|
||||
rorl $16,%eax
|
||||
movb %dh,%ch
|
||||
|
||||
addl %ebp,%edx
|
||||
movb 0x12345678(%ebx),%ah
|
||||
LBPatch2:
|
||||
|
||||
movb 11(%esi),%bl
|
||||
movb 0x12345678(%ecx),%al
|
||||
LBPatch3:
|
||||
|
||||
movb 10(%esi),%cl
|
||||
movl %eax,12(%edi)
|
||||
|
||||
movb %dh,%bh
|
||||
addl %ebp,%edx
|
||||
|
||||
movb %dh,%ch
|
||||
addl %ebp,%edx
|
||||
|
||||
movb 0x12345678(%ebx),%ah
|
||||
LBPatch4:
|
||||
movb 9(%esi),%bl
|
||||
|
||||
movb 0x12345678(%ecx),%al
|
||||
LBPatch5:
|
||||
movb 8(%esi),%cl
|
||||
|
||||
movb %dh,%bh
|
||||
addl %ebp,%edx
|
||||
|
||||
rorl $16,%eax
|
||||
movb %dh,%ch
|
||||
|
||||
addl %ebp,%edx
|
||||
movb 0x12345678(%ebx),%ah
|
||||
LBPatch6:
|
||||
|
||||
movb 7(%esi),%bl
|
||||
movb 0x12345678(%ecx),%al
|
||||
LBPatch7:
|
||||
|
||||
movb 6(%esi),%cl
|
||||
movl %eax,8(%edi)
|
||||
|
||||
movb %dh,%bh
|
||||
addl %ebp,%edx
|
||||
|
||||
movb %dh,%ch
|
||||
addl %ebp,%edx
|
||||
|
||||
movb 0x12345678(%ebx),%ah
|
||||
LBPatch8:
|
||||
movb 5(%esi),%bl
|
||||
|
||||
movb 0x12345678(%ecx),%al
|
||||
LBPatch9:
|
||||
movb 4(%esi),%cl
|
||||
|
||||
movb %dh,%bh
|
||||
addl %ebp,%edx
|
||||
|
||||
rorl $16,%eax
|
||||
movb %dh,%ch
|
||||
|
||||
addl %ebp,%edx
|
||||
movb 0x12345678(%ebx),%ah
|
||||
LBPatch10:
|
||||
|
||||
movb 3(%esi),%bl
|
||||
movb 0x12345678(%ecx),%al
|
||||
LBPatch11:
|
||||
|
||||
movb 2(%esi),%cl
|
||||
movl %eax,4(%edi)
|
||||
|
||||
movb %dh,%bh
|
||||
addl %ebp,%edx
|
||||
|
||||
movb %dh,%ch
|
||||
addl %ebp,%edx
|
||||
|
||||
movb 0x12345678(%ebx),%ah
|
||||
LBPatch12:
|
||||
movb 1(%esi),%bl
|
||||
|
||||
movb 0x12345678(%ecx),%al
|
||||
LBPatch13:
|
||||
movb (%esi),%cl
|
||||
|
||||
movb %dh,%bh
|
||||
addl %ebp,%edx
|
||||
|
||||
rorl $16,%eax
|
||||
movb %dh,%ch
|
||||
|
||||
movb 0x12345678(%ebx),%ah
|
||||
LBPatch14:
|
||||
movl C(lightright),%edx
|
||||
|
||||
movb 0x12345678(%ecx),%al
|
||||
LBPatch15:
|
||||
movl C(lightdelta),%ebp
|
||||
|
||||
movl %eax,(%edi)
|
||||
|
||||
addl C(sourcetstep),%esi
|
||||
addl C(surfrowbytes),%edi
|
||||
|
||||
addl C(lightrightstep),%edx
|
||||
addl C(lightdeltastep),%ebp
|
||||
|
||||
movl %edx,C(lightright)
|
||||
jc Lblockloop8_mip0
|
||||
|
||||
// if (pbasesource >= r_sourcemax)
|
||||
// pbasesource -= stepback;
|
||||
|
||||
cmpl C(r_sourcemax),%esi
|
||||
jb LSkip_mip0
|
||||
subl C(r_stepback),%esi
|
||||
LSkip_mip0:
|
||||
|
||||
movl C(r_lightptr),%ebx
|
||||
decl sb_v
|
||||
|
||||
jnz Lv_loop_mip0
|
||||
|
||||
popl %ebx // restore register variables
|
||||
popl %esi
|
||||
popl %edi
|
||||
popl %ebp // restore the caller's stack frame
|
||||
ret
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Surface block drawer for mip level 1
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
.align 4
|
||||
.globl C(R_DrawSurfaceBlock8_mip1)
|
||||
C(R_DrawSurfaceBlock8_mip1):
|
||||
pushl %ebp // preserve caller's stack frame
|
||||
pushl %edi
|
||||
pushl %esi // preserve register variables
|
||||
pushl %ebx
|
||||
|
||||
// for (v=0 ; v<numvblocks ; v++)
|
||||
// {
|
||||
movl C(r_lightptr),%ebx
|
||||
movl C(r_numvblocks),%eax
|
||||
|
||||
movl %eax,sb_v
|
||||
movl C(prowdestbase),%edi
|
||||
|
||||
movl C(pbasesource),%esi
|
||||
|
||||
Lv_loop_mip1:
|
||||
|
||||
// lightleft = lightptr[0];
|
||||
// lightright = lightptr[1];
|
||||
// lightdelta = (lightleft - lightright) & 0xFFFFF;
|
||||
movl (%ebx),%eax // lightleft
|
||||
movl 4(%ebx),%edx // lightright
|
||||
|
||||
movl %eax,%ebp
|
||||
movl C(r_lightwidth),%ecx
|
||||
|
||||
movl %edx,C(lightright)
|
||||
subl %edx,%ebp
|
||||
|
||||
andl $0xFFFFF,%ebp
|
||||
leal (%ebx,%ecx,4),%ebx
|
||||
|
||||
// lightptr += lightwidth;
|
||||
movl %ebx,C(r_lightptr)
|
||||
|
||||
// lightleftstep = (lightptr[0] - lightleft) >> blockdivshift;
|
||||
// lightrightstep = (lightptr[1] - lightright) >> blockdivshift;
|
||||
// lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) |
|
||||
// 0xF0000000;
|
||||
movl 4(%ebx),%ecx // lightptr[1]
|
||||
movl (%ebx),%ebx // lightptr[0]
|
||||
|
||||
subl %eax,%ebx
|
||||
subl %edx,%ecx
|
||||
|
||||
sarl $3,%ecx
|
||||
orl $0x70000000,%ebp
|
||||
|
||||
sarl $3,%ebx
|
||||
movl %ecx,C(lightrightstep)
|
||||
|
||||
subl %ecx,%ebx
|
||||
andl $0xFFFFF,%ebx
|
||||
|
||||
orl $0xF0000000,%ebx
|
||||
subl %ecx,%ecx // high word must be 0 in loop for addressing
|
||||
|
||||
movl %ebx,C(lightdeltastep)
|
||||
subl %ebx,%ebx // high word must be 0 in loop for addressing
|
||||
|
||||
Lblockloop8_mip1:
|
||||
movl %ebp,C(lightdelta)
|
||||
movb 6(%esi),%cl
|
||||
|
||||
sarl $3,%ebp
|
||||
movb %dh,%bh
|
||||
|
||||
movb 7(%esi),%bl
|
||||
addl %ebp,%edx
|
||||
|
||||
movb %dh,%ch
|
||||
addl %ebp,%edx
|
||||
|
||||
movb 0x12345678(%ebx),%ah
|
||||
LBPatch22:
|
||||
movb 5(%esi),%bl
|
||||
|
||||
movb 0x12345678(%ecx),%al
|
||||
LBPatch23:
|
||||
movb 4(%esi),%cl
|
||||
|
||||
movb %dh,%bh
|
||||
addl %ebp,%edx
|
||||
|
||||
rorl $16,%eax
|
||||
movb %dh,%ch
|
||||
|
||||
addl %ebp,%edx
|
||||
movb 0x12345678(%ebx),%ah
|
||||
LBPatch24:
|
||||
|
||||
movb 3(%esi),%bl
|
||||
movb 0x12345678(%ecx),%al
|
||||
LBPatch25:
|
||||
|
||||
movb 2(%esi),%cl
|
||||
movl %eax,4(%edi)
|
||||
|
||||
movb %dh,%bh
|
||||
addl %ebp,%edx
|
||||
|
||||
movb %dh,%ch
|
||||
addl %ebp,%edx
|
||||
|
||||
movb 0x12345678(%ebx),%ah
|
||||
LBPatch26:
|
||||
movb 1(%esi),%bl
|
||||
|
||||
movb 0x12345678(%ecx),%al
|
||||
LBPatch27:
|
||||
movb (%esi),%cl
|
||||
|
||||
movb %dh,%bh
|
||||
addl %ebp,%edx
|
||||
|
||||
rorl $16,%eax
|
||||
movb %dh,%ch
|
||||
|
||||
movb 0x12345678(%ebx),%ah
|
||||
LBPatch28:
|
||||
movl C(lightright),%edx
|
||||
|
||||
movb 0x12345678(%ecx),%al
|
||||
LBPatch29:
|
||||
movl C(lightdelta),%ebp
|
||||
|
||||
movl %eax,(%edi)
|
||||
movl C(sourcetstep),%eax
|
||||
|
||||
addl %eax,%esi
|
||||
movl C(surfrowbytes),%eax
|
||||
|
||||
addl %eax,%edi
|
||||
movl C(lightrightstep),%eax
|
||||
|
||||
addl %eax,%edx
|
||||
movl C(lightdeltastep),%eax
|
||||
|
||||
addl %eax,%ebp
|
||||
movl %edx,C(lightright)
|
||||
|
||||
jc Lblockloop8_mip1
|
||||
|
||||
// if (pbasesource >= r_sourcemax)
|
||||
// pbasesource -= stepback;
|
||||
|
||||
cmpl C(r_sourcemax),%esi
|
||||
jb LSkip_mip1
|
||||
subl C(r_stepback),%esi
|
||||
LSkip_mip1:
|
||||
|
||||
movl C(r_lightptr),%ebx
|
||||
decl sb_v
|
||||
|
||||
jnz Lv_loop_mip1
|
||||
|
||||
popl %ebx // restore register variables
|
||||
popl %esi
|
||||
popl %edi
|
||||
popl %ebp // restore the caller's stack frame
|
||||
ret
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Surface block drawer for mip level 2
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
.align 4
|
||||
.globl C(R_DrawSurfaceBlock8_mip2)
|
||||
C(R_DrawSurfaceBlock8_mip2):
|
||||
pushl %ebp // preserve caller's stack frame
|
||||
pushl %edi
|
||||
pushl %esi // preserve register variables
|
||||
pushl %ebx
|
||||
|
||||
// for (v=0 ; v<numvblocks ; v++)
|
||||
// {
|
||||
movl C(r_lightptr),%ebx
|
||||
movl C(r_numvblocks),%eax
|
||||
|
||||
movl %eax,sb_v
|
||||
movl C(prowdestbase),%edi
|
||||
|
||||
movl C(pbasesource),%esi
|
||||
|
||||
Lv_loop_mip2:
|
||||
|
||||
// lightleft = lightptr[0];
|
||||
// lightright = lightptr[1];
|
||||
// lightdelta = (lightleft - lightright) & 0xFFFFF;
|
||||
movl (%ebx),%eax // lightleft
|
||||
movl 4(%ebx),%edx // lightright
|
||||
|
||||
movl %eax,%ebp
|
||||
movl C(r_lightwidth),%ecx
|
||||
|
||||
movl %edx,C(lightright)
|
||||
subl %edx,%ebp
|
||||
|
||||
andl $0xFFFFF,%ebp
|
||||
leal (%ebx,%ecx,4),%ebx
|
||||
|
||||
// lightptr += lightwidth;
|
||||
movl %ebx,C(r_lightptr)
|
||||
|
||||
// lightleftstep = (lightptr[0] - lightleft) >> blockdivshift;
|
||||
// lightrightstep = (lightptr[1] - lightright) >> blockdivshift;
|
||||
// lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) |
|
||||
// 0xF0000000;
|
||||
movl 4(%ebx),%ecx // lightptr[1]
|
||||
movl (%ebx),%ebx // lightptr[0]
|
||||
|
||||
subl %eax,%ebx
|
||||
subl %edx,%ecx
|
||||
|
||||
sarl $2,%ecx
|
||||
orl $0x30000000,%ebp
|
||||
|
||||
sarl $2,%ebx
|
||||
movl %ecx,C(lightrightstep)
|
||||
|
||||
subl %ecx,%ebx
|
||||
|
||||
andl $0xFFFFF,%ebx
|
||||
|
||||
orl $0xF0000000,%ebx
|
||||
subl %ecx,%ecx // high word must be 0 in loop for addressing
|
||||
|
||||
movl %ebx,C(lightdeltastep)
|
||||
subl %ebx,%ebx // high word must be 0 in loop for addressing
|
||||
|
||||
Lblockloop8_mip2:
|
||||
movl %ebp,C(lightdelta)
|
||||
movb 2(%esi),%cl
|
||||
|
||||
sarl $2,%ebp
|
||||
movb %dh,%bh
|
||||
|
||||
movb 3(%esi),%bl
|
||||
addl %ebp,%edx
|
||||
|
||||
movb %dh,%ch
|
||||
addl %ebp,%edx
|
||||
|
||||
movb 0x12345678(%ebx),%ah
|
||||
LBPatch18:
|
||||
movb 1(%esi),%bl
|
||||
|
||||
movb 0x12345678(%ecx),%al
|
||||
LBPatch19:
|
||||
movb (%esi),%cl
|
||||
|
||||
movb %dh,%bh
|
||||
addl %ebp,%edx
|
||||
|
||||
rorl $16,%eax
|
||||
movb %dh,%ch
|
||||
|
||||
movb 0x12345678(%ebx),%ah
|
||||
LBPatch20:
|
||||
movl C(lightright),%edx
|
||||
|
||||
movb 0x12345678(%ecx),%al
|
||||
LBPatch21:
|
||||
movl C(lightdelta),%ebp
|
||||
|
||||
movl %eax,(%edi)
|
||||
movl C(sourcetstep),%eax
|
||||
|
||||
addl %eax,%esi
|
||||
movl C(surfrowbytes),%eax
|
||||
|
||||
addl %eax,%edi
|
||||
movl C(lightrightstep),%eax
|
||||
|
||||
addl %eax,%edx
|
||||
movl C(lightdeltastep),%eax
|
||||
|
||||
addl %eax,%ebp
|
||||
movl %edx,C(lightright)
|
||||
|
||||
jc Lblockloop8_mip2
|
||||
|
||||
// if (pbasesource >= r_sourcemax)
|
||||
// pbasesource -= stepback;
|
||||
|
||||
cmpl C(r_sourcemax),%esi
|
||||
jb LSkip_mip2
|
||||
subl C(r_stepback),%esi
|
||||
LSkip_mip2:
|
||||
|
||||
movl C(r_lightptr),%ebx
|
||||
decl sb_v
|
||||
|
||||
jnz Lv_loop_mip2
|
||||
|
||||
popl %ebx // restore register variables
|
||||
popl %esi
|
||||
popl %edi
|
||||
popl %ebp // restore the caller's stack frame
|
||||
ret
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Surface block drawer for mip level 3
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
.align 4
|
||||
.globl C(R_DrawSurfaceBlock8_mip3)
|
||||
C(R_DrawSurfaceBlock8_mip3):
|
||||
pushl %ebp // preserve caller's stack frame
|
||||
pushl %edi
|
||||
pushl %esi // preserve register variables
|
||||
pushl %ebx
|
||||
|
||||
// for (v=0 ; v<numvblocks ; v++)
|
||||
// {
|
||||
movl C(r_lightptr),%ebx
|
||||
movl C(r_numvblocks),%eax
|
||||
|
||||
movl %eax,sb_v
|
||||
movl C(prowdestbase),%edi
|
||||
|
||||
movl C(pbasesource),%esi
|
||||
|
||||
Lv_loop_mip3:
|
||||
|
||||
// lightleft = lightptr[0];
|
||||
// lightright = lightptr[1];
|
||||
// lightdelta = (lightleft - lightright) & 0xFFFFF;
|
||||
movl (%ebx),%eax // lightleft
|
||||
movl 4(%ebx),%edx // lightright
|
||||
|
||||
movl %eax,%ebp
|
||||
movl C(r_lightwidth),%ecx
|
||||
|
||||
movl %edx,C(lightright)
|
||||
subl %edx,%ebp
|
||||
|
||||
andl $0xFFFFF,%ebp
|
||||
leal (%ebx,%ecx,4),%ebx
|
||||
|
||||
movl %ebp,C(lightdelta)
|
||||
// lightptr += lightwidth;
|
||||
movl %ebx,C(r_lightptr)
|
||||
|
||||
// lightleftstep = (lightptr[0] - lightleft) >> blockdivshift;
|
||||
// lightrightstep = (lightptr[1] - lightright) >> blockdivshift;
|
||||
// lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) |
|
||||
// 0xF0000000;
|
||||
movl 4(%ebx),%ecx // lightptr[1]
|
||||
movl (%ebx),%ebx // lightptr[0]
|
||||
|
||||
subl %eax,%ebx
|
||||
subl %edx,%ecx
|
||||
|
||||
sarl $1,%ecx
|
||||
|
||||
sarl $1,%ebx
|
||||
movl %ecx,C(lightrightstep)
|
||||
|
||||
subl %ecx,%ebx
|
||||
andl $0xFFFFF,%ebx
|
||||
|
||||
sarl $1,%ebp
|
||||
orl $0xF0000000,%ebx
|
||||
|
||||
movl %ebx,C(lightdeltastep)
|
||||
subl %ebx,%ebx // high word must be 0 in loop for addressing
|
||||
|
||||
movb 1(%esi),%bl
|
||||
subl %ecx,%ecx // high word must be 0 in loop for addressing
|
||||
|
||||
movb %dh,%bh
|
||||
movb (%esi),%cl
|
||||
|
||||
addl %ebp,%edx
|
||||
movb %dh,%ch
|
||||
|
||||
movb 0x12345678(%ebx),%al
|
||||
LBPatch16:
|
||||
movl C(lightright),%edx
|
||||
|
||||
movb %al,1(%edi)
|
||||
movb 0x12345678(%ecx),%al
|
||||
LBPatch17:
|
||||
|
||||
movb %al,(%edi)
|
||||
movl C(sourcetstep),%eax
|
||||
|
||||
addl %eax,%esi
|
||||
movl C(surfrowbytes),%eax
|
||||
|
||||
addl %eax,%edi
|
||||
movl C(lightdeltastep),%eax
|
||||
|
||||
movl C(lightdelta),%ebp
|
||||
movb (%esi),%cl
|
||||
|
||||
addl %eax,%ebp
|
||||
movl C(lightrightstep),%eax
|
||||
|
||||
sarl $1,%ebp
|
||||
addl %eax,%edx
|
||||
|
||||
movb %dh,%bh
|
||||
movb 1(%esi),%bl
|
||||
|
||||
addl %ebp,%edx
|
||||
movb %dh,%ch
|
||||
|
||||
movb 0x12345678(%ebx),%al
|
||||
LBPatch30:
|
||||
movl C(sourcetstep),%edx
|
||||
|
||||
movb %al,1(%edi)
|
||||
movb 0x12345678(%ecx),%al
|
||||
LBPatch31:
|
||||
|
||||
movb %al,(%edi)
|
||||
movl C(surfrowbytes),%ebp
|
||||
|
||||
addl %edx,%esi
|
||||
addl %ebp,%edi
|
||||
|
||||
// if (pbasesource >= r_sourcemax)
|
||||
// pbasesource -= stepback;
|
||||
|
||||
cmpl C(r_sourcemax),%esi
|
||||
jb LSkip_mip3
|
||||
subl C(r_stepback),%esi
|
||||
LSkip_mip3:
|
||||
|
||||
movl C(r_lightptr),%ebx
|
||||
decl sb_v
|
||||
|
||||
jnz Lv_loop_mip3
|
||||
|
||||
popl %ebx // restore register variables
|
||||
popl %esi
|
||||
popl %edi
|
||||
popl %ebp // restore the caller's stack frame
|
||||
ret
|
||||
|
||||
|
||||
.globl C(R_Surf8End)
|
||||
C(R_Surf8End):
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Code patching routines
|
||||
//----------------------------------------------------------------------
|
||||
.data
|
||||
|
||||
.align 4
|
||||
LPatchTable8:
|
||||
.long LBPatch0-4
|
||||
.long LBPatch1-4
|
||||
.long LBPatch2-4
|
||||
.long LBPatch3-4
|
||||
.long LBPatch4-4
|
||||
.long LBPatch5-4
|
||||
.long LBPatch6-4
|
||||
.long LBPatch7-4
|
||||
.long LBPatch8-4
|
||||
.long LBPatch9-4
|
||||
.long LBPatch10-4
|
||||
.long LBPatch11-4
|
||||
.long LBPatch12-4
|
||||
.long LBPatch13-4
|
||||
.long LBPatch14-4
|
||||
.long LBPatch15-4
|
||||
.long LBPatch16-4
|
||||
.long LBPatch17-4
|
||||
.long LBPatch18-4
|
||||
.long LBPatch19-4
|
||||
.long LBPatch20-4
|
||||
.long LBPatch21-4
|
||||
.long LBPatch22-4
|
||||
.long LBPatch23-4
|
||||
.long LBPatch24-4
|
||||
.long LBPatch25-4
|
||||
.long LBPatch26-4
|
||||
.long LBPatch27-4
|
||||
.long LBPatch28-4
|
||||
.long LBPatch29-4
|
||||
.long LBPatch30-4
|
||||
.long LBPatch31-4
|
||||
|
||||
.text
|
||||
|
||||
.align 4
|
||||
.globl C(R_Surf8Patch)
|
||||
C(R_Surf8Patch):
|
||||
pushl %ebx
|
||||
|
||||
movl C(colormap),%eax
|
||||
movl $LPatchTable8,%ebx
|
||||
movl $32,%ecx
|
||||
LPatchLoop8:
|
||||
movl (%ebx),%edx
|
||||
addl $4,%ebx
|
||||
movl %eax,(%edx)
|
||||
decl %ecx
|
||||
jnz LPatchLoop8
|
||||
|
||||
popl %ebx
|
||||
|
||||
ret
|
||||
|
||||
#endif // id386
|
953
sys_dos.c
953
sys_dos.c
|
@ -1,953 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <dir.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <dpmi.h>
|
||||
#include <sys/nearptr.h>
|
||||
#include <conio.h>
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "dosisms.h"
|
||||
|
||||
#define MINIMUM_WIN_MEMORY 0x800000
|
||||
#define MINIMUM_WIN_MEMORY_LEVELPAK (MINIMUM_WIN_MEMORY + 0x100000)
|
||||
|
||||
int end_of_memory;
|
||||
qboolean lockmem, lockunlockmem, unlockmem;
|
||||
static int win95;
|
||||
|
||||
#define STDOUT 1
|
||||
|
||||
#define KEYBUF_SIZE 256
|
||||
static unsigned char keybuf[KEYBUF_SIZE];
|
||||
static int keybuf_head=0;
|
||||
static int keybuf_tail=0;
|
||||
|
||||
static quakeparms_t quakeparms;
|
||||
int sys_checksum;
|
||||
static double curtime = 0.0;
|
||||
static double lastcurtime = 0.0;
|
||||
static double oldtime = 0.0;
|
||||
|
||||
static qboolean isDedicated;
|
||||
|
||||
static int minmem;
|
||||
|
||||
float fptest_temp;
|
||||
|
||||
extern char start_of_memory __asm__("start");
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// this is totally dependent on cwsdpmi putting the stack right after tge
|
||||
// global data
|
||||
|
||||
// This does evil things in a Win95 DOS box!!!
|
||||
#if 0
|
||||
extern byte end;
|
||||
#define CHECKBYTE 0xed
|
||||
void Sys_InitStackCheck (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<128*1024 ; i++)
|
||||
(&end)[i] = CHECKBYTE;
|
||||
}
|
||||
|
||||
void Sys_StackCheck (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<128*1024 ; i++)
|
||||
if ( (&end)[i] != CHECKBYTE )
|
||||
break;
|
||||
|
||||
Con_Printf ("%i undisturbed stack bytes\n", i);
|
||||
if (end != CHECKBYTE)
|
||||
Sys_Error ("System stack overflow!");
|
||||
}
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
|
||||
byte scantokey[128] =
|
||||
{
|
||||
// 0 1 2 3 4 5 6 7
|
||||
// 8 9 A B C D E F
|
||||
0 , 27, '1', '2', '3', '4', '5', '6',
|
||||
'7', '8', '9', '0', '-', '=', K_BACKSPACE, 9, // 0
|
||||
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
|
||||
'o', 'p', '[', ']', 13 , K_CTRL,'a', 's', // 1
|
||||
'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
|
||||
'\'' , '`', K_SHIFT,'\\', 'z', 'x', 'c', 'v', // 2
|
||||
'b', 'n', 'm', ',', '.', '/', K_SHIFT,'*',
|
||||
K_ALT,' ', 0 , K_F1, K_F2, K_F3, K_F4, K_F5, // 3
|
||||
K_F6, K_F7, K_F8, K_F9, K_F10,0 , 0 , K_HOME,
|
||||
K_UPARROW,K_PGUP,'-',K_LEFTARROW,'5',K_RIGHTARROW,'+',K_END, //4
|
||||
K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, 0, K_F11,
|
||||
K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0, // 5
|
||||
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
|
||||
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6
|
||||
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
|
||||
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7
|
||||
};
|
||||
|
||||
byte shiftscantokey[128] =
|
||||
{
|
||||
// 0 1 2 3 4 5 6 7
|
||||
// 8 9 A B C D E F
|
||||
0 , 27, '!', '@', '#', '$', '%', '^',
|
||||
'&', '*', '(', ')', '_', '+', K_BACKSPACE, 9, // 0
|
||||
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
|
||||
'O', 'P', '{', '}', 13 , K_CTRL,'A', 'S', // 1
|
||||
'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
|
||||
'"' , '~', K_SHIFT,'|', 'Z', 'X', 'C', 'V', // 2
|
||||
'B', 'N', 'M', '<', '>', '?', K_SHIFT,'*',
|
||||
K_ALT,' ', 0 , K_F1, K_F2, K_F3, K_F4, K_F5, // 3
|
||||
K_F6, K_F7, K_F8, K_F9, K_F10,0 , 0 , K_HOME,
|
||||
K_UPARROW,K_PGUP,'_',K_LEFTARROW,'%',K_RIGHTARROW,'+',K_END, //4
|
||||
K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, 0, K_F11,
|
||||
K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0, // 5
|
||||
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
|
||||
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6
|
||||
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
|
||||
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7
|
||||
};
|
||||
|
||||
void TrapKey(void)
|
||||
{
|
||||
// static int ctrl=0;
|
||||
keybuf[keybuf_head] = dos_inportb(0x60);
|
||||
dos_outportb(0x20, 0x20);
|
||||
/*
|
||||
if (scantokey[keybuf[keybuf_head]&0x7f] == K_CTRL)
|
||||
ctrl=keybuf[keybuf_head]&0x80;
|
||||
if (ctrl && scantokey[keybuf[keybuf_head]&0x7f] == 'c')
|
||||
Sys_Error("ctrl-c hit\n");
|
||||
*/
|
||||
keybuf_head = (keybuf_head + 1) & (KEYBUF_SIZE-1);
|
||||
}
|
||||
|
||||
#define SC_UPARROW 0x48
|
||||
#define SC_DOWNARROW 0x50
|
||||
#define SC_LEFTARROW 0x4b
|
||||
#define SC_RIGHTARROW 0x4d
|
||||
#define SC_LEFTSHIFT 0x2a
|
||||
#define SC_RIGHTSHIFT 0x36
|
||||
#define SC_RIGHTARROW 0x4d
|
||||
|
||||
void MaskExceptions (void);
|
||||
void Sys_InitFloatTime (void);
|
||||
void Sys_PushFPCW_SetHigh (void);
|
||||
void Sys_PopFPCW (void);
|
||||
|
||||
#define LEAVE_FOR_CACHE (512*1024) //FIXME: tune
|
||||
#define LOCKED_FOR_MALLOC (128*1024) //FIXME: tune
|
||||
|
||||
|
||||
void Sys_DetectWin95 (void)
|
||||
{
|
||||
__dpmi_regs r;
|
||||
|
||||
r.x.ax = 0x160a; /* Get Windows Version */
|
||||
__dpmi_int(0x2f, &r);
|
||||
|
||||
if(r.x.ax || r.h.bh < 4) /* Not windows or earlier than Win95 */
|
||||
{
|
||||
win95 = 0;
|
||||
lockmem = true;
|
||||
lockunlockmem = false;
|
||||
unlockmem = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
win95 = 1;
|
||||
lockunlockmem = COM_CheckParm ("-winlockunlock");
|
||||
|
||||
if (lockunlockmem)
|
||||
lockmem = true;
|
||||
else
|
||||
lockmem = COM_CheckParm ("-winlock");
|
||||
|
||||
unlockmem = lockmem && !lockunlockmem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void *dos_getmaxlockedmem(int *size)
|
||||
{
|
||||
__dpmi_free_mem_info meminfo;
|
||||
__dpmi_meminfo info;
|
||||
int working_size;
|
||||
void *working_memory;
|
||||
int last_locked;
|
||||
int extra, i, j, allocsize;
|
||||
static char *msg = "Locking data...";
|
||||
int m, n;
|
||||
byte *x;
|
||||
|
||||
// first lock all the current executing image so the locked count will
|
||||
// be accurate. It doesn't hurt to lock the memory multiple times
|
||||
last_locked = __djgpp_selector_limit + 1;
|
||||
info.size = last_locked - 4096;
|
||||
info.address = __djgpp_base_address + 4096;
|
||||
|
||||
if (lockmem)
|
||||
{
|
||||
if(__dpmi_lock_linear_region(&info))
|
||||
{
|
||||
Sys_Error ("Lock of current memory at 0x%lx for %ldKb failed!\n",
|
||||
info.address, info.size/1024);
|
||||
}
|
||||
}
|
||||
|
||||
__dpmi_get_free_memory_information(&meminfo);
|
||||
|
||||
if (!win95) /* Not windows or earlier than Win95 */
|
||||
{
|
||||
working_size = meminfo.maximum_locked_page_allocation_in_pages * 4096;
|
||||
}
|
||||
else
|
||||
{
|
||||
working_size = meminfo.largest_available_free_block_in_bytes -
|
||||
LEAVE_FOR_CACHE;
|
||||
}
|
||||
|
||||
working_size &= ~0xffff; /* Round down to 64K */
|
||||
working_size += 0x10000;
|
||||
|
||||
do
|
||||
{
|
||||
working_size -= 0x10000; /* Decrease 64K and try again */
|
||||
working_memory = sbrk(working_size);
|
||||
} while (working_memory == (void *)-1);
|
||||
|
||||
extra = 0xfffc - ((unsigned)sbrk(0) & 0xffff);
|
||||
|
||||
if (extra > 0)
|
||||
{
|
||||
sbrk(extra);
|
||||
working_size += extra;
|
||||
}
|
||||
|
||||
// now grab the memory
|
||||
info.address = last_locked + __djgpp_base_address;
|
||||
|
||||
if (!win95)
|
||||
{
|
||||
info.size = __djgpp_selector_limit + 1 - last_locked;
|
||||
|
||||
while (info.size > 0 && __dpmi_lock_linear_region(&info))
|
||||
{
|
||||
info.size -= 0x1000;
|
||||
working_size -= 0x1000;
|
||||
sbrk(-0x1000);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* Win95 section */
|
||||
j = COM_CheckParm("-winmem");
|
||||
|
||||
if (standard_quake)
|
||||
minmem = MINIMUM_WIN_MEMORY;
|
||||
else
|
||||
minmem = MINIMUM_WIN_MEMORY_LEVELPAK;
|
||||
|
||||
if (j)
|
||||
{
|
||||
allocsize = ((int)(Q_atoi(com_argv[j+1]))) * 0x100000 +
|
||||
LOCKED_FOR_MALLOC;
|
||||
|
||||
if (allocsize < (minmem + LOCKED_FOR_MALLOC))
|
||||
allocsize = minmem + LOCKED_FOR_MALLOC;
|
||||
}
|
||||
else
|
||||
{
|
||||
allocsize = minmem + LOCKED_FOR_MALLOC;
|
||||
}
|
||||
|
||||
if (!lockmem)
|
||||
{
|
||||
// we won't lock, just sbrk the memory
|
||||
info.size = allocsize;
|
||||
goto UpdateSbrk;
|
||||
}
|
||||
|
||||
// lock the memory down
|
||||
write (STDOUT, msg, strlen (msg));
|
||||
|
||||
for (j=allocsize ; j>(minmem + LOCKED_FOR_MALLOC) ;
|
||||
j -= 0x100000)
|
||||
{
|
||||
info.size = j;
|
||||
|
||||
if (!__dpmi_lock_linear_region(&info))
|
||||
goto Locked;
|
||||
|
||||
write (STDOUT, ".", 1);
|
||||
}
|
||||
|
||||
// finally, try with the absolute minimum amount
|
||||
for (i=0 ; i<10 ; i++)
|
||||
{
|
||||
info.size = minmem + LOCKED_FOR_MALLOC;
|
||||
|
||||
if (!__dpmi_lock_linear_region(&info))
|
||||
goto Locked;
|
||||
}
|
||||
|
||||
Sys_Error ("Can't lock memory; %d Mb lockable RAM required. "
|
||||
"Try shrinking smartdrv.", info.size / 0x100000);
|
||||
|
||||
Locked:
|
||||
|
||||
UpdateSbrk:
|
||||
|
||||
info.address += info.size;
|
||||
info.address -= __djgpp_base_address + 4; // ending point, malloc align
|
||||
working_size = info.address - (int)working_memory;
|
||||
sbrk(info.address-(int)sbrk(0)); // negative adjustment
|
||||
}
|
||||
|
||||
|
||||
if (lockunlockmem)
|
||||
{
|
||||
__dpmi_unlock_linear_region (&info);
|
||||
printf ("Locked and unlocked %d Mb data\n", working_size / 0x100000);
|
||||
}
|
||||
else if (lockmem)
|
||||
{
|
||||
printf ("Locked %d Mb data\n", working_size / 0x100000);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("Allocated %d Mb data\n", working_size / 0x100000);
|
||||
}
|
||||
|
||||
// touch all the memory to make sure it's there. The 16-page skip is to
|
||||
// keep Win 95 from thinking we're trying to page ourselves in (we are
|
||||
// doing that, of course, but there's no reason we shouldn't)
|
||||
x = (byte *)working_memory;
|
||||
|
||||
for (n=0 ; n<4 ; n++)
|
||||
{
|
||||
for (m=0 ; m<(working_size - 16 * 0x1000) ; m += 4)
|
||||
{
|
||||
sys_checksum += *(int *)&x[m];
|
||||
sys_checksum += *(int *)&x[m + 16 * 0x1000];
|
||||
}
|
||||
}
|
||||
|
||||
// give some of what we locked back for malloc before returning. Done
|
||||
// by cheating and passing a negative value to sbrk
|
||||
working_size -= LOCKED_FOR_MALLOC;
|
||||
sbrk( -(LOCKED_FOR_MALLOC));
|
||||
*size = working_size;
|
||||
return working_memory;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Sys_FileTime
|
||||
|
||||
returns -1 if not present
|
||||
============
|
||||
*/
|
||||
int Sys_FileTime (char *path)
|
||||
{
|
||||
struct stat buf;
|
||||
|
||||
if (stat (path,&buf) == -1)
|
||||
return -1;
|
||||
|
||||
return buf.st_mtime;
|
||||
}
|
||||
|
||||
void Sys_mkdir (char *path)
|
||||
{
|
||||
mkdir (path, 0777);
|
||||
}
|
||||
|
||||
|
||||
void Sys_Sleep(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
char *Sys_ConsoleInput(void)
|
||||
{
|
||||
static char text[256];
|
||||
static int len = 0;
|
||||
char ch;
|
||||
|
||||
if (!isDedicated)
|
||||
return NULL;
|
||||
|
||||
if (! kbhit())
|
||||
return NULL;
|
||||
|
||||
ch = getche();
|
||||
|
||||
switch (ch)
|
||||
{
|
||||
case '\r':
|
||||
putch('\n');
|
||||
if (len)
|
||||
{
|
||||
text[len] = 0;
|
||||
len = 0;
|
||||
return text;
|
||||
}
|
||||
break;
|
||||
|
||||
case '\b':
|
||||
putch(' ');
|
||||
if (len)
|
||||
{
|
||||
len--;
|
||||
putch('\b');
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
text[len] = ch;
|
||||
len = (len + 1) & 0xff;
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Sys_Init(void)
|
||||
{
|
||||
|
||||
MaskExceptions ();
|
||||
|
||||
Sys_SetFPCW ();
|
||||
|
||||
dos_outportb(0x43, 0x34); // set system timer to mode 2
|
||||
dos_outportb(0x40, 0); // for the Sys_FloatTime() function
|
||||
dos_outportb(0x40, 0);
|
||||
|
||||
Sys_InitFloatTime ();
|
||||
|
||||
_go32_interrupt_stack_size = 4 * 1024;;
|
||||
_go32_rmcb_stack_size = 4 * 1024;
|
||||
}
|
||||
|
||||
void Sys_Shutdown(void)
|
||||
{
|
||||
if (!isDedicated)
|
||||
dos_restoreintr(9);
|
||||
|
||||
if (unlockmem)
|
||||
{
|
||||
dos_unlockmem (&start_of_memory,
|
||||
end_of_memory - (int)&start_of_memory);
|
||||
dos_unlockmem (quakeparms.membase, quakeparms.memsize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define SC_RSHIFT 0x36
|
||||
#define SC_LSHIFT 0x2a
|
||||
void Sys_SendKeyEvents (void)
|
||||
{
|
||||
int k, next;
|
||||
int outkey;
|
||||
|
||||
// get key events
|
||||
|
||||
while (keybuf_head != keybuf_tail)
|
||||
{
|
||||
|
||||
k = keybuf[keybuf_tail++];
|
||||
keybuf_tail &= (KEYBUF_SIZE-1);
|
||||
|
||||
if (k==0xe0)
|
||||
continue; // special / pause keys
|
||||
next = keybuf[(keybuf_tail-2)&(KEYBUF_SIZE-1)];
|
||||
if (next == 0xe1)
|
||||
continue; // pause key bullshit
|
||||
if (k==0xc5 && next == 0x9d)
|
||||
{
|
||||
Key_Event (K_PAUSE, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
// extended keyboard shift key bullshit
|
||||
if ( (k&0x7f)==SC_LSHIFT || (k&0x7f)==SC_RSHIFT )
|
||||
{
|
||||
if ( keybuf[(keybuf_tail-2)&(KEYBUF_SIZE-1)]==0xe0 )
|
||||
continue;
|
||||
k &= 0x80;
|
||||
k |= SC_RSHIFT;
|
||||
}
|
||||
|
||||
if (k==0xc5 && keybuf[(keybuf_tail-2)&(KEYBUF_SIZE-1)] == 0x9d)
|
||||
continue; // more pause bullshit
|
||||
|
||||
outkey = scantokey[k & 0x7f];
|
||||
|
||||
if (k & 0x80)
|
||||
Key_Event (outkey, false);
|
||||
else
|
||||
Key_Event (outkey, true);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// General routines
|
||||
// =======================================================================
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_Printf
|
||||
================
|
||||
*/
|
||||
|
||||
void Sys_Printf (char *fmt, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char text[1024];
|
||||
|
||||
va_start (argptr,fmt);
|
||||
vsprintf (text,fmt,argptr);
|
||||
va_end (argptr);
|
||||
|
||||
if (cls.state == ca_dedicated)
|
||||
fprintf(stderr, "%s", text);
|
||||
}
|
||||
|
||||
void Sys_AtExit (void)
|
||||
{
|
||||
|
||||
// shutdown only once (so Sys_Error can call this function to shutdown, then
|
||||
// print the error message, then call exit without exit calling this function
|
||||
// again)
|
||||
Sys_Shutdown();
|
||||
}
|
||||
|
||||
|
||||
void Sys_Quit (void)
|
||||
{
|
||||
byte screen[80*25*2];
|
||||
byte *d;
|
||||
char ver[6];
|
||||
int i;
|
||||
|
||||
|
||||
// load the sell screen before shuting everything down
|
||||
if (registered.value)
|
||||
d = COM_LoadHunkFile ("end2.bin");
|
||||
else
|
||||
d = COM_LoadHunkFile ("end1.bin");
|
||||
if (d)
|
||||
memcpy (screen, d, sizeof(screen));
|
||||
|
||||
// write the version number directly to the end screen
|
||||
sprintf (ver, " v%4.2f", VERSION);
|
||||
for (i=0 ; i<6 ; i++)
|
||||
screen[0*80*2 + 72*2 + i*2] = ver[i];
|
||||
|
||||
Host_Shutdown();
|
||||
|
||||
// do the text mode sell screen
|
||||
if (d)
|
||||
{
|
||||
memcpy ((void *)real2ptr(0xb8000), screen,80*25*2);
|
||||
|
||||
// set text pos
|
||||
regs.x.ax = 0x0200;
|
||||
regs.h.bh = 0;
|
||||
regs.h.dl = 0;
|
||||
regs.h.dh = 22;
|
||||
dos_int86 (0x10);
|
||||
}
|
||||
else
|
||||
printf ("couldn't load endscreen.\n");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void Sys_Error (char *error, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char string[1024];
|
||||
|
||||
va_start (argptr,error);
|
||||
vsprintf (string,error,argptr);
|
||||
va_end (argptr);
|
||||
|
||||
Host_Shutdown();
|
||||
fprintf(stderr, "Error: %s\n", string);
|
||||
// Sys_AtExit is called by exit to shutdown the system
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
int Sys_FileOpenRead (char *path, int *handle)
|
||||
{
|
||||
int h;
|
||||
struct stat fileinfo;
|
||||
|
||||
h = open (path, O_RDONLY|O_BINARY, 0666);
|
||||
*handle = h;
|
||||
if (h == -1)
|
||||
return -1;
|
||||
|
||||
if (fstat (h,&fileinfo) == -1)
|
||||
Sys_Error ("Error fstating %s", path);
|
||||
|
||||
return fileinfo.st_size;
|
||||
}
|
||||
|
||||
int Sys_FileOpenWrite (char *path)
|
||||
{
|
||||
int handle;
|
||||
|
||||
umask (0);
|
||||
|
||||
handle = open(path,O_RDWR | O_BINARY | O_CREAT | O_TRUNC
|
||||
, 0666);
|
||||
|
||||
if (handle == -1)
|
||||
Sys_Error ("Error opening %s: %s", path,strerror(errno));
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void Sys_FileClose (int handle)
|
||||
{
|
||||
close (handle);
|
||||
}
|
||||
|
||||
void Sys_FileSeek (int handle, int position)
|
||||
{
|
||||
lseek (handle, position, SEEK_SET);
|
||||
}
|
||||
|
||||
int Sys_FileRead (int handle, void *dest, int count)
|
||||
{
|
||||
return read (handle, dest, count);
|
||||
}
|
||||
|
||||
int Sys_FileWrite (int handle, void *data, int count)
|
||||
{
|
||||
return write (handle, data, count);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_MakeCodeWriteable
|
||||
================
|
||||
*/
|
||||
void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
|
||||
{
|
||||
// it's always writeable
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_FloatTime
|
||||
================
|
||||
*/
|
||||
double Sys_FloatTime (void)
|
||||
{
|
||||
int r;
|
||||
unsigned t, tick;
|
||||
double ft, time;
|
||||
static int sametimecount;
|
||||
|
||||
Sys_PushFPCW_SetHigh ();
|
||||
|
||||
//{static float t = 0; t=t+0.05; return t;} // DEBUG
|
||||
|
||||
t = *(unsigned short*)real2ptr(0x46c) * 65536;
|
||||
|
||||
dos_outportb(0x43, 0); // latch time
|
||||
r = dos_inportb(0x40);
|
||||
r |= dos_inportb(0x40) << 8;
|
||||
r = (r-1) & 0xffff;
|
||||
|
||||
tick = *(unsigned short*)real2ptr(0x46c) * 65536;
|
||||
if ((tick != t) && (r & 0x8000))
|
||||
t = tick;
|
||||
|
||||
ft = (double) (t+(65536-r)) / 1193200.0;
|
||||
time = ft - oldtime;
|
||||
oldtime = ft;
|
||||
|
||||
if (time < 0)
|
||||
{
|
||||
if (time > -3000.0)
|
||||
time = 0.0;
|
||||
else
|
||||
time += 3600.0;
|
||||
}
|
||||
|
||||
curtime += time;
|
||||
|
||||
if (curtime == lastcurtime)
|
||||
{
|
||||
sametimecount++;
|
||||
|
||||
if (sametimecount > 100000)
|
||||
{
|
||||
curtime += 1.0;
|
||||
sametimecount = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sametimecount = 0;
|
||||
}
|
||||
|
||||
lastcurtime = curtime;
|
||||
|
||||
Sys_PopFPCW ();
|
||||
|
||||
return curtime;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_InitFloatTime
|
||||
================
|
||||
*/
|
||||
void Sys_InitFloatTime (void)
|
||||
{
|
||||
int j;
|
||||
|
||||
Sys_FloatTime ();
|
||||
|
||||
oldtime = curtime;
|
||||
|
||||
j = COM_CheckParm("-starttime");
|
||||
|
||||
if (j)
|
||||
{
|
||||
curtime = (double) (Q_atof(com_argv[j+1]));
|
||||
}
|
||||
else
|
||||
{
|
||||
curtime = 0.0;
|
||||
}
|
||||
lastcurtime = curtime;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_GetMemory
|
||||
================
|
||||
*/
|
||||
void Sys_GetMemory(void)
|
||||
{
|
||||
int j, tsize;
|
||||
|
||||
j = COM_CheckParm("-mem");
|
||||
if (j)
|
||||
{
|
||||
quakeparms.memsize = (int) (Q_atof(com_argv[j+1]) * 1024 * 1024);
|
||||
quakeparms.membase = malloc (quakeparms.memsize);
|
||||
}
|
||||
else
|
||||
{
|
||||
quakeparms.membase = dos_getmaxlockedmem (&quakeparms.memsize);
|
||||
}
|
||||
|
||||
fprintf(stderr, "malloc'd: %d\n", quakeparms.memsize);
|
||||
|
||||
if (COM_CheckParm ("-heapsize"))
|
||||
{
|
||||
tsize = Q_atoi (com_argv[COM_CheckParm("-heapsize") + 1]) * 1024;
|
||||
|
||||
if (tsize < quakeparms.memsize)
|
||||
quakeparms.memsize = tsize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_PageInProgram
|
||||
|
||||
walks the text, data, and bss to make sure it's all paged in so that the
|
||||
actual physical memory detected by Sys_GetMemory is correct.
|
||||
================
|
||||
*/
|
||||
void Sys_PageInProgram(void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
end_of_memory = (int)sbrk(0);
|
||||
|
||||
if (lockmem)
|
||||
{
|
||||
if (dos_lockmem ((void *)&start_of_memory,
|
||||
end_of_memory - (int)&start_of_memory))
|
||||
Sys_Error ("Couldn't lock text and data");
|
||||
}
|
||||
|
||||
if (lockunlockmem)
|
||||
{
|
||||
dos_unlockmem((void *)&start_of_memory,
|
||||
end_of_memory - (int)&start_of_memory);
|
||||
printf ("Locked and unlocked %d Mb image\n",
|
||||
(end_of_memory - (int)&start_of_memory) / 0x100000);
|
||||
}
|
||||
else if (lockmem)
|
||||
{
|
||||
printf ("Locked %d Mb image\n",
|
||||
(end_of_memory - (int)&start_of_memory) / 0x100000);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("Loaded %d Mb image\n",
|
||||
(end_of_memory - (int)&start_of_memory) / 0x100000);
|
||||
}
|
||||
|
||||
// touch the entire image, doing the 16-page skip so Win95 doesn't think we're
|
||||
// trying to page ourselves in
|
||||
for (j=0 ; j<4 ; j++)
|
||||
{
|
||||
for(i=(int)&start_of_memory ; i<(end_of_memory - 16 * 0x1000) ; i += 4)
|
||||
{
|
||||
sys_checksum += *(int *)i;
|
||||
sys_checksum += *(int *)(i + 16 * 0x1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_NoFPUExceptionHandler
|
||||
================
|
||||
*/
|
||||
void Sys_NoFPUExceptionHandler(int whatever)
|
||||
{
|
||||
printf ("\nError: Quake requires a floating-point processor\n");
|
||||
exit (0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_DefaultExceptionHandler
|
||||
================
|
||||
*/
|
||||
void Sys_DefaultExceptionHandler(int whatever)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
main
|
||||
================
|
||||
*/
|
||||
int main (int c, char **v)
|
||||
{
|
||||
double time, oldtime, newtime;
|
||||
extern void (*dos_error_func)(char *, ...);
|
||||
static char cwd[1024];
|
||||
|
||||
printf ("Quake v%4.2f\n", VERSION);
|
||||
|
||||
// make sure there's an FPU
|
||||
signal(SIGNOFP, Sys_NoFPUExceptionHandler);
|
||||
signal(SIGABRT, Sys_DefaultExceptionHandler);
|
||||
signal(SIGALRM, Sys_DefaultExceptionHandler);
|
||||
signal(SIGKILL, Sys_DefaultExceptionHandler);
|
||||
signal(SIGQUIT, Sys_DefaultExceptionHandler);
|
||||
signal(SIGINT, Sys_DefaultExceptionHandler);
|
||||
|
||||
if (fptest_temp >= 0.0)
|
||||
fptest_temp += 0.1;
|
||||
|
||||
COM_InitArgv (c, v);
|
||||
|
||||
quakeparms.argc = com_argc;
|
||||
quakeparms.argv = com_argv;
|
||||
|
||||
dos_error_func = Sys_Error;
|
||||
|
||||
Sys_DetectWin95 ();
|
||||
Sys_PageInProgram ();
|
||||
Sys_GetMemory ();
|
||||
|
||||
atexit (Sys_AtExit); // in case we crash
|
||||
|
||||
getwd (cwd);
|
||||
if (cwd[Q_strlen(cwd)-1] == '/') cwd[Q_strlen(cwd)-1] = 0;
|
||||
quakeparms.basedir = cwd; //"f:/quake";
|
||||
|
||||
isDedicated = (COM_CheckParm ("-dedicated") != 0);
|
||||
|
||||
Sys_Init ();
|
||||
|
||||
if (!isDedicated)
|
||||
dos_registerintr(9, TrapKey);
|
||||
|
||||
//Sys_InitStackCheck ();
|
||||
|
||||
Host_Init(&quakeparms);
|
||||
|
||||
//Sys_StackCheck ();
|
||||
|
||||
//Con_Printf ("Top of stack: 0x%x\n", &time);
|
||||
oldtime = Sys_FloatTime ();
|
||||
while (1)
|
||||
{
|
||||
newtime = Sys_FloatTime ();
|
||||
time = newtime - oldtime;
|
||||
|
||||
if (cls.state == ca_dedicated && (time<sys_ticrate.value))
|
||||
continue;
|
||||
|
||||
Host_Frame (time);
|
||||
|
||||
//Sys_StackCheck ();
|
||||
|
||||
oldtime = newtime;
|
||||
}
|
||||
}
|
||||
|
||||
|
95
sys_dosa.s
95
sys_dosa.s
|
@ -1,95 +0,0 @@
|
|||
//
|
||||
// sys_dosa.s
|
||||
// x86 assembly-language DOS-dependent routines.
|
||||
|
||||
#include "asm_i386.h"
|
||||
#include "quakeasm.h"
|
||||
|
||||
|
||||
.data
|
||||
|
||||
.align 4
|
||||
fpenv:
|
||||
.long 0, 0, 0, 0, 0, 0, 0, 0
|
||||
|
||||
.text
|
||||
|
||||
.globl C(MaskExceptions)
|
||||
C(MaskExceptions):
|
||||
fnstenv fpenv
|
||||
orl $0x3F,fpenv
|
||||
fldenv fpenv
|
||||
|
||||
ret
|
||||
|
||||
#if 0
|
||||
.globl C(unmaskexceptions)
|
||||
C(unmaskexceptions):
|
||||
fnstenv fpenv
|
||||
andl $0xFFFFFFE0,fpenv
|
||||
fldenv fpenv
|
||||
|
||||
ret
|
||||
#endif
|
||||
|
||||
.data
|
||||
|
||||
.align 4
|
||||
.globl ceil_cw, single_cw, full_cw, cw, pushed_cw
|
||||
ceil_cw: .long 0
|
||||
single_cw: .long 0
|
||||
full_cw: .long 0
|
||||
cw: .long 0
|
||||
pushed_cw: .long 0
|
||||
|
||||
.text
|
||||
|
||||
.globl C(Sys_LowFPPrecision)
|
||||
C(Sys_LowFPPrecision):
|
||||
fldcw single_cw
|
||||
|
||||
ret
|
||||
|
||||
.globl C(Sys_HighFPPrecision)
|
||||
C(Sys_HighFPPrecision):
|
||||
fldcw full_cw
|
||||
|
||||
ret
|
||||
|
||||
.globl C(Sys_PushFPCW_SetHigh)
|
||||
C(Sys_PushFPCW_SetHigh):
|
||||
fnstcw pushed_cw
|
||||
fldcw full_cw
|
||||
|
||||
ret
|
||||
|
||||
.globl C(Sys_PopFPCW)
|
||||
C(Sys_PopFPCW):
|
||||
fldcw pushed_cw
|
||||
|
||||
ret
|
||||
|
||||
.globl C(Sys_SetFPCW)
|
||||
C(Sys_SetFPCW):
|
||||
fnstcw cw
|
||||
movl cw,%eax
|
||||
#if id386
|
||||
andb $0xF0,%ah
|
||||
orb $0x03,%ah // round mode, 64-bit precision
|
||||
#endif
|
||||
movl %eax,full_cw
|
||||
|
||||
#if id386
|
||||
andb $0xF0,%ah
|
||||
orb $0x0C,%ah // chop mode, single precision
|
||||
#endif
|
||||
movl %eax,single_cw
|
||||
|
||||
#if id386
|
||||
andb $0xF0,%ah
|
||||
orb $0x08,%ah // ceil mode, single precision
|
||||
#endif
|
||||
movl %eax,ceil_cw
|
||||
|
||||
ret
|
||||
|
778
vid_dos.c
778
vid_dos.c
|
@ -1,778 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
//
|
||||
// vid_dos.c: DOS-specific video routines
|
||||
//
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <dos.h>
|
||||
#include <dpmi.h>
|
||||
#include <go32.h>
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "d_local.h"
|
||||
#include "dosisms.h"
|
||||
#include "vid_dos.h"
|
||||
|
||||
int vid_modenum;
|
||||
vmode_t *pcurrentmode = NULL;
|
||||
int vid_testingmode, vid_realmode;
|
||||
double vid_testendtime;
|
||||
|
||||
cvar_t vid_mode = {"vid_mode","0", false};
|
||||
cvar_t vid_wait = {"vid_wait","0"};
|
||||
cvar_t vid_nopageflip = {"vid_nopageflip","0", true};
|
||||
cvar_t _vid_wait_override = {"_vid_wait_override", "0", true};
|
||||
cvar_t _vid_default_mode = {"_vid_default_mode","0", true};
|
||||
cvar_t _vid_default_mode_win = {"_vid_default_mode_win","1", true};
|
||||
cvar_t vid_config_x = {"vid_config_x","800", true};
|
||||
cvar_t vid_config_y = {"vid_config_y","600", true};
|
||||
cvar_t vid_stretch_by_2 = {"vid_stretch_by_2","1", true};
|
||||
cvar_t m_windowed = {"m_windowed","0", true};
|
||||
cvar_t vid_fullscreen_mode = {"vid_fullscreen_mode","3", true};
|
||||
cvar_t vid_windowed_mode = {"vid_windowed_mode","0", true};
|
||||
cvar_t block_switch = {"block_switch","0", true};
|
||||
cvar_t vid_window_x = {"vid_window_x", "0", true};
|
||||
cvar_t vid_window_y = {"vid_window_y", "0", true};
|
||||
|
||||
int d_con_indirect = 0;
|
||||
|
||||
int numvidmodes;
|
||||
vmode_t *pvidmodes;
|
||||
|
||||
static int firstupdate = 1;
|
||||
|
||||
extern regs_t regs;
|
||||
|
||||
void VID_TestMode_f (void);
|
||||
void VID_NumModes_f (void);
|
||||
void VID_DescribeCurrentMode_f (void);
|
||||
void VID_DescribeMode_f (void);
|
||||
void VID_DescribeModes_f (void);
|
||||
|
||||
byte vid_current_palette[768]; // save for mode changes
|
||||
|
||||
|
||||
static qboolean nomodecheck = false;
|
||||
|
||||
unsigned short d_8to16table[256]; // not used in 8 bpp mode
|
||||
unsigned d_8to24table[256]; // not used in 8 bpp mode
|
||||
|
||||
void VID_MenuDraw (void);
|
||||
void VID_MenuKey (int key);
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VID_Init
|
||||
================
|
||||
*/
|
||||
void VID_Init (unsigned char *palette)
|
||||
{
|
||||
Cvar_RegisterVariable (&vid_mode);
|
||||
Cvar_RegisterVariable (&vid_wait);
|
||||
Cvar_RegisterVariable (&vid_nopageflip);
|
||||
Cvar_RegisterVariable (&_vid_wait_override);
|
||||
Cvar_RegisterVariable (&_vid_default_mode);
|
||||
Cvar_RegisterVariable (&_vid_default_mode_win);
|
||||
Cvar_RegisterVariable (&vid_config_x);
|
||||
Cvar_RegisterVariable (&vid_config_y);
|
||||
Cvar_RegisterVariable (&vid_stretch_by_2);
|
||||
Cvar_RegisterVariable (&m_windowed);
|
||||
Cvar_RegisterVariable (&vid_fullscreen_mode);
|
||||
Cvar_RegisterVariable (&vid_windowed_mode);
|
||||
Cvar_RegisterVariable (&block_switch);
|
||||
|
||||
Cmd_AddCommand ("vid_testmode", VID_TestMode_f);
|
||||
Cmd_AddCommand ("vid_nummodes", VID_NumModes_f);
|
||||
Cmd_AddCommand ("vid_describecurrentmode", VID_DescribeCurrentMode_f);
|
||||
Cmd_AddCommand ("vid_describemode", VID_DescribeMode_f);
|
||||
Cmd_AddCommand ("vid_describemodes", VID_DescribeModes_f);
|
||||
|
||||
// set up the mode list; note that later inits link in their modes ahead of
|
||||
// earlier ones, so the standard VGA modes are always first in the list. This
|
||||
// is important because mode 0 must always be VGA mode 0x13
|
||||
if (!COM_CheckParm ("-stdvid"))
|
||||
VID_InitExtra ();
|
||||
VGA_Init ();
|
||||
|
||||
vid_testingmode = 0;
|
||||
|
||||
vid_modenum = vid_mode.value;
|
||||
|
||||
VID_SetMode (vid_modenum, palette);
|
||||
|
||||
vid_realmode = vid_modenum;
|
||||
|
||||
vid_menudrawfn = VID_MenuDraw;
|
||||
vid_menukeyfn = VID_MenuKey;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
VID_GetModePtr
|
||||
=================
|
||||
*/
|
||||
vmode_t *VID_GetModePtr (int modenum)
|
||||
{
|
||||
vmode_t *pv;
|
||||
|
||||
pv = pvidmodes;
|
||||
if (!pv)
|
||||
Sys_Error ("VID_GetModePtr: empty vid mode list");
|
||||
|
||||
while (modenum--)
|
||||
{
|
||||
pv = pv->pnext;
|
||||
if (!pv)
|
||||
Sys_Error ("VID_GetModePtr: corrupt vid mode list");
|
||||
}
|
||||
|
||||
return pv;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
VID_NumModes
|
||||
================
|
||||
*/
|
||||
int VID_NumModes ()
|
||||
{
|
||||
return (numvidmodes);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VID_ModeInfo
|
||||
================
|
||||
*/
|
||||
char *VID_ModeInfo (int modenum, char **ppheader)
|
||||
{
|
||||
static char *badmodestr = "Bad mode number";
|
||||
vmode_t *pv;
|
||||
|
||||
pv = VID_GetModePtr (modenum);
|
||||
|
||||
if (!pv)
|
||||
{
|
||||
if (ppheader)
|
||||
*ppheader = NULL;
|
||||
return badmodestr;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ppheader)
|
||||
*ppheader = pv->header;
|
||||
return pv->name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VID_SetMode
|
||||
================
|
||||
*/
|
||||
int VID_SetMode (int modenum, unsigned char *palette)
|
||||
{
|
||||
int stat;
|
||||
vmode_t *pnewmode, *poldmode;
|
||||
|
||||
if ((modenum >= numvidmodes) || (modenum < 0))
|
||||
{
|
||||
Cvar_SetValue ("vid_mode", (float)vid_modenum);
|
||||
|
||||
nomodecheck = true;
|
||||
Con_Printf ("No such video mode: %d\n", modenum);
|
||||
nomodecheck = false;
|
||||
|
||||
if (pcurrentmode == NULL)
|
||||
{
|
||||
modenum = 0; // mode hasn't been set yet, so initialize to base
|
||||
// mode since they gave us an invalid initial mode
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
pnewmode = VID_GetModePtr (modenum);
|
||||
|
||||
if (pnewmode == pcurrentmode)
|
||||
return 1; // already in the desired mode
|
||||
|
||||
// initialize the new mode
|
||||
poldmode = pcurrentmode;
|
||||
pcurrentmode = pnewmode;
|
||||
|
||||
vid.width = pcurrentmode->width;
|
||||
vid.height = pcurrentmode->height;
|
||||
vid.aspect = pcurrentmode->aspect;
|
||||
vid.rowbytes = pcurrentmode->rowbytes;
|
||||
|
||||
stat = (*pcurrentmode->setmode) (&vid, pcurrentmode);
|
||||
|
||||
if (stat < 1)
|
||||
{
|
||||
if (stat == 0)
|
||||
{
|
||||
// real, hard failure that requires resetting the mode
|
||||
if (!VID_SetMode (vid_modenum, palette)) // restore prior mode
|
||||
Sys_Error ("VID_SetMode: Unable to set any mode, probably "
|
||||
"because there's not enough memory available");
|
||||
Con_Printf ("Failed to set mode %d\n", modenum);
|
||||
return 0;
|
||||
}
|
||||
else if (stat == -1)
|
||||
{
|
||||
// not enough memory; just put things back the way they were
|
||||
pcurrentmode = poldmode;
|
||||
vid.width = pcurrentmode->width;
|
||||
vid.height = pcurrentmode->height;
|
||||
vid.aspect = pcurrentmode->aspect;
|
||||
vid.rowbytes = pcurrentmode->rowbytes;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Sys_Error ("VID_SetMode: invalid setmode return code %d");
|
||||
}
|
||||
}
|
||||
|
||||
(*pcurrentmode->setpalette) (&vid, pcurrentmode, palette);
|
||||
|
||||
vid_modenum = modenum;
|
||||
Cvar_SetValue ("vid_mode", (float)vid_modenum);
|
||||
|
||||
nomodecheck = true;
|
||||
Con_Printf ("%s\n", VID_ModeInfo (vid_modenum, NULL));
|
||||
nomodecheck = false;
|
||||
|
||||
vid.recalc_refdef = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VID_SetPalette
|
||||
================
|
||||
*/
|
||||
void VID_SetPalette (unsigned char *palette)
|
||||
{
|
||||
if (palette != vid_current_palette)
|
||||
Q_memcpy(vid_current_palette, palette, 768);
|
||||
(*pcurrentmode->setpalette)(&vid, pcurrentmode, vid_current_palette);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VID_ShiftPalette
|
||||
================
|
||||
*/
|
||||
void VID_ShiftPalette (unsigned char *palette)
|
||||
{
|
||||
|
||||
VID_SetPalette (palette);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VID_Shutdown
|
||||
================
|
||||
*/
|
||||
void VID_Shutdown (void)
|
||||
{
|
||||
|
||||
regs.h.ah = 0;
|
||||
regs.h.al = 0x3;
|
||||
dos_int86(0x10);
|
||||
|
||||
vid_testingmode = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VID_Update
|
||||
================
|
||||
*/
|
||||
void VID_Update (vrect_t *rects)
|
||||
{
|
||||
if (firstupdate && _vid_default_mode.value)
|
||||
{
|
||||
if(_vid_default_mode.value >= numvidmodes)
|
||||
Cvar_SetValue ("_vid_default_mode", 0);
|
||||
|
||||
firstupdate = 0;
|
||||
Cvar_SetValue ("vid_mode", _vid_default_mode.value);
|
||||
}
|
||||
|
||||
(*pcurrentmode->swapbuffers)(&vid, pcurrentmode, rects);
|
||||
|
||||
if (!nomodecheck)
|
||||
{
|
||||
if (vid_testingmode)
|
||||
{
|
||||
if (realtime >= vid_testendtime)
|
||||
{
|
||||
VID_SetMode (vid_realmode, vid_current_palette);
|
||||
vid_testingmode = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (vid_mode.value != vid_realmode)
|
||||
{
|
||||
VID_SetMode ((int)vid_mode.value, vid_current_palette);
|
||||
Cvar_SetValue ("vid_mode", (float)vid_modenum);
|
||||
// so if mode set fails, we don't keep on
|
||||
// trying to set that mode
|
||||
vid_realmode = vid_modenum;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
VID_NumModes_f
|
||||
=================
|
||||
*/
|
||||
void VID_NumModes_f (void)
|
||||
{
|
||||
int nummodes;
|
||||
|
||||
nummodes = VID_NumModes ();
|
||||
if (nummodes == 1)
|
||||
Con_Printf ("%d video mode is available\n", VID_NumModes ());
|
||||
else
|
||||
Con_Printf ("%d video modes are available\n", VID_NumModes ());
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
VID_DescribeCurrentMode_f
|
||||
=================
|
||||
*/
|
||||
void VID_DescribeCurrentMode_f (void)
|
||||
{
|
||||
Con_Printf ("%s\n", VID_ModeInfo (vid_modenum, NULL));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
VID_DescribeMode_f
|
||||
=================
|
||||
*/
|
||||
void VID_DescribeMode_f (void)
|
||||
{
|
||||
int modenum;
|
||||
|
||||
modenum = Q_atoi (Cmd_Argv(1));
|
||||
|
||||
Con_Printf ("%s\n", VID_ModeInfo (modenum, NULL));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
VID_DescribeModes_f
|
||||
=================
|
||||
*/
|
||||
void VID_DescribeModes_f (void)
|
||||
{
|
||||
int i, nummodes;
|
||||
char *pinfo, *pheader;
|
||||
vmode_t *pv;
|
||||
qboolean na;
|
||||
|
||||
na = false;
|
||||
|
||||
nummodes = VID_NumModes ();
|
||||
for (i=0 ; i<nummodes ; i++)
|
||||
{
|
||||
pv = VID_GetModePtr (i);
|
||||
pinfo = VID_ModeInfo (i, &pheader);
|
||||
if (pheader)
|
||||
Con_Printf ("\n%s\n", pheader);
|
||||
|
||||
if (VGA_CheckAdequateMem (pv->width, pv->height, pv->rowbytes,
|
||||
(pv->numpages == 1) || vid_nopageflip.value))
|
||||
{
|
||||
Con_Printf ("%2d: %s\n", i, pinfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
Con_Printf ("**: %s\n", pinfo);
|
||||
na = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (na)
|
||||
{
|
||||
Con_Printf ("\n[**: not enough system RAM for mode]\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
VID_GetModeDescription
|
||||
=================
|
||||
*/
|
||||
char *VID_GetModeDescription (int mode)
|
||||
{
|
||||
char *pinfo, *pheader;
|
||||
vmode_t *pv;
|
||||
|
||||
pv = VID_GetModePtr (mode);
|
||||
pinfo = VID_ModeInfo (mode, &pheader);
|
||||
|
||||
if (VGA_CheckAdequateMem (pv->width, pv->height, pv->rowbytes,
|
||||
(pv->numpages == 1) || vid_nopageflip.value))
|
||||
{
|
||||
return pinfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
VID_TestMode_f
|
||||
=================
|
||||
*/
|
||||
void VID_TestMode_f (void)
|
||||
{
|
||||
int modenum;
|
||||
double testduration;
|
||||
|
||||
if (!vid_testingmode)
|
||||
{
|
||||
modenum = Q_atoi (Cmd_Argv(1));
|
||||
|
||||
if (VID_SetMode (modenum, vid_current_palette))
|
||||
{
|
||||
vid_testingmode = 1;
|
||||
testduration = Q_atof (Cmd_Argv(2));
|
||||
if (testduration == 0)
|
||||
testduration = 5.0;
|
||||
vid_testendtime = realtime + testduration;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
D_BeginDirectRect
|
||||
================
|
||||
*/
|
||||
void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
|
||||
{
|
||||
|
||||
if (!vid.direct || !pcurrentmode)
|
||||
return;
|
||||
|
||||
if ((width > 24) || (height > 24) || (width < 1) || (height < 1))
|
||||
return;
|
||||
|
||||
if (width & 0x03)
|
||||
return;
|
||||
|
||||
(*pcurrentmode->begindirectrect) (&vid, pcurrentmode, x, y, pbitmap, width,
|
||||
height);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
D_EndDirectRect
|
||||
================
|
||||
*/
|
||||
void D_EndDirectRect (int x, int y, int width, int height)
|
||||
{
|
||||
|
||||
if (!vid.direct || !pcurrentmode)
|
||||
return;
|
||||
|
||||
if ((width > 24) || (height > 24) || (width < 1) || (height < 1))
|
||||
return;
|
||||
|
||||
if ((width & 0x03) || (height & 0x03))
|
||||
return;
|
||||
|
||||
(*pcurrentmode->enddirectrect) (&vid, pcurrentmode, x, y, width, height);
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
|
||||
extern void M_Menu_Options_f (void);
|
||||
extern void M_Print (int cx, int cy, char *str);
|
||||
extern void M_PrintWhite (int cx, int cy, char *str);
|
||||
extern void M_DrawCharacter (int cx, int line, int num);
|
||||
extern void M_DrawTransPic (int x, int y, qpic_t *pic);
|
||||
extern void M_DrawPic (int x, int y, qpic_t *pic);
|
||||
|
||||
static int vid_line, vid_wmodes, vid_column_size;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int modenum;
|
||||
char *desc;
|
||||
int iscur;
|
||||
} modedesc_t;
|
||||
|
||||
#define MAX_COLUMN_SIZE 11
|
||||
|
||||
#define MAX_MODEDESCS (MAX_COLUMN_SIZE*3)
|
||||
|
||||
static modedesc_t modedescs[MAX_MODEDESCS];
|
||||
|
||||
/*
|
||||
================
|
||||
VID_MenuDraw
|
||||
================
|
||||
*/
|
||||
void VID_MenuDraw (void)
|
||||
{
|
||||
qpic_t *p;
|
||||
char *ptr;
|
||||
int nummodes, i, j, column, row, dup;
|
||||
char temp[100];
|
||||
|
||||
vid_wmodes = 0;
|
||||
nummodes = VID_NumModes ();
|
||||
|
||||
p = Draw_CachePic ("gfx/vidmodes.lmp");
|
||||
M_DrawPic ( (320-p->width)/2, 4, p);
|
||||
|
||||
for (i=0 ; i<nummodes ; i++)
|
||||
{
|
||||
if (vid_wmodes < MAX_MODEDESCS)
|
||||
{
|
||||
if (i != 1)
|
||||
{
|
||||
ptr = VID_GetModeDescription (i);
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
dup = 0;
|
||||
|
||||
for (j=0 ; j<vid_wmodes ; j++)
|
||||
{
|
||||
if (!strcmp (modedescs[j].desc, ptr))
|
||||
{
|
||||
if (modedescs[j].modenum != 0)
|
||||
{
|
||||
modedescs[j].modenum = i;
|
||||
dup = 1;
|
||||
|
||||
if (i == vid_modenum)
|
||||
modedescs[j].iscur = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
dup = 1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dup)
|
||||
{
|
||||
modedescs[vid_wmodes].modenum = i;
|
||||
modedescs[vid_wmodes].desc = ptr;
|
||||
modedescs[vid_wmodes].iscur = 0;
|
||||
|
||||
if (i == vid_modenum)
|
||||
modedescs[vid_wmodes].iscur = 1;
|
||||
|
||||
vid_wmodes++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vid_column_size = (vid_wmodes + 2) / 3;
|
||||
|
||||
column = 16;
|
||||
row = 36;
|
||||
|
||||
for (i=0 ; i<vid_wmodes ; i++)
|
||||
{
|
||||
if (modedescs[i].iscur)
|
||||
M_PrintWhite (column, row, modedescs[i].desc);
|
||||
else
|
||||
M_Print (column, row, modedescs[i].desc);
|
||||
|
||||
row += 8;
|
||||
|
||||
if ((i % vid_column_size) == (vid_column_size - 1))
|
||||
{
|
||||
column += 13*8;
|
||||
row = 36;
|
||||
}
|
||||
}
|
||||
|
||||
// line cursor
|
||||
if (vid_testingmode)
|
||||
{
|
||||
sprintf (temp, "TESTING %s",
|
||||
modedescs[vid_line].desc);
|
||||
M_Print (13*8, 36 + MAX_COLUMN_SIZE * 8 + 8*4, temp);
|
||||
M_Print (9*8, 36 + MAX_COLUMN_SIZE * 8 + 8*6,
|
||||
"Please wait 5 seconds...");
|
||||
}
|
||||
else
|
||||
{
|
||||
M_Print (9*8, 36 + MAX_COLUMN_SIZE * 8 + 8,
|
||||
"Press Enter to set mode");
|
||||
M_Print (6*8, 36 + MAX_COLUMN_SIZE * 8 + 8*3,
|
||||
"T to test mode for 5 seconds");
|
||||
ptr = VID_GetModeDescription (vid_modenum);
|
||||
sprintf (temp, "D to make %s the default", ptr);
|
||||
M_Print (6*8, 36 + MAX_COLUMN_SIZE * 8 + 8*5, temp);
|
||||
ptr = VID_GetModeDescription ((int)_vid_default_mode.value);
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
sprintf (temp, "Current default is %s", ptr);
|
||||
M_Print (7*8, 36 + MAX_COLUMN_SIZE * 8 + 8*6, temp);
|
||||
}
|
||||
|
||||
M_Print (15*8, 36 + MAX_COLUMN_SIZE * 8 + 8*8,
|
||||
"Esc to exit");
|
||||
|
||||
row = 36 + (vid_line % vid_column_size) * 8;
|
||||
column = 8 + (vid_line / vid_column_size) * 13*8;
|
||||
|
||||
M_DrawCharacter (column, row, 12+((int)(realtime*4)&1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VID_MenuKey
|
||||
================
|
||||
*/
|
||||
void VID_MenuKey (int key)
|
||||
{
|
||||
if (vid_testingmode)
|
||||
return;
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case K_ESCAPE:
|
||||
S_LocalSound ("misc/menu1.wav");
|
||||
M_Menu_Options_f ();
|
||||
break;
|
||||
|
||||
case K_UPARROW:
|
||||
S_LocalSound ("misc/menu1.wav");
|
||||
vid_line--;
|
||||
|
||||
if (vid_line < 0)
|
||||
vid_line = vid_wmodes - 1;
|
||||
break;
|
||||
|
||||
case K_DOWNARROW:
|
||||
S_LocalSound ("misc/menu1.wav");
|
||||
vid_line++;
|
||||
|
||||
if (vid_line >= vid_wmodes)
|
||||
vid_line = 0;
|
||||
break;
|
||||
|
||||
case K_LEFTARROW:
|
||||
S_LocalSound ("misc/menu1.wav");
|
||||
vid_line -= vid_column_size;
|
||||
|
||||
if (vid_line < 0)
|
||||
{
|
||||
vid_line += ((vid_wmodes + (vid_column_size - 1)) /
|
||||
vid_column_size) * vid_column_size;
|
||||
|
||||
while (vid_line >= vid_wmodes)
|
||||
vid_line -= vid_column_size;
|
||||
}
|
||||
break;
|
||||
|
||||
case K_RIGHTARROW:
|
||||
S_LocalSound ("misc/menu1.wav");
|
||||
vid_line += vid_column_size;
|
||||
|
||||
if (vid_line >= vid_wmodes)
|
||||
{
|
||||
vid_line -= ((vid_wmodes + (vid_column_size - 1)) /
|
||||
vid_column_size) * vid_column_size;
|
||||
|
||||
while (vid_line < 0)
|
||||
vid_line += vid_column_size;
|
||||
}
|
||||
break;
|
||||
|
||||
case K_ENTER:
|
||||
S_LocalSound ("misc/menu1.wav");
|
||||
VID_SetMode (modedescs[vid_line].modenum, vid_current_palette);
|
||||
break;
|
||||
|
||||
case 'T':
|
||||
case 't':
|
||||
S_LocalSound ("misc/menu1.wav");
|
||||
if (VID_SetMode (modedescs[vid_line].modenum, vid_current_palette))
|
||||
{
|
||||
vid_testingmode = 1;
|
||||
vid_testendtime = realtime + 5.0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
case 'd':
|
||||
S_LocalSound ("misc/menu1.wav");
|
||||
firstupdate = 0;
|
||||
Cvar_SetValue ("_vid_default_mode", vid_modenum);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
83
vid_dos.h
83
vid_dos.h
|
@ -1,83 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// vid_dos.h: header file for DOS-specific video stuff
|
||||
|
||||
typedef struct vmode_s {
|
||||
struct vmode_s *pnext;
|
||||
char *name;
|
||||
char *header;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
float aspect;
|
||||
unsigned rowbytes;
|
||||
int planar;
|
||||
int numpages;
|
||||
void *pextradata;
|
||||
int (*setmode)(viddef_t *vid, struct vmode_s *pcurrentmode);
|
||||
void (*swapbuffers)(viddef_t *vid, struct vmode_s *pcurrentmode,
|
||||
vrect_t *rects);
|
||||
void (*setpalette)(viddef_t *vid, struct vmode_s *pcurrentmode,
|
||||
unsigned char *palette);
|
||||
void (*begindirectrect)(viddef_t *vid, struct vmode_s *pcurrentmode,
|
||||
int x, int y, byte *pbitmap, int width,
|
||||
int height);
|
||||
void (*enddirectrect)(viddef_t *vid, struct vmode_s *pcurrentmode,
|
||||
int x, int y, int width, int height);
|
||||
} vmode_t;
|
||||
|
||||
// vid_wait settings
|
||||
#define VID_WAIT_NONE 0
|
||||
#define VID_WAIT_VSYNC 1
|
||||
#define VID_WAIT_DISPLAY_ENABLE 2
|
||||
|
||||
extern int numvidmodes;
|
||||
extern vmode_t *pvidmodes;
|
||||
|
||||
extern int VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes;
|
||||
extern byte *VGA_pagebase;
|
||||
extern vmode_t *VGA_pcurmode;
|
||||
|
||||
extern cvar_t vid_wait;
|
||||
extern cvar_t vid_nopageflip;
|
||||
extern cvar_t _vid_wait_override;
|
||||
|
||||
extern unsigned char colormap256[32][256];
|
||||
|
||||
extern void *vid_surfcache;
|
||||
extern int vid_surfcachesize;
|
||||
|
||||
void VGA_Init (void);
|
||||
void VID_InitVESA (void);
|
||||
void VID_InitExtra (void);
|
||||
void VGA_WaitVsync (void);
|
||||
void VGA_ClearVideoMem (int planar);
|
||||
void VGA_SetPalette(viddef_t *vid, vmode_t *pcurrentmode, unsigned char *pal);
|
||||
void VGA_SwapBuffersCopy (viddef_t *vid, vmode_t *pcurrentmode,
|
||||
vrect_t *rects);
|
||||
qboolean VGA_FreeAndAllocVidbuffer (viddef_t *vid, int allocnewbuffer);
|
||||
qboolean VGA_CheckAdequateMem (int width, int height, int rowbytes,
|
||||
int allocnewbuffer);
|
||||
void VGA_BeginDirectRect (viddef_t *vid, struct vmode_s *pcurrentmode, int x,
|
||||
int y, byte *pbitmap, int width, int height);
|
||||
void VGA_EndDirectRect (viddef_t *vid, struct vmode_s *pcurrentmode, int x,
|
||||
int y, int width, int height);
|
||||
void VGA_UpdateLinearScreen (void *srcptr, void *destptr, int width,
|
||||
int height, int srcrowbytes, int destrowbytes);
|
||||
|
795
vid_ext.c
795
vid_ext.c
|
@ -1,795 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
//
|
||||
// vid_ext.c: extended video modes
|
||||
// in this implementation, VESA-specific DOS video stuff
|
||||
//
|
||||
|
||||
// TODO: make dependencies on vid_vga.c explicit or eliminate them
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <dos.h>
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "d_local.h"
|
||||
#include "dosisms.h"
|
||||
#include "vid_dos.h"
|
||||
#include <dpmi.h>
|
||||
|
||||
#define MODE_SUPPORTED_IN_HW 0x0001
|
||||
#define COLOR_MODE 0x0008
|
||||
#define GRAPHICS_MODE 0x0010
|
||||
#define VGA_INCOMPATIBLE 0x0020
|
||||
#define LINEAR_FRAME_BUFFER 0x0080
|
||||
|
||||
#define LINEAR_MODE 0x4000
|
||||
|
||||
#define VESA_DONT_WAIT_VSYNC 0 // when page flipping
|
||||
#define VESA_WAIT_VSYNC 0x80
|
||||
|
||||
#define MAX_VESA_MODES 30 // we'll just take the first 30 if there
|
||||
// are more
|
||||
typedef struct {
|
||||
int pages[3]; // either 2 or 3 is valid
|
||||
int vesamode; // LINEAR_MODE set if linear mode
|
||||
void *plinearmem; // linear address of start of frame buffer
|
||||
qboolean vga_incompatible;
|
||||
} vesa_extra_t;
|
||||
|
||||
static vmode_t vesa_modes[MAX_VESA_MODES] =
|
||||
{{NULL, NULL, " ********* VESA modes ********* "}};
|
||||
static vesa_extra_t vesa_extra[MAX_VESA_MODES];
|
||||
static char names[MAX_VESA_MODES][10];
|
||||
|
||||
extern regs_t regs;
|
||||
|
||||
static int VID_currentpage;
|
||||
static int VID_displayedpage;
|
||||
static int *VID_pagelist;
|
||||
static byte *VID_membase;
|
||||
static int VID_banked;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int modenum;
|
||||
int mode_attributes;
|
||||
int winasegment;
|
||||
int winbsegment;
|
||||
int bytes_per_scanline; // bytes per logical scanline (+16)
|
||||
int win; // window number (A=0, B=1)
|
||||
int win_size; // window size (+6)
|
||||
int granularity; // how finely i can set the window in vid mem (+4)
|
||||
int width, height; // displayed width and height (+18, +20)
|
||||
int bits_per_pixel; // er, better be 8, 15, 16, 24, or 32 (+25)
|
||||
int bytes_per_pixel; // er, better be 1, 2, or 4
|
||||
int memory_model; // and better be 4 or 6, packed or direct color (+27)
|
||||
int num_pages; // number of complete frame buffer pages (+29)
|
||||
int red_width; // the # of bits in the red component (+31)
|
||||
int red_pos; // the bit position of the red component (+32)
|
||||
int green_width; // etc.. (+33)
|
||||
int green_pos; // (+34)
|
||||
int blue_width; // (+35)
|
||||
int blue_pos; // (+36)
|
||||
int pptr;
|
||||
int pagesize;
|
||||
int numpages;
|
||||
} modeinfo_t;
|
||||
|
||||
static modeinfo_t modeinfo;
|
||||
|
||||
// all bytes to avoid problems with compiler field packing
|
||||
typedef struct vbeinfoblock_s {
|
||||
byte VbeSignature[4];
|
||||
byte VbeVersion[2];
|
||||
byte OemStringPtr[4];
|
||||
byte Capabilities[4];
|
||||
byte VideoModePtr[4];
|
||||
byte TotalMemory[2];
|
||||
byte OemSoftwareRev[2];
|
||||
byte OemVendorNamePtr[4];
|
||||
byte OemProductNamePtr[4];
|
||||
byte OemProductRevPtr[4];
|
||||
byte Reserved[222];
|
||||
byte OemData[256];
|
||||
} vbeinfoblock_t;
|
||||
|
||||
static int totalvidmem;
|
||||
static byte *ppal;
|
||||
qboolean vsync_exists, de_exists;
|
||||
|
||||
qboolean VID_ExtraGetModeInfo(int modenum);
|
||||
int VID_ExtraInitMode (viddef_t *vid, vmode_t *pcurrentmode);
|
||||
void VID_ExtraSwapBuffers (viddef_t *vid, vmode_t *pcurrentmode,
|
||||
vrect_t *rects);
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VGA_BankedBeginDirectRect
|
||||
================
|
||||
*/
|
||||
void VGA_BankedBeginDirectRect (viddef_t *lvid, struct vmode_s *pcurrentmode,
|
||||
int x, int y, byte *pbitmap, int width, int height)
|
||||
{
|
||||
|
||||
if (!lvid->direct)
|
||||
return;
|
||||
|
||||
regs.x.ax = 0x4f05;
|
||||
regs.x.bx = 0;
|
||||
regs.x.dx = VID_displayedpage;
|
||||
dos_int86(0x10);
|
||||
|
||||
VGA_BeginDirectRect (lvid, pcurrentmode, x, y, pbitmap, width, height);
|
||||
|
||||
regs.x.ax = 0x4f05;
|
||||
regs.x.bx = 0;
|
||||
regs.x.dx = VID_currentpage;
|
||||
dos_int86(0x10);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VGA_BankedEndDirectRect
|
||||
================
|
||||
*/
|
||||
void VGA_BankedEndDirectRect (viddef_t *lvid, struct vmode_s *pcurrentmode,
|
||||
int x, int y, int width, int height)
|
||||
{
|
||||
|
||||
if (!lvid->direct)
|
||||
return;
|
||||
|
||||
regs.x.ax = 0x4f05;
|
||||
regs.x.bx = 0;
|
||||
regs.x.dx = VID_displayedpage;
|
||||
dos_int86(0x10);
|
||||
|
||||
VGA_EndDirectRect (lvid, pcurrentmode, x, y, width, height);
|
||||
|
||||
regs.x.ax = 0x4f05;
|
||||
regs.x.bx = 0;
|
||||
regs.x.dx = VID_currentpage;
|
||||
dos_int86(0x10);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VID_SetVESAPalette
|
||||
================
|
||||
*/
|
||||
void VID_SetVESAPalette (viddef_t *lvid, vmode_t *pcurrentmode,
|
||||
unsigned char *pal)
|
||||
{
|
||||
int i;
|
||||
byte *pp;
|
||||
|
||||
UNUSED(lvid);
|
||||
UNUSED(pcurrentmode);
|
||||
|
||||
pp = ppal;
|
||||
|
||||
for (i=0 ; i<256 ; i++)
|
||||
{
|
||||
pp[2] = pal[0] >> 2;
|
||||
pp[1] = pal[1] >> 2;
|
||||
pp[0] = pal[2] >> 2;
|
||||
pp += 4;
|
||||
pal += 3;
|
||||
}
|
||||
|
||||
regs.x.ax = 0x4F09;
|
||||
regs.x.bx = 0;
|
||||
regs.x.cx = 256;
|
||||
regs.x.dx = 0;
|
||||
regs.x.es = ptr2real(ppal) >> 4;
|
||||
regs.x.di = ptr2real(ppal) & 0xf;
|
||||
dos_int86(0x10);
|
||||
|
||||
if (regs.x.ax != 0x4f)
|
||||
Sys_Error ("Unable to load VESA palette\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VID_ExtraFarToLinear
|
||||
================
|
||||
*/
|
||||
void *VID_ExtraFarToLinear (void *ptr)
|
||||
{
|
||||
int temp;
|
||||
|
||||
temp = (int)ptr;
|
||||
return real2ptr(((temp & 0xFFFF0000) >> 12) + (temp & 0xFFFF));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VID_ExtraWaitDisplayEnable
|
||||
================
|
||||
*/
|
||||
void VID_ExtraWaitDisplayEnable ()
|
||||
{
|
||||
while ((inportb (0x3DA) & 0x01) == 1)
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VID_ExtraVidLookForState
|
||||
================
|
||||
*/
|
||||
qboolean VID_ExtraVidLookForState (unsigned state, unsigned mask)
|
||||
{
|
||||
int i;
|
||||
double starttime, time;
|
||||
|
||||
starttime = Sys_FloatTime ();
|
||||
|
||||
do
|
||||
{
|
||||
for (i=0 ; i<100000 ; i++)
|
||||
{
|
||||
if ((inportb (0x3DA) & mask) == state)
|
||||
return true;
|
||||
}
|
||||
|
||||
time = Sys_FloatTime ();
|
||||
} while ((time - starttime) < 0.1);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VID_ExtraStateFound
|
||||
================
|
||||
*/
|
||||
qboolean VID_ExtraStateFound (unsigned state)
|
||||
{
|
||||
int i, workingstate;
|
||||
|
||||
workingstate = 0;
|
||||
|
||||
for (i=0 ; i<10 ; i++)
|
||||
{
|
||||
if (!VID_ExtraVidLookForState(workingstate, state))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
workingstate ^= state;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VID_InitExtra
|
||||
================
|
||||
*/
|
||||
void VID_InitExtra (void)
|
||||
{
|
||||
int nummodes;
|
||||
short *pmodenums;
|
||||
vbeinfoblock_t *pinfoblock;
|
||||
__dpmi_meminfo phys_mem_info;
|
||||
|
||||
pinfoblock = dos_getmemory(sizeof(vbeinfoblock_t));
|
||||
|
||||
*(long *)pinfoblock->VbeSignature = 'V' + ('B'<<8) + ('E'<<16) + ('2'<<24);
|
||||
|
||||
// see if VESA support is available
|
||||
regs.x.ax = 0x4f00;
|
||||
regs.x.es = ptr2real(pinfoblock) >> 4;
|
||||
regs.x.di = ptr2real(pinfoblock) & 0xf;
|
||||
dos_int86(0x10);
|
||||
|
||||
if (regs.x.ax != 0x4f)
|
||||
return; // no VESA support
|
||||
|
||||
if (pinfoblock->VbeVersion[1] < 0x02)
|
||||
return; // not VESA 2.0 or greater
|
||||
|
||||
Con_Printf ("VESA 2.0 compliant adapter:\n%s\n",
|
||||
VID_ExtraFarToLinear (*(byte **)&pinfoblock->OemStringPtr[0]));
|
||||
|
||||
totalvidmem = *(unsigned short *)&pinfoblock->TotalMemory[0] << 16;
|
||||
|
||||
pmodenums = (short *)
|
||||
VID_ExtraFarToLinear (*(byte **)&pinfoblock->VideoModePtr[0]);
|
||||
|
||||
// find 8 bit modes until we either run out of space or run out of modes
|
||||
nummodes = 0;
|
||||
|
||||
while ((*pmodenums != -1) && (nummodes < MAX_VESA_MODES))
|
||||
{
|
||||
if (VID_ExtraGetModeInfo (*pmodenums))
|
||||
{
|
||||
vesa_modes[nummodes].pnext = &vesa_modes[nummodes+1];
|
||||
if (modeinfo.width > 999)
|
||||
{
|
||||
if (modeinfo.height > 999)
|
||||
{
|
||||
sprintf (&names[nummodes][0], "%4dx%4d", modeinfo.width,
|
||||
modeinfo.height);
|
||||
names[nummodes][9] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (&names[nummodes][0], "%4dx%3d", modeinfo.width,
|
||||
modeinfo.height);
|
||||
names[nummodes][8] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (modeinfo.height > 999)
|
||||
{
|
||||
sprintf (&names[nummodes][0], "%3dx%4d", modeinfo.width,
|
||||
modeinfo.height);
|
||||
names[nummodes][8] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (&names[nummodes][0], "%3dx%3d", modeinfo.width,
|
||||
modeinfo.height);
|
||||
names[nummodes][7] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
vesa_modes[nummodes].name = &names[nummodes][0];
|
||||
vesa_modes[nummodes].width = modeinfo.width;
|
||||
vesa_modes[nummodes].height = modeinfo.height;
|
||||
vesa_modes[nummodes].aspect =
|
||||
((float)modeinfo.height / (float)modeinfo.width) *
|
||||
(320.0 / 240.0);
|
||||
vesa_modes[nummodes].rowbytes = modeinfo.bytes_per_scanline;
|
||||
vesa_modes[nummodes].planar = 0;
|
||||
vesa_modes[nummodes].pextradata = &vesa_extra[nummodes];
|
||||
vesa_modes[nummodes].setmode = VID_ExtraInitMode;
|
||||
vesa_modes[nummodes].swapbuffers = VID_ExtraSwapBuffers;
|
||||
vesa_modes[nummodes].setpalette = VID_SetVESAPalette;
|
||||
|
||||
if (modeinfo.mode_attributes & LINEAR_FRAME_BUFFER)
|
||||
{
|
||||
// add linear bit to mode for linear modes
|
||||
vesa_extra[nummodes].vesamode = modeinfo.modenum | LINEAR_MODE;
|
||||
vesa_extra[nummodes].pages[0] = 0;
|
||||
vesa_extra[nummodes].pages[1] = modeinfo.pagesize;
|
||||
vesa_extra[nummodes].pages[2] = modeinfo.pagesize * 2;
|
||||
vesa_modes[nummodes].numpages = modeinfo.numpages;
|
||||
|
||||
vesa_modes[nummodes].begindirectrect = VGA_BeginDirectRect;
|
||||
vesa_modes[nummodes].enddirectrect = VGA_EndDirectRect;
|
||||
|
||||
phys_mem_info.address = (int)modeinfo.pptr;
|
||||
phys_mem_info.size = 0x400000;
|
||||
|
||||
if (__dpmi_physical_address_mapping(&phys_mem_info))
|
||||
goto NextMode;
|
||||
|
||||
vesa_extra[nummodes].plinearmem =
|
||||
real2ptr (phys_mem_info.address);
|
||||
}
|
||||
else
|
||||
{
|
||||
// banked at 0xA0000
|
||||
vesa_extra[nummodes].vesamode = modeinfo.modenum;
|
||||
vesa_extra[nummodes].pages[0] = 0;
|
||||
vesa_extra[nummodes].plinearmem =
|
||||
real2ptr(modeinfo.winasegment<<4);
|
||||
|
||||
vesa_modes[nummodes].begindirectrect =
|
||||
VGA_BankedBeginDirectRect;
|
||||
vesa_modes[nummodes].enddirectrect = VGA_BankedEndDirectRect;
|
||||
vesa_extra[nummodes].pages[1] = modeinfo.pagesize;
|
||||
vesa_extra[nummodes].pages[2] = modeinfo.pagesize * 2;
|
||||
vesa_modes[nummodes].numpages = modeinfo.numpages;
|
||||
}
|
||||
|
||||
vesa_extra[nummodes].vga_incompatible =
|
||||
modeinfo.mode_attributes & VGA_INCOMPATIBLE;
|
||||
|
||||
nummodes++;
|
||||
}
|
||||
NextMode:
|
||||
pmodenums++;
|
||||
}
|
||||
|
||||
// add the VESA modes at the start of the mode list (if there are any)
|
||||
if (nummodes)
|
||||
{
|
||||
vesa_modes[nummodes-1].pnext = pvidmodes;
|
||||
pvidmodes = &vesa_modes[0];
|
||||
numvidmodes += nummodes;
|
||||
ppal = dos_getmemory(256*4);
|
||||
}
|
||||
|
||||
dos_freememory(pinfoblock);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VID_ExtraGetModeInfo
|
||||
================
|
||||
*/
|
||||
qboolean VID_ExtraGetModeInfo(int modenum)
|
||||
{
|
||||
char *infobuf;
|
||||
int numimagepages;
|
||||
|
||||
infobuf = dos_getmemory(256);
|
||||
|
||||
regs.x.ax = 0x4f01;
|
||||
regs.x.cx = modenum;
|
||||
regs.x.es = ptr2real(infobuf) >> 4;
|
||||
regs.x.di = ptr2real(infobuf) & 0xf;
|
||||
dos_int86(0x10);
|
||||
if (regs.x.ax != 0x4f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
modeinfo.modenum = modenum;
|
||||
modeinfo.bits_per_pixel = *(char*)(infobuf+25);
|
||||
modeinfo.bytes_per_pixel = (modeinfo.bits_per_pixel+1)/8;
|
||||
modeinfo.width = *(short*)(infobuf+18);
|
||||
modeinfo.height = *(short*)(infobuf+20);
|
||||
|
||||
// we do only 8-bpp in software
|
||||
if ((modeinfo.bits_per_pixel != 8) ||
|
||||
(modeinfo.bytes_per_pixel != 1) ||
|
||||
(modeinfo.width > MAXWIDTH) ||
|
||||
(modeinfo.height > MAXHEIGHT))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
modeinfo.mode_attributes = *(short*)infobuf;
|
||||
|
||||
// we only want color graphics modes that are supported by the hardware
|
||||
if ((modeinfo.mode_attributes &
|
||||
(MODE_SUPPORTED_IN_HW | COLOR_MODE | GRAPHICS_MODE)) !=
|
||||
(MODE_SUPPORTED_IN_HW | COLOR_MODE | GRAPHICS_MODE))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// we only work with linear frame buffers, except for 320x200, which can
|
||||
// effectively be linear when banked at 0xA000
|
||||
if (!(modeinfo.mode_attributes & LINEAR_FRAME_BUFFER))
|
||||
{
|
||||
if ((modeinfo.width != 320) || (modeinfo.height != 200))
|
||||
return false;
|
||||
}
|
||||
|
||||
modeinfo.bytes_per_scanline = *(short*)(infobuf+16);
|
||||
|
||||
modeinfo.pagesize = modeinfo.bytes_per_scanline * modeinfo.height;
|
||||
|
||||
if (modeinfo.pagesize > totalvidmem)
|
||||
return false;
|
||||
|
||||
// force to one page if the adapter reports it doesn't support more pages
|
||||
// than that, no matter how much memory it has--it may not have hardware
|
||||
// support for page flipping
|
||||
numimagepages = *(unsigned char *)(infobuf+29);
|
||||
|
||||
if (numimagepages <= 0)
|
||||
{
|
||||
// wrong, but there seems to be an ATI VESA driver that reports 0
|
||||
modeinfo.numpages = 1;
|
||||
}
|
||||
else if (numimagepages < 3)
|
||||
{
|
||||
modeinfo.numpages = numimagepages;
|
||||
}
|
||||
else
|
||||
{
|
||||
modeinfo.numpages = 3;
|
||||
}
|
||||
|
||||
if (*(char*)(infobuf+2) & 5)
|
||||
{
|
||||
modeinfo.winasegment = *(unsigned short*)(infobuf+8);
|
||||
modeinfo.win = 0;
|
||||
}
|
||||
else if (*(char*)(infobuf+3) & 5)
|
||||
{
|
||||
modeinfo.winbsegment = *(unsigned short*)(infobuf+8);
|
||||
modeinfo.win = 1;
|
||||
}
|
||||
modeinfo.granularity = *(short*)(infobuf+4) * 1024;
|
||||
modeinfo.win_size = *(short*)(infobuf+6) * 1024;
|
||||
modeinfo.bits_per_pixel = *(char*)(infobuf+25);
|
||||
modeinfo.bytes_per_pixel = (modeinfo.bits_per_pixel+1)/8;
|
||||
modeinfo.memory_model = *(unsigned char*)(infobuf+27);
|
||||
modeinfo.num_pages = *(char*)(infobuf+29) + 1;
|
||||
|
||||
modeinfo.red_width = *(char*)(infobuf+31);
|
||||
modeinfo.red_pos = *(char*)(infobuf+32);
|
||||
modeinfo.green_width = *(char*)(infobuf+33);
|
||||
modeinfo.green_pos = *(char*)(infobuf+34);
|
||||
modeinfo.blue_width = *(char*)(infobuf+35);
|
||||
modeinfo.blue_pos = *(char*)(infobuf+36);
|
||||
|
||||
modeinfo.pptr = *(long *)(infobuf+40);
|
||||
|
||||
#if 0
|
||||
printf("VID: (VESA) info for mode 0x%x\n", modeinfo.modenum);
|
||||
printf(" mode attrib = 0x%0x\n", modeinfo.mode_attributes);
|
||||
printf(" win a attrib = 0x%0x\n", *(unsigned char*)(infobuf+2));
|
||||
printf(" win b attrib = 0x%0x\n", *(unsigned char*)(infobuf+3));
|
||||
printf(" win a seg 0x%0x\n", (int) modeinfo.winasegment);
|
||||
printf(" win b seg 0x%0x\n", (int) modeinfo.winbsegment);
|
||||
printf(" bytes per scanline = %d\n",
|
||||
modeinfo.bytes_per_scanline);
|
||||
printf(" width = %d, height = %d\n", modeinfo.width,
|
||||
modeinfo.height);
|
||||
printf(" win = %c\n", 'A' + modeinfo.win);
|
||||
printf(" win granularity = %d\n", modeinfo.granularity);
|
||||
printf(" win size = %d\n", modeinfo.win_size);
|
||||
printf(" bits per pixel = %d\n", modeinfo.bits_per_pixel);
|
||||
printf(" bytes per pixel = %d\n", modeinfo.bytes_per_pixel);
|
||||
printf(" memory model = 0x%x\n", modeinfo.memory_model);
|
||||
printf(" num pages = %d\n", modeinfo.num_pages);
|
||||
printf(" red width = %d\n", modeinfo.red_width);
|
||||
printf(" red pos = %d\n", modeinfo.red_pos);
|
||||
printf(" green width = %d\n", modeinfo.green_width);
|
||||
printf(" green pos = %d\n", modeinfo.green_pos);
|
||||
printf(" blue width = %d\n", modeinfo.blue_width);
|
||||
printf(" blue pos = %d\n", modeinfo.blue_pos);
|
||||
printf(" phys mem = %x\n", modeinfo.pptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
dos_freememory(infobuf);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VID_ExtraInitMode
|
||||
================
|
||||
*/
|
||||
int VID_ExtraInitMode (viddef_t *lvid, vmode_t *pcurrentmode)
|
||||
{
|
||||
vesa_extra_t *pextra;
|
||||
int pageoffset;
|
||||
|
||||
pextra = pcurrentmode->pextradata;
|
||||
|
||||
if (vid_nopageflip.value)
|
||||
lvid->numpages = 1;
|
||||
else
|
||||
lvid->numpages = pcurrentmode->numpages;
|
||||
|
||||
// clean up any old vid buffer lying around, alloc new if needed
|
||||
if (!VGA_FreeAndAllocVidbuffer (lvid, lvid->numpages == 1))
|
||||
return -1; // memory alloc failed
|
||||
|
||||
// clear the screen and wait for the next frame. VGA_pcurmode, which
|
||||
// VGA_ClearVideoMem relies on, is guaranteed to be set because mode 0 is
|
||||
// always the first mode set in a session
|
||||
if (VGA_pcurmode)
|
||||
VGA_ClearVideoMem (VGA_pcurmode->planar);
|
||||
|
||||
// set the mode
|
||||
regs.x.ax = 0x4f02;
|
||||
regs.x.bx = pextra->vesamode;
|
||||
dos_int86(0x10);
|
||||
|
||||
if (regs.x.ax != 0x4f)
|
||||
return 0;
|
||||
|
||||
VID_banked = !(pextra->vesamode & LINEAR_MODE);
|
||||
VID_membase = pextra->plinearmem;
|
||||
VGA_width = lvid->width;
|
||||
VGA_height = lvid->height;
|
||||
VGA_rowbytes = lvid->rowbytes;
|
||||
|
||||
lvid->colormap = host_colormap;
|
||||
|
||||
VID_pagelist = &pextra->pages[0];
|
||||
|
||||
// wait for display enable by default only when triple-buffering on a VGA-
|
||||
// compatible machine that actually has a functioning display enable status
|
||||
vsync_exists = VID_ExtraStateFound (0x08);
|
||||
de_exists = VID_ExtraStateFound (0x01);
|
||||
|
||||
if (!pextra->vga_incompatible &&
|
||||
(lvid->numpages == 3) &&
|
||||
de_exists &&
|
||||
(_vid_wait_override.value == 0.0))
|
||||
{
|
||||
Cvar_SetValue ("vid_wait", (float)VID_WAIT_DISPLAY_ENABLE);
|
||||
|
||||
VID_displayedpage = 0;
|
||||
VID_currentpage = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((lvid->numpages == 1) && (_vid_wait_override.value == 0.0))
|
||||
{
|
||||
Cvar_SetValue ("vid_wait", (float)VID_WAIT_NONE);
|
||||
VID_displayedpage = VID_currentpage = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Cvar_SetValue ("vid_wait", (float)VID_WAIT_VSYNC);
|
||||
|
||||
VID_displayedpage = 0;
|
||||
|
||||
if (lvid->numpages > 1)
|
||||
VID_currentpage = 1;
|
||||
else
|
||||
VID_currentpage = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: really should be a call to a function
|
||||
pageoffset = VID_pagelist[VID_displayedpage];
|
||||
|
||||
regs.x.ax = 0x4f07;
|
||||
regs.x.bx = 0x80; // wait for vsync so we know page 0 is visible
|
||||
regs.x.cx = pageoffset % VGA_rowbytes;
|
||||
regs.x.dx = pageoffset / VGA_rowbytes;
|
||||
dos_int86(0x10);
|
||||
|
||||
if (VID_banked)
|
||||
{
|
||||
regs.x.ax = 0x4f05;
|
||||
regs.x.bx = 0;
|
||||
regs.x.dx = VID_currentpage;
|
||||
dos_int86(0x10);
|
||||
|
||||
VGA_pagebase = VID_membase;
|
||||
}
|
||||
else
|
||||
{
|
||||
VGA_pagebase = VID_membase + VID_pagelist[VID_currentpage];
|
||||
}
|
||||
|
||||
if (lvid->numpages > 1)
|
||||
{
|
||||
lvid->buffer = VGA_pagebase;
|
||||
lvid->conbuffer = lvid->buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
lvid->rowbytes = lvid->width;
|
||||
}
|
||||
|
||||
lvid->direct = VGA_pagebase;
|
||||
lvid->conrowbytes = lvid->rowbytes;
|
||||
lvid->conwidth = lvid->width;
|
||||
lvid->conheight = lvid->height;
|
||||
|
||||
lvid->maxwarpwidth = WARP_WIDTH;
|
||||
lvid->maxwarpheight = WARP_HEIGHT;
|
||||
|
||||
VGA_pcurmode = pcurrentmode;
|
||||
|
||||
D_InitCaches (vid_surfcache, vid_surfcachesize);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VID_ExtraSwapBuffers
|
||||
================
|
||||
*/
|
||||
void VID_ExtraSwapBuffers (viddef_t *lvid, vmode_t *pcurrentmode,
|
||||
vrect_t *rects)
|
||||
{
|
||||
int pageoffset;
|
||||
|
||||
UNUSED(rects);
|
||||
UNUSED(pcurrentmode);
|
||||
|
||||
pageoffset = VID_pagelist[VID_currentpage];
|
||||
|
||||
// display the newly finished page
|
||||
if (lvid->numpages > 1)
|
||||
{
|
||||
// page flipped
|
||||
regs.x.ax = 0x4f07;
|
||||
|
||||
if (vid_wait.value != VID_WAIT_VSYNC)
|
||||
{
|
||||
if ((vid_wait.value == VID_WAIT_DISPLAY_ENABLE) && de_exists)
|
||||
VID_ExtraWaitDisplayEnable ();
|
||||
|
||||
regs.x.bx = VESA_DONT_WAIT_VSYNC;
|
||||
}
|
||||
else
|
||||
{
|
||||
regs.x.bx = VESA_WAIT_VSYNC; // double buffered has to wait
|
||||
}
|
||||
|
||||
regs.x.cx = pageoffset % VGA_rowbytes;
|
||||
regs.x.dx = pageoffset / VGA_rowbytes;
|
||||
dos_int86(0x10);
|
||||
|
||||
VID_displayedpage = VID_currentpage;
|
||||
if (++VID_currentpage >= lvid->numpages)
|
||||
VID_currentpage = 0;
|
||||
|
||||
//
|
||||
// set the new write window if this is a banked mode; otherwise, set the
|
||||
// new address to which to write
|
||||
//
|
||||
if (VID_banked)
|
||||
{
|
||||
regs.x.ax = 0x4f05;
|
||||
regs.x.bx = 0;
|
||||
regs.x.dx = VID_currentpage;
|
||||
dos_int86(0x10);
|
||||
}
|
||||
else
|
||||
{
|
||||
lvid->direct = lvid->buffer; // direct drawing goes to the
|
||||
// currently displayed page
|
||||
lvid->buffer = VID_membase + VID_pagelist[VID_currentpage];
|
||||
lvid->conbuffer = lvid->buffer;
|
||||
}
|
||||
|
||||
VGA_pagebase = lvid->buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
// non-page-flipped
|
||||
if (vsync_exists && (vid_wait.value == VID_WAIT_VSYNC))
|
||||
{
|
||||
VGA_WaitVsync ();
|
||||
}
|
||||
|
||||
while (rects)
|
||||
{
|
||||
VGA_UpdateLinearScreen (
|
||||
lvid->buffer + rects->x + (rects->y * lvid->rowbytes),
|
||||
VGA_pagebase + rects->x + (rects->y * VGA_rowbytes),
|
||||
rects->width,
|
||||
rects->height,
|
||||
lvid->rowbytes,
|
||||
VGA_rowbytes);
|
||||
|
||||
rects = rects->pnext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
1257
vid_sunx.c
1257
vid_sunx.c
File diff suppressed because it is too large
Load diff
1288
vid_sunxil.c
1288
vid_sunxil.c
File diff suppressed because it is too large
Load diff
1003
vid_svgalib.c
1003
vid_svgalib.c
File diff suppressed because it is too large
Load diff
478
vid_vga.c
478
vid_vga.c
|
@ -1,478 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
//
|
||||
// vid_vga.c: VGA-specific DOS video stuff
|
||||
//
|
||||
|
||||
// TODO: proper handling of page-swap failure
|
||||
|
||||
#include <dos.h>
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "d_local.h"
|
||||
#include "dosisms.h"
|
||||
#include "vid_dos.h"
|
||||
#include <dpmi.h>
|
||||
|
||||
extern regs_t regs;
|
||||
|
||||
int VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes;
|
||||
byte *VGA_pagebase;
|
||||
vmode_t *VGA_pcurmode;
|
||||
|
||||
static int VGA_planar;
|
||||
static int VGA_numpages;
|
||||
static int VGA_buffersize;
|
||||
|
||||
void *vid_surfcache;
|
||||
int vid_surfcachesize;
|
||||
|
||||
int VGA_highhunkmark;
|
||||
|
||||
#include "vgamodes.h"
|
||||
|
||||
#define NUMVIDMODES (sizeof(vgavidmodes) / sizeof(vgavidmodes[0]))
|
||||
|
||||
void VGA_UpdatePlanarScreen (void *srcbuffer);
|
||||
|
||||
static byte backingbuf[48*24];
|
||||
|
||||
/*
|
||||
================
|
||||
VGA_BeginDirectRect
|
||||
================
|
||||
*/
|
||||
void VGA_BeginDirectRect (viddef_t *lvid, struct vmode_s *pcurrentmode, int x,
|
||||
int y, byte *pbitmap, int width, int height)
|
||||
{
|
||||
int i, j, k, plane, reps, repshift;
|
||||
|
||||
if (!lvid->direct)
|
||||
return;
|
||||
|
||||
if (lvid->aspect > 1.5)
|
||||
{
|
||||
reps = 2;
|
||||
repshift = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
reps = 1;
|
||||
repshift = 0;
|
||||
}
|
||||
|
||||
if (pcurrentmode->planar)
|
||||
{
|
||||
for (plane=0 ; plane<4 ; plane++)
|
||||
{
|
||||
// select the correct plane for reading and writing
|
||||
outportb (SC_INDEX, MAP_MASK);
|
||||
outportb (SC_DATA, 1 << plane);
|
||||
outportb (GC_INDEX, READ_MAP);
|
||||
outportb (GC_DATA, plane);
|
||||
|
||||
for (i=0 ; i<(height << repshift) ; i += reps)
|
||||
{
|
||||
for (k=0 ; k<reps ; k++)
|
||||
{
|
||||
for (j=0 ; j<(width >> 2) ; j++)
|
||||
{
|
||||
backingbuf[(i + k) * 24 + (j << 2) + plane] =
|
||||
lvid->direct[(y + i + k) * VGA_rowbytes +
|
||||
(x >> 2) + j];
|
||||
lvid->direct[(y + i + k) * VGA_rowbytes + (x>>2) + j] =
|
||||
pbitmap[(i >> repshift) * 24 +
|
||||
(j << 2) + plane];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=0 ; i<(height << repshift) ; i += reps)
|
||||
{
|
||||
for (j=0 ; j<reps ; j++)
|
||||
{
|
||||
memcpy (&backingbuf[(i + j) * 24],
|
||||
lvid->direct + x + ((y << repshift) + i + j) *
|
||||
VGA_rowbytes,
|
||||
width);
|
||||
memcpy (lvid->direct + x + ((y << repshift) + i + j) *
|
||||
VGA_rowbytes,
|
||||
&pbitmap[(i >> repshift) * width],
|
||||
width);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VGA_EndDirectRect
|
||||
================
|
||||
*/
|
||||
void VGA_EndDirectRect (viddef_t *lvid, struct vmode_s *pcurrentmode, int x,
|
||||
int y, int width, int height)
|
||||
{
|
||||
int i, j, k, plane, reps, repshift;
|
||||
|
||||
if (!lvid->direct)
|
||||
return;
|
||||
|
||||
if (lvid->aspect > 1.5)
|
||||
{
|
||||
reps = 2;
|
||||
repshift = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
reps = 1;
|
||||
repshift = 0;
|
||||
}
|
||||
|
||||
if (pcurrentmode->planar)
|
||||
{
|
||||
for (plane=0 ; plane<4 ; plane++)
|
||||
{
|
||||
// select the correct plane for writing
|
||||
outportb (SC_INDEX, MAP_MASK);
|
||||
outportb (SC_DATA, 1 << plane);
|
||||
|
||||
for (i=0 ; i<(height << repshift) ; i += reps)
|
||||
{
|
||||
for (k=0 ; k<reps ; k++)
|
||||
{
|
||||
for (j=0 ; j<(width >> 2) ; j++)
|
||||
{
|
||||
lvid->direct[(y + i + k) * VGA_rowbytes + (x>>2) + j] =
|
||||
backingbuf[(i + k) * 24 + (j << 2) + plane];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=0 ; i<(height << repshift) ; i += reps)
|
||||
{
|
||||
for (j=0 ; j<reps ; j++)
|
||||
{
|
||||
memcpy (lvid->direct + x + ((y << repshift) + i + j) *
|
||||
VGA_rowbytes,
|
||||
&backingbuf[(i + j) * 24],
|
||||
width);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VGA_Init
|
||||
================
|
||||
*/
|
||||
void VGA_Init (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
// link together all the VGA modes
|
||||
for (i=0 ; i<(NUMVIDMODES - 1) ; i++)
|
||||
{
|
||||
vgavidmodes[i].pnext = &vgavidmodes[i+1];
|
||||
}
|
||||
|
||||
// add the VGA modes at the start of the mode list
|
||||
vgavidmodes[NUMVIDMODES-1].pnext = pvidmodes;
|
||||
pvidmodes = &vgavidmodes[0];
|
||||
|
||||
numvidmodes += NUMVIDMODES;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VGA_WaitVsync
|
||||
================
|
||||
*/
|
||||
void VGA_WaitVsync (void)
|
||||
{
|
||||
while ((inportb (0x3DA) & 0x08) == 0)
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VGA_ClearVideoMem
|
||||
================
|
||||
*/
|
||||
void VGA_ClearVideoMem (int planar)
|
||||
{
|
||||
|
||||
if (planar)
|
||||
{
|
||||
// enable all planes for writing
|
||||
outportb (SC_INDEX, MAP_MASK);
|
||||
outportb (SC_DATA, 0x0F);
|
||||
}
|
||||
|
||||
Q_memset (VGA_pagebase, 0, VGA_rowbytes * VGA_height);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
VGA_FreeAndAllocVidbuffer
|
||||
================
|
||||
*/
|
||||
qboolean VGA_FreeAndAllocVidbuffer (viddef_t *lvid, int allocnewbuffer)
|
||||
{
|
||||
int tsize, tbuffersize;
|
||||
|
||||
if (allocnewbuffer)
|
||||
{
|
||||
// alloc an extra line in case we want to wrap, and allocate the z-buffer
|
||||
tbuffersize = (lvid->rowbytes * (lvid->height + 1)) +
|
||||
(lvid->width * lvid->height * sizeof (*d_pzbuffer));
|
||||
}
|
||||
else
|
||||
{
|
||||
// just allocate the z-buffer
|
||||
tbuffersize = lvid->width * lvid->height * sizeof (*d_pzbuffer);
|
||||
}
|
||||
|
||||
tsize = D_SurfaceCacheForRes (lvid->width, lvid->height);
|
||||
|
||||
tbuffersize += tsize;
|
||||
|
||||
// see if there's enough memory, allowing for the normal mode 0x13 pixel,
|
||||
// z, and surface buffers
|
||||
if ((host_parms.memsize - tbuffersize + SURFCACHE_SIZE_AT_320X200 +
|
||||
0x10000 * 3) < minimum_memory)
|
||||
{
|
||||
Con_Printf ("Not enough memory for video mode\n");
|
||||
VGA_pcurmode = NULL; // so no further accesses to the buffer are
|
||||
// attempted, particularly when clearing
|
||||
return false; // not enough memory for mode
|
||||
}
|
||||
|
||||
VGA_buffersize = tbuffersize;
|
||||
vid_surfcachesize = tsize;
|
||||
|
||||
if (d_pzbuffer)
|
||||
{
|
||||
D_FlushCaches ();
|
||||
Hunk_FreeToHighMark (VGA_highhunkmark);
|
||||
d_pzbuffer = NULL;
|
||||
}
|
||||
|
||||
VGA_highhunkmark = Hunk_HighMark ();
|
||||
|
||||
d_pzbuffer = Hunk_HighAllocName (VGA_buffersize, "video");
|
||||
|
||||
vid_surfcache = (byte *)d_pzbuffer
|
||||
+ lvid->width * lvid->height * sizeof (*d_pzbuffer);
|
||||
|
||||
if (allocnewbuffer)
|
||||
{
|
||||
lvid->buffer = (void *)( (byte *)vid_surfcache + vid_surfcachesize);
|
||||
lvid->conbuffer = lvid->buffer;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VGA_CheckAdequateMem
|
||||
================
|
||||
*/
|
||||
qboolean VGA_CheckAdequateMem (int width, int height, int rowbytes,
|
||||
int allocnewbuffer)
|
||||
{
|
||||
int tbuffersize;
|
||||
|
||||
tbuffersize = width * height * sizeof (*d_pzbuffer);
|
||||
|
||||
if (allocnewbuffer)
|
||||
{
|
||||
// alloc an extra line in case we want to wrap, and allocate the z-buffer
|
||||
tbuffersize += (rowbytes * (height + 1));
|
||||
}
|
||||
|
||||
tbuffersize += D_SurfaceCacheForRes (width, height);
|
||||
|
||||
// see if there's enough memory, allowing for the normal mode 0x13 pixel,
|
||||
// z, and surface buffers
|
||||
if ((host_parms.memsize - tbuffersize + SURFCACHE_SIZE_AT_320X200 +
|
||||
0x10000 * 3) < minimum_memory)
|
||||
{
|
||||
return false; // not enough memory for mode
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VGA_InitMode
|
||||
================
|
||||
*/
|
||||
int VGA_InitMode (viddef_t *lvid, vmode_t *pcurrentmode)
|
||||
{
|
||||
vextra_t *pextra;
|
||||
|
||||
pextra = pcurrentmode->pextradata;
|
||||
|
||||
if (!VGA_FreeAndAllocVidbuffer (lvid, pextra->vidbuffer))
|
||||
return -1; // memory alloc failed
|
||||
|
||||
if (VGA_pcurmode)
|
||||
VGA_ClearVideoMem (VGA_pcurmode->planar);
|
||||
|
||||
// mode 0x13 is the base for all the Mode X-class mode sets
|
||||
regs.h.ah = 0;
|
||||
regs.h.al = 0x13;
|
||||
dos_int86(0x10);
|
||||
|
||||
VGA_pagebase = (void *)real2ptr(0xa0000);
|
||||
lvid->direct = (pixel_t *)VGA_pagebase;
|
||||
|
||||
// set additional registers as needed
|
||||
VideoRegisterSet (pextra->pregset);
|
||||
|
||||
VGA_numpages = 1;
|
||||
lvid->numpages = VGA_numpages;
|
||||
|
||||
VGA_width = (lvid->width + 0x1F) & ~0x1F;
|
||||
VGA_height = lvid->height;
|
||||
VGA_planar = pcurrentmode->planar;
|
||||
if (VGA_planar)
|
||||
VGA_rowbytes = lvid->rowbytes / 4;
|
||||
else
|
||||
VGA_rowbytes = lvid->rowbytes;
|
||||
VGA_bufferrowbytes = lvid->rowbytes;
|
||||
lvid->colormap = host_colormap;
|
||||
lvid->fullbright = 256 - LittleLong (*((int *)lvid->colormap + 2048));
|
||||
|
||||
lvid->maxwarpwidth = WARP_WIDTH;
|
||||
lvid->maxwarpheight = WARP_HEIGHT;
|
||||
|
||||
lvid->conbuffer = lvid->buffer;
|
||||
lvid->conrowbytes = lvid->rowbytes;
|
||||
lvid->conwidth = lvid->width;
|
||||
lvid->conheight = lvid->height;
|
||||
|
||||
VGA_pcurmode = pcurrentmode;
|
||||
|
||||
VGA_ClearVideoMem (pcurrentmode->planar);
|
||||
|
||||
if (_vid_wait_override.value)
|
||||
{
|
||||
Cvar_SetValue ("vid_wait", (float)VID_WAIT_VSYNC);
|
||||
}
|
||||
else
|
||||
{
|
||||
Cvar_SetValue ("vid_wait", (float)VID_WAIT_NONE);
|
||||
}
|
||||
|
||||
D_InitCaches (vid_surfcache, vid_surfcachesize);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VGA_SetPalette
|
||||
================
|
||||
*/
|
||||
void VGA_SetPalette(viddef_t *lvid, vmode_t *pcurrentmode, unsigned char *pal)
|
||||
{
|
||||
int shiftcomponents=2;
|
||||
int i;
|
||||
|
||||
UNUSED(lvid);
|
||||
UNUSED(pcurrentmode);
|
||||
|
||||
dos_outportb(0x3c8, 0);
|
||||
for (i=0 ; i<768 ; i++)
|
||||
outportb(0x3c9, pal[i]>>shiftcomponents);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VGA_SwapBuffersCopy
|
||||
================
|
||||
*/
|
||||
void VGA_SwapBuffersCopy (viddef_t *lvid, vmode_t *pcurrentmode,
|
||||
vrect_t *rects)
|
||||
{
|
||||
|
||||
UNUSED(pcurrentmode);
|
||||
|
||||
// TODO: can write a dword at a time
|
||||
// TODO: put in ASM
|
||||
// TODO: copy only specified rectangles
|
||||
if (VGA_planar)
|
||||
{
|
||||
|
||||
// TODO: copy only specified rectangles
|
||||
|
||||
VGA_UpdatePlanarScreen (lvid->buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (rects)
|
||||
{
|
||||
VGA_UpdateLinearScreen (
|
||||
lvid->buffer + rects->x + (rects->y * lvid->rowbytes),
|
||||
VGA_pagebase + rects->x + (rects->y * VGA_rowbytes),
|
||||
rects->width,
|
||||
rects->height,
|
||||
lvid->rowbytes,
|
||||
VGA_rowbytes);
|
||||
|
||||
rects = rects->pnext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
VGA_SwapBuffers
|
||||
================
|
||||
*/
|
||||
void VGA_SwapBuffers (viddef_t *lvid, vmode_t *pcurrentmode, vrect_t *rects)
|
||||
{
|
||||
UNUSED(lvid);
|
||||
|
||||
if (vid_wait.value == VID_WAIT_VSYNC)
|
||||
VGA_WaitVsync ();
|
||||
|
||||
VGA_SwapBuffersCopy (lvid, pcurrentmode, rects);
|
||||
}
|
||||
|
Loading…
Reference in a new issue