#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 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 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 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 #else #include #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 void doom_exit_impl(int code) { exit(code); } #else void doom_exit_impl(int code) {} #endif #if defined(DOOM_IMPLEMENT_GETENV) #include 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); } }