742 lines
14 KiB
C
742 lines
14 KiB
C
#if defined(WIN32)
|
|
#define _CRT_SECURE_NO_WARNINGS
|
|
#define _WINSOCK_DEPRECATED_NO_WARNINGS
|
|
#define _CRT_NONSTDC_NO_DEPRECATE
|
|
#endif
|
|
|
|
#include "DOOM.h"
|
|
|
|
#include "d_main.h"
|
|
#include "doomdef.h"
|
|
#include "doomtype.h"
|
|
#include "i_system.h"
|
|
#include "m_argv.h"
|
|
#include "m_misc.h"
|
|
|
|
|
|
extern byte* screens[5];
|
|
extern unsigned char screen_palette[256 * 3];
|
|
extern doom_boolean is_wiping_screen;
|
|
extern default_t defaults[];
|
|
extern int numdefaults;
|
|
extern signed short mixbuffer[2048];
|
|
|
|
|
|
static unsigned char* screen_buffer = 0;
|
|
static unsigned char* final_screen_buffer = 0;
|
|
static int last_update_time = 0;
|
|
static int button_states[3] = { 0 };
|
|
static char itoa_buf[20];
|
|
|
|
|
|
char error_buf[260];
|
|
int doom_flags = 0;
|
|
doom_print_fn doom_print = 0;
|
|
doom_malloc_fn doom_malloc = 0;
|
|
doom_free_fn doom_free = 0;
|
|
doom_open_fn doom_open = 0;
|
|
doom_close_fn doom_close = 0;
|
|
doom_read_fn doom_read = 0;
|
|
doom_write_fn doom_write = 0;
|
|
doom_seek_fn doom_seek = 0;
|
|
doom_tell_fn doom_tell = 0;
|
|
doom_eof_fn doom_eof = 0;
|
|
doom_gettime_fn doom_gettime = 0;
|
|
doom_exit_fn doom_exit = 0;
|
|
doom_getenv_fn doom_getenv = 0;
|
|
|
|
|
|
void D_DoomLoop(void);
|
|
void D_UpdateWipe(void);
|
|
void I_UpdateSound();
|
|
unsigned long I_TickSong();
|
|
|
|
|
|
#if defined(DOOM_IMPLEMENT_PRINT)
|
|
#include <stdio.h>
|
|
static void doom_print_impl(const char* str)
|
|
{
|
|
printf("%s", str);
|
|
}
|
|
#else
|
|
static void doom_print_impl(const char* str) {}
|
|
#endif
|
|
|
|
#if defined(DOOM_IMPLEMENT_MALLOC)
|
|
#include <stdlib.h>
|
|
static void* doom_malloc_impl(int size)
|
|
{
|
|
return malloc((size_t)size);
|
|
}
|
|
static void doom_free_impl(void* ptr)
|
|
{
|
|
free(ptr);
|
|
}
|
|
#else
|
|
static void* doom_malloc_impl(int size) { return 0; }
|
|
static void doom_free_impl(void* ptr) {}
|
|
#endif
|
|
|
|
|
|
#if defined(DOOM_IMPLEMENT_FILE_IO)
|
|
#include <stdio.h>
|
|
void* doom_open_impl(const char* filename, const char* mode)
|
|
{
|
|
return fopen(filename, mode);
|
|
}
|
|
void doom_close_impl(void* handle)
|
|
{
|
|
fclose(handle);
|
|
}
|
|
int doom_read_impl(void* handle, void *buf, int count)
|
|
{
|
|
return (int)fread(buf, 1, count, handle);
|
|
}
|
|
int doom_write_impl(void* handle, const void *buf, int count)
|
|
{
|
|
return (int)fwrite(buf, 1, count, handle);
|
|
}
|
|
int doom_seek_impl(void* handle, int offset, doom_seek_t origin)
|
|
{
|
|
return fseek(handle, offset, origin);
|
|
}
|
|
int doom_tell_impl(void* handle)
|
|
{
|
|
return (int)ftell(handle);
|
|
}
|
|
int doom_eof_impl(void* handle)
|
|
{
|
|
return feof(handle);
|
|
}
|
|
#else
|
|
void* doom_open_impl(const char* filename, const char* mode)
|
|
{
|
|
return 0;
|
|
}
|
|
void doom_close_impl(void* handle) {}
|
|
int doom_read_impl(void* handle, void *buf, int count)
|
|
{
|
|
return -1;
|
|
}
|
|
int doom_write_impl(void* handle, const void *buf, int count)
|
|
{
|
|
return -1;
|
|
}
|
|
int doom_seek_impl(void* handle, int offset, doom_seek_t origin)
|
|
{
|
|
return -1;
|
|
}
|
|
int doom_tell_impl(void* handle)
|
|
{
|
|
return -1;
|
|
}
|
|
int doom_eof_impl(void* handle)
|
|
{
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
|
|
#if defined(DOOM_IMPLEMENT_GETTIME)
|
|
#if defined(WIN32)
|
|
#include <winsock.h>
|
|
#else
|
|
#include <sys/time.h>
|
|
#endif
|
|
void doom_gettime_impl(int* sec, int* usec)
|
|
{
|
|
#if defined(WIN32)
|
|
static const unsigned long long EPOCH = ((unsigned long long)116444736000000000ULL);
|
|
SYSTEMTIME system_time;
|
|
FILETIME file_time;
|
|
unsigned long long time;
|
|
GetSystemTime(&system_time);
|
|
SystemTimeToFileTime(&system_time, &file_time);
|
|
time = ((unsigned long long)file_time.dwLowDateTime);
|
|
time += ((unsigned long long)file_time.dwHighDateTime) << 32;
|
|
*sec = (int)((time - EPOCH) / 10000000L);
|
|
*usec = (int)(system_time.wMilliseconds * 1000);
|
|
#else
|
|
struct timeval tp;
|
|
struct timezone tzp;
|
|
gettimeofday(&tp, &tzp);
|
|
*sec = tp.tv_sec;
|
|
*usec = tp.tv_usec;
|
|
#endif
|
|
}
|
|
#else
|
|
void doom_gettime_impl(int* sec, int* usec)
|
|
{
|
|
*sec = 0;
|
|
*usec = 0;
|
|
}
|
|
#endif
|
|
|
|
|
|
#if defined(DOOM_IMPLEMENT_EXIT)
|
|
#include <stdlib.h>
|
|
void doom_exit_impl(int code)
|
|
{
|
|
exit(code);
|
|
}
|
|
#else
|
|
void doom_exit_impl(int code) {}
|
|
#endif
|
|
|
|
|
|
#if defined(DOOM_IMPLEMENT_GETENV)
|
|
#include <stdlib.h>
|
|
char* doom_getenv_impl(const char* var)
|
|
{
|
|
return getenv(var);
|
|
}
|
|
#else
|
|
char* doom_getenv_impl(const char* var) {
|
|
return (char*)0; //< @r-lyeh add missing return
|
|
}
|
|
#endif
|
|
|
|
|
|
void doom_memset(void* ptr, int value, int num)
|
|
{
|
|
unsigned char* p = ptr;
|
|
for (int i = 0; i < num; ++i, ++p)
|
|
{
|
|
*p = (unsigned char)value;
|
|
}
|
|
}
|
|
|
|
|
|
void* doom_memcpy(void* destination, const void* source, int num)
|
|
{
|
|
unsigned char* dst = destination;
|
|
const unsigned char* src = source;
|
|
|
|
for (int i = 0; i < num; ++i, ++dst, ++src)
|
|
{
|
|
*dst = *src;
|
|
}
|
|
|
|
return destination;
|
|
}
|
|
|
|
|
|
int doom_strlen(const char* str)
|
|
{
|
|
int len = 0;
|
|
while (*str++) ++len;
|
|
return len;
|
|
}
|
|
|
|
|
|
char* doom_concat(char* dst, const char* src)
|
|
{
|
|
char* ret = dst;
|
|
dst += doom_strlen(dst);
|
|
|
|
while (*src) *dst++ = *src++;
|
|
*dst = *src; // \0
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
char* doom_strcpy(char* dst, const char* src)
|
|
{
|
|
char* ret = dst;
|
|
|
|
while (*src) *dst++ = *src++;
|
|
*dst = *src; // \0
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
char* doom_strncpy(char* dst, const char* src, int num)
|
|
{
|
|
int i = 0;
|
|
|
|
for (; i < num; ++i)
|
|
{
|
|
if (!src[i]) break;
|
|
dst[i] = src[i];
|
|
}
|
|
|
|
while (i < num) dst[i++] = '\0';
|
|
|
|
return dst;
|
|
}
|
|
|
|
|
|
int doom_strcmp(const char* str1, const char* str2)
|
|
{
|
|
int ret = 0;
|
|
|
|
while (!(ret = *(unsigned char*)str1 - *(unsigned char*) str2) && *str1)
|
|
++str1, ++str2;
|
|
|
|
if (ret < 0)
|
|
ret = -1;
|
|
else if (ret > 0)
|
|
ret = 1;
|
|
|
|
return (ret);
|
|
}
|
|
|
|
|
|
int doom_strncmp(const char* str1, const char* str2, int n)
|
|
{
|
|
int ret = 0;
|
|
int count = 1;
|
|
|
|
while (!(ret = *(unsigned char*)str1 - *(unsigned char*) str2) && *str1 && count++ < n)
|
|
++str1, ++str2;
|
|
|
|
if (ret < 0)
|
|
ret = -1;
|
|
else if (ret > 0)
|
|
ret = 1;
|
|
|
|
return (ret);
|
|
}
|
|
|
|
|
|
int doom_toupper(int c)
|
|
{
|
|
if (c >= 'a' && c <= 'z') return c - 'a' + 'A';
|
|
return c;
|
|
}
|
|
|
|
|
|
int doom_strcasecmp(const char* str1, const char* str2)
|
|
{
|
|
int ret = 0;
|
|
|
|
while (!(ret = doom_toupper(*(unsigned char*)str1) - doom_toupper(*(unsigned char*)str2)) && *str1)
|
|
++str1, ++str2;
|
|
|
|
if (ret < 0)
|
|
ret = -1;
|
|
else if (ret > 0)
|
|
ret = 1;
|
|
|
|
return (ret);
|
|
}
|
|
|
|
|
|
int doom_strncasecmp(const char* str1, const char* str2, int n)
|
|
{
|
|
int ret = 0;
|
|
int count = 1;
|
|
|
|
while (!(ret = doom_toupper(*(unsigned char*)str1) - doom_toupper(*(unsigned char*)str2)) && *str1 && count++ < n)
|
|
++str1, ++str2;
|
|
|
|
if (ret < 0)
|
|
ret = -1;
|
|
else if (ret > 0)
|
|
ret = 1;
|
|
|
|
return (ret);
|
|
}
|
|
|
|
|
|
int doom_atoi(const char* str)
|
|
{
|
|
int i = 0;
|
|
int c;
|
|
|
|
while ((c = *str++) != 0)
|
|
{
|
|
i *= 10;
|
|
i += c - '0';
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
|
|
int doom_atox(const char* str)
|
|
{
|
|
int i = 0;
|
|
int c;
|
|
|
|
while ((c = *str++) != 0)
|
|
{
|
|
i *= 16;
|
|
if (c >= '0' && c <= '9')
|
|
i += c - '0';
|
|
else
|
|
i += c - 'A' + 10;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
|
|
const char* doom_itoa(int k, int radix)
|
|
{
|
|
int i = k < 0 ? -k : k;
|
|
if (i == 0)
|
|
{
|
|
itoa_buf[0] = '0';
|
|
itoa_buf[1] = '\0';
|
|
return itoa_buf;
|
|
}
|
|
|
|
int idx = k < 0 ? 1 : 0;
|
|
int j = i;
|
|
while (j)
|
|
{
|
|
j /= radix;
|
|
idx++;
|
|
}
|
|
itoa_buf[idx] = '\0';
|
|
|
|
if (radix == 10)
|
|
{
|
|
while (i)
|
|
{
|
|
itoa_buf[--idx] = '0' + (i % 10);
|
|
i /= 10;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (i)
|
|
{
|
|
int k = (i & 0xF);
|
|
if (k >= 10)
|
|
itoa_buf[--idx] = 'A' + ((i & 0xF) - 10);
|
|
else
|
|
itoa_buf[--idx] = '0' + (i & 0xF);
|
|
i >>= 4;
|
|
}
|
|
}
|
|
|
|
if (k < 0) itoa_buf[0] = '-';
|
|
|
|
return itoa_buf;
|
|
}
|
|
|
|
|
|
const char* doom_ctoa(char c)
|
|
{
|
|
itoa_buf[0] = c;
|
|
itoa_buf[1] = '\0';
|
|
return itoa_buf;
|
|
}
|
|
|
|
|
|
const char* doom_ptoa(void* p)
|
|
{
|
|
int idx = 0;
|
|
unsigned long long i = (unsigned long long)p;
|
|
|
|
itoa_buf[idx++] = '0';
|
|
itoa_buf[idx++] = 'x';
|
|
|
|
while (i)
|
|
{
|
|
int k = (i & 0xF);
|
|
if (k >= 10)
|
|
itoa_buf[idx++] = 'A' + ((i & 0xF) - 10);
|
|
else
|
|
itoa_buf[idx++] = '0' + (i & 0xF);
|
|
i >>= 4;
|
|
}
|
|
|
|
itoa_buf[idx] = '\0';
|
|
return itoa_buf;
|
|
}
|
|
|
|
|
|
int doom_fprint(void* handle, const char* str)
|
|
{
|
|
return doom_write(handle, str, doom_strlen(str));
|
|
}
|
|
|
|
|
|
static default_t* get_default(const char* name)
|
|
{
|
|
for (int i = 0; i < numdefaults; ++i)
|
|
{
|
|
if (doom_strcmp(defaults[i].name, name) == 0) return &defaults[i];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
void doom_set_resolution(int width, int height)
|
|
{
|
|
if (width <= 0 || height <= 0) return;
|
|
// SCREENWIDTH = width;
|
|
// SCREENHEIGHT = height;
|
|
}
|
|
|
|
|
|
void doom_set_default_int(const char* name, int value)
|
|
{
|
|
default_t* def = get_default(name);
|
|
if (!def) return;
|
|
def->defaultvalue = value;
|
|
}
|
|
|
|
|
|
void doom_set_default_string(const char* name, const char* value)
|
|
{
|
|
default_t* def = get_default(name);
|
|
if (!def) return;
|
|
def->default_text_value = (char*)value;
|
|
}
|
|
|
|
|
|
void doom_set_print(doom_print_fn print_fn)
|
|
{
|
|
doom_print = print_fn;
|
|
}
|
|
|
|
|
|
void doom_set_malloc(doom_malloc_fn malloc_fn, doom_free_fn free_fn)
|
|
{
|
|
doom_malloc = malloc_fn;
|
|
doom_free = free_fn;
|
|
}
|
|
|
|
|
|
void doom_set_file_io(doom_open_fn open_fn,
|
|
doom_close_fn close_fn,
|
|
doom_read_fn read_fn,
|
|
doom_write_fn write_fn,
|
|
doom_seek_fn seek_fn,
|
|
doom_tell_fn tell_fn,
|
|
doom_eof_fn eof_fn)
|
|
{
|
|
doom_open = open_fn;
|
|
doom_close = close_fn;
|
|
doom_read = read_fn;
|
|
doom_write = write_fn;
|
|
doom_seek = seek_fn;
|
|
doom_tell = tell_fn;
|
|
doom_eof = eof_fn;
|
|
}
|
|
|
|
|
|
void doom_set_gettime(doom_gettime_fn gettime_fn)
|
|
{
|
|
doom_gettime = gettime_fn;
|
|
}
|
|
|
|
|
|
void doom_set_exit(doom_exit_fn exit_fn)
|
|
{
|
|
doom_exit = exit_fn;
|
|
}
|
|
|
|
|
|
void doom_set_getenv(doom_getenv_fn getenv_fn)
|
|
{
|
|
doom_getenv = getenv_fn;
|
|
}
|
|
|
|
|
|
void doom_init(int argc, char** argv, int flags)
|
|
{
|
|
if (!doom_print) doom_print = doom_print_impl;
|
|
if (!doom_malloc) doom_malloc = doom_malloc_impl;
|
|
if (!doom_free) doom_free = doom_free_impl;
|
|
if (!doom_open) doom_open = doom_open_impl;
|
|
if (!doom_close) doom_close = doom_close_impl;
|
|
if (!doom_read) doom_read = doom_read_impl;
|
|
if (!doom_write) doom_write = doom_write_impl;
|
|
if (!doom_seek) doom_seek = doom_seek_impl;
|
|
if (!doom_tell) doom_tell = doom_tell_impl;
|
|
if (!doom_eof) doom_eof = doom_eof_impl;
|
|
if (!doom_gettime) doom_gettime = doom_gettime_impl;
|
|
if (!doom_exit) doom_exit = doom_exit_impl;
|
|
if (!doom_getenv) doom_getenv = doom_getenv_impl;
|
|
|
|
screen_buffer = doom_malloc(SCREENWIDTH * SCREENHEIGHT);
|
|
final_screen_buffer = doom_malloc(SCREENWIDTH * SCREENHEIGHT * 4);
|
|
last_update_time = I_GetTime();
|
|
|
|
myargc = argc;
|
|
myargv = argv;
|
|
doom_flags = flags;
|
|
|
|
D_DoomMain();
|
|
}
|
|
|
|
|
|
void doom_update()
|
|
{
|
|
int now = I_GetTime();
|
|
int delta_time = now - last_update_time;
|
|
|
|
while (delta_time-- > 0)
|
|
{
|
|
if (is_wiping_screen)
|
|
D_UpdateWipe();
|
|
else
|
|
D_DoomLoop();
|
|
}
|
|
|
|
last_update_time = now;
|
|
}
|
|
|
|
|
|
const unsigned char* doom_get_framebuffer(int channels)
|
|
{
|
|
int i, len;
|
|
|
|
doom_memcpy(screen_buffer, screens[0], SCREENWIDTH * SCREENHEIGHT);
|
|
|
|
extern doom_boolean menuactive;
|
|
extern gamestate_t gamestate;
|
|
extern doom_boolean automapactive;
|
|
extern int crosshair;
|
|
|
|
// Draw crosshair
|
|
if (crosshair &&
|
|
!menuactive &&
|
|
gamestate == GS_LEVEL &&
|
|
!automapactive)
|
|
{
|
|
int y;
|
|
extern int setblocks;
|
|
if (setblocks == 11) y = SCREENHEIGHT / 2 + 8;
|
|
else y = SCREENHEIGHT / 2 - 8;
|
|
for (i = 0; i < 2; ++i)
|
|
{
|
|
screen_buffer[SCREENWIDTH / 2 - 2 - i + y * SCREENWIDTH] = 4;
|
|
screen_buffer[SCREENWIDTH / 2 + 2 + i + y * SCREENWIDTH] = 4;
|
|
}
|
|
for (i = 0; i < 2; ++i)
|
|
{
|
|
screen_buffer[SCREENWIDTH / 2 + (y - 2 - i) * SCREENWIDTH] = 4;
|
|
screen_buffer[SCREENWIDTH / 2 + (y + 2 + i) * SCREENWIDTH] = 4;
|
|
}
|
|
}
|
|
|
|
if (channels == 1)
|
|
{
|
|
return screen_buffer;
|
|
}
|
|
else if (channels == 3)
|
|
{
|
|
for (i = 0, len = SCREENWIDTH * SCREENHEIGHT; i < len; ++i)
|
|
{
|
|
int k = i * 3;
|
|
int kpal = screen_buffer[i] * 3;
|
|
final_screen_buffer[k + 0] = screen_palette[kpal + 0];
|
|
final_screen_buffer[k + 1] = screen_palette[kpal + 1];
|
|
final_screen_buffer[k + 2] = screen_palette[kpal + 2];
|
|
}
|
|
return final_screen_buffer;
|
|
}
|
|
else if (channels == 4)
|
|
{
|
|
for (i = 0, len = SCREENWIDTH * SCREENHEIGHT; i < len; ++i)
|
|
{
|
|
int k = i * 4;
|
|
int kpal = screen_buffer[i] * 3;
|
|
final_screen_buffer[k + 0] = screen_palette[kpal + 0];
|
|
final_screen_buffer[k + 1] = screen_palette[kpal + 1];
|
|
final_screen_buffer[k + 2] = screen_palette[kpal + 2];
|
|
final_screen_buffer[k + 3] = 255;
|
|
}
|
|
return final_screen_buffer;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
unsigned long doom_tick_midi()
|
|
{
|
|
return I_TickSong();
|
|
}
|
|
|
|
|
|
short* doom_get_sound_buffer()
|
|
{
|
|
I_UpdateSound();
|
|
return mixbuffer;
|
|
}
|
|
|
|
|
|
void doom_key_down(doom_key_t key)
|
|
{
|
|
event_t event;
|
|
event.type = ev_keydown;
|
|
event.data1 = (int)key;
|
|
D_PostEvent(&event);
|
|
}
|
|
|
|
|
|
void doom_key_up(doom_key_t key)
|
|
{
|
|
event_t event;
|
|
event.type = ev_keyup;
|
|
event.data1 = (int)key;
|
|
D_PostEvent(&event);
|
|
}
|
|
|
|
|
|
void doom_button_down(doom_button_t button)
|
|
{
|
|
button_states[button] = 1;
|
|
|
|
event_t event;
|
|
event.type = ev_mouse;
|
|
event.data1 =
|
|
(button_states[0]) |
|
|
(button_states[1] ? 2 : 0) |
|
|
(button_states[2] ? 4 : 0);
|
|
event.data2 = event.data3 = 0;
|
|
D_PostEvent(&event);
|
|
}
|
|
|
|
|
|
void doom_button_up(doom_button_t button)
|
|
{
|
|
button_states[button] = 0;
|
|
|
|
event_t event;
|
|
event.type = ev_mouse;
|
|
event.data1 =
|
|
(button_states[0]) |
|
|
(button_states[1] ? 2 : 0) |
|
|
(button_states[2] ? 4 : 0);
|
|
|
|
event.data1 =
|
|
event.data1
|
|
^ (button_states[0] ? 1 : 0)
|
|
^ (button_states[1] ? 2 : 0)
|
|
^ (button_states[2] ? 4 : 0);
|
|
|
|
event.data2 = event.data3 = 0;
|
|
D_PostEvent(&event);
|
|
}
|
|
|
|
|
|
void doom_mouse_move(int delta_x, int delta_y)
|
|
{
|
|
event_t event;
|
|
|
|
event.type = ev_mouse;
|
|
event.data1 =
|
|
(button_states[0]) |
|
|
(button_states[1] ? 2 : 0) |
|
|
(button_states[2] ? 4 : 0);
|
|
event.data2 = delta_x;
|
|
event.data3 = -delta_y;
|
|
|
|
if (event.data2 || event.data3)
|
|
{
|
|
D_PostEvent(&event);
|
|
}
|
|
}
|