diff --git a/CMakeLists.txt b/CMakeLists.txt index dd2c7730f..3e375a2df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,7 +123,7 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS( GME if( MSVC ) # Eliminate unreferenced functions and data # Perform identical COMDAT folding - set( REL_LINKER_FLAGS "/opt:ref /opt:icf /nodefaultlib:msvcrt /TSAWARE" ) + set( REL_LINKER_FLAGS "/opt:ref /opt:icf /nodefaultlib:msvcrt /TSAWARE /LARGEADDRESSAWARE" ) # String pooling # Function-level linking diff --git a/dumb/CMakeLists.txt b/dumb/CMakeLists.txt index e95c69154..b590aa165 100644 --- a/dumb/CMakeLists.txt +++ b/dumb/CMakeLists.txt @@ -39,7 +39,6 @@ add_library( dumb src/helpers/memfile.c src/helpers/clickrem.c src/helpers/barray.c - src/helpers/tarray.c src/it/xmeffect.c src/it/readxm2.c src/it/readxm.c diff --git a/dumb/include/dumb.h b/dumb/include/dumb.h index c2c0aaa32..385335da7 100644 --- a/dumb/include/dumb.h +++ b/dumb/include/dumb.h @@ -36,24 +36,24 @@ #endif -#define DUMB_MAJOR_VERSION 0 -#define DUMB_MINOR_VERSION 9 -#define DUMB_REVISION_VERSION 3 +#define DUMB_MAJOR_VERSION 1 +#define DUMB_MINOR_VERSION 0 +#define DUMB_REVISION_VERSION 0 #define DUMB_VERSION (DUMB_MAJOR_VERSION*10000 + DUMB_MINOR_VERSION*100 + DUMB_REVISION_VERSION) -#define DUMB_VERSION_STR "0.9.3" +#define DUMB_VERSION_STR "1.0.0" #define DUMB_NAME "DUMB v" DUMB_VERSION_STR -#define DUMB_YEAR 2005 -#define DUMB_MONTH 8 -#define DUMB_DAY 7 +#define DUMB_YEAR 2015 +#define DUMB_MONTH 1 +#define DUMB_DAY 17 -#define DUMB_YEAR_STR2 "05" -#define DUMB_YEAR_STR4 "2005" -#define DUMB_MONTH_STR1 "8" -#define DUMB_DAY_STR1 "7" +#define DUMB_YEAR_STR2 "15" +#define DUMB_YEAR_STR4 "2015" +#define DUMB_MONTH_STR1 "1" +#define DUMB_DAY_STR1 "17" #if DUMB_MONTH < 10 #define DUMB_MONTH_STR2 "0" DUMB_MONTH_STR1 @@ -606,10 +606,6 @@ typedef void (*DUH_SIGRENDERER_GET_CURRENT_SAMPLE)( sample_t *samples ); -typedef int32 (*DUH_SIGRENDERER_GET_POSITION)( - sigrenderer_t *sigrenderer -); - typedef void (*DUH_END_SIGRENDERER)(sigrenderer_t *sigrenderer); typedef void (*DUH_UNLOAD_SIGDATA)(sigdata_t *sigdata); @@ -625,7 +621,6 @@ typedef struct DUH_SIGTYPE_DESC DUH_SIGRENDERER_SET_SIGPARAM sigrenderer_set_sigparam; DUH_SIGRENDERER_GENERATE_SAMPLES sigrenderer_generate_samples; DUH_SIGRENDERER_GET_CURRENT_SAMPLE sigrenderer_get_current_sample; - DUH_SIGRENDERER_GET_POSITION sigrenderer_get_position; DUH_END_SIGRENDERER end_sigrenderer; DUH_UNLOAD_SIGDATA unload_sigdata; } diff --git a/dumb/include/internal/it.h b/dumb/include/internal/it.h index 6defa759a..a9196b316 100644 --- a/dumb/include/internal/it.h +++ b/dumb/include/internal/it.h @@ -33,7 +33,6 @@ #include #include "barray.h" -#include "tarray.h" /** TO DO: THINK ABOUT THE FOLLOWING: @@ -724,21 +723,6 @@ struct DUMB_IT_SIGRENDERER #ifdef BIT_ARRAY_BULLSHIT /* bit array, which rows are played, only checked by pattern break or loop commands */ void * played; - - /* - Loop indicator for internal processes, may also be useful for external processes - 0 - Not looped - 1 - Looped - -1 - Continued past loop - */ - int looped; - - /* - Kept until looped - */ - LONG_LONG time_played; - - void * row_timekeeper; #endif int32 gvz_time; diff --git a/dumb/include/internal/tarray.h b/dumb/include/internal/tarray.h deleted file mode 100644 index 7eb3af7c6..000000000 --- a/dumb/include/internal/tarray.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef _T_ARRAY_H_ -#define _T_ARRAY_H_ - -#include - -#ifndef LONG_LONG -#if defined __GNUC__ || defined __INTEL_COMPILER || defined __MWERKS__ -#define LONG_LONG long long -#elif defined _MSC_VER || defined __WATCOMC__ -#define LONG_LONG __int64 -#elif defined __sgi -#define LONG_LONG long long -#else -#error 64-bit integer type unknown -#endif -#endif - -void * timekeeping_array_create(size_t size); -void timekeeping_array_destroy(void * array); -void * timekeeping_array_dup(void * array); - -void timekeeping_array_reset(void * array, size_t loop_start); - -void timekeeping_array_push(void * array, size_t index, LONG_LONG time); -void timekeeping_array_bump(void * array, size_t index); - -unsigned int timekeeping_array_get_count(void * array, size_t index); - -LONG_LONG timekeeping_array_get_item(void * array, size_t index); - -#endif diff --git a/dumb/prj/dumb/dumb.pro b/dumb/prj/dumb/dumb.pro index 629a9294a..9244ce4bd 100644 --- a/dumb/prj/dumb/dumb.pro +++ b/dumb/prj/dumb/dumb.pro @@ -37,7 +37,6 @@ SOURCES += \ ../../src/helpers/memfile.c \ ../../src/helpers/clickrem.c \ ../../src/helpers/barray.c \ - ../../src/helpers/tarray.c \ ../../src/it/xmeffect.c \ ../../src/it/readxm2.c \ ../../src/it/readxm.c \ @@ -109,7 +108,6 @@ HEADERS += \ ../../include/internal/it.h \ ../../include/internal/dumb.h \ ../../include/internal/barray.h \ - ../../include/internal/tarray.h \ ../../include/internal/aldumb.h \ ../../include/internal/sinc_resampler.h \ ../../include/internal/stack_alloc.h \ diff --git a/dumb/src/core/rendsig.c b/dumb/src/core/rendsig.c index 053011a11..72da173c5 100644 --- a/dumb/src/core/rendsig.c +++ b/dumb/src/core/rendsig.c @@ -147,15 +147,7 @@ int DUMBEXPORT duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer) int32 DUMBEXPORT duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer) { - DUH_SIGRENDERER_GET_POSITION proc; - - if (!sigrenderer) return -1; - - proc = sigrenderer->desc->sigrenderer_get_position; - if (proc) - return (*proc)(sigrenderer->sigrenderer); - else - return sigrenderer->pos; + return sigrenderer ? sigrenderer->pos : -1; } diff --git a/dumb/src/helpers/tarray.c b/dumb/src/helpers/tarray.c deleted file mode 100644 index f3ba422d8..000000000 --- a/dumb/src/helpers/tarray.c +++ /dev/null @@ -1,175 +0,0 @@ -#include "internal/tarray.h" - -#include - - /* - Structures which contain the play times of each pattern and row combination in the song, - not guaranteed to be valid for the whole song until the loop status is no longer zero. - The initial count and restart count will both be zero on song start, then both will be - incremented until the song loops. Restart count will be reset to zero on loop for all - rows which have a time equal to or greater than the loop start point, so time keeping - functions will know which timestamp the song is currently located at. - - Timestamp lists are guaranteed to be allocated in blocks of 16 timestamps at a time. - */ - - /* - We don't need full timekeeping because the player loop only wants the first play time - of the loop start order/row. We also don't really want full timekeeping because it - involves a lot of memory allocations, which is also slow. - */ - -#undef FULL_TIMEKEEPING - -typedef struct DUMB_IT_ROW_TIME -{ - unsigned int count, restart_count; -#ifndef FULL_TIMEKEEPING - LONG_LONG first_time; -#else - LONG_LONG * times; -#endif -} DUMB_IT_ROW_TIME; - -void * timekeeping_array_create(size_t size) -{ - size_t * _size = (size_t *) calloc( 1, sizeof(size_t) + sizeof(DUMB_IT_ROW_TIME) * size ); - if ( _size ) { - *_size = size; - } - return _size; -} - -void timekeeping_array_destroy(void * array) -{ -#ifdef FULL_TIMEKEEPING - size_t i; - size_t * size = (size_t *) array; - DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1); - - for (i = 0; i < *size; i++) { - if (s[i].times) free(s[i].times); - } -#endif - - free(array); -} - -void * timekeeping_array_dup(void * array) -{ - size_t i; - size_t * size = (size_t *) array; - DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1); - size_t * new_size = (size_t *) calloc( 1, sizeof(size_t) + sizeof(DUMB_IT_ROW_TIME) * *size ); - if ( new_size ) { - DUMB_IT_ROW_TIME * new_s = (DUMB_IT_ROW_TIME *)(new_size + 1); - - *new_size = *size; - - for (i = 0; i < *size; i++) { - new_s[i].count = s[i].count; - new_s[i].restart_count = s[i].restart_count; - -#ifndef FULL_TIMEKEEPING - new_s[i].first_time = s[i].first_time; -#else - if ( s[i].times ) { - size_t time_count = ( s[i].count + 15 ) & ~15; - new_s[i].times = (LONG_LONG *) malloc( sizeof(LONG_LONG) * time_count ); - if ( new_s[i].times == (void *)0 ) { - timekeeping_array_destroy( new_size ); - return (void *) 0; - } - memcpy( new_s[i].times, s[i].times, sizeof(LONG_LONG) * s[i].count ); - } -#endif - } - } - - return new_size; -} - -void timekeeping_array_reset(void * array, size_t loop_start) -{ - size_t i; - size_t * size = (size_t *) array; - DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1); - - DUMB_IT_ROW_TIME * s_loop_start = s + loop_start; - LONG_LONG loop_start_time; - - if ( loop_start >= *size || s_loop_start->count < 1 ) return; - -#ifndef FULL_TIMEKEEPING - loop_start_time = s_loop_start->first_time; -#else - loop_start_time = s_loop_start->times[0]; -#endif - - for ( i = 0; i < *size; i++ ) { -#ifndef FULL_TIMEKEEPING - if ( s[i].count && s[i].first_time >= loop_start_time ) { -#else - if ( s[i].count && s[i].times[0] >= loop_start_time ) { -#endif - s[i].restart_count = 0; - } - } -} - -void timekeeping_array_push(void * array, size_t index, LONG_LONG time) -{ -#ifdef FULL_TIMEKEEPING - size_t i; - size_t time_count; -#endif - size_t * size = (size_t *) array; - DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1); - - if (index >= *size) return; - -#ifndef FULL_TIMEKEEPING - if ( !s[index].count++ ) - s[index].first_time = time; -#else - time_count = ( s[index].count + 16 ) & ~15; - - s[index].times = (LONG_LONG *) realloc( s[index].times, sizeof(LONG_LONG) * time_count ); - - s[index].times[s[index].count++] = time; -#endif -} - -void timekeeping_array_bump(void * array, size_t index) -{ - size_t * size = (size_t *) array; - DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1); - - if (index >= *size) return; - - s[index].restart_count++; -} - -unsigned int timekeeping_array_get_count(void * array, size_t index) -{ - size_t * size = (size_t *) array; - DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1); - - if (index >= *size) return 0; - - return s[index].count; -} - -LONG_LONG timekeeping_array_get_item(void * array, size_t index) -{ - size_t * size = (size_t *) array; - DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1); - - if (index >= *size || s[index].restart_count >= s[index].count) return 0; - -#ifndef FULL_TIMEKEEPING - return s[index].first_time; -#else - return s[index].times[s[index].restart_count]; -#endif -} diff --git a/dumb/src/it/itread.c b/dumb/src/it/itread.c index e8661807e..ca1dde55d 100644 --- a/dumb/src/it/itread.c +++ b/dumb/src/it/itread.c @@ -290,12 +290,15 @@ static int it_read_envelope(IT_ENVELOPE *envelope, DUMBFILE *f) envelope->flags = dumbfile_getc(f); envelope->n_nodes = dumbfile_getc(f); + if(envelope->n_nodes > 25) { + TRACE("IT error: wrong number of envelope nodes (%d)\n", envelope->n_nodes); + envelope->n_nodes = 0; + return -1; + } envelope->loop_start = dumbfile_getc(f); envelope->loop_end = dumbfile_getc(f); envelope->sus_loop_start = dumbfile_getc(f); envelope->sus_loop_end = dumbfile_getc(f); - if (envelope->n_nodes > 25) - envelope->n_nodes = 25; for (n = 0; n < envelope->n_nodes; n++) { envelope->node_y[n] = dumbfile_getc(f); envelope->node_t[n] = dumbfile_igetw(f); diff --git a/dumb/src/it/itrender.c b/dumb/src/it/itrender.c index 0491e7e59..0a7feae3c 100644 --- a/dumb/src/it/itrender.c +++ b/dumb/src/it/itrender.c @@ -352,10 +352,6 @@ static DUMB_IT_SIGRENDERER *dup_sigrenderer(DUMB_IT_SIGRENDERER *src, int n_chan #ifdef BIT_ARRAY_BULLSHIT dst->played = bit_array_dup(src->played); - - dst->looped = src->looped; - dst->time_played = src->time_played; - dst->row_timekeeper = timekeeping_array_dup(src->row_timekeeper); #endif dst->gvz_time = src->gvz_time; @@ -2221,9 +2217,6 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than bit_array_set(sigrenderer->played, sigrenderer->order * 256 + sigrenderer->row); #endif sigrenderer->speed = 0; -#ifdef BIT_ARRAY_BULLSHIT - sigrenderer->looped = 1; -#endif if (sigrenderer->callbacks->xm_speed_zero && (*sigrenderer->callbacks->xm_speed_zero)(sigrenderer->callbacks->xm_speed_zero_data)) return 1; } @@ -4341,8 +4334,6 @@ static int process_tick(DUMB_IT_SIGRENDERER *sigrenderer) /* Fix play tracking and timekeeping for orders containing skip commands */ for (n = 0; n < 256; n++) { bit_array_set(sigrenderer->played, sigrenderer->processorder * 256 + n); - timekeeping_array_push(sigrenderer->row_timekeeper, sigrenderer->processorder * 256 + n, sigrenderer->time_played); - timekeeping_array_bump(sigrenderer->row_timekeeper, sigrenderer->processorder * 256 + n); } #endif } @@ -4367,9 +4358,6 @@ static int process_tick(DUMB_IT_SIGRENDERER *sigrenderer) && bit_array_test(sigrenderer->played, sigrenderer->processorder * 256 + sigrenderer->processrow) #endif ) { -#ifdef BIT_ARRAY_BULLSHIT - sigrenderer->looped = 1; -#endif if (sigrenderer->callbacks->loop) { if ((*sigrenderer->callbacks->loop)(sigrenderer->callbacks->loop_data)) return 1; @@ -4413,13 +4401,6 @@ static int process_tick(DUMB_IT_SIGRENDERER *sigrenderer) } } -#ifdef BIT_ARRAY_BULLSHIT - if (sigrenderer->looped == 0) { - timekeeping_array_push(sigrenderer->row_timekeeper, sigrenderer->order * 256 + sigrenderer->row, sigrenderer->time_played); - } - timekeeping_array_bump(sigrenderer->row_timekeeper, sigrenderer->order * 256 + sigrenderer->row); -#endif - if (!(sigdata->flags & IT_WAS_A_669)) reset_effects(sigrenderer); @@ -4471,9 +4452,6 @@ static int process_tick(DUMB_IT_SIGRENDERER *sigrenderer) sigrenderer->gvz_time += (int)(t >> 16); sigrenderer->gvz_sub_time = (int)t & 65535; if (sigrenderer->gvz_time >= 65536 * 12) { -#ifdef BIT_ARRAY_BULLSHIT - sigrenderer->looped = 1; -#endif if ((*sigrenderer->callbacks->global_volume_zero)(sigrenderer->callbacks->global_volume_zero_data)) return 1; } @@ -5288,10 +5266,6 @@ static DUMB_IT_SIGRENDERER *init_sigrenderer(DUMB_IT_SIGDATA *sigdata, int n_cha #ifdef BIT_ARRAY_BULLSHIT sigrenderer->played = bit_array_create(sigdata->n_orders * 256); - - sigrenderer->looped = 0; - sigrenderer->time_played = 0; - sigrenderer->row_timekeeper = timekeeping_array_create(sigdata->n_orders * 256); #endif { @@ -5310,8 +5284,6 @@ static DUMB_IT_SIGRENDERER *init_sigrenderer(DUMB_IT_SIGDATA *sigdata, int n_cha /* Fix for played order detection for songs which have skips at the start of the orders list */ for (n = 0; n < 256; n++) { bit_array_set(sigrenderer->played, order * 256 + n); - timekeeping_array_push(sigrenderer->row_timekeeper, order * 256 + n, 0); - timekeeping_array_bump(sigrenderer->row_timekeeper, order * 256 + n); } #endif } @@ -5324,6 +5296,10 @@ static DUMB_IT_SIGRENDERER *init_sigrenderer(DUMB_IT_SIGDATA *sigdata, int n_cha sigrenderer->time_left = 0; sigrenderer->sub_time_left = 0; +#ifdef BIT_ARRAY_BULLSHIT + sigrenderer->played = bit_array_create(sigdata->n_orders * 256); +#endif + sigrenderer->gvz_time = 0; sigrenderer->gvz_sub_time = 0; @@ -5482,10 +5458,6 @@ static sigrenderer_t *it_start_sigrenderer(DUH *duh, sigdata_t *vsigdata, int n_ while (pos > 0 && pos >= sigrenderer->time_left) { render(sigrenderer, 0, 1.0f, 0, sigrenderer->time_left, NULL); -#ifdef BIT_ARRAY_BULLSHIT - sigrenderer->time_played += (LONG_LONG)sigrenderer->time_left << 16; -#endif - pos -= sigrenderer->time_left; sigrenderer->time_left = 0; @@ -5498,10 +5470,6 @@ static sigrenderer_t *it_start_sigrenderer(DUH *duh, sigdata_t *vsigdata, int n_ render(sigrenderer, 0, 1.0f, 0, pos, NULL); sigrenderer->time_left -= pos; -#ifdef BIT_ARRAY_BULLSHIT - sigrenderer->time_played += (LONG_LONG)pos << 16; -#endif - return sigrenderer; } @@ -5517,7 +5485,6 @@ static int32 it_sigrenderer_get_samples( int32 pos; int dt; int32 todo; - int ret; LONG_LONG t; if (sigrenderer->order < 0) return 0; // problematic @@ -5531,7 +5498,7 @@ static int32 it_sigrenderer_get_samples( if (!samples) volume = 0; for (;;) { - todo = (int32)((((LONG_LONG)sigrenderer->time_left << 16) | sigrenderer->sub_time_left) / dt); + todo = (long)((((LONG_LONG)sigrenderer->time_left << 16) | sigrenderer->sub_time_left) / dt); if (todo >= size) break; @@ -5545,28 +5512,9 @@ static int32 it_sigrenderer_get_samples( sigrenderer->sub_time_left = (int32)t & 65535; sigrenderer->time_left += (int32)(t >> 16); -#ifdef BIT_ARRAY_BULLSHIT - sigrenderer->time_played += (LONG_LONG)todo * dt; -#endif - - ret = process_tick(sigrenderer); - - if (ret) { + if (process_tick(sigrenderer)) { sigrenderer->order = -1; sigrenderer->row = -1; - } - -#ifdef BIT_ARRAY_BULLSHIT - if (sigrenderer->looped == 1) { - sigrenderer->looped = -1; - size = 0; - timekeeping_array_reset(sigrenderer->row_timekeeper, sigrenderer->order * 256 + sigrenderer->row); - sigrenderer->time_played = timekeeping_array_get_item(sigrenderer->row_timekeeper, sigrenderer->order * 256 + sigrenderer->row); - break; - } -#endif - - if (ret) { return pos; } } @@ -5579,10 +5527,6 @@ static int32 it_sigrenderer_get_samples( sigrenderer->sub_time_left = (int32)t & 65535; sigrenderer->time_left += (int32)(t >> 16); -#ifdef BIT_ARRAY_BULLSHIT - sigrenderer->time_played += (LONG_LONG)size * dt; -#endif - if (samples) dumb_remove_clicks_array(sigrenderer->n_channels, sigrenderer->click_remover, samples, pos, 512.0f / delta); @@ -5634,8 +5578,6 @@ void _dumb_it_end_sigrenderer(sigrenderer_t *vsigrenderer) #ifdef BIT_ARRAY_BULLSHIT bit_array_destroy(sigrenderer->played); - - timekeeping_array_destroy(sigrenderer->row_timekeeper); #endif free(vsigrenderer); @@ -5644,17 +5586,6 @@ void _dumb_it_end_sigrenderer(sigrenderer_t *vsigrenderer) -#ifdef BIT_ARRAY_BULLSHIT -static int32 it_sigrenderer_get_position(sigrenderer_t *vsigrenderer) -{ - DUMB_IT_SIGRENDERER *sigrenderer = vsigrenderer; - - return (int32)(sigrenderer->time_played >> 16); -} -#endif - - - DUH_SIGTYPE_DESC _dumb_sigtype_it = { SIGTYPE_IT, NULL, @@ -5662,11 +5593,6 @@ DUH_SIGTYPE_DESC _dumb_sigtype_it = { NULL, &it_sigrenderer_get_samples, &it_sigrenderer_get_current_sample, -#ifdef BIT_ARRAY_BULLSHIT - &it_sigrenderer_get_position, -#else - NULL, -#endif &_dumb_it_end_sigrenderer, &_dumb_it_unload_sigdata }; diff --git a/dumb/src/it/readamf.c b/dumb/src/it/readamf.c index 83f6075e7..820709e9d 100644 --- a/dumb/src/it/readamf.c +++ b/dumb/src/it/readamf.c @@ -320,6 +320,8 @@ static DUMB_IT_SIGDATA *it_amf_load_sigdata(DUMBFILE *f, int * version) free( sigdata ); return NULL; } + + sigdata->n_pchannels = nchannels; memset( sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS ); diff --git a/dumb/src/it/readptm.c b/dumb/src/it/readptm.c index 885929e42..9b34861db 100644 --- a/dumb/src/it/readptm.c +++ b/dumb/src/it/readptm.c @@ -439,6 +439,7 @@ static DUMB_IT_SIGDATA *it_ptm_load_sigdata(DUMBFILE *f) } if (dumbfile_seek(f, 352, DFS_SEEK_SET)) { + free(component); _dumb_it_unload_sigdata(sigdata); return NULL; } @@ -451,12 +452,14 @@ static DUMB_IT_SIGDATA *it_ptm_load_sigdata(DUMBFILE *f) } if (dumbfile_seek(f, 608, DFS_SEEK_SET)) { + free(component); _dumb_it_unload_sigdata(sigdata); return NULL; } for (n = 0; n < sigdata->n_samples; n++) { if (it_ptm_read_sample_header(&sigdata->sample[n], &component[n_components].offset, f)) { + free(component); _dumb_it_unload_sigdata(sigdata); return NULL; } diff --git a/dumb/src/it/readxm.c b/dumb/src/it/readxm.c index a06fd1e99..0c838ade8 100644 --- a/dumb/src/it/readxm.c +++ b/dumb/src/it/readxm.c @@ -1197,6 +1197,7 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version) sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument)); if (!sigdata->instrument) { + free(roguebytes); _dumb_it_unload_sigdata(sigdata); return NULL; } diff --git a/dumb/vc6/dumb/dumb.vcxproj b/dumb/vc6/dumb/dumb.vcxproj index 6e49557cf..ae8ebdb0b 100644 --- a/dumb/vc6/dumb/dumb.vcxproj +++ b/dumb/vc6/dumb/dumb.vcxproj @@ -118,7 +118,6 @@ - @@ -210,7 +209,6 @@ - diff --git a/dumb/vc6/dumb/dumb.vcxproj.filters b/dumb/vc6/dumb/dumb.vcxproj.filters index 167393748..422556dc2 100644 --- a/dumb/vc6/dumb/dumb.vcxproj.filters +++ b/dumb/vc6/dumb/dumb.vcxproj.filters @@ -279,9 +279,6 @@ src\helpers - - src\helpers - @@ -314,9 +311,6 @@ include\internal - - include\internal - diff --git a/dumb/vc6/dumb_static/dumb_static.vcproj b/dumb/vc6/dumb_static/dumb_static.vcproj index 497fe4a99..6d6736259 100644 --- a/dumb/vc6/dumb_static/dumb_static.vcproj +++ b/dumb/vc6/dumb_static/dumb_static.vcproj @@ -1203,10 +1203,6 @@ /> - - > 3] & (0x80 >> ((i) & 7))) != 0) + +#define SzBitWithVals_Check(p, i) ((p)->Defs && ((p)->Defs[(i) >> 3] & (0x80 >> ((i) & 7))) != 0) typedef struct { - UInt64 *PackSizes; - Byte *PackCRCsDefined; - UInt32 *PackCRCs; - CSzFolder *Folders; - CSzFileItem *Files; UInt32 NumPackStreams; UInt32 NumFolders; - UInt32 NumFiles; + + UInt64 *PackPositions; // NumPackStreams + 1 + CSzBitUi32s FolderCRCs; // NumFolders + + size_t *FoCodersOffsets; // NumFolders + 1 + UInt32 *FoStartPackStreamIndex; // NumFolders + 1 + UInt32 *FoToCoderUnpackSizes; // NumFolders + 1 + Byte *FoToMainUnpackSizeIndex; // NumFolders + UInt64 *CoderUnpackSizes; // for all coders in all folders + + Byte *CodersData; } CSzAr; -void SzAr_Init(CSzAr *p); -void SzAr_Free(CSzAr *p, ISzAlloc *alloc); +UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex); + +SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex, + ILookInStream *stream, UInt64 startPos, + Byte *outBuffer, size_t outSize, + ISzAlloc *allocMain); + +typedef struct +{ + CSzAr db; + + UInt64 startPosAfterHeader; + UInt64 dataPos; + + UInt32 NumFiles; + + UInt64 *UnpackPositions; // NumFiles + 1 + // Byte *IsEmptyFiles; + Byte *IsDirs; + CSzBitUi32s CRCs; + + CSzBitUi32s Attribs; + // CSzBitUi32s Parents; + CSzBitUi64s MTime; + CSzBitUi64s CTime; + + UInt32 *FolderToFile; // NumFolders + 1 + UInt32 *FileToFolder; // NumFiles + + size_t *FileNameOffsets; /* in 2-byte steps */ + Byte *FileNames; /* UTF-16-LE */ +} CSzArEx; + +#define SzArEx_IsDir(p, i) (SzBitArray_Check((p)->IsDirs, i)) + +#define SzArEx_GetFileSize(p, i) ((p)->UnpackPositions[(i) + 1] - (p)->UnpackPositions[i]) + +void SzArEx_Init(CSzArEx *p); +void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc); +UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder); +int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize); + +/* +if dest == NULL, the return value specifies the required size of the buffer, + in 16-bit characters, including the null-terminating character. +if dest != NULL, the return value specifies the number of 16-bit characters that + are written to the dest, including the null-terminating character. */ + +size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest); + +/* +size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex); +UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest); +*/ + /* - SzExtract extracts file from archive + SzArEx_Extract extracts file from archive *outBuffer must be 0 before first call for each new archive. @@ -143,35 +170,6 @@ void SzAr_Free(CSzAr *p, ISzAlloc *alloc); Free *outBuffer and set *outBuffer to 0, if you want to flush cache. */ -typedef struct -{ - CSzAr db; - - UInt64 startPosAfterHeader; - UInt64 dataPos; - - UInt32 *FolderStartPackStreamIndex; - UInt64 *PackStreamStartPositions; - UInt32 *FolderStartFileIndex; - UInt32 *FileIndexToFolderIndexMap; - - size_t *FileNameOffsets; /* in 2-byte steps */ - CBuf FileNames; /* UTF-16-LE */ -} CSzArEx; - -void SzArEx_Init(CSzArEx *p); -void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc); -UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder); -int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize); - -/* -if dest == NULL, the return value specifies the required size of the buffer, - in 16-bit characters, including the null-terminating character. -if dest != NULL, the return value specifies the number of 16-bit characters that - are written to the dest, including the null-terminating character. */ - -size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest); - SRes SzArEx_Extract( const CSzArEx *db, ILookInStream *inStream, @@ -196,7 +194,8 @@ SZ_ERROR_INPUT_EOF SZ_ERROR_FAIL */ -SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp); +SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, + ISzAlloc *allocMain, ISzAlloc *allocTemp); EXTERN_C_END diff --git a/lzma/C/7zArcIn.c b/lzma/C/7zArcIn.c new file mode 100644 index 000000000..06e35de0d --- /dev/null +++ b/lzma/C/7zArcIn.c @@ -0,0 +1,1770 @@ +/* 7zArcIn.c -- 7z Input functions +2015-11-18 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#include "7z.h" +#include "7zBuf.h" +#include "7zCrc.h" +#include "CpuArch.h" + +#define MY_ALLOC(T, p, size, alloc) { \ + if ((p = (T *)IAlloc_Alloc(alloc, (size) * sizeof(T))) == NULL) return SZ_ERROR_MEM; } + +#define MY_ALLOC_ZE(T, p, size, alloc) { if ((size) == 0) p = NULL; else MY_ALLOC(T, p, size, alloc) } + +#define MY_ALLOC_AND_CPY(to, size, from, alloc) \ + { MY_ALLOC(Byte, to, size, alloc); memcpy(to, from, size); } + +#define MY_ALLOC_ZE_AND_CPY(to, size, from, alloc) \ + { if ((size) == 0) p = NULL; else { MY_ALLOC_AND_CPY(to, size, from, alloc) } } + +#define k7zMajorVersion 0 + +enum EIdEnum +{ + k7zIdEnd, + k7zIdHeader, + k7zIdArchiveProperties, + k7zIdAdditionalStreamsInfo, + k7zIdMainStreamsInfo, + k7zIdFilesInfo, + k7zIdPackInfo, + k7zIdUnpackInfo, + k7zIdSubStreamsInfo, + k7zIdSize, + k7zIdCRC, + k7zIdFolder, + k7zIdCodersUnpackSize, + k7zIdNumUnpackStream, + k7zIdEmptyStream, + k7zIdEmptyFile, + k7zIdAnti, + k7zIdName, + k7zIdCTime, + k7zIdATime, + k7zIdMTime, + k7zIdWinAttrib, + k7zIdComment, + k7zIdEncodedHeader, + k7zIdStartPos, + k7zIdDummy + // k7zNtSecure, + // k7zParent, + // k7zIsReal +}; + +const Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; + +#define SzBitUi32s_Init(p) { (p)->Defs = NULL; (p)->Vals = NULL; } + +static SRes SzBitUi32s_Alloc(CSzBitUi32s *p, size_t num, ISzAlloc *alloc) +{ + if (num == 0) + { + p->Defs = NULL; + p->Vals = NULL; + } + else + { + MY_ALLOC(Byte, p->Defs, (num + 7) >> 3, alloc); + MY_ALLOC(UInt32, p->Vals, num, alloc); + } + return SZ_OK; +} + +void SzBitUi32s_Free(CSzBitUi32s *p, ISzAlloc *alloc) +{ + IAlloc_Free(alloc, p->Defs); p->Defs = NULL; + IAlloc_Free(alloc, p->Vals); p->Vals = NULL; +} + +#define SzBitUi64s_Init(p) { (p)->Defs = NULL; (p)->Vals = NULL; } + +void SzBitUi64s_Free(CSzBitUi64s *p, ISzAlloc *alloc) +{ + IAlloc_Free(alloc, p->Defs); p->Defs = NULL; + IAlloc_Free(alloc, p->Vals); p->Vals = NULL; +} + + +static void SzAr_Init(CSzAr *p) +{ + p->NumPackStreams = 0; + p->NumFolders = 0; + + p->PackPositions = NULL; + SzBitUi32s_Init(&p->FolderCRCs); + + p->FoCodersOffsets = NULL; + p->FoStartPackStreamIndex = NULL; + p->FoToCoderUnpackSizes = NULL; + p->FoToMainUnpackSizeIndex = NULL; + p->CoderUnpackSizes = NULL; + + p->CodersData = NULL; +} + +static void SzAr_Free(CSzAr *p, ISzAlloc *alloc) +{ + IAlloc_Free(alloc, p->PackPositions); + SzBitUi32s_Free(&p->FolderCRCs, alloc); + + IAlloc_Free(alloc, p->FoCodersOffsets); + IAlloc_Free(alloc, p->FoStartPackStreamIndex); + IAlloc_Free(alloc, p->FoToCoderUnpackSizes); + IAlloc_Free(alloc, p->FoToMainUnpackSizeIndex); + IAlloc_Free(alloc, p->CoderUnpackSizes); + + IAlloc_Free(alloc, p->CodersData); + + SzAr_Init(p); +} + + +void SzArEx_Init(CSzArEx *p) +{ + SzAr_Init(&p->db); + + p->NumFiles = 0; + p->dataPos = 0; + + p->UnpackPositions = NULL; + p->IsDirs = NULL; + + p->FolderToFile = NULL; + p->FileToFolder = NULL; + + p->FileNameOffsets = NULL; + p->FileNames = NULL; + + SzBitUi32s_Init(&p->CRCs); + SzBitUi32s_Init(&p->Attribs); + // SzBitUi32s_Init(&p->Parents); + SzBitUi64s_Init(&p->MTime); + SzBitUi64s_Init(&p->CTime); +} + +void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc) +{ + IAlloc_Free(alloc, p->UnpackPositions); + IAlloc_Free(alloc, p->IsDirs); + + IAlloc_Free(alloc, p->FolderToFile); + IAlloc_Free(alloc, p->FileToFolder); + + IAlloc_Free(alloc, p->FileNameOffsets); + IAlloc_Free(alloc, p->FileNames); + + SzBitUi32s_Free(&p->CRCs, alloc); + SzBitUi32s_Free(&p->Attribs, alloc); + // SzBitUi32s_Free(&p->Parents, alloc); + SzBitUi64s_Free(&p->MTime, alloc); + SzBitUi64s_Free(&p->CTime, alloc); + + SzAr_Free(&p->db, alloc); + SzArEx_Init(p); +} + + +static int TestSignatureCandidate(const Byte *testBytes) +{ + unsigned i; + for (i = 0; i < k7zSignatureSize; i++) + if (testBytes[i] != k7zSignature[i]) + return 0; + return 1; +} + +#define SzData_Clear(p) { (p)->Data = NULL; (p)->Size = 0; } + +#define SZ_READ_BYTE_SD(_sd_, dest) if ((_sd_)->Size == 0) return SZ_ERROR_ARCHIVE; (_sd_)->Size--; dest = *(_sd_)->Data++; +#define SZ_READ_BYTE(dest) SZ_READ_BYTE_SD(sd, dest) +#define SZ_READ_BYTE_2(dest) if (sd.Size == 0) return SZ_ERROR_ARCHIVE; sd.Size--; dest = *sd.Data++; + +#define SKIP_DATA(sd, size) { sd->Size -= (size_t)(size); sd->Data += (size_t)(size); } +#define SKIP_DATA2(sd, size) { sd.Size -= (size_t)(size); sd.Data += (size_t)(size); } + +#define SZ_READ_32(dest) if (sd.Size < 4) return SZ_ERROR_ARCHIVE; \ + dest = GetUi32(sd.Data); SKIP_DATA2(sd, 4); + +static MY_NO_INLINE SRes ReadNumber(CSzData *sd, UInt64 *value) +{ + Byte firstByte, mask; + unsigned i; + UInt32 v; + + SZ_READ_BYTE(firstByte); + if ((firstByte & 0x80) == 0) + { + *value = firstByte; + return SZ_OK; + } + SZ_READ_BYTE(v); + if ((firstByte & 0x40) == 0) + { + *value = (((UInt32)firstByte & 0x3F) << 8) | v; + return SZ_OK; + } + SZ_READ_BYTE(mask); + *value = v | ((UInt32)mask << 8); + mask = 0x20; + for (i = 2; i < 8; i++) + { + Byte b; + if ((firstByte & mask) == 0) + { + UInt64 highPart = (unsigned)firstByte & (unsigned)(mask - 1); + *value |= (highPart << (8 * i)); + return SZ_OK; + } + SZ_READ_BYTE(b); + *value |= ((UInt64)b << (8 * i)); + mask >>= 1; + } + return SZ_OK; +} + + +static MY_NO_INLINE SRes SzReadNumber32(CSzData *sd, UInt32 *value) +{ + Byte firstByte; + UInt64 value64; + if (sd->Size == 0) + return SZ_ERROR_ARCHIVE; + firstByte = *sd->Data; + if ((firstByte & 0x80) == 0) + { + *value = firstByte; + sd->Data++; + sd->Size--; + return SZ_OK; + } + RINOK(ReadNumber(sd, &value64)); + if (value64 >= (UInt32)0x80000000 - 1) + return SZ_ERROR_UNSUPPORTED; + if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 4))) + return SZ_ERROR_UNSUPPORTED; + *value = (UInt32)value64; + return SZ_OK; +} + +#define ReadID(sd, value) ReadNumber(sd, value) + +static SRes SkipData(CSzData *sd) +{ + UInt64 size; + RINOK(ReadNumber(sd, &size)); + if (size > sd->Size) + return SZ_ERROR_ARCHIVE; + SKIP_DATA(sd, size); + return SZ_OK; +} + +static SRes WaitId(CSzData *sd, UInt32 id) +{ + for (;;) + { + UInt64 type; + RINOK(ReadID(sd, &type)); + if (type == id) + return SZ_OK; + if (type == k7zIdEnd) + return SZ_ERROR_ARCHIVE; + RINOK(SkipData(sd)); + } +} + +static SRes RememberBitVector(CSzData *sd, UInt32 numItems, const Byte **v) +{ + UInt32 numBytes = (numItems + 7) >> 3; + if (numBytes > sd->Size) + return SZ_ERROR_ARCHIVE; + *v = sd->Data; + SKIP_DATA(sd, numBytes); + return SZ_OK; +} + +static UInt32 CountDefinedBits(const Byte *bits, UInt32 numItems) +{ + Byte b = 0; + unsigned m = 0; + UInt32 sum = 0; + for (; numItems != 0; numItems--) + { + if (m == 0) + { + b = *bits++; + m = 8; + } + m--; + sum += ((b >> m) & 1); + } + return sum; +} + +static MY_NO_INLINE SRes ReadBitVector(CSzData *sd, UInt32 numItems, Byte **v, ISzAlloc *alloc) +{ + Byte allAreDefined; + Byte *v2; + UInt32 numBytes = (numItems + 7) >> 3; + *v = NULL; + SZ_READ_BYTE(allAreDefined); + if (numBytes == 0) + return SZ_OK; + if (allAreDefined == 0) + { + if (numBytes > sd->Size) + return SZ_ERROR_ARCHIVE; + MY_ALLOC_AND_CPY(*v, numBytes, sd->Data, alloc); + SKIP_DATA(sd, numBytes); + return SZ_OK; + } + MY_ALLOC(Byte, *v, numBytes, alloc); + v2 = *v; + memset(v2, 0xFF, (size_t)numBytes); + { + unsigned numBits = (unsigned)numItems & 7; + if (numBits != 0) + v2[numBytes - 1] = (Byte)((((UInt32)1 << numBits) - 1) << (8 - numBits)); + } + return SZ_OK; +} + +static MY_NO_INLINE SRes ReadUi32s(CSzData *sd2, UInt32 numItems, CSzBitUi32s *crcs, ISzAlloc *alloc) +{ + UInt32 i; + CSzData sd; + UInt32 *vals; + const Byte *defs; + MY_ALLOC_ZE(UInt32, crcs->Vals, numItems, alloc); + sd = *sd2; + defs = crcs->Defs; + vals = crcs->Vals; + for (i = 0; i < numItems; i++) + if (SzBitArray_Check(defs, i)) + { + SZ_READ_32(vals[i]); + } + else + vals[i] = 0; + *sd2 = sd; + return SZ_OK; +} + +static SRes ReadBitUi32s(CSzData *sd, UInt32 numItems, CSzBitUi32s *crcs, ISzAlloc *alloc) +{ + SzBitUi32s_Free(crcs, alloc); + RINOK(ReadBitVector(sd, numItems, &crcs->Defs, alloc)); + return ReadUi32s(sd, numItems, crcs, alloc); +} + +static SRes SkipBitUi32s(CSzData *sd, UInt32 numItems) +{ + Byte allAreDefined; + UInt32 numDefined = numItems; + SZ_READ_BYTE(allAreDefined); + if (!allAreDefined) + { + size_t numBytes = (numItems + 7) >> 3; + if (numBytes > sd->Size) + return SZ_ERROR_ARCHIVE; + numDefined = CountDefinedBits(sd->Data, numItems); + SKIP_DATA(sd, numBytes); + } + if (numDefined > (sd->Size >> 2)) + return SZ_ERROR_ARCHIVE; + SKIP_DATA(sd, (size_t)numDefined * 4); + return SZ_OK; +} + +static SRes ReadPackInfo(CSzAr *p, CSzData *sd, ISzAlloc *alloc) +{ + RINOK(SzReadNumber32(sd, &p->NumPackStreams)); + + RINOK(WaitId(sd, k7zIdSize)); + MY_ALLOC(UInt64, p->PackPositions, (size_t)p->NumPackStreams + 1, alloc); + { + UInt64 sum = 0; + UInt32 i; + UInt32 numPackStreams = p->NumPackStreams; + for (i = 0; i < numPackStreams; i++) + { + UInt64 packSize; + p->PackPositions[i] = sum; + RINOK(ReadNumber(sd, &packSize)); + sum += packSize; + if (sum < packSize) + return SZ_ERROR_ARCHIVE; + } + p->PackPositions[i] = sum; + } + + for (;;) + { + UInt64 type; + RINOK(ReadID(sd, &type)); + if (type == k7zIdEnd) + return SZ_OK; + if (type == k7zIdCRC) + { + /* CRC of packed streams is unused now */ + RINOK(SkipBitUi32s(sd, p->NumPackStreams)); + continue; + } + RINOK(SkipData(sd)); + } +} + +/* +static SRes SzReadSwitch(CSzData *sd) +{ + Byte external; + RINOK(SzReadByte(sd, &external)); + return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED; +} +*/ + +#define k_NumCodersStreams_in_Folder_MAX (SZ_NUM_BONDS_IN_FOLDER_MAX + SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX) + +SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd) +{ + UInt32 numCoders, i; + UInt32 numInStreams = 0; + const Byte *dataStart = sd->Data; + + f->NumCoders = 0; + f->NumBonds = 0; + f->NumPackStreams = 0; + f->UnpackStream = 0; + + RINOK(SzReadNumber32(sd, &numCoders)); + if (numCoders == 0 || numCoders > SZ_NUM_CODERS_IN_FOLDER_MAX) + return SZ_ERROR_UNSUPPORTED; + + for (i = 0; i < numCoders; i++) + { + Byte mainByte; + CSzCoderInfo *coder = f->Coders + i; + unsigned idSize, j; + UInt64 id; + + SZ_READ_BYTE(mainByte); + if ((mainByte & 0xC0) != 0) + return SZ_ERROR_UNSUPPORTED; + + idSize = (unsigned)(mainByte & 0xF); + if (idSize > sizeof(id)) + return SZ_ERROR_UNSUPPORTED; + if (idSize > sd->Size) + return SZ_ERROR_ARCHIVE; + id = 0; + for (j = 0; j < idSize; j++) + { + id = ((id << 8) | *sd->Data); + sd->Data++; + sd->Size--; + } + if (id > (UInt32)0xFFFFFFFF) + return SZ_ERROR_UNSUPPORTED; + coder->MethodID = (UInt32)id; + + coder->NumStreams = 1; + coder->PropsOffset = 0; + coder->PropsSize = 0; + + if ((mainByte & 0x10) != 0) + { + UInt32 numStreams; + + RINOK(SzReadNumber32(sd, &numStreams)); + if (numStreams > k_NumCodersStreams_in_Folder_MAX) + return SZ_ERROR_UNSUPPORTED; + coder->NumStreams = (Byte)numStreams; + + RINOK(SzReadNumber32(sd, &numStreams)); + if (numStreams != 1) + return SZ_ERROR_UNSUPPORTED; + } + + numInStreams += coder->NumStreams; + + if (numInStreams > k_NumCodersStreams_in_Folder_MAX) + return SZ_ERROR_UNSUPPORTED; + + if ((mainByte & 0x20) != 0) + { + UInt32 propsSize = 0; + RINOK(SzReadNumber32(sd, &propsSize)); + if (propsSize > sd->Size) + return SZ_ERROR_ARCHIVE; + if (propsSize >= 0x80) + return SZ_ERROR_UNSUPPORTED; + coder->PropsOffset = sd->Data - dataStart; + coder->PropsSize = (Byte)propsSize; + sd->Data += (size_t)propsSize; + sd->Size -= (size_t)propsSize; + } + } + + /* + if (numInStreams == 1 && numCoders == 1) + { + f->NumPackStreams = 1; + f->PackStreams[0] = 0; + } + else + */ + { + Byte streamUsed[k_NumCodersStreams_in_Folder_MAX]; + UInt32 numBonds, numPackStreams; + + numBonds = numCoders - 1; + if (numInStreams < numBonds) + return SZ_ERROR_ARCHIVE; + if (numBonds > SZ_NUM_BONDS_IN_FOLDER_MAX) + return SZ_ERROR_UNSUPPORTED; + f->NumBonds = numBonds; + + numPackStreams = numInStreams - numBonds; + if (numPackStreams > SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX) + return SZ_ERROR_UNSUPPORTED; + f->NumPackStreams = numPackStreams; + + for (i = 0; i < numInStreams; i++) + streamUsed[i] = False; + + if (numBonds != 0) + { + Byte coderUsed[SZ_NUM_CODERS_IN_FOLDER_MAX]; + + for (i = 0; i < numCoders; i++) + coderUsed[i] = False; + + for (i = 0; i < numBonds; i++) + { + CSzBond *bp = f->Bonds + i; + + RINOK(SzReadNumber32(sd, &bp->InIndex)); + if (bp->InIndex >= numInStreams || streamUsed[bp->InIndex]) + return SZ_ERROR_ARCHIVE; + streamUsed[bp->InIndex] = True; + + RINOK(SzReadNumber32(sd, &bp->OutIndex)); + if (bp->OutIndex >= numCoders || coderUsed[bp->OutIndex]) + return SZ_ERROR_ARCHIVE; + coderUsed[bp->OutIndex] = True; + } + + for (i = 0; i < numCoders; i++) + if (!coderUsed[i]) + { + f->UnpackStream = i; + break; + } + + if (i == numCoders) + return SZ_ERROR_ARCHIVE; + } + + if (numPackStreams == 1) + { + for (i = 0; i < numInStreams; i++) + if (!streamUsed[i]) + break; + if (i == numInStreams) + return SZ_ERROR_ARCHIVE; + f->PackStreams[0] = i; + } + else + for (i = 0; i < numPackStreams; i++) + { + UInt32 index; + RINOK(SzReadNumber32(sd, &index)); + if (index >= numInStreams || streamUsed[index]) + return SZ_ERROR_ARCHIVE; + streamUsed[index] = True; + f->PackStreams[i] = index; + } + } + + f->NumCoders = numCoders; + + return SZ_OK; +} + + +static MY_NO_INLINE SRes SkipNumbers(CSzData *sd2, UInt32 num) +{ + CSzData sd; + sd = *sd2; + for (; num != 0; num--) + { + Byte firstByte, mask; + unsigned i; + SZ_READ_BYTE_2(firstByte); + if ((firstByte & 0x80) == 0) + continue; + if ((firstByte & 0x40) == 0) + { + if (sd.Size == 0) + return SZ_ERROR_ARCHIVE; + sd.Size--; + sd.Data++; + continue; + } + mask = 0x20; + for (i = 2; i < 8 && (firstByte & mask) != 0; i++) + mask >>= 1; + if (i > sd.Size) + return SZ_ERROR_ARCHIVE; + SKIP_DATA2(sd, i); + } + *sd2 = sd; + return SZ_OK; +} + + +#define k_Scan_NumCoders_MAX 64 +#define k_Scan_NumCodersStreams_in_Folder_MAX 64 + + +static SRes ReadUnpackInfo(CSzAr *p, + CSzData *sd2, + UInt32 numFoldersMax, + const CBuf *tempBufs, UInt32 numTempBufs, + ISzAlloc *alloc) +{ + CSzData sd; + + UInt32 fo, numFolders, numCodersOutStreams, packStreamIndex; + const Byte *startBufPtr; + Byte external; + + RINOK(WaitId(sd2, k7zIdFolder)); + + RINOK(SzReadNumber32(sd2, &numFolders)); + if (numFolders > numFoldersMax) + return SZ_ERROR_UNSUPPORTED; + p->NumFolders = numFolders; + + SZ_READ_BYTE_SD(sd2, external); + if (external == 0) + sd = *sd2; + else + { + UInt32 index; + RINOK(SzReadNumber32(sd2, &index)); + if (index >= numTempBufs) + return SZ_ERROR_ARCHIVE; + sd.Data = tempBufs[index].data; + sd.Size = tempBufs[index].size; + } + + MY_ALLOC(size_t, p->FoCodersOffsets, (size_t)numFolders + 1, alloc); + MY_ALLOC(UInt32, p->FoStartPackStreamIndex, (size_t)numFolders + 1, alloc); + MY_ALLOC(UInt32, p->FoToCoderUnpackSizes, (size_t)numFolders + 1, alloc); + MY_ALLOC(Byte, p->FoToMainUnpackSizeIndex, (size_t)numFolders, alloc); + + startBufPtr = sd.Data; + + packStreamIndex = 0; + numCodersOutStreams = 0; + + for (fo = 0; fo < numFolders; fo++) + { + UInt32 numCoders, ci, numInStreams = 0; + + p->FoCodersOffsets[fo] = sd.Data - startBufPtr; + + RINOK(SzReadNumber32(&sd, &numCoders)); + if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX) + return SZ_ERROR_UNSUPPORTED; + + for (ci = 0; ci < numCoders; ci++) + { + Byte mainByte; + unsigned idSize; + UInt32 coderInStreams; + + SZ_READ_BYTE_2(mainByte); + if ((mainByte & 0xC0) != 0) + return SZ_ERROR_UNSUPPORTED; + idSize = (mainByte & 0xF); + if (idSize > 8) + return SZ_ERROR_UNSUPPORTED; + if (idSize > sd.Size) + return SZ_ERROR_ARCHIVE; + SKIP_DATA2(sd, idSize); + + coderInStreams = 1; + + if ((mainByte & 0x10) != 0) + { + UInt32 coderOutStreams; + RINOK(SzReadNumber32(&sd, &coderInStreams)); + RINOK(SzReadNumber32(&sd, &coderOutStreams)); + if (coderInStreams > k_Scan_NumCodersStreams_in_Folder_MAX || coderOutStreams != 1) + return SZ_ERROR_UNSUPPORTED; + } + + numInStreams += coderInStreams; + + if ((mainByte & 0x20) != 0) + { + UInt32 propsSize; + RINOK(SzReadNumber32(&sd, &propsSize)); + if (propsSize > sd.Size) + return SZ_ERROR_ARCHIVE; + SKIP_DATA2(sd, propsSize); + } + } + + { + UInt32 indexOfMainStream = 0; + UInt32 numPackStreams = 1; + + if (numCoders != 1 || numInStreams != 1) + { + Byte streamUsed[k_Scan_NumCodersStreams_in_Folder_MAX]; + Byte coderUsed[k_Scan_NumCoders_MAX]; + + UInt32 i; + UInt32 numBonds = numCoders - 1; + if (numInStreams < numBonds) + return SZ_ERROR_ARCHIVE; + + if (numInStreams > k_Scan_NumCodersStreams_in_Folder_MAX) + return SZ_ERROR_UNSUPPORTED; + + for (i = 0; i < numInStreams; i++) + streamUsed[i] = False; + for (i = 0; i < numCoders; i++) + coderUsed[i] = False; + + for (i = 0; i < numBonds; i++) + { + UInt32 index; + + RINOK(SzReadNumber32(&sd, &index)); + if (index >= numInStreams || streamUsed[index]) + return SZ_ERROR_ARCHIVE; + streamUsed[index] = True; + + RINOK(SzReadNumber32(&sd, &index)); + if (index >= numCoders || coderUsed[index]) + return SZ_ERROR_ARCHIVE; + coderUsed[index] = True; + } + + numPackStreams = numInStreams - numBonds; + + if (numPackStreams != 1) + for (i = 0; i < numPackStreams; i++) + { + UInt32 index; + RINOK(SzReadNumber32(&sd, &index)); + if (index >= numInStreams || streamUsed[index]) + return SZ_ERROR_ARCHIVE; + streamUsed[index] = True; + } + + for (i = 0; i < numCoders; i++) + if (!coderUsed[i]) + { + indexOfMainStream = i; + break; + } + + if (i == numCoders) + return SZ_ERROR_ARCHIVE; + } + + p->FoStartPackStreamIndex[fo] = packStreamIndex; + p->FoToCoderUnpackSizes[fo] = numCodersOutStreams; + p->FoToMainUnpackSizeIndex[fo] = (Byte)indexOfMainStream; + numCodersOutStreams += numCoders; + if (numCodersOutStreams < numCoders) + return SZ_ERROR_UNSUPPORTED; + + packStreamIndex += numPackStreams; + if (packStreamIndex < numPackStreams) + return SZ_ERROR_UNSUPPORTED; + + if (packStreamIndex > p->NumPackStreams) + return SZ_ERROR_ARCHIVE; + } + } + + p->FoToCoderUnpackSizes[fo] = numCodersOutStreams; + + { + size_t dataSize = sd.Data - startBufPtr; + p->FoStartPackStreamIndex[fo] = packStreamIndex; + p->FoCodersOffsets[fo] = dataSize; + MY_ALLOC_ZE_AND_CPY(p->CodersData, dataSize, startBufPtr, alloc); + } + + if (external != 0) + { + if (sd.Size != 0) + return SZ_ERROR_ARCHIVE; + sd = *sd2; + } + + RINOK(WaitId(&sd, k7zIdCodersUnpackSize)); + + MY_ALLOC_ZE(UInt64, p->CoderUnpackSizes, (size_t)numCodersOutStreams, alloc); + { + UInt32 i; + for (i = 0; i < numCodersOutStreams; i++) + { + RINOK(ReadNumber(&sd, p->CoderUnpackSizes + i)); + } + } + + for (;;) + { + UInt64 type; + RINOK(ReadID(&sd, &type)); + if (type == k7zIdEnd) + { + *sd2 = sd; + return SZ_OK; + } + if (type == k7zIdCRC) + { + RINOK(ReadBitUi32s(&sd, numFolders, &p->FolderCRCs, alloc)); + continue; + } + RINOK(SkipData(&sd)); + } +} + + +UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex) +{ + return p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex] + p->FoToMainUnpackSizeIndex[folderIndex]]; +} + + +typedef struct +{ + UInt32 NumTotalSubStreams; + UInt32 NumSubDigests; + CSzData sdNumSubStreams; + CSzData sdSizes; + CSzData sdCRCs; +} CSubStreamInfo; + + +static SRes ReadSubStreamsInfo(CSzAr *p, CSzData *sd, CSubStreamInfo *ssi) +{ + UInt64 type = 0; + UInt32 numSubDigests = 0; + UInt32 numFolders = p->NumFolders; + UInt32 numUnpackStreams = numFolders; + UInt32 numUnpackSizesInData = 0; + + for (;;) + { + RINOK(ReadID(sd, &type)); + if (type == k7zIdNumUnpackStream) + { + UInt32 i; + ssi->sdNumSubStreams.Data = sd->Data; + numUnpackStreams = 0; + numSubDigests = 0; + for (i = 0; i < numFolders; i++) + { + UInt32 numStreams; + RINOK(SzReadNumber32(sd, &numStreams)); + if (numUnpackStreams > numUnpackStreams + numStreams) + return SZ_ERROR_UNSUPPORTED; + numUnpackStreams += numStreams; + if (numStreams != 0) + numUnpackSizesInData += (numStreams - 1); + if (numStreams != 1 || !SzBitWithVals_Check(&p->FolderCRCs, i)) + numSubDigests += numStreams; + } + ssi->sdNumSubStreams.Size = sd->Data - ssi->sdNumSubStreams.Data; + continue; + } + if (type == k7zIdCRC || type == k7zIdSize || type == k7zIdEnd) + break; + RINOK(SkipData(sd)); + } + + if (!ssi->sdNumSubStreams.Data) + { + numSubDigests = numFolders; + if (p->FolderCRCs.Defs) + numSubDigests = numFolders - CountDefinedBits(p->FolderCRCs.Defs, numFolders); + } + + ssi->NumTotalSubStreams = numUnpackStreams; + ssi->NumSubDigests = numSubDigests; + + if (type == k7zIdSize) + { + ssi->sdSizes.Data = sd->Data; + RINOK(SkipNumbers(sd, numUnpackSizesInData)); + ssi->sdSizes.Size = sd->Data - ssi->sdSizes.Data; + RINOK(ReadID(sd, &type)); + } + + for (;;) + { + if (type == k7zIdEnd) + return SZ_OK; + if (type == k7zIdCRC) + { + ssi->sdCRCs.Data = sd->Data; + RINOK(SkipBitUi32s(sd, numSubDigests)); + ssi->sdCRCs.Size = sd->Data - ssi->sdCRCs.Data; + } + else + { + RINOK(SkipData(sd)); + } + RINOK(ReadID(sd, &type)); + } +} + +static SRes SzReadStreamsInfo(CSzAr *p, + CSzData *sd, + UInt32 numFoldersMax, const CBuf *tempBufs, UInt32 numTempBufs, + UInt64 *dataOffset, + CSubStreamInfo *ssi, + ISzAlloc *alloc) +{ + UInt64 type; + + SzData_Clear(&ssi->sdSizes); + SzData_Clear(&ssi->sdCRCs); + SzData_Clear(&ssi->sdNumSubStreams); + + *dataOffset = 0; + RINOK(ReadID(sd, &type)); + if (type == k7zIdPackInfo) + { + RINOK(ReadNumber(sd, dataOffset)); + RINOK(ReadPackInfo(p, sd, alloc)); + RINOK(ReadID(sd, &type)); + } + if (type == k7zIdUnpackInfo) + { + RINOK(ReadUnpackInfo(p, sd, numFoldersMax, tempBufs, numTempBufs, alloc)); + RINOK(ReadID(sd, &type)); + } + if (type == k7zIdSubStreamsInfo) + { + RINOK(ReadSubStreamsInfo(p, sd, ssi)); + RINOK(ReadID(sd, &type)); + } + else + { + ssi->NumTotalSubStreams = p->NumFolders; + // ssi->NumSubDigests = 0; + } + + return (type == k7zIdEnd ? SZ_OK : SZ_ERROR_UNSUPPORTED); +} + +static SRes SzReadAndDecodePackedStreams( + ILookInStream *inStream, + CSzData *sd, + CBuf *tempBufs, + UInt32 numFoldersMax, + UInt64 baseOffset, + CSzAr *p, + ISzAlloc *allocTemp) +{ + UInt64 dataStartPos; + UInt32 fo; + CSubStreamInfo ssi; + + RINOK(SzReadStreamsInfo(p, sd, numFoldersMax, NULL, 0, &dataStartPos, &ssi, allocTemp)); + + dataStartPos += baseOffset; + if (p->NumFolders == 0) + return SZ_ERROR_ARCHIVE; + + for (fo = 0; fo < p->NumFolders; fo++) + Buf_Init(tempBufs + fo); + + for (fo = 0; fo < p->NumFolders; fo++) + { + CBuf *tempBuf = tempBufs + fo; + UInt64 unpackSize = SzAr_GetFolderUnpackSize(p, fo); + if ((size_t)unpackSize != unpackSize) + return SZ_ERROR_MEM; + if (!Buf_Create(tempBuf, (size_t)unpackSize, allocTemp)) + return SZ_ERROR_MEM; + } + + for (fo = 0; fo < p->NumFolders; fo++) + { + const CBuf *tempBuf = tempBufs + fo; + RINOK(LookInStream_SeekTo(inStream, dataStartPos)); + RINOK(SzAr_DecodeFolder(p, fo, inStream, dataStartPos, tempBuf->data, tempBuf->size, allocTemp)); + } + + return SZ_OK; +} + +static SRes SzReadFileNames(const Byte *data, size_t size, UInt32 numFiles, size_t *offsets) +{ + size_t pos = 0; + *offsets++ = 0; + if (numFiles == 0) + return (size == 0) ? SZ_OK : SZ_ERROR_ARCHIVE; + if (size < 2) + return SZ_ERROR_ARCHIVE; + if (data[size - 2] != 0 || data[size - 1] != 0) + return SZ_ERROR_ARCHIVE; + do + { + const Byte *p; + if (pos == size) + return SZ_ERROR_ARCHIVE; + for (p = data + pos; + #ifdef _WIN32 + *(const UInt16 *)p != 0 + #else + p[0] != 0 || p[1] != 0 + #endif + ; p += 2); + pos = p - data + 2; + *offsets++ = (pos >> 1); + } + while (--numFiles); + return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; +} + +static MY_NO_INLINE SRes ReadTime(CSzBitUi64s *p, UInt32 num, + CSzData *sd2, + const CBuf *tempBufs, UInt32 numTempBufs, + ISzAlloc *alloc) +{ + CSzData sd; + UInt32 i; + CNtfsFileTime *vals; + Byte *defs; + Byte external; + + RINOK(ReadBitVector(sd2, num, &p->Defs, alloc)); + + SZ_READ_BYTE_SD(sd2, external); + if (external == 0) + sd = *sd2; + else + { + UInt32 index; + RINOK(SzReadNumber32(sd2, &index)); + if (index >= numTempBufs) + return SZ_ERROR_ARCHIVE; + sd.Data = tempBufs[index].data; + sd.Size = tempBufs[index].size; + } + + MY_ALLOC_ZE(CNtfsFileTime, p->Vals, num, alloc); + vals = p->Vals; + defs = p->Defs; + for (i = 0; i < num; i++) + if (SzBitArray_Check(defs, i)) + { + if (sd.Size < 8) + return SZ_ERROR_ARCHIVE; + vals[i].Low = GetUi32(sd.Data); + vals[i].High = GetUi32(sd.Data + 4); + SKIP_DATA2(sd, 8); + } + else + vals[i].High = vals[i].Low = 0; + + if (external == 0) + *sd2 = sd; + + return SZ_OK; +} + + +#define NUM_ADDITIONAL_STREAMS_MAX 8 + + +static SRes SzReadHeader2( + CSzArEx *p, /* allocMain */ + CSzData *sd, + ILookInStream *inStream, + CBuf *tempBufs, UInt32 *numTempBufs, + ISzAlloc *allocMain, + ISzAlloc *allocTemp + ) +{ + UInt64 type; + UInt32 numFiles = 0; + UInt32 numEmptyStreams = 0; + CSubStreamInfo ssi; + const Byte *emptyStreams = NULL; + const Byte *emptyFiles = NULL; + + SzData_Clear(&ssi.sdSizes); + SzData_Clear(&ssi.sdCRCs); + SzData_Clear(&ssi.sdNumSubStreams); + + ssi.NumSubDigests = 0; + ssi.NumTotalSubStreams = 0; + + RINOK(ReadID(sd, &type)); + + if (type == k7zIdArchiveProperties) + { + for (;;) + { + UInt64 type; + RINOK(ReadID(sd, &type)); + if (type == k7zIdEnd) + break; + RINOK(SkipData(sd)); + } + RINOK(ReadID(sd, &type)); + } + + if (type == k7zIdAdditionalStreamsInfo) + { + CSzAr tempAr; + SRes res; + + SzAr_Init(&tempAr); + res = SzReadAndDecodePackedStreams(inStream, sd, tempBufs, NUM_ADDITIONAL_STREAMS_MAX, + p->startPosAfterHeader, &tempAr, allocTemp); + *numTempBufs = tempAr.NumFolders; + SzAr_Free(&tempAr, allocTemp); + + if (res != SZ_OK) + return res; + RINOK(ReadID(sd, &type)); + } + + if (type == k7zIdMainStreamsInfo) + { + RINOK(SzReadStreamsInfo(&p->db, sd, (UInt32)1 << 30, tempBufs, *numTempBufs, + &p->dataPos, &ssi, allocMain)); + p->dataPos += p->startPosAfterHeader; + RINOK(ReadID(sd, &type)); + } + + if (type == k7zIdEnd) + { + return SZ_OK; + } + + if (type != k7zIdFilesInfo) + return SZ_ERROR_ARCHIVE; + + RINOK(SzReadNumber32(sd, &numFiles)); + p->NumFiles = numFiles; + + for (;;) + { + UInt64 type; + UInt64 size; + RINOK(ReadID(sd, &type)); + if (type == k7zIdEnd) + break; + RINOK(ReadNumber(sd, &size)); + if (size > sd->Size) + return SZ_ERROR_ARCHIVE; + + if (type >= ((UInt32)1 << 8)) + { + SKIP_DATA(sd, size); + } + else switch ((unsigned)type) + { + case k7zIdName: + { + size_t namesSize; + const Byte *namesData; + Byte external; + + SZ_READ_BYTE(external); + if (external == 0) + { + namesSize = (size_t)size - 1; + namesData = sd->Data; + } + else + { + UInt32 index; + RINOK(SzReadNumber32(sd, &index)); + if (index >= *numTempBufs) + return SZ_ERROR_ARCHIVE; + namesData = (tempBufs)[index].data; + namesSize = (tempBufs)[index].size; + } + + if ((namesSize & 1) != 0) + return SZ_ERROR_ARCHIVE; + MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain); + MY_ALLOC_ZE_AND_CPY(p->FileNames, namesSize, namesData, allocMain); + RINOK(SzReadFileNames(p->FileNames, namesSize, numFiles, p->FileNameOffsets)) + if (external == 0) + { + SKIP_DATA(sd, namesSize); + } + break; + } + case k7zIdEmptyStream: + { + RINOK(RememberBitVector(sd, numFiles, &emptyStreams)); + numEmptyStreams = CountDefinedBits(emptyStreams, numFiles); + emptyFiles = NULL; + break; + } + case k7zIdEmptyFile: + { + RINOK(RememberBitVector(sd, numEmptyStreams, &emptyFiles)); + break; + } + case k7zIdWinAttrib: + { + Byte external; + CSzData sdSwitch; + CSzData *sdPtr; + SzBitUi32s_Free(&p->Attribs, allocMain); + RINOK(ReadBitVector(sd, numFiles, &p->Attribs.Defs, allocMain)); + + SZ_READ_BYTE(external); + if (external == 0) + sdPtr = sd; + else + { + UInt32 index; + RINOK(SzReadNumber32(sd, &index)); + if (index >= *numTempBufs) + return SZ_ERROR_ARCHIVE; + sdSwitch.Data = (tempBufs)[index].data; + sdSwitch.Size = (tempBufs)[index].size; + sdPtr = &sdSwitch; + } + RINOK(ReadUi32s(sdPtr, numFiles, &p->Attribs, allocMain)); + break; + } + /* + case k7zParent: + { + SzBitUi32s_Free(&p->Parents, allocMain); + RINOK(ReadBitVector(sd, numFiles, &p->Parents.Defs, allocMain)); + RINOK(SzReadSwitch(sd)); + RINOK(ReadUi32s(sd, numFiles, &p->Parents, allocMain)); + break; + } + */ + case k7zIdMTime: RINOK(ReadTime(&p->MTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)); break; + case k7zIdCTime: RINOK(ReadTime(&p->CTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)); break; + default: + { + SKIP_DATA(sd, size); + } + } + } + + if (numFiles - numEmptyStreams != ssi.NumTotalSubStreams) + return SZ_ERROR_ARCHIVE; + + for (;;) + { + UInt64 type; + RINOK(ReadID(sd, &type)); + if (type == k7zIdEnd) + break; + RINOK(SkipData(sd)); + } + + { + UInt32 i; + UInt32 emptyFileIndex = 0; + UInt32 folderIndex = 0; + UInt32 remSubStreams = 0; + UInt32 numSubStreams = 0; + UInt64 unpackPos = 0; + const Byte *digestsDefs = NULL; + const Byte *digestsVals = NULL; + UInt32 digestsValsIndex = 0; + UInt32 digestIndex; + Byte allDigestsDefined = 0; + Byte isDirMask = 0; + Byte crcMask = 0; + Byte mask = 0x80; + + MY_ALLOC(UInt32, p->FolderToFile, p->db.NumFolders + 1, allocMain); + MY_ALLOC_ZE(UInt32, p->FileToFolder, p->NumFiles, allocMain); + MY_ALLOC(UInt64, p->UnpackPositions, p->NumFiles + 1, allocMain); + MY_ALLOC_ZE(Byte, p->IsDirs, (p->NumFiles + 7) >> 3, allocMain); + + RINOK(SzBitUi32s_Alloc(&p->CRCs, p->NumFiles, allocMain)); + + if (ssi.sdCRCs.Size != 0) + { + SZ_READ_BYTE_SD(&ssi.sdCRCs, allDigestsDefined); + if (allDigestsDefined) + digestsVals = ssi.sdCRCs.Data; + else + { + size_t numBytes = (ssi.NumSubDigests + 7) >> 3; + digestsDefs = ssi.sdCRCs.Data; + digestsVals = digestsDefs + numBytes; + } + } + + digestIndex = 0; + + for (i = 0; i < numFiles; i++, mask >>= 1) + { + if (mask == 0) + { + UInt32 byteIndex = (i - 1) >> 3; + p->IsDirs[byteIndex] = isDirMask; + p->CRCs.Defs[byteIndex] = crcMask; + isDirMask = 0; + crcMask = 0; + mask = 0x80; + } + + p->UnpackPositions[i] = unpackPos; + p->CRCs.Vals[i] = 0; + + if (emptyStreams && SzBitArray_Check(emptyStreams, i)) + { + if (emptyFiles) + { + if (!SzBitArray_Check(emptyFiles, emptyFileIndex)) + isDirMask |= mask; + emptyFileIndex++; + } + else + isDirMask |= mask; + if (remSubStreams == 0) + { + p->FileToFolder[i] = (UInt32)-1; + continue; + } + } + + if (remSubStreams == 0) + { + for (;;) + { + if (folderIndex >= p->db.NumFolders) + return SZ_ERROR_ARCHIVE; + p->FolderToFile[folderIndex] = i; + numSubStreams = 1; + if (ssi.sdNumSubStreams.Data) + { + RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams)); + } + remSubStreams = numSubStreams; + if (numSubStreams != 0) + break; + { + UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + unpackPos += folderUnpackSize; + if (unpackPos < folderUnpackSize) + return SZ_ERROR_ARCHIVE; + } + + folderIndex++; + } + } + + p->FileToFolder[i] = folderIndex; + + if (emptyStreams && SzBitArray_Check(emptyStreams, i)) + continue; + + if (--remSubStreams == 0) + { + UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + UInt64 startFolderUnpackPos = p->UnpackPositions[p->FolderToFile[folderIndex]]; + if (folderUnpackSize < unpackPos - startFolderUnpackPos) + return SZ_ERROR_ARCHIVE; + unpackPos = startFolderUnpackPos + folderUnpackSize; + if (unpackPos < folderUnpackSize) + return SZ_ERROR_ARCHIVE; + + if (numSubStreams == 1 && SzBitWithVals_Check(&p->db.FolderCRCs, i)) + { + p->CRCs.Vals[i] = p->db.FolderCRCs.Vals[folderIndex]; + crcMask |= mask; + } + else if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex))) + { + p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4); + digestsValsIndex++; + crcMask |= mask; + } + + folderIndex++; + } + else + { + UInt64 v; + RINOK(ReadNumber(&ssi.sdSizes, &v)); + unpackPos += v; + if (unpackPos < v) + return SZ_ERROR_ARCHIVE; + if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex))) + { + p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4); + digestsValsIndex++; + crcMask |= mask; + } + } + } + + if (mask != 0x80) + { + UInt32 byteIndex = (i - 1) >> 3; + p->IsDirs[byteIndex] = isDirMask; + p->CRCs.Defs[byteIndex] = crcMask; + } + + p->UnpackPositions[i] = unpackPos; + + if (remSubStreams != 0) + return SZ_ERROR_ARCHIVE; + + for (;;) + { + p->FolderToFile[folderIndex] = i; + if (folderIndex >= p->db.NumFolders) + break; + if (!ssi.sdNumSubStreams.Data) + return SZ_ERROR_ARCHIVE; + RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams)); + if (numSubStreams != 0) + return SZ_ERROR_ARCHIVE; + /* + { + UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + unpackPos += folderUnpackSize; + if (unpackPos < folderUnpackSize) + return SZ_ERROR_ARCHIVE; + } + */ + folderIndex++; + } + + if (ssi.sdNumSubStreams.Data && ssi.sdNumSubStreams.Size != 0) + return SZ_ERROR_ARCHIVE; + } + + return SZ_OK; +} + + +static SRes SzReadHeader( + CSzArEx *p, + CSzData *sd, + ILookInStream *inStream, + ISzAlloc *allocMain, + ISzAlloc *allocTemp) +{ + UInt32 i; + UInt32 numTempBufs = 0; + SRes res; + CBuf tempBufs[NUM_ADDITIONAL_STREAMS_MAX]; + + for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++) + Buf_Init(tempBufs + i); + + res = SzReadHeader2(p, sd, inStream, + tempBufs, &numTempBufs, + allocMain, allocTemp); + + for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++) + Buf_Free(tempBufs + i, allocTemp); + + RINOK(res); + + if (sd->Size != 0) + return SZ_ERROR_FAIL; + + return res; +} + +static SRes SzArEx_Open2( + CSzArEx *p, + ILookInStream *inStream, + ISzAlloc *allocMain, + ISzAlloc *allocTemp) +{ + Byte header[k7zStartHeaderSize]; + Int64 startArcPos; + UInt64 nextHeaderOffset, nextHeaderSize; + size_t nextHeaderSizeT; + UInt32 nextHeaderCRC; + CBuf buf; + SRes res; + + startArcPos = 0; + RINOK(inStream->Seek(inStream, &startArcPos, SZ_SEEK_CUR)); + + RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE)); + + if (!TestSignatureCandidate(header)) + return SZ_ERROR_NO_ARCHIVE; + if (header[6] != k7zMajorVersion) + return SZ_ERROR_UNSUPPORTED; + + nextHeaderOffset = GetUi64(header + 12); + nextHeaderSize = GetUi64(header + 20); + nextHeaderCRC = GetUi32(header + 28); + + p->startPosAfterHeader = startArcPos + k7zStartHeaderSize; + + if (CrcCalc(header + 12, 20) != GetUi32(header + 8)) + return SZ_ERROR_CRC; + + nextHeaderSizeT = (size_t)nextHeaderSize; + if (nextHeaderSizeT != nextHeaderSize) + return SZ_ERROR_MEM; + if (nextHeaderSizeT == 0) + return SZ_OK; + if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize || + nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize) + return SZ_ERROR_NO_ARCHIVE; + + { + Int64 pos = 0; + RINOK(inStream->Seek(inStream, &pos, SZ_SEEK_END)); + if ((UInt64)pos < startArcPos + nextHeaderOffset || + (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset || + (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize) + return SZ_ERROR_INPUT_EOF; + } + + RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset)); + + if (!Buf_Create(&buf, nextHeaderSizeT, allocTemp)) + return SZ_ERROR_MEM; + + res = LookInStream_Read(inStream, buf.data, nextHeaderSizeT); + + if (res == SZ_OK) + { + res = SZ_ERROR_ARCHIVE; + if (CrcCalc(buf.data, nextHeaderSizeT) == nextHeaderCRC) + { + CSzData sd; + UInt64 type; + sd.Data = buf.data; + sd.Size = buf.size; + + res = ReadID(&sd, &type); + + if (res == SZ_OK && type == k7zIdEncodedHeader) + { + CSzAr tempAr; + CBuf tempBuf; + Buf_Init(&tempBuf); + + SzAr_Init(&tempAr); + res = SzReadAndDecodePackedStreams(inStream, &sd, &tempBuf, 1, p->startPosAfterHeader, &tempAr, allocTemp); + SzAr_Free(&tempAr, allocTemp); + + if (res != SZ_OK) + { + Buf_Free(&tempBuf, allocTemp); + } + else + { + Buf_Free(&buf, allocTemp); + buf.data = tempBuf.data; + buf.size = tempBuf.size; + sd.Data = buf.data; + sd.Size = buf.size; + res = ReadID(&sd, &type); + } + } + + if (res == SZ_OK) + { + if (type == k7zIdHeader) + { + /* + CSzData sd2; + unsigned ttt; + for (ttt = 0; ttt < 40000; ttt++) + { + SzArEx_Free(p, allocMain); + sd2 = sd; + res = SzReadHeader(p, &sd2, inStream, allocMain, allocTemp); + if (res != SZ_OK) + break; + } + */ + res = SzReadHeader(p, &sd, inStream, allocMain, allocTemp); + } + else + res = SZ_ERROR_UNSUPPORTED; + } + } + } + + Buf_Free(&buf, allocTemp); + return res; +} + + +SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, + ISzAlloc *allocMain, ISzAlloc *allocTemp) +{ + SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp); + if (res != SZ_OK) + SzArEx_Free(p, allocMain); + return res; +} + + +SRes SzArEx_Extract( + const CSzArEx *p, + ILookInStream *inStream, + UInt32 fileIndex, + UInt32 *blockIndex, + Byte **tempBuf, + size_t *outBufferSize, + size_t *offset, + size_t *outSizeProcessed, + ISzAlloc *allocMain, + ISzAlloc *allocTemp) +{ + UInt32 folderIndex = p->FileToFolder[fileIndex]; + SRes res = SZ_OK; + + *offset = 0; + *outSizeProcessed = 0; + + if (folderIndex == (UInt32)-1) + { + IAlloc_Free(allocMain, *tempBuf); + *blockIndex = folderIndex; + *tempBuf = NULL; + *outBufferSize = 0; + return SZ_OK; + } + + if (*tempBuf == NULL || *blockIndex != folderIndex) + { + UInt64 unpackSizeSpec = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + /* + UInt64 unpackSizeSpec = + p->UnpackPositions[p->FolderToFile[folderIndex + 1]] - + p->UnpackPositions[p->FolderToFile[folderIndex]]; + */ + size_t unpackSize = (size_t)unpackSizeSpec; + + if (unpackSize != unpackSizeSpec) + return SZ_ERROR_MEM; + *blockIndex = folderIndex; + IAlloc_Free(allocMain, *tempBuf); + *tempBuf = NULL; + + if (res == SZ_OK) + { + *outBufferSize = unpackSize; + if (unpackSize != 0) + { + *tempBuf = (Byte *)IAlloc_Alloc(allocMain, unpackSize); + if (*tempBuf == NULL) + res = SZ_ERROR_MEM; + } + + if (res == SZ_OK) + { + res = SzAr_DecodeFolder(&p->db, folderIndex, + inStream, p->dataPos, *tempBuf, unpackSize, allocTemp); + } + } + } + + if (res == SZ_OK) + { + UInt64 unpackPos = p->UnpackPositions[fileIndex]; + *offset = (size_t)(unpackPos - p->UnpackPositions[p->FolderToFile[folderIndex]]); + *outSizeProcessed = (size_t)(p->UnpackPositions[fileIndex + 1] - unpackPos); + if (*offset + *outSizeProcessed > *outBufferSize) + return SZ_ERROR_FAIL; + if (SzBitWithVals_Check(&p->CRCs, fileIndex)) + if (CrcCalc(*tempBuf + *offset, *outSizeProcessed) != p->CRCs.Vals[fileIndex]) + res = SZ_ERROR_CRC; + } + + return res; +} + + +size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest) +{ + size_t offs = p->FileNameOffsets[fileIndex]; + size_t len = p->FileNameOffsets[fileIndex + 1] - offs; + if (dest != 0) + { + size_t i; + const Byte *src = p->FileNames + offs * 2; + for (i = 0; i < len; i++) + dest[i] = GetUi16(src + i * 2); + } + return len; +} + +/* +size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex) +{ + size_t len; + if (!p->FileNameOffsets) + return 1; + len = 0; + for (;;) + { + UInt32 parent = (UInt32)(Int32)-1; + len += p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex]; + if SzBitWithVals_Check(&p->Parents, fileIndex) + parent = p->Parents.Vals[fileIndex]; + if (parent == (UInt32)(Int32)-1) + return len; + fileIndex = parent; + } +} + +UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest) +{ + Bool needSlash; + if (!p->FileNameOffsets) + { + *(--dest) = 0; + return dest; + } + needSlash = False; + for (;;) + { + UInt32 parent = (UInt32)(Int32)-1; + size_t curLen = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex]; + SzArEx_GetFileNameUtf16(p, fileIndex, dest - curLen); + if (needSlash) + *(dest - 1) = '/'; + needSlash = True; + dest -= curLen; + + if SzBitWithVals_Check(&p->Parents, fileIndex) + parent = p->Parents.Vals[fileIndex]; + if (parent == (UInt32)(Int32)-1) + return dest; + fileIndex = parent; + } +} +*/ diff --git a/lzma/C/7zBuf.c b/lzma/C/7zBuf.c index a35fa2f98..b0ac1104b 100644 --- a/lzma/C/7zBuf.c +++ b/lzma/C/7zBuf.c @@ -1,7 +1,7 @@ /* 7zBuf.c -- Byte Buffer -2008-03-28 -Igor Pavlov -Public domain */ +2013-01-21 : Igor Pavlov : Public domain */ + +#include "Precomp.h" #include "7zBuf.h" diff --git a/lzma/C/7zBuf.h b/lzma/C/7zBuf.h index 88ff0c2f2..e5f9218be 100644 --- a/lzma/C/7zBuf.h +++ b/lzma/C/7zBuf.h @@ -1,14 +1,12 @@ /* 7zBuf.h -- Byte Buffer -2009-02-07 : Igor Pavlov : Public domain */ +2013-01-18 : Igor Pavlov : Public domain */ #ifndef __7Z_BUF_H #define __7Z_BUF_H -#include "Types.h" +#include "7zTypes.h" -#ifdef __cplusplus -extern "C" { -#endif +EXTERN_C_BEGIN typedef struct { @@ -32,8 +30,6 @@ void DynBuf_SeekToBeg(CDynBuf *p); int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAlloc *alloc); void DynBuf_Free(CDynBuf *p, ISzAlloc *alloc); -#ifdef __cplusplus -} -#endif +EXTERN_C_END #endif diff --git a/lzma/C/7zCrc.c b/lzma/C/7zCrc.c index 6993a6988..607db3404 100644 --- a/lzma/C/7zCrc.c +++ b/lzma/C/7zCrc.c @@ -1,29 +1,35 @@ /* 7zCrc.c -- CRC32 init -2010-12-01 : Igor Pavlov : Public domain */ +2015-03-10 : Igor Pavlov : Public domain */ + +#include "Precomp.h" #include "7zCrc.h" #include "CpuArch.h" #define kCrcPoly 0xEDB88320 -#ifdef MY_CPU_X86_OR_AMD64 +#ifdef MY_CPU_LE #define CRC_NUM_TABLES 8 - UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table); -#elif defined(MY_CPU_LE) - #define CRC_NUM_TABLES 4 #else - #define CRC_NUM_TABLES 5 + #define CRC_NUM_TABLES 9 + #define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24)) + UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table); + UInt32 MY_FAST_CALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table); #endif #ifndef MY_CPU_BE UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table); + UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table); #endif typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table); -static CRC_FUNC g_CrcUpdate; +CRC_FUNC g_CrcUpdateT4; +CRC_FUNC g_CrcUpdateT8; +CRC_FUNC g_CrcUpdate; + UInt32 g_CrcTable[256 * CRC_NUM_TABLES]; UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size) @@ -36,6 +42,17 @@ UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size) return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL; } +#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table) +{ + const Byte *p = (const Byte *)data; + const Byte *pEnd = p + size; + for (; p != pEnd; p++) + v = CRC_UPDATE_BYTE_2(v, *p); + return v; +} + void MY_FAST_CALL CrcGenerateTable() { UInt32 i; @@ -52,22 +69,43 @@ void MY_FAST_CALL CrcGenerateTable() UInt32 r = g_CrcTable[i - 256]; g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8); } + + #if CRC_NUM_TABLES < 4 + g_CrcUpdate = CrcUpdateT1; + + #else + #ifdef MY_CPU_LE - g_CrcUpdate = CrcUpdateT4; + g_CrcUpdateT4 = CrcUpdateT4; + g_CrcUpdate = CrcUpdateT4; + + #if CRC_NUM_TABLES >= 8 + g_CrcUpdateT8 = CrcUpdateT8; - #if CRC_NUM_TABLES == 8 - if (!CPU_Is_InOrder()) - g_CrcUpdate = CrcUpdateT8; - #endif + #ifdef MY_CPU_X86_OR_AMD64 + if (!CPU_Is_InOrder()) + g_CrcUpdate = CrcUpdateT8; + #endif + #endif #else { #ifndef MY_CPU_BE - UInt32 k = 1; - if (*(const Byte *)&k == 1) + UInt32 k = 0x01020304; + const Byte *p = (const Byte *)&k; + if (p[0] == 4 && p[1] == 3) + { + g_CrcUpdateT4 = CrcUpdateT4; g_CrcUpdate = CrcUpdateT4; + #if CRC_NUM_TABLES >= 8 + g_CrcUpdateT8 = CrcUpdateT8; + // g_CrcUpdate = CrcUpdateT8; + #endif + } + else if (p[0] != 1 || p[1] != 2) + g_CrcUpdate = CrcUpdateT1; else #endif { @@ -76,8 +114,15 @@ void MY_FAST_CALL CrcGenerateTable() UInt32 x = g_CrcTable[i - 256]; g_CrcTable[i] = CRC_UINT32_SWAP(x); } + g_CrcUpdateT4 = CrcUpdateT1_BeT4; g_CrcUpdate = CrcUpdateT1_BeT4; + #if CRC_NUM_TABLES >= 8 + g_CrcUpdateT8 = CrcUpdateT1_BeT8; + // g_CrcUpdate = CrcUpdateT1_BeT8; + #endif } } #endif + + #endif } diff --git a/lzma/C/7zCrc.h b/lzma/C/7zCrc.h index 4a1ec38c9..3b0459402 100644 --- a/lzma/C/7zCrc.h +++ b/lzma/C/7zCrc.h @@ -1,10 +1,10 @@ /* 7zCrc.h -- CRC32 calculation -2009-11-21 : Igor Pavlov : Public domain */ +2013-01-18 : Igor Pavlov : Public domain */ #ifndef __7Z_CRC_H #define __7Z_CRC_H -#include "Types.h" +#include "7zTypes.h" EXTERN_C_BEGIN diff --git a/lzma/C/7zCrcOpt.c b/lzma/C/7zCrcOpt.c index 85405ccfc..58628efe5 100644 --- a/lzma/C/7zCrcOpt.c +++ b/lzma/C/7zCrcOpt.c @@ -1,12 +1,14 @@ /* 7zCrcOpt.c -- CRC32 calculation -2010-12-01 : Igor Pavlov : Public domain */ +2015-03-01 : Igor Pavlov : Public domain */ + +#include "Precomp.h" #include "CpuArch.h" -#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) - #ifndef MY_CPU_BE +#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table) { const Byte *p = (const Byte *)data; @@ -16,10 +18,10 @@ UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const U { v ^= *(const UInt32 *)p; v = - table[0x300 + (v & 0xFF)] ^ - table[0x200 + ((v >> 8) & 0xFF)] ^ - table[0x100 + ((v >> 16) & 0xFF)] ^ - table[0x000 + ((v >> 24))]; + table[0x300 + ((v ) & 0xFF)] + ^ table[0x200 + ((v >> 8) & 0xFF)] + ^ table[0x100 + ((v >> 16) & 0xFF)] + ^ table[0x000 + ((v >> 24))]; } for (; size > 0; size--, p++) v = CRC_UPDATE_BYTE_2(v, *p); @@ -28,7 +30,28 @@ UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const U UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table) { - return CrcUpdateT4(v, data, size, table); + const Byte *p = (const Byte *)data; + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++) + v = CRC_UPDATE_BYTE_2(v, *p); + for (; size >= 8; size -= 8, p += 8) + { + UInt32 d; + v ^= *(const UInt32 *)p; + v = + table[0x700 + ((v ) & 0xFF)] + ^ table[0x600 + ((v >> 8) & 0xFF)] + ^ table[0x500 + ((v >> 16) & 0xFF)] + ^ table[0x400 + ((v >> 24))]; + d = *((const UInt32 *)p + 1); + v ^= + table[0x300 + ((d ) & 0xFF)] + ^ table[0x200 + ((d >> 8) & 0xFF)] + ^ table[0x100 + ((d >> 16) & 0xFF)] + ^ table[0x000 + ((d >> 24))]; + } + for (; size > 0; size--, p++) + v = CRC_UPDATE_BYTE_2(v, *p); + return v; } #endif @@ -38,27 +61,55 @@ UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const U #define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24)) +#define CRC_UPDATE_BYTE_2_BE(crc, b) (table[(((crc) >> 24) ^ (b))] ^ ((crc) << 8)) + UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table) { const Byte *p = (const Byte *)data; - for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) - v = CRC_UPDATE_BYTE_2(v, *p); - v = CRC_UINT32_SWAP(v); table += 0x100; + v = CRC_UINT32_SWAP(v); + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) + v = CRC_UPDATE_BYTE_2_BE(v, *p); for (; size >= 4; size -= 4, p += 4) { v ^= *(const UInt32 *)p; v = - table[0x000 + (v & 0xFF)] ^ - table[0x100 + ((v >> 8) & 0xFF)] ^ - table[0x200 + ((v >> 16) & 0xFF)] ^ - table[0x300 + ((v >> 24))]; + table[0x000 + ((v ) & 0xFF)] + ^ table[0x100 + ((v >> 8) & 0xFF)] + ^ table[0x200 + ((v >> 16) & 0xFF)] + ^ table[0x300 + ((v >> 24))]; } - table -= 0x100; - v = CRC_UINT32_SWAP(v); for (; size > 0; size--, p++) - v = CRC_UPDATE_BYTE_2(v, *p); - return v; + v = CRC_UPDATE_BYTE_2_BE(v, *p); + return CRC_UINT32_SWAP(v); +} + +UInt32 MY_FAST_CALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table) +{ + const Byte *p = (const Byte *)data; + table += 0x100; + v = CRC_UINT32_SWAP(v); + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++) + v = CRC_UPDATE_BYTE_2_BE(v, *p); + for (; size >= 8; size -= 8, p += 8) + { + UInt32 d; + v ^= *(const UInt32 *)p; + v = + table[0x400 + ((v ) & 0xFF)] + ^ table[0x500 + ((v >> 8) & 0xFF)] + ^ table[0x600 + ((v >> 16) & 0xFF)] + ^ table[0x700 + ((v >> 24))]; + d = *((const UInt32 *)p + 1); + v ^= + table[0x000 + ((d ) & 0xFF)] + ^ table[0x100 + ((d >> 8) & 0xFF)] + ^ table[0x200 + ((d >> 16) & 0xFF)] + ^ table[0x300 + ((d >> 24))]; + } + for (; size > 0; size--, p++) + v = CRC_UPDATE_BYTE_2_BE(v, *p); + return CRC_UINT32_SWAP(v); } #endif diff --git a/lzma/C/7zDec.c b/lzma/C/7zDec.c index 338680747..e39b4ff12 100644 --- a/lzma/C/7zDec.c +++ b/lzma/C/7zDec.c @@ -1,15 +1,19 @@ /* 7zDec.c -- Decoding from 7z folder -2010-11-02 : Igor Pavlov : Public domain */ +2015-11-18 : Igor Pavlov : Public domain */ + +#include "Precomp.h" #include /* #define _7ZIP_PPMD_SUPPPORT */ #include "7z.h" +#include "7zCrc.h" #include "Bcj2.h" #include "Bra.h" #include "CpuArch.h" +#include "Delta.h" #include "LzmaDec.h" #include "Lzma2Dec.h" #ifdef _7ZIP_PPMD_SUPPPORT @@ -17,14 +21,17 @@ #endif #define k_Copy 0 +#define k_Delta 3 #define k_LZMA2 0x21 #define k_LZMA 0x30101 -#define k_BCJ 0x03030103 -#define k_PPC 0x03030205 -#define k_ARM 0x03030501 -#define k_ARMT 0x03030701 -#define k_SPARC 0x03030805 -#define k_BCJ2 0x0303011B +#define k_BCJ 0x3030103 +#define k_BCJ2 0x303011B +#define k_PPC 0x3030205 +#define k_IA64 0x3030401 +#define k_ARM 0x3030501 +#define k_ARMT 0x3030701 +#define k_SPARC 0x3030805 + #ifdef _7ZIP_PPMD_SUPPPORT @@ -63,7 +70,7 @@ static Byte ReadByte(void *pp) return 0; } -static SRes SzDecodePpmd(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream, +static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream, Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain) { CPpmd7 ppmd; @@ -77,12 +84,12 @@ static SRes SzDecodePpmd(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inSt s.res = SZ_OK; s.processed = 0; - if (coder->Props.size != 5) + if (propsSize != 5) return SZ_ERROR_UNSUPPORTED; { - unsigned order = coder->Props.data[0]; - UInt32 memSize = GetUi32(coder->Props.data + 1); + unsigned order = props[0]; + UInt32 memSize = GetUi32(props + 1); if (order < PPMD7_MIN_ORDER || order > PPMD7_MAX_ORDER || memSize < PPMD7_MIN_MEM_SIZE || @@ -124,25 +131,25 @@ static SRes SzDecodePpmd(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inSt #endif -static SRes SzDecodeLzma(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream, +static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream, Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain) { CLzmaDec state; SRes res = SZ_OK; LzmaDec_Construct(&state); - RINOK(LzmaDec_AllocateProbs(&state, coder->Props.data, (unsigned)coder->Props.size, allocMain)); + RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain)); state.dic = outBuffer; state.dicBufSize = outSize; LzmaDec_Init(&state); for (;;) { - Byte *inBuf = NULL; + const void *inBuf = NULL; size_t lookahead = (1 << 18); if (lookahead > inSize) lookahead = (size_t)inSize; - res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead); + res = inStream->Look(inStream, &inBuf, &lookahead); if (res != SZ_OK) break; @@ -154,14 +161,23 @@ static SRes SzDecodeLzma(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inSt inSize -= inProcessed; if (res != SZ_OK) break; - if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == state.dicPos)) + + if (status == LZMA_STATUS_FINISHED_WITH_MARK) { - if (state.dicBufSize != outSize || lookahead != 0 || - (status != LZMA_STATUS_FINISHED_WITH_MARK && - status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)) + if (outSize != state.dicPos || inSize != 0) res = SZ_ERROR_DATA; break; } + + if (outSize == state.dicPos && inSize == 0 && status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) + break; + + if (inProcessed == 0 && dicPos == state.dicPos) + { + res = SZ_ERROR_DATA; + break; + } + res = inStream->Skip((void *)inStream, inProcessed); if (res != SZ_OK) break; @@ -172,27 +188,30 @@ static SRes SzDecodeLzma(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inSt return res; } -static SRes SzDecodeLzma2(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream, + +#ifndef _7Z_NO_METHOD_LZMA2 + +static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream, Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain) { CLzma2Dec state; SRes res = SZ_OK; Lzma2Dec_Construct(&state); - if (coder->Props.size != 1) + if (propsSize != 1) return SZ_ERROR_DATA; - RINOK(Lzma2Dec_AllocateProbs(&state, coder->Props.data[0], allocMain)); + RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain)); state.decoder.dic = outBuffer; state.decoder.dicBufSize = outSize; Lzma2Dec_Init(&state); for (;;) { - Byte *inBuf = NULL; + const void *inBuf = NULL; size_t lookahead = (1 << 18); if (lookahead > inSize) lookahead = (size_t)inSize; - res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead); + res = inStream->Look(inStream, &inBuf, &lookahead); if (res != SZ_OK) break; @@ -204,13 +223,20 @@ static SRes SzDecodeLzma2(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inS inSize -= inProcessed; if (res != SZ_OK) break; - if (state.decoder.dicPos == state.decoder.dicBufSize || (inProcessed == 0 && dicPos == state.decoder.dicPos)) + + if (status == LZMA_STATUS_FINISHED_WITH_MARK) { - if (state.decoder.dicBufSize != outSize || lookahead != 0 || - (status != LZMA_STATUS_FINISHED_WITH_MARK)) + if (outSize != state.decoder.dicPos || inSize != 0) res = SZ_ERROR_DATA; break; } + + if (inProcessed == 0 && dicPos == state.decoder.dicPos) + { + res = SZ_ERROR_DATA; + break; + } + res = inStream->Skip((void *)inStream, inProcessed); if (res != SZ_OK) break; @@ -221,15 +247,18 @@ static SRes SzDecodeLzma2(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inS return res; } +#endif + + static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer) { while (inSize > 0) { - void *inBuf; + const void *inBuf; size_t curSize = (1 << 18); if (curSize > inSize) curSize = (size_t)inSize; - RINOK(inStream->Look((void *)inStream, (const void **)&inBuf, &curSize)); + RINOK(inStream->Look(inStream, &inBuf, &curSize)); if (curSize == 0) return SZ_ERROR_INPUT_EOF; memcpy(outBuffer, inBuf, curSize); @@ -242,11 +271,13 @@ static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer static Bool IS_MAIN_METHOD(UInt32 m) { - switch(m) + switch (m) { case k_Copy: case k_LZMA: + #ifndef _7Z_NO_METHOD_LZMA2 case k_LZMA2: + #endif #ifdef _7ZIP_PPMD_SUPPPORT case k_PPMD: #endif @@ -258,13 +289,12 @@ static Bool IS_MAIN_METHOD(UInt32 m) static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c) { return - c->NumInStreams == 1 && - c->NumOutStreams == 1 && - c->MethodID <= (UInt32)0xFFFFFFFF && - IS_MAIN_METHOD((UInt32)c->MethodID); + c->NumStreams == 1 + /* && c->MethodID <= (UInt32)0xFFFFFFFF */ + && IS_MAIN_METHOD((UInt32)c->MethodID); } -#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumInStreams == 4 && (c)->NumOutStreams == 1) +#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumStreams == 4) static SRes CheckSupportedFolder(const CSzFolder *f) { @@ -274,65 +304,73 @@ static SRes CheckSupportedFolder(const CSzFolder *f) return SZ_ERROR_UNSUPPORTED; if (f->NumCoders == 1) { - if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0) + if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBonds != 0) return SZ_ERROR_UNSUPPORTED; return SZ_OK; } + + + #ifndef _7Z_NO_METHODS_FILTERS + if (f->NumCoders == 2) { - CSzCoderInfo *c = &f->Coders[1]; - if (c->MethodID > (UInt32)0xFFFFFFFF || - c->NumInStreams != 1 || - c->NumOutStreams != 1 || - f->NumPackStreams != 1 || - f->PackStreams[0] != 0 || - f->NumBindPairs != 1 || - f->BindPairs[0].InIndex != 1 || - f->BindPairs[0].OutIndex != 0) + const CSzCoderInfo *c = &f->Coders[1]; + if ( + /* c->MethodID > (UInt32)0xFFFFFFFF || */ + c->NumStreams != 1 + || f->NumPackStreams != 1 + || f->PackStreams[0] != 0 + || f->NumBonds != 1 + || f->Bonds[0].InIndex != 1 + || f->Bonds[0].OutIndex != 0) return SZ_ERROR_UNSUPPORTED; switch ((UInt32)c->MethodID) { + case k_Delta: case k_BCJ: + case k_PPC: + case k_IA64: + case k_SPARC: case k_ARM: + case k_ARMT: break; default: return SZ_ERROR_UNSUPPORTED; } return SZ_OK; } + + #endif + + if (f->NumCoders == 4) { - if (!IS_SUPPORTED_CODER(&f->Coders[1]) || - !IS_SUPPORTED_CODER(&f->Coders[2]) || - !IS_BCJ2(&f->Coders[3])) + if (!IS_SUPPORTED_CODER(&f->Coders[1]) + || !IS_SUPPORTED_CODER(&f->Coders[2]) + || !IS_BCJ2(&f->Coders[3])) return SZ_ERROR_UNSUPPORTED; - if (f->NumPackStreams != 4 || - f->PackStreams[0] != 2 || - f->PackStreams[1] != 6 || - f->PackStreams[2] != 1 || - f->PackStreams[3] != 0 || - f->NumBindPairs != 3 || - f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 || - f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 || - f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2) + if (f->NumPackStreams != 4 + || f->PackStreams[0] != 2 + || f->PackStreams[1] != 6 + || f->PackStreams[2] != 1 + || f->PackStreams[3] != 0 + || f->NumBonds != 3 + || f->Bonds[0].InIndex != 5 || f->Bonds[0].OutIndex != 0 + || f->Bonds[1].InIndex != 4 || f->Bonds[1].OutIndex != 1 + || f->Bonds[2].InIndex != 3 || f->Bonds[2].OutIndex != 2) return SZ_ERROR_UNSUPPORTED; return SZ_OK; } + return SZ_ERROR_UNSUPPORTED; } -static UInt64 GetSum(const UInt64 *values, UInt32 index) -{ - UInt64 sum = 0; - UInt32 i; - for (i = 0; i < index; i++) - sum += values[i]; - return sum; -} - #define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break; -static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes, +static SRes SzFolder_Decode2(const CSzFolder *folder, + const Byte *propsData, + const UInt64 *unpackSizes, + const UInt64 *packPositions, ILookInStream *inStream, UInt64 startPos, Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain, Byte *tempBuf[]) @@ -346,7 +384,7 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes, for (ci = 0; ci < folder->NumCoders; ci++) { - CSzCoderInfo *coder = &folder->Coders[ci]; + const CSzCoderInfo *coder = &folder->Coders[ci]; if (IS_MAIN_METHOD((UInt32)coder->MethodID)) { @@ -358,7 +396,7 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes, if (folder->NumCoders == 4) { UInt32 indices[] = { 3, 2, 0 }; - UInt64 unpackSize = folder->UnpackSizes[ci]; + UInt64 unpackSize = unpackSizes[ci]; si = indices[ci]; if (ci < 2) { @@ -367,7 +405,7 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes, if (outSizeCur != unpackSize) return SZ_ERROR_MEM; temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur); - if (temp == 0 && outSizeCur != 0) + if (!temp && outSizeCur != 0) return SZ_ERROR_MEM; outBufCur = tempBuf[1 - ci] = temp; tempSizes[1 - ci] = outSizeCur; @@ -382,8 +420,8 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes, else return SZ_ERROR_UNSUPPORTED; } - offset = GetSum(packSizes, si); - inSize = packSizes[si]; + offset = packPositions[si]; + inSize = packPositions[si + 1] - offset; RINOK(LookInStream_SeekTo(inStream, startPos + offset)); if (coder->MethodID == k_Copy) @@ -394,77 +432,160 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes, } else if (coder->MethodID == k_LZMA) { - RINOK(SzDecodeLzma(coder, inSize, inStream, outBufCur, outSizeCur, allocMain)); + RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); } + #ifndef _7Z_NO_METHOD_LZMA2 else if (coder->MethodID == k_LZMA2) { - RINOK(SzDecodeLzma2(coder, inSize, inStream, outBufCur, outSizeCur, allocMain)); + RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); } - else + #endif + #ifdef _7ZIP_PPMD_SUPPPORT + else if (coder->MethodID == k_PPMD) { - #ifdef _7ZIP_PPMD_SUPPPORT - RINOK(SzDecodePpmd(coder, inSize, inStream, outBufCur, outSizeCur, allocMain)); - #else - return SZ_ERROR_UNSUPPORTED; - #endif + RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); } + #endif + else + return SZ_ERROR_UNSUPPORTED; } else if (coder->MethodID == k_BCJ2) { - UInt64 offset = GetSum(packSizes, 1); - UInt64 s3Size = packSizes[1]; - SRes res; + UInt64 offset = packPositions[1]; + UInt64 s3Size = packPositions[2] - offset; + if (ci != 3) return SZ_ERROR_UNSUPPORTED; - RINOK(LookInStream_SeekTo(inStream, startPos + offset)); + tempSizes[2] = (SizeT)s3Size; if (tempSizes[2] != s3Size) return SZ_ERROR_MEM; tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]); - if (tempBuf[2] == 0 && tempSizes[2] != 0) + if (!tempBuf[2] && tempSizes[2] != 0) return SZ_ERROR_MEM; - res = SzDecodeCopy(s3Size, inStream, tempBuf[2]); - RINOK(res) + + RINOK(LookInStream_SeekTo(inStream, startPos + offset)); + RINOK(SzDecodeCopy(s3Size, inStream, tempBuf[2])); + + if ((tempSizes[0] & 3) != 0 || + (tempSizes[1] & 3) != 0 || + tempSize3 + tempSizes[0] + tempSizes[1] != outSize) + return SZ_ERROR_DATA; - res = Bcj2_Decode( - tempBuf3, tempSize3, - tempBuf[0], tempSizes[0], - tempBuf[1], tempSizes[1], - tempBuf[2], tempSizes[2], - outBuffer, outSize); - RINOK(res) - } - else - { - if (ci != 1) - return SZ_ERROR_UNSUPPORTED; - switch(coder->MethodID) { - case k_BCJ: + CBcj2Dec p; + + p.bufs[0] = tempBuf3; p.lims[0] = tempBuf3 + tempSize3; + p.bufs[1] = tempBuf[0]; p.lims[1] = tempBuf[0] + tempSizes[0]; + p.bufs[2] = tempBuf[1]; p.lims[2] = tempBuf[1] + tempSizes[1]; + p.bufs[3] = tempBuf[2]; p.lims[3] = tempBuf[2] + tempSizes[2]; + + p.dest = outBuffer; + p.destLim = outBuffer + outSize; + + Bcj2Dec_Init(&p); + RINOK(Bcj2Dec_Decode(&p)); + { - UInt32 state; - x86_Convert_Init(state); - x86_Convert(outBuffer, outSize, 0, &state, 0); - break; + unsigned i; + for (i = 0; i < 4; i++) + if (p.bufs[i] != p.lims[i]) + return SZ_ERROR_DATA; + + if (!Bcj2Dec_IsFinished(&p)) + return SZ_ERROR_DATA; + + if (p.dest != p.destLim + || p.state != BCJ2_STREAM_MAIN) + return SZ_ERROR_DATA; } - CASE_BRA_CONV(ARM) - default: - return SZ_ERROR_UNSUPPORTED; } } + #ifndef _7Z_NO_METHODS_FILTERS + else if (ci == 1) + { + if (coder->MethodID == k_Delta) + { + if (coder->PropsSize != 1) + return SZ_ERROR_UNSUPPORTED; + { + Byte state[DELTA_STATE_SIZE]; + Delta_Init(state); + Delta_Decode(state, (unsigned)(propsData[coder->PropsOffset]) + 1, outBuffer, outSize); + } + } + else + { + if (coder->PropsSize != 0) + return SZ_ERROR_UNSUPPORTED; + switch (coder->MethodID) + { + case k_BCJ: + { + UInt32 state; + x86_Convert_Init(state); + x86_Convert(outBuffer, outSize, 0, &state, 0); + break; + } + CASE_BRA_CONV(PPC) + CASE_BRA_CONV(IA64) + CASE_BRA_CONV(SPARC) + CASE_BRA_CONV(ARM) + CASE_BRA_CONV(ARMT) + default: + return SZ_ERROR_UNSUPPORTED; + } + } + } + #endif + else + return SZ_ERROR_UNSUPPORTED; } + return SZ_OK; } -SRes SzFolder_Decode(const CSzFolder *folder, const UInt64 *packSizes, + +SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex, ILookInStream *inStream, UInt64 startPos, - Byte *outBuffer, size_t outSize, ISzAlloc *allocMain) + Byte *outBuffer, size_t outSize, + ISzAlloc *allocMain) { - Byte *tempBuf[3] = { 0, 0, 0}; - int i; - SRes res = SzFolder_Decode2(folder, packSizes, inStream, startPos, - outBuffer, (SizeT)outSize, allocMain, tempBuf); - for (i = 0; i < 3; i++) - IAlloc_Free(allocMain, tempBuf[i]); - return res; + SRes res; + CSzFolder folder; + CSzData sd; + + const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex]; + sd.Data = data; + sd.Size = p->FoCodersOffsets[folderIndex + 1] - p->FoCodersOffsets[folderIndex]; + + res = SzGetNextFolderItem(&folder, &sd); + + if (res != SZ_OK) + return res; + + if (sd.Size != 0 + || folder.UnpackStream != p->FoToMainUnpackSizeIndex[folderIndex] + || outSize != SzAr_GetFolderUnpackSize(p, folderIndex)) + return SZ_ERROR_FAIL; + { + unsigned i; + Byte *tempBuf[3] = { 0, 0, 0}; + + res = SzFolder_Decode2(&folder, data, + &p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex]], + p->PackPositions + p->FoStartPackStreamIndex[folderIndex], + inStream, startPos, + outBuffer, (SizeT)outSize, allocMain, tempBuf); + + for (i = 0; i < 3; i++) + IAlloc_Free(allocMain, tempBuf[i]); + + if (res == SZ_OK) + if (SzBitWithVals_Check(&p->FolderCRCs, folderIndex)) + if (CrcCalc(outBuffer, outSize) != p->FolderCRCs.Vals[folderIndex]) + res = SZ_ERROR_CRC; + + return res; + } } diff --git a/lzma/C/7zIn.c b/lzma/C/7zIn.c deleted file mode 100644 index f1a44928e..000000000 --- a/lzma/C/7zIn.c +++ /dev/null @@ -1,1402 +0,0 @@ -/* 7zIn.c -- 7z Input functions -2010-10-29 : Igor Pavlov : Public domain */ - -#include - -#include "7z.h" -#include "7zCrc.h" -#include "CpuArch.h" - -Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; - -#define RINOM(x) { if ((x) == 0) return SZ_ERROR_MEM; } - -#define NUM_FOLDER_CODERS_MAX 32 -#define NUM_CODER_STREAMS_MAX 32 - -void SzCoderInfo_Init(CSzCoderInfo *p) -{ - Buf_Init(&p->Props); -} - -void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc) -{ - Buf_Free(&p->Props, alloc); - SzCoderInfo_Init(p); -} - -void SzFolder_Init(CSzFolder *p) -{ - p->Coders = 0; - p->BindPairs = 0; - p->PackStreams = 0; - p->UnpackSizes = 0; - p->NumCoders = 0; - p->NumBindPairs = 0; - p->NumPackStreams = 0; - p->UnpackCRCDefined = 0; - p->UnpackCRC = 0; - p->NumUnpackStreams = 0; -} - -void SzFolder_Free(CSzFolder *p, ISzAlloc *alloc) -{ - UInt32 i; - if (p->Coders) - for (i = 0; i < p->NumCoders; i++) - SzCoderInfo_Free(&p->Coders[i], alloc); - IAlloc_Free(alloc, p->Coders); - IAlloc_Free(alloc, p->BindPairs); - IAlloc_Free(alloc, p->PackStreams); - IAlloc_Free(alloc, p->UnpackSizes); - SzFolder_Init(p); -} - -UInt32 SzFolder_GetNumOutStreams(CSzFolder *p) -{ - UInt32 result = 0; - UInt32 i; - for (i = 0; i < p->NumCoders; i++) - result += p->Coders[i].NumOutStreams; - return result; -} - -int SzFolder_FindBindPairForInStream(CSzFolder *p, UInt32 inStreamIndex) -{ - UInt32 i; - for (i = 0; i < p->NumBindPairs; i++) - if (p->BindPairs[i].InIndex == inStreamIndex) - return i; - return -1; -} - - -int SzFolder_FindBindPairForOutStream(CSzFolder *p, UInt32 outStreamIndex) -{ - UInt32 i; - for (i = 0; i < p->NumBindPairs; i++) - if (p->BindPairs[i].OutIndex == outStreamIndex) - return i; - return -1; -} - -UInt64 SzFolder_GetUnpackSize(CSzFolder *p) -{ - int i = (int)SzFolder_GetNumOutStreams(p); - if (i == 0) - return 0; - for (i--; i >= 0; i--) - if (SzFolder_FindBindPairForOutStream(p, i) < 0) - return p->UnpackSizes[i]; - /* throw 1; */ - return 0; -} - -void SzFile_Init(CSzFileItem *p) -{ - p->HasStream = 1; - p->IsDir = 0; - p->IsAnti = 0; - p->CrcDefined = 0; - p->MTimeDefined = 0; -} - -void SzAr_Init(CSzAr *p) -{ - p->PackSizes = 0; - p->PackCRCsDefined = 0; - p->PackCRCs = 0; - p->Folders = 0; - p->Files = 0; - p->NumPackStreams = 0; - p->NumFolders = 0; - p->NumFiles = 0; -} - -void SzAr_Free(CSzAr *p, ISzAlloc *alloc) -{ - UInt32 i; - if (p->Folders) - for (i = 0; i < p->NumFolders; i++) - SzFolder_Free(&p->Folders[i], alloc); - - IAlloc_Free(alloc, p->PackSizes); - IAlloc_Free(alloc, p->PackCRCsDefined); - IAlloc_Free(alloc, p->PackCRCs); - IAlloc_Free(alloc, p->Folders); - IAlloc_Free(alloc, p->Files); - SzAr_Init(p); -} - - -void SzArEx_Init(CSzArEx *p) -{ - SzAr_Init(&p->db); - p->FolderStartPackStreamIndex = 0; - p->PackStreamStartPositions = 0; - p->FolderStartFileIndex = 0; - p->FileIndexToFolderIndexMap = 0; - p->FileNameOffsets = 0; - Buf_Init(&p->FileNames); -} - -void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc) -{ - IAlloc_Free(alloc, p->FolderStartPackStreamIndex); - IAlloc_Free(alloc, p->PackStreamStartPositions); - IAlloc_Free(alloc, p->FolderStartFileIndex); - IAlloc_Free(alloc, p->FileIndexToFolderIndexMap); - - IAlloc_Free(alloc, p->FileNameOffsets); - Buf_Free(&p->FileNames, alloc); - - SzAr_Free(&p->db, alloc); - SzArEx_Init(p); -} - -/* -UInt64 GetFolderPackStreamSize(int folderIndex, int streamIndex) const -{ - return PackSizes[FolderStartPackStreamIndex[folderIndex] + streamIndex]; -} - -UInt64 GetFilePackSize(int fileIndex) const -{ - int folderIndex = FileIndexToFolderIndexMap[fileIndex]; - if (folderIndex >= 0) - { - const CSzFolder &folderInfo = Folders[folderIndex]; - if (FolderStartFileIndex[folderIndex] == fileIndex) - return GetFolderFullPackSize(folderIndex); - } - return 0; -} -*/ - -#define MY_ALLOC(T, p, size, alloc) { if ((size) == 0) p = 0; else \ - if ((p = (T *)IAlloc_Alloc(alloc, (size) * sizeof(T))) == 0) return SZ_ERROR_MEM; } - -static SRes SzArEx_Fill(CSzArEx *p, ISzAlloc *alloc) -{ - UInt32 startPos = 0; - UInt64 startPosSize = 0; - UInt32 i; - UInt32 folderIndex = 0; - UInt32 indexInFolder = 0; - MY_ALLOC(UInt32, p->FolderStartPackStreamIndex, p->db.NumFolders, alloc); - for (i = 0; i < p->db.NumFolders; i++) - { - p->FolderStartPackStreamIndex[i] = startPos; - startPos += p->db.Folders[i].NumPackStreams; - } - - MY_ALLOC(UInt64, p->PackStreamStartPositions, p->db.NumPackStreams, alloc); - - for (i = 0; i < p->db.NumPackStreams; i++) - { - p->PackStreamStartPositions[i] = startPosSize; - startPosSize += p->db.PackSizes[i]; - } - - MY_ALLOC(UInt32, p->FolderStartFileIndex, p->db.NumFolders, alloc); - MY_ALLOC(UInt32, p->FileIndexToFolderIndexMap, p->db.NumFiles, alloc); - - for (i = 0; i < p->db.NumFiles; i++) - { - CSzFileItem *file = p->db.Files + i; - int emptyStream = !file->HasStream; - if (emptyStream && indexInFolder == 0) - { - p->FileIndexToFolderIndexMap[i] = (UInt32)-1; - continue; - } - if (indexInFolder == 0) - { - /* - v3.13 incorrectly worked with empty folders - v4.07: Loop for skipping empty folders - */ - for (;;) - { - if (folderIndex >= p->db.NumFolders) - return SZ_ERROR_ARCHIVE; - p->FolderStartFileIndex[folderIndex] = i; - if (p->db.Folders[folderIndex].NumUnpackStreams != 0) - break; - folderIndex++; - } - } - p->FileIndexToFolderIndexMap[i] = folderIndex; - if (emptyStream) - continue; - indexInFolder++; - if (indexInFolder >= p->db.Folders[folderIndex].NumUnpackStreams) - { - folderIndex++; - indexInFolder = 0; - } - } - return SZ_OK; -} - - -UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder) -{ - return p->dataPos + - p->PackStreamStartPositions[p->FolderStartPackStreamIndex[folderIndex] + indexInFolder]; -} - -int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize) -{ - UInt32 packStreamIndex = p->FolderStartPackStreamIndex[folderIndex]; - CSzFolder *folder = p->db.Folders + folderIndex; - UInt64 size = 0; - UInt32 i; - for (i = 0; i < folder->NumPackStreams; i++) - { - UInt64 t = size + p->db.PackSizes[packStreamIndex + i]; - if (t < size) /* check it */ - return SZ_ERROR_FAIL; - size = t; - } - *resSize = size; - return SZ_OK; -} - - -/* -SRes SzReadTime(const CObjectVector &dataVector, - CObjectVector &files, UInt64 type) -{ - CBoolVector boolVector; - RINOK(ReadBoolVector2(files.Size(), boolVector)) - - CStreamSwitch streamSwitch; - RINOK(streamSwitch.Set(this, &dataVector)); - - for (int i = 0; i < files.Size(); i++) - { - CSzFileItem &file = files[i]; - CArchiveFileTime fileTime; - bool defined = boolVector[i]; - if (defined) - { - UInt32 low, high; - RINOK(SzReadUInt32(low)); - RINOK(SzReadUInt32(high)); - fileTime.dwLowDateTime = low; - fileTime.dwHighDateTime = high; - } - switch(type) - { - case k7zIdCTime: file.IsCTimeDefined = defined; if (defined) file.CTime = fileTime; break; - case k7zIdATime: file.IsATimeDefined = defined; if (defined) file.ATime = fileTime; break; - case k7zIdMTime: file.IsMTimeDefined = defined; if (defined) file.MTime = fileTime; break; - } - } - return SZ_OK; -} -*/ - -static int TestSignatureCandidate(Byte *testBytes) -{ - size_t i; - for (i = 0; i < k7zSignatureSize; i++) - if (testBytes[i] != k7zSignature[i]) - return 0; - return 1; -} - -typedef struct _CSzState -{ - Byte *Data; - size_t Size; -}CSzData; - -static SRes SzReadByte(CSzData *sd, Byte *b) -{ - if (sd->Size == 0) - return SZ_ERROR_ARCHIVE; - sd->Size--; - *b = *sd->Data++; - return SZ_OK; -} - -static SRes SzReadBytes(CSzData *sd, Byte *data, size_t size) -{ - size_t i; - for (i = 0; i < size; i++) - { - RINOK(SzReadByte(sd, data + i)); - } - return SZ_OK; -} - -static SRes SzReadUInt32(CSzData *sd, UInt32 *value) -{ - int i; - *value = 0; - for (i = 0; i < 4; i++) - { - Byte b; - RINOK(SzReadByte(sd, &b)); - *value |= ((UInt32)(b) << (8 * i)); - } - return SZ_OK; -} - -static SRes SzReadNumber(CSzData *sd, UInt64 *value) -{ - Byte firstByte; - Byte mask = 0x80; - int i; - RINOK(SzReadByte(sd, &firstByte)); - *value = 0; - for (i = 0; i < 8; i++) - { - Byte b; - if ((firstByte & mask) == 0) - { - UInt64 highPart = firstByte & (mask - 1); - *value += (highPart << (8 * i)); - return SZ_OK; - } - RINOK(SzReadByte(sd, &b)); - *value |= ((UInt64)b << (8 * i)); - mask >>= 1; - } - return SZ_OK; -} - -static SRes SzReadNumber32(CSzData *sd, UInt32 *value) -{ - UInt64 value64; - RINOK(SzReadNumber(sd, &value64)); - if (value64 >= 0x80000000) - return SZ_ERROR_UNSUPPORTED; - if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 2))) - return SZ_ERROR_UNSUPPORTED; - *value = (UInt32)value64; - return SZ_OK; -} - -static SRes SzReadID(CSzData *sd, UInt64 *value) -{ - return SzReadNumber(sd, value); -} - -static SRes SzSkeepDataSize(CSzData *sd, UInt64 size) -{ - if (size > sd->Size) - return SZ_ERROR_ARCHIVE; - sd->Size -= (size_t)size; - sd->Data += (size_t)size; - return SZ_OK; -} - -static SRes SzSkeepData(CSzData *sd) -{ - UInt64 size; - RINOK(SzReadNumber(sd, &size)); - return SzSkeepDataSize(sd, size); -} - -static SRes SzReadArchiveProperties(CSzData *sd) -{ - for (;;) - { - UInt64 type; - RINOK(SzReadID(sd, &type)); - if (type == k7zIdEnd) - break; - SzSkeepData(sd); - } - return SZ_OK; -} - -static SRes SzWaitAttribute(CSzData *sd, UInt64 attribute) -{ - for (;;) - { - UInt64 type; - RINOK(SzReadID(sd, &type)); - if (type == attribute) - return SZ_OK; - if (type == k7zIdEnd) - return SZ_ERROR_ARCHIVE; - RINOK(SzSkeepData(sd)); - } -} - -static SRes SzReadBoolVector(CSzData *sd, size_t numItems, Byte **v, ISzAlloc *alloc) -{ - Byte b = 0; - Byte mask = 0; - size_t i; - MY_ALLOC(Byte, *v, numItems, alloc); - for (i = 0; i < numItems; i++) - { - if (mask == 0) - { - RINOK(SzReadByte(sd, &b)); - mask = 0x80; - } - (*v)[i] = (Byte)(((b & mask) != 0) ? 1 : 0); - mask >>= 1; - } - return SZ_OK; -} - -static SRes SzReadBoolVector2(CSzData *sd, size_t numItems, Byte **v, ISzAlloc *alloc) -{ - Byte allAreDefined; - size_t i; - RINOK(SzReadByte(sd, &allAreDefined)); - if (allAreDefined == 0) - return SzReadBoolVector(sd, numItems, v, alloc); - MY_ALLOC(Byte, *v, numItems, alloc); - for (i = 0; i < numItems; i++) - (*v)[i] = 1; - return SZ_OK; -} - -static SRes SzReadHashDigests( - CSzData *sd, - size_t numItems, - Byte **digestsDefined, - UInt32 **digests, - ISzAlloc *alloc) -{ - size_t i; - RINOK(SzReadBoolVector2(sd, numItems, digestsDefined, alloc)); - MY_ALLOC(UInt32, *digests, numItems, alloc); - for (i = 0; i < numItems; i++) - if ((*digestsDefined)[i]) - { - RINOK(SzReadUInt32(sd, (*digests) + i)); - } - return SZ_OK; -} - -static SRes SzReadPackInfo( - CSzData *sd, - UInt64 *dataOffset, - UInt32 *numPackStreams, - UInt64 **packSizes, - Byte **packCRCsDefined, - UInt32 **packCRCs, - ISzAlloc *alloc) -{ - UInt32 i; - RINOK(SzReadNumber(sd, dataOffset)); - RINOK(SzReadNumber32(sd, numPackStreams)); - - RINOK(SzWaitAttribute(sd, k7zIdSize)); - - MY_ALLOC(UInt64, *packSizes, (size_t)*numPackStreams, alloc); - - for (i = 0; i < *numPackStreams; i++) - { - RINOK(SzReadNumber(sd, (*packSizes) + i)); - } - - for (;;) - { - UInt64 type; - RINOK(SzReadID(sd, &type)); - if (type == k7zIdEnd) - break; - if (type == k7zIdCRC) - { - RINOK(SzReadHashDigests(sd, (size_t)*numPackStreams, packCRCsDefined, packCRCs, alloc)); - continue; - } - RINOK(SzSkeepData(sd)); - } - if (*packCRCsDefined == 0) - { - MY_ALLOC(Byte, *packCRCsDefined, (size_t)*numPackStreams, alloc); - MY_ALLOC(UInt32, *packCRCs, (size_t)*numPackStreams, alloc); - for (i = 0; i < *numPackStreams; i++) - { - (*packCRCsDefined)[i] = 0; - (*packCRCs)[i] = 0; - } - } - return SZ_OK; -} - -static SRes SzReadSwitch(CSzData *sd) -{ - Byte external; - RINOK(SzReadByte(sd, &external)); - return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED; -} - -static SRes SzGetNextFolderItem(CSzData *sd, CSzFolder *folder, ISzAlloc *alloc) -{ - UInt32 numCoders, numBindPairs, numPackStreams, i; - UInt32 numInStreams = 0, numOutStreams = 0; - - RINOK(SzReadNumber32(sd, &numCoders)); - if (numCoders > NUM_FOLDER_CODERS_MAX) - return SZ_ERROR_UNSUPPORTED; - folder->NumCoders = numCoders; - - MY_ALLOC(CSzCoderInfo, folder->Coders, (size_t)numCoders, alloc); - - for (i = 0; i < numCoders; i++) - SzCoderInfo_Init(folder->Coders + i); - - for (i = 0; i < numCoders; i++) - { - Byte mainByte; - CSzCoderInfo *coder = folder->Coders + i; - { - unsigned idSize, j; - Byte longID[15]; - RINOK(SzReadByte(sd, &mainByte)); - idSize = (unsigned)(mainByte & 0xF); - RINOK(SzReadBytes(sd, longID, idSize)); - if (idSize > sizeof(coder->MethodID)) - return SZ_ERROR_UNSUPPORTED; - coder->MethodID = 0; - for (j = 0; j < idSize; j++) - coder->MethodID |= (UInt64)longID[idSize - 1 - j] << (8 * j); - - if ((mainByte & 0x10) != 0) - { - RINOK(SzReadNumber32(sd, &coder->NumInStreams)); - RINOK(SzReadNumber32(sd, &coder->NumOutStreams)); - if (coder->NumInStreams > NUM_CODER_STREAMS_MAX || - coder->NumOutStreams > NUM_CODER_STREAMS_MAX) - return SZ_ERROR_UNSUPPORTED; - } - else - { - coder->NumInStreams = 1; - coder->NumOutStreams = 1; - } - if ((mainByte & 0x20) != 0) - { - UInt64 propertiesSize = 0; - RINOK(SzReadNumber(sd, &propertiesSize)); - if (!Buf_Create(&coder->Props, (size_t)propertiesSize, alloc)) - return SZ_ERROR_MEM; - RINOK(SzReadBytes(sd, coder->Props.data, (size_t)propertiesSize)); - } - } - while ((mainByte & 0x80) != 0) - { - RINOK(SzReadByte(sd, &mainByte)); - RINOK(SzSkeepDataSize(sd, (mainByte & 0xF))); - if ((mainByte & 0x10) != 0) - { - UInt32 n; - RINOK(SzReadNumber32(sd, &n)); - RINOK(SzReadNumber32(sd, &n)); - } - if ((mainByte & 0x20) != 0) - { - UInt64 propertiesSize = 0; - RINOK(SzReadNumber(sd, &propertiesSize)); - RINOK(SzSkeepDataSize(sd, propertiesSize)); - } - } - numInStreams += coder->NumInStreams; - numOutStreams += coder->NumOutStreams; - } - - if (numOutStreams == 0) - return SZ_ERROR_UNSUPPORTED; - - folder->NumBindPairs = numBindPairs = numOutStreams - 1; - MY_ALLOC(CSzBindPair, folder->BindPairs, (size_t)numBindPairs, alloc); - - for (i = 0; i < numBindPairs; i++) - { - CSzBindPair *bp = folder->BindPairs + i; - RINOK(SzReadNumber32(sd, &bp->InIndex)); - RINOK(SzReadNumber32(sd, &bp->OutIndex)); - } - - if (numInStreams < numBindPairs) - return SZ_ERROR_UNSUPPORTED; - - folder->NumPackStreams = numPackStreams = numInStreams - numBindPairs; - MY_ALLOC(UInt32, folder->PackStreams, (size_t)numPackStreams, alloc); - - if (numPackStreams == 1) - { - for (i = 0; i < numInStreams ; i++) - if (SzFolder_FindBindPairForInStream(folder, i) < 0) - break; - if (i == numInStreams) - return SZ_ERROR_UNSUPPORTED; - folder->PackStreams[0] = i; - } - else - for (i = 0; i < numPackStreams; i++) - { - RINOK(SzReadNumber32(sd, folder->PackStreams + i)); - } - return SZ_OK; -} - -static SRes SzReadUnpackInfo( - CSzData *sd, - UInt32 *numFolders, - CSzFolder **folders, /* for alloc */ - ISzAlloc *alloc, - ISzAlloc *allocTemp) -{ - UInt32 i; - RINOK(SzWaitAttribute(sd, k7zIdFolder)); - RINOK(SzReadNumber32(sd, numFolders)); - { - RINOK(SzReadSwitch(sd)); - - MY_ALLOC(CSzFolder, *folders, (size_t)*numFolders, alloc); - - for (i = 0; i < *numFolders; i++) - SzFolder_Init((*folders) + i); - - for (i = 0; i < *numFolders; i++) - { - RINOK(SzGetNextFolderItem(sd, (*folders) + i, alloc)); - } - } - - RINOK(SzWaitAttribute(sd, k7zIdCodersUnpackSize)); - - for (i = 0; i < *numFolders; i++) - { - UInt32 j; - CSzFolder *folder = (*folders) + i; - UInt32 numOutStreams = SzFolder_GetNumOutStreams(folder); - - MY_ALLOC(UInt64, folder->UnpackSizes, (size_t)numOutStreams, alloc); - - for (j = 0; j < numOutStreams; j++) - { - RINOK(SzReadNumber(sd, folder->UnpackSizes + j)); - } - } - - for (;;) - { - UInt64 type; - RINOK(SzReadID(sd, &type)); - if (type == k7zIdEnd) - return SZ_OK; - if (type == k7zIdCRC) - { - SRes res; - Byte *crcsDefined = 0; - UInt32 *crcs = 0; - res = SzReadHashDigests(sd, *numFolders, &crcsDefined, &crcs, allocTemp); - if (res == SZ_OK) - { - for (i = 0; i < *numFolders; i++) - { - CSzFolder *folder = (*folders) + i; - folder->UnpackCRCDefined = crcsDefined[i]; - folder->UnpackCRC = crcs[i]; - } - } - IAlloc_Free(allocTemp, crcs); - IAlloc_Free(allocTemp, crcsDefined); - RINOK(res); - continue; - } - RINOK(SzSkeepData(sd)); - } -} - -static SRes SzReadSubStreamsInfo( - CSzData *sd, - UInt32 numFolders, - CSzFolder *folders, - UInt32 *numUnpackStreams, - UInt64 **unpackSizes, - Byte **digestsDefined, - UInt32 **digests, - ISzAlloc *allocTemp) -{ - UInt64 type = 0; - UInt32 i; - UInt32 si = 0; - UInt32 numDigests = 0; - - for (i = 0; i < numFolders; i++) - folders[i].NumUnpackStreams = 1; - *numUnpackStreams = numFolders; - - for (;;) - { - RINOK(SzReadID(sd, &type)); - if (type == k7zIdNumUnpackStream) - { - *numUnpackStreams = 0; - for (i = 0; i < numFolders; i++) - { - UInt32 numStreams; - RINOK(SzReadNumber32(sd, &numStreams)); - folders[i].NumUnpackStreams = numStreams; - *numUnpackStreams += numStreams; - } - continue; - } - if (type == k7zIdCRC || type == k7zIdSize) - break; - if (type == k7zIdEnd) - break; - RINOK(SzSkeepData(sd)); - } - - if (*numUnpackStreams == 0) - { - *unpackSizes = 0; - *digestsDefined = 0; - *digests = 0; - } - else - { - *unpackSizes = (UInt64 *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(UInt64)); - RINOM(*unpackSizes); - *digestsDefined = (Byte *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(Byte)); - RINOM(*digestsDefined); - *digests = (UInt32 *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(UInt32)); - RINOM(*digests); - } - - for (i = 0; i < numFolders; i++) - { - /* - v3.13 incorrectly worked with empty folders - v4.07: we check that folder is empty - */ - UInt64 sum = 0; - UInt32 j; - UInt32 numSubstreams = folders[i].NumUnpackStreams; - if (numSubstreams == 0) - continue; - if (type == k7zIdSize) - for (j = 1; j < numSubstreams; j++) - { - UInt64 size; - RINOK(SzReadNumber(sd, &size)); - (*unpackSizes)[si++] = size; - sum += size; - } - (*unpackSizes)[si++] = SzFolder_GetUnpackSize(folders + i) - sum; - } - if (type == k7zIdSize) - { - RINOK(SzReadID(sd, &type)); - } - - for (i = 0; i < *numUnpackStreams; i++) - { - (*digestsDefined)[i] = 0; - (*digests)[i] = 0; - } - - - for (i = 0; i < numFolders; i++) - { - UInt32 numSubstreams = folders[i].NumUnpackStreams; - if (numSubstreams != 1 || !folders[i].UnpackCRCDefined) - numDigests += numSubstreams; - } - - - si = 0; - for (;;) - { - if (type == k7zIdCRC) - { - int digestIndex = 0; - Byte *digestsDefined2 = 0; - UInt32 *digests2 = 0; - SRes res = SzReadHashDigests(sd, numDigests, &digestsDefined2, &digests2, allocTemp); - if (res == SZ_OK) - { - for (i = 0; i < numFolders; i++) - { - CSzFolder *folder = folders + i; - UInt32 numSubstreams = folder->NumUnpackStreams; - if (numSubstreams == 1 && folder->UnpackCRCDefined) - { - (*digestsDefined)[si] = 1; - (*digests)[si] = folder->UnpackCRC; - si++; - } - else - { - UInt32 j; - for (j = 0; j < numSubstreams; j++, digestIndex++) - { - (*digestsDefined)[si] = digestsDefined2[digestIndex]; - (*digests)[si] = digests2[digestIndex]; - si++; - } - } - } - } - IAlloc_Free(allocTemp, digestsDefined2); - IAlloc_Free(allocTemp, digests2); - RINOK(res); - } - else if (type == k7zIdEnd) - return SZ_OK; - else - { - RINOK(SzSkeepData(sd)); - } - RINOK(SzReadID(sd, &type)); - } -} - - -static SRes SzReadStreamsInfo( - CSzData *sd, - UInt64 *dataOffset, - CSzAr *p, - UInt32 *numUnpackStreams, - UInt64 **unpackSizes, /* allocTemp */ - Byte **digestsDefined, /* allocTemp */ - UInt32 **digests, /* allocTemp */ - ISzAlloc *alloc, - ISzAlloc *allocTemp) -{ - for (;;) - { - UInt64 type; - RINOK(SzReadID(sd, &type)); - if ((UInt64)(int)type != type) - return SZ_ERROR_UNSUPPORTED; - switch((int)type) - { - case k7zIdEnd: - return SZ_OK; - case k7zIdPackInfo: - { - RINOK(SzReadPackInfo(sd, dataOffset, &p->NumPackStreams, - &p->PackSizes, &p->PackCRCsDefined, &p->PackCRCs, alloc)); - break; - } - case k7zIdUnpackInfo: - { - RINOK(SzReadUnpackInfo(sd, &p->NumFolders, &p->Folders, alloc, allocTemp)); - break; - } - case k7zIdSubStreamsInfo: - { - RINOK(SzReadSubStreamsInfo(sd, p->NumFolders, p->Folders, - numUnpackStreams, unpackSizes, digestsDefined, digests, allocTemp)); - break; - } - default: - return SZ_ERROR_UNSUPPORTED; - } - } -} - -size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest) -{ - size_t len = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex]; - if (dest != 0) - { - size_t i; - const Byte *src = p->FileNames.data + (p->FileNameOffsets[fileIndex] * 2); - for (i = 0; i < len; i++) - dest[i] = GetUi16(src + i * 2); - } - return len; -} - -static SRes SzReadFileNames(const Byte *p, size_t size, UInt32 numFiles, size_t *sizes) -{ - UInt32 i; - size_t pos = 0; - for (i = 0; i < numFiles; i++) - { - sizes[i] = pos; - for (;;) - { - if (pos >= size) - return SZ_ERROR_ARCHIVE; - if (p[pos * 2] == 0 && p[pos * 2 + 1] == 0) - break; - pos++; - } - pos++; - } - sizes[i] = pos; - return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; -} - -static SRes SzReadHeader2( - CSzArEx *p, /* allocMain */ - CSzData *sd, - UInt64 **unpackSizes, /* allocTemp */ - Byte **digestsDefined, /* allocTemp */ - UInt32 **digests, /* allocTemp */ - Byte **emptyStreamVector, /* allocTemp */ - Byte **emptyFileVector, /* allocTemp */ - Byte **lwtVector, /* allocTemp */ - ISzAlloc *allocMain, - ISzAlloc *allocTemp) -{ - UInt64 type; - UInt32 numUnpackStreams = 0; - UInt32 numFiles = 0; - CSzFileItem *files = 0; - UInt32 numEmptyStreams = 0; - UInt32 i; - - RINOK(SzReadID(sd, &type)); - - if (type == k7zIdArchiveProperties) - { - RINOK(SzReadArchiveProperties(sd)); - RINOK(SzReadID(sd, &type)); - } - - - if (type == k7zIdMainStreamsInfo) - { - RINOK(SzReadStreamsInfo(sd, - &p->dataPos, - &p->db, - &numUnpackStreams, - unpackSizes, - digestsDefined, - digests, allocMain, allocTemp)); - p->dataPos += p->startPosAfterHeader; - RINOK(SzReadID(sd, &type)); - } - - if (type == k7zIdEnd) - return SZ_OK; - if (type != k7zIdFilesInfo) - return SZ_ERROR_ARCHIVE; - - RINOK(SzReadNumber32(sd, &numFiles)); - p->db.NumFiles = numFiles; - - MY_ALLOC(CSzFileItem, files, (size_t)numFiles, allocMain); - - p->db.Files = files; - for (i = 0; i < numFiles; i++) - SzFile_Init(files + i); - - for (;;) - { - UInt64 type; - UInt64 size; - RINOK(SzReadID(sd, &type)); - if (type == k7zIdEnd) - break; - RINOK(SzReadNumber(sd, &size)); - if (size > sd->Size) - return SZ_ERROR_ARCHIVE; - if ((UInt64)(int)type != type) - { - RINOK(SzSkeepDataSize(sd, size)); - } - else - switch((int)type) - { - case k7zIdName: - { - size_t namesSize; - RINOK(SzReadSwitch(sd)); - namesSize = (size_t)size - 1; - if ((namesSize & 1) != 0) - return SZ_ERROR_ARCHIVE; - if (!Buf_Create(&p->FileNames, namesSize, allocMain)) - return SZ_ERROR_MEM; - MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain); - memcpy(p->FileNames.data, sd->Data, namesSize); - RINOK(SzReadFileNames(sd->Data, namesSize >> 1, numFiles, p->FileNameOffsets)) - RINOK(SzSkeepDataSize(sd, namesSize)); - break; - } - case k7zIdEmptyStream: - { - RINOK(SzReadBoolVector(sd, numFiles, emptyStreamVector, allocTemp)); - numEmptyStreams = 0; - for (i = 0; i < numFiles; i++) - if ((*emptyStreamVector)[i]) - numEmptyStreams++; - break; - } - case k7zIdEmptyFile: - { - RINOK(SzReadBoolVector(sd, numEmptyStreams, emptyFileVector, allocTemp)); - break; - } - case k7zIdWinAttributes: - { - RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp)); - RINOK(SzReadSwitch(sd)); - for (i = 0; i < numFiles; i++) - { - CSzFileItem *f = &files[i]; - Byte defined = (*lwtVector)[i]; - f->AttribDefined = defined; - f->Attrib = 0; - if (defined) - { - RINOK(SzReadUInt32(sd, &f->Attrib)); - } - } - IAlloc_Free(allocTemp, *lwtVector); - *lwtVector = NULL; - break; - } - case k7zIdMTime: - { - RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp)); - RINOK(SzReadSwitch(sd)); - for (i = 0; i < numFiles; i++) - { - CSzFileItem *f = &files[i]; - Byte defined = (*lwtVector)[i]; - f->MTimeDefined = defined; - f->MTime.Low = f->MTime.High = 0; - if (defined) - { - RINOK(SzReadUInt32(sd, &f->MTime.Low)); - RINOK(SzReadUInt32(sd, &f->MTime.High)); - } - } - IAlloc_Free(allocTemp, *lwtVector); - *lwtVector = NULL; - break; - } - default: - { - RINOK(SzSkeepDataSize(sd, size)); - } - } - } - - { - UInt32 emptyFileIndex = 0; - UInt32 sizeIndex = 0; - for (i = 0; i < numFiles; i++) - { - CSzFileItem *file = files + i; - file->IsAnti = 0; - if (*emptyStreamVector == 0) - file->HasStream = 1; - else - file->HasStream = (Byte)((*emptyStreamVector)[i] ? 0 : 1); - if (file->HasStream) - { - file->IsDir = 0; - file->Size = (*unpackSizes)[sizeIndex]; - file->Crc = (*digests)[sizeIndex]; - file->CrcDefined = (Byte)(*digestsDefined)[sizeIndex]; - sizeIndex++; - } - else - { - if (*emptyFileVector == 0) - file->IsDir = 1; - else - file->IsDir = (Byte)((*emptyFileVector)[emptyFileIndex] ? 0 : 1); - emptyFileIndex++; - file->Size = 0; - file->Crc = 0; - file->CrcDefined = 0; - } - } - } - return SzArEx_Fill(p, allocMain); -} - -static SRes SzReadHeader( - CSzArEx *p, - CSzData *sd, - ISzAlloc *allocMain, - ISzAlloc *allocTemp) -{ - UInt64 *unpackSizes = 0; - Byte *digestsDefined = 0; - UInt32 *digests = 0; - Byte *emptyStreamVector = 0; - Byte *emptyFileVector = 0; - Byte *lwtVector = 0; - SRes res = SzReadHeader2(p, sd, - &unpackSizes, &digestsDefined, &digests, - &emptyStreamVector, &emptyFileVector, &lwtVector, - allocMain, allocTemp); - IAlloc_Free(allocTemp, unpackSizes); - IAlloc_Free(allocTemp, digestsDefined); - IAlloc_Free(allocTemp, digests); - IAlloc_Free(allocTemp, emptyStreamVector); - IAlloc_Free(allocTemp, emptyFileVector); - IAlloc_Free(allocTemp, lwtVector); - return res; -} - -static SRes SzReadAndDecodePackedStreams2( - ILookInStream *inStream, - CSzData *sd, - CBuf *outBuffer, - UInt64 baseOffset, - CSzAr *p, - UInt64 **unpackSizes, - Byte **digestsDefined, - UInt32 **digests, - ISzAlloc *allocTemp) -{ - - UInt32 numUnpackStreams = 0; - UInt64 dataStartPos; - CSzFolder *folder; - UInt64 unpackSize; - SRes res; - - RINOK(SzReadStreamsInfo(sd, &dataStartPos, p, - &numUnpackStreams, unpackSizes, digestsDefined, digests, - allocTemp, allocTemp)); - - dataStartPos += baseOffset; - if (p->NumFolders != 1) - return SZ_ERROR_ARCHIVE; - - folder = p->Folders; - unpackSize = SzFolder_GetUnpackSize(folder); - - RINOK(LookInStream_SeekTo(inStream, dataStartPos)); - - if (!Buf_Create(outBuffer, (size_t)unpackSize, allocTemp)) - return SZ_ERROR_MEM; - - res = SzFolder_Decode(folder, p->PackSizes, - inStream, dataStartPos, - outBuffer->data, (size_t)unpackSize, allocTemp); - RINOK(res); - if (folder->UnpackCRCDefined) - if (CrcCalc(outBuffer->data, (size_t)unpackSize) != folder->UnpackCRC) - return SZ_ERROR_CRC; - return SZ_OK; -} - -static SRes SzReadAndDecodePackedStreams( - ILookInStream *inStream, - CSzData *sd, - CBuf *outBuffer, - UInt64 baseOffset, - ISzAlloc *allocTemp) -{ - CSzAr p; - UInt64 *unpackSizes = 0; - Byte *digestsDefined = 0; - UInt32 *digests = 0; - SRes res; - SzAr_Init(&p); - res = SzReadAndDecodePackedStreams2(inStream, sd, outBuffer, baseOffset, - &p, &unpackSizes, &digestsDefined, &digests, - allocTemp); - SzAr_Free(&p, allocTemp); - IAlloc_Free(allocTemp, unpackSizes); - IAlloc_Free(allocTemp, digestsDefined); - IAlloc_Free(allocTemp, digests); - return res; -} - -static SRes SzArEx_Open2( - CSzArEx *p, - ILookInStream *inStream, - ISzAlloc *allocMain, - ISzAlloc *allocTemp) -{ - Byte header[k7zStartHeaderSize]; - Int64 startArcPos; - UInt64 nextHeaderOffset, nextHeaderSize; - size_t nextHeaderSizeT; - UInt32 nextHeaderCRC; - CBuf buffer; - SRes res; - - startArcPos = 0; - RINOK(inStream->Seek(inStream, &startArcPos, SZ_SEEK_CUR)); - - RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE)); - - if (!TestSignatureCandidate(header)) - return SZ_ERROR_NO_ARCHIVE; - if (header[6] != k7zMajorVersion) - return SZ_ERROR_UNSUPPORTED; - - nextHeaderOffset = GetUi64(header + 12); - nextHeaderSize = GetUi64(header + 20); - nextHeaderCRC = GetUi32(header + 28); - - p->startPosAfterHeader = startArcPos + k7zStartHeaderSize; - - if (CrcCalc(header + 12, 20) != GetUi32(header + 8)) - return SZ_ERROR_CRC; - - nextHeaderSizeT = (size_t)nextHeaderSize; - if (nextHeaderSizeT != nextHeaderSize) - return SZ_ERROR_MEM; - if (nextHeaderSizeT == 0) - return SZ_OK; - if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize || - nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize) - return SZ_ERROR_NO_ARCHIVE; - - { - Int64 pos = 0; - RINOK(inStream->Seek(inStream, &pos, SZ_SEEK_END)); - if ((UInt64)pos < startArcPos + nextHeaderOffset || - (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset || - (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize) - return SZ_ERROR_INPUT_EOF; - } - - RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset)); - - if (!Buf_Create(&buffer, nextHeaderSizeT, allocTemp)) - return SZ_ERROR_MEM; - - res = LookInStream_Read(inStream, buffer.data, nextHeaderSizeT); - if (res == SZ_OK) - { - res = SZ_ERROR_ARCHIVE; - if (CrcCalc(buffer.data, nextHeaderSizeT) == nextHeaderCRC) - { - CSzData sd; - UInt64 type; - sd.Data = buffer.data; - sd.Size = buffer.size; - res = SzReadID(&sd, &type); - if (res == SZ_OK) - { - if (type == k7zIdEncodedHeader) - { - CBuf outBuffer; - Buf_Init(&outBuffer); - res = SzReadAndDecodePackedStreams(inStream, &sd, &outBuffer, p->startPosAfterHeader, allocTemp); - if (res != SZ_OK) - Buf_Free(&outBuffer, allocTemp); - else - { - Buf_Free(&buffer, allocTemp); - buffer.data = outBuffer.data; - buffer.size = outBuffer.size; - sd.Data = buffer.data; - sd.Size = buffer.size; - res = SzReadID(&sd, &type); - } - } - } - if (res == SZ_OK) - { - if (type == k7zIdHeader) - res = SzReadHeader(p, &sd, allocMain, allocTemp); - else - res = SZ_ERROR_UNSUPPORTED; - } - } - } - Buf_Free(&buffer, allocTemp); - return res; -} - -SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp) -{ - SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp); - if (res != SZ_OK) - SzArEx_Free(p, allocMain); - return res; -} - -SRes SzArEx_Extract( - const CSzArEx *p, - ILookInStream *inStream, - UInt32 fileIndex, - UInt32 *blockIndex, - Byte **outBuffer, - size_t *outBufferSize, - size_t *offset, - size_t *outSizeProcessed, - ISzAlloc *allocMain, - ISzAlloc *allocTemp) -{ - UInt32 folderIndex = p->FileIndexToFolderIndexMap[fileIndex]; - SRes res = SZ_OK; - *offset = 0; - *outSizeProcessed = 0; - if (folderIndex == (UInt32)-1) - { - IAlloc_Free(allocMain, *outBuffer); - *blockIndex = folderIndex; - *outBuffer = 0; - *outBufferSize = 0; - return SZ_OK; - } - - if (*outBuffer == 0 || *blockIndex != folderIndex) - { - CSzFolder *folder = p->db.Folders + folderIndex; - UInt64 unpackSizeSpec = SzFolder_GetUnpackSize(folder); - size_t unpackSize = (size_t)unpackSizeSpec; - UInt64 startOffset = SzArEx_GetFolderStreamPos(p, folderIndex, 0); - - if (unpackSize != unpackSizeSpec) - return SZ_ERROR_MEM; - *blockIndex = folderIndex; - IAlloc_Free(allocMain, *outBuffer); - *outBuffer = 0; - - RINOK(LookInStream_SeekTo(inStream, startOffset)); - - if (res == SZ_OK) - { - *outBufferSize = unpackSize; - if (unpackSize != 0) - { - *outBuffer = (Byte *)IAlloc_Alloc(allocMain, unpackSize); - if (*outBuffer == 0) - res = SZ_ERROR_MEM; - } - if (res == SZ_OK) - { - res = SzFolder_Decode(folder, - p->db.PackSizes + p->FolderStartPackStreamIndex[folderIndex], - inStream, startOffset, - *outBuffer, unpackSize, allocTemp); - if (res == SZ_OK) - { - if (folder->UnpackCRCDefined) - { - if (CrcCalc(*outBuffer, unpackSize) != folder->UnpackCRC) - res = SZ_ERROR_CRC; - } - } - } - } - } - if (res == SZ_OK) - { - UInt32 i; - CSzFileItem *fileItem = p->db.Files + fileIndex; - *offset = 0; - for (i = p->FolderStartFileIndex[folderIndex]; i < fileIndex; i++) - *offset += (UInt32)p->db.Files[i].Size; - *outSizeProcessed = (size_t)fileItem->Size; - if (*offset + *outSizeProcessed > *outBufferSize) - return SZ_ERROR_FAIL; - if (fileItem->CrcDefined && CrcCalc(*outBuffer + *offset, *outSizeProcessed) != fileItem->Crc) - res = SZ_ERROR_CRC; - } - return res; -} diff --git a/lzma/C/7zStream.c b/lzma/C/7zStream.c index f0959fb07..5a92d532c 100644 --- a/lzma/C/7zStream.c +++ b/lzma/C/7zStream.c @@ -1,9 +1,11 @@ /* 7zStream.c -- 7z Stream functions -2010-03-11 : Igor Pavlov : Public domain */ +2013-11-12 : Igor Pavlov : Public domain */ + +#include "Precomp.h" #include -#include "Types.h" +#include "7zTypes.h" SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType) { diff --git a/lzma/C/Types.h b/lzma/C/7zTypes.h similarity index 94% rename from lzma/C/Types.h rename to lzma/C/7zTypes.h index f193ce2f5..adde88e75 100644 --- a/lzma/C/Types.h +++ b/lzma/C/7zTypes.h @@ -1,254 +1,256 @@ -/* Types.h -- Basic types -2010-10-09 : Igor Pavlov : Public domain */ - -#ifndef __7Z_TYPES_H -#define __7Z_TYPES_H - -#include - -#ifdef _WIN32 -#include -#endif - -#ifndef EXTERN_C_BEGIN -#ifdef __cplusplus -#define EXTERN_C_BEGIN extern "C" { -#define EXTERN_C_END } -#else -#define EXTERN_C_BEGIN -#define EXTERN_C_END -#endif -#endif - -EXTERN_C_BEGIN - -#define SZ_OK 0 - -#define SZ_ERROR_DATA 1 -#define SZ_ERROR_MEM 2 -#define SZ_ERROR_CRC 3 -#define SZ_ERROR_UNSUPPORTED 4 -#define SZ_ERROR_PARAM 5 -#define SZ_ERROR_INPUT_EOF 6 -#define SZ_ERROR_OUTPUT_EOF 7 -#define SZ_ERROR_READ 8 -#define SZ_ERROR_WRITE 9 -#define SZ_ERROR_PROGRESS 10 -#define SZ_ERROR_FAIL 11 -#define SZ_ERROR_THREAD 12 - -#define SZ_ERROR_ARCHIVE 16 -#define SZ_ERROR_NO_ARCHIVE 17 - -typedef int SRes; - -#ifdef _WIN32 -typedef DWORD WRes; -#else -typedef int WRes; -#endif - -#ifndef RINOK -#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } -#endif - -typedef unsigned char Byte; -typedef short Int16; -typedef unsigned short UInt16; - -#ifdef _LZMA_UINT32_IS_ULONG -typedef long Int32; -typedef unsigned long UInt32; -#else -typedef int Int32; -typedef unsigned int UInt32; -#endif - -#ifdef _SZ_NO_INT_64 - -/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. - NOTES: Some code will work incorrectly in that case! */ - -typedef long Int64; -typedef unsigned long UInt64; - -#else - -#if defined(_MSC_VER) || defined(__BORLANDC__) -typedef __int64 Int64; -typedef unsigned __int64 UInt64; -#define UINT64_CONST(n) n -#else -typedef long long int Int64; -typedef unsigned long long int UInt64; -#define UINT64_CONST(n) n ## ULL -#endif - -#endif - -#ifdef _LZMA_NO_SYSTEM_SIZE_T -typedef UInt32 SizeT; -#else -typedef size_t SizeT; -#endif - -typedef int Bool; -#define True 1 -#define False 0 - - -#ifdef _WIN32 -#define MY_STD_CALL __stdcall -#else -#define MY_STD_CALL -#endif - -#ifdef _MSC_VER - -#if _MSC_VER >= 1300 -#define MY_NO_INLINE __declspec(noinline) -#else -#define MY_NO_INLINE -#endif - -#define MY_CDECL __cdecl -#define MY_FAST_CALL __fastcall - -#else - -#define MY_CDECL -#define MY_FAST_CALL - -#endif - - -/* The following interfaces use first parameter as pointer to structure */ - -typedef struct -{ - Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */ -} IByteIn; - -typedef struct -{ - void (*Write)(void *p, Byte b); -} IByteOut; - -typedef struct -{ - SRes (*Read)(void *p, void *buf, size_t *size); - /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. - (output(*size) < input(*size)) is allowed */ -} ISeqInStream; - -/* it can return SZ_ERROR_INPUT_EOF */ -SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); -SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); -SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); - -typedef struct -{ - size_t (*Write)(void *p, const void *buf, size_t size); - /* Returns: result - the number of actually written bytes. - (result < size) means error */ -} ISeqOutStream; - -typedef enum -{ - SZ_SEEK_SET = 0, - SZ_SEEK_CUR = 1, - SZ_SEEK_END = 2 -} ESzSeek; - -typedef struct -{ - SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ - SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); -} ISeekInStream; - -typedef struct -{ - SRes (*Look)(void *p, const void **buf, size_t *size); - /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. - (output(*size) > input(*size)) is not allowed - (output(*size) < input(*size)) is allowed */ - SRes (*Skip)(void *p, size_t offset); - /* offset must be <= output(*size) of Look */ - - SRes (*Read)(void *p, void *buf, size_t *size); - /* reads directly (without buffer). It's same as ISeqInStream::Read */ - SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); -} ILookInStream; - -SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); -SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); - -/* reads via ILookInStream::Read */ -SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); -SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); - -#define LookToRead_BUF_SIZE (1 << 14) - -typedef struct -{ - ILookInStream s; - ISeekInStream *realStream; - size_t pos; - size_t size; - Byte buf[LookToRead_BUF_SIZE]; -} CLookToRead; - -void LookToRead_CreateVTable(CLookToRead *p, int lookahead); -void LookToRead_Init(CLookToRead *p); - -typedef struct -{ - ISeqInStream s; - ILookInStream *realStream; -} CSecToLook; - -void SecToLook_CreateVTable(CSecToLook *p); - -typedef struct -{ - ISeqInStream s; - ILookInStream *realStream; -} CSecToRead; - -void SecToRead_CreateVTable(CSecToRead *p); - -typedef struct -{ - SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); - /* Returns: result. (result != SZ_OK) means break. - Value (UInt64)(Int64)-1 for size means unknown value. */ -} ICompressProgress; - -typedef struct -{ - void *(*Alloc)(void *p, size_t size); - void (*Free)(void *p, void *address); /* address can be 0 */ -} ISzAlloc; - -#define IAlloc_Alloc(p, size) (p)->Alloc((p), size) -#define IAlloc_Free(p, a) (p)->Free((p), a) - -#ifdef _WIN32 - -#define CHAR_PATH_SEPARATOR '\\' -#define WCHAR_PATH_SEPARATOR L'\\' -#define STRING_PATH_SEPARATOR "\\" -#define WSTRING_PATH_SEPARATOR L"\\" - -#else - -#define CHAR_PATH_SEPARATOR '/' -#define WCHAR_PATH_SEPARATOR L'/' -#define STRING_PATH_SEPARATOR "/" -#define WSTRING_PATH_SEPARATOR L"/" - -#endif - -EXTERN_C_END - -#endif +/* 7zTypes.h -- Basic types +2013-11-12 : Igor Pavlov : Public domain */ + +#ifndef __7Z_TYPES_H +#define __7Z_TYPES_H + +#ifdef _WIN32 +#include +#endif + +#include + +#ifndef EXTERN_C_BEGIN +#ifdef __cplusplus +#define EXTERN_C_BEGIN extern "C" { +#define EXTERN_C_END } +#else +#define EXTERN_C_BEGIN +#define EXTERN_C_END +#endif +#endif + +EXTERN_C_BEGIN + +#define SZ_OK 0 + +#define SZ_ERROR_DATA 1 +#define SZ_ERROR_MEM 2 +#define SZ_ERROR_CRC 3 +#define SZ_ERROR_UNSUPPORTED 4 +#define SZ_ERROR_PARAM 5 +#define SZ_ERROR_INPUT_EOF 6 +#define SZ_ERROR_OUTPUT_EOF 7 +#define SZ_ERROR_READ 8 +#define SZ_ERROR_WRITE 9 +#define SZ_ERROR_PROGRESS 10 +#define SZ_ERROR_FAIL 11 +#define SZ_ERROR_THREAD 12 + +#define SZ_ERROR_ARCHIVE 16 +#define SZ_ERROR_NO_ARCHIVE 17 + +typedef int SRes; + +#ifdef _WIN32 +typedef DWORD WRes; +/* typedef unsigned WRes; */ +#else +typedef int WRes; +#endif + +#ifndef RINOK +#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } +#endif + +typedef unsigned char Byte; +typedef short Int16; +typedef unsigned short UInt16; + +#ifdef _LZMA_UINT32_IS_ULONG +typedef long Int32; +typedef unsigned long UInt32; +#else +typedef int Int32; +typedef unsigned int UInt32; +#endif + +#ifdef _SZ_NO_INT_64 + +/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. + NOTES: Some code will work incorrectly in that case! */ + +typedef long Int64; +typedef unsigned long UInt64; + +#else + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#define UINT64_CONST(n) n +#else +typedef long long int Int64; +typedef unsigned long long int UInt64; +#define UINT64_CONST(n) n ## ULL +#endif + +#endif + +#ifdef _LZMA_NO_SYSTEM_SIZE_T +typedef UInt32 SizeT; +#else +typedef size_t SizeT; +#endif + +typedef int Bool; +#define True 1 +#define False 0 + + +#ifdef _WIN32 +#define MY_STD_CALL __stdcall +#else +#define MY_STD_CALL +#endif + +#ifdef _MSC_VER + +#if _MSC_VER >= 1300 +#define MY_NO_INLINE __declspec(noinline) +#else +#define MY_NO_INLINE +#endif + +#define MY_CDECL __cdecl +#define MY_FAST_CALL __fastcall + +#else + +#define MY_NO_INLINE +#define MY_CDECL +#define MY_FAST_CALL + +#endif + + +/* The following interfaces use first parameter as pointer to structure */ + +typedef struct +{ + Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */ +} IByteIn; + +typedef struct +{ + void (*Write)(void *p, Byte b); +} IByteOut; + +typedef struct +{ + SRes (*Read)(void *p, void *buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) < input(*size)) is allowed */ +} ISeqInStream; + +/* it can return SZ_ERROR_INPUT_EOF */ +SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); +SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); +SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); + +typedef struct +{ + size_t (*Write)(void *p, const void *buf, size_t size); + /* Returns: result - the number of actually written bytes. + (result < size) means error */ +} ISeqOutStream; + +typedef enum +{ + SZ_SEEK_SET = 0, + SZ_SEEK_CUR = 1, + SZ_SEEK_END = 2 +} ESzSeek; + +typedef struct +{ + SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ + SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); +} ISeekInStream; + +typedef struct +{ + SRes (*Look)(void *p, const void **buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) > input(*size)) is not allowed + (output(*size) < input(*size)) is allowed */ + SRes (*Skip)(void *p, size_t offset); + /* offset must be <= output(*size) of Look */ + + SRes (*Read)(void *p, void *buf, size_t *size); + /* reads directly (without buffer). It's same as ISeqInStream::Read */ + SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); +} ILookInStream; + +SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); +SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); + +/* reads via ILookInStream::Read */ +SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); +SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); + +#define LookToRead_BUF_SIZE (1 << 14) + +typedef struct +{ + ILookInStream s; + ISeekInStream *realStream; + size_t pos; + size_t size; + Byte buf[LookToRead_BUF_SIZE]; +} CLookToRead; + +void LookToRead_CreateVTable(CLookToRead *p, int lookahead); +void LookToRead_Init(CLookToRead *p); + +typedef struct +{ + ISeqInStream s; + ILookInStream *realStream; +} CSecToLook; + +void SecToLook_CreateVTable(CSecToLook *p); + +typedef struct +{ + ISeqInStream s; + ILookInStream *realStream; +} CSecToRead; + +void SecToRead_CreateVTable(CSecToRead *p); + +typedef struct +{ + SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); + /* Returns: result. (result != SZ_OK) means break. + Value (UInt64)(Int64)-1 for size means unknown value. */ +} ICompressProgress; + +typedef struct +{ + void *(*Alloc)(void *p, size_t size); + void (*Free)(void *p, void *address); /* address can be 0 */ +} ISzAlloc; + +#define IAlloc_Alloc(p, size) (p)->Alloc((p), size) +#define IAlloc_Free(p, a) (p)->Free((p), a) + +#ifdef _WIN32 + +#define CHAR_PATH_SEPARATOR '\\' +#define WCHAR_PATH_SEPARATOR L'\\' +#define STRING_PATH_SEPARATOR "\\" +#define WSTRING_PATH_SEPARATOR L"\\" + +#else + +#define CHAR_PATH_SEPARATOR '/' +#define WCHAR_PATH_SEPARATOR L'/' +#define STRING_PATH_SEPARATOR "/" +#define WSTRING_PATH_SEPARATOR L"/" + +#endif + +EXTERN_C_END + +#endif diff --git a/lzma/C/7zVersion.h b/lzma/C/7zVersion.h index 43f0fef6f..52ad3c1b1 100644 --- a/lzma/C/7zVersion.h +++ b/lzma/C/7zVersion.h @@ -1,8 +1,19 @@ -#define MY_VER_MAJOR 9 -#define MY_VER_MINOR 22 -#define MY_VER_BUILD 00 -#define MY_VERSION "9.22 beta" -#define MY_7ZIP_VERSION "9.22 beta" -#define MY_DATE "2011-04-18" -#define MY_COPYRIGHT ": Igor Pavlov : Public domain" -#define MY_VERSION_COPYRIGHT_DATE MY_VERSION " " MY_COPYRIGHT " : " MY_DATE +#define MY_VER_MAJOR 15 +#define MY_VER_MINOR 14 +#define MY_VER_BUILD 0 +#define MY_VERSION_NUMBERS "15.14" +#define MY_VERSION "15.14" +#define MY_DATE "2015-12-31" +#undef MY_COPYRIGHT +#undef MY_VERSION_COPYRIGHT_DATE +#define MY_AUTHOR_NAME "Igor Pavlov" +#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain" +#define MY_COPYRIGHT_CR "Copyright (c) 1999-2015 Igor Pavlov" + +#ifdef USE_COPYRIGHT_CR + #define MY_COPYRIGHT MY_COPYRIGHT_CR +#else + #define MY_COPYRIGHT MY_COPYRIGHT_PD +#endif + +#define MY_VERSION_COPYRIGHT_DATE MY_VERSION " : " MY_COPYRIGHT " : " MY_DATE diff --git a/lzma/C/Bcj2.c b/lzma/C/Bcj2.c index 474bdd45d..707362a61 100644 --- a/lzma/C/Bcj2.c +++ b/lzma/C/Bcj2.c @@ -1,132 +1,256 @@ -/* Bcj2.c -- Converter for x86 code (BCJ2) -2008-10-04 : Igor Pavlov : Public domain */ +/* Bcj2.c -- BCJ2 Decoder (Converter for x86 code) +2015-08-01 : Igor Pavlov : Public domain */ + +#include "Precomp.h" #include "Bcj2.h" +#include "CpuArch.h" -#ifdef _LZMA_PROB32 -#define CProb UInt32 -#else #define CProb UInt16 -#endif -#define IsJcc(b0, b1) ((b0) == 0x0F && ((b1) & 0xF0) == 0x80) -#define IsJ(b0, b1) ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1)) - -#define kNumTopBits 24 -#define kTopValue ((UInt32)1 << kNumTopBits) - -#define kNumBitModelTotalBits 11 -#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kTopValue ((UInt32)1 << 24) +#define kNumModelBits 11 +#define kBitModelTotal (1 << kNumModelBits) #define kNumMoveBits 5 -#define RC_READ_BYTE (*buffer++) -#define RC_TEST { if (buffer == bufferLim) return SZ_ERROR_DATA; } -#define RC_INIT2 code = 0; range = 0xFFFFFFFF; \ - { int i; for (i = 0; i < 5; i++) { RC_TEST; code = (code << 8) | RC_READ_BYTE; }} +#define _IF_BIT_0 ttt = *prob; bound = (p->range >> kNumModelBits) * ttt; if (p->code < bound) +#define _UPDATE_0 p->range = bound; *prob = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); +#define _UPDATE_1 p->range -= bound; p->code -= bound; *prob = (CProb)(ttt - (ttt >> kNumMoveBits)); -#define NORMALIZE if (range < kTopValue) { RC_TEST; range <<= 8; code = (code << 8) | RC_READ_BYTE; } - -#define IF_BIT_0(p) ttt = *(p); bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) -#define UPDATE_0(p) range = bound; *(p) = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); NORMALIZE; -#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CProb)(ttt - (ttt >> kNumMoveBits)); NORMALIZE; - -int Bcj2_Decode( - const Byte *buf0, SizeT size0, - const Byte *buf1, SizeT size1, - const Byte *buf2, SizeT size2, - const Byte *buf3, SizeT size3, - Byte *outBuf, SizeT outSize) +void Bcj2Dec_Init(CBcj2Dec *p) { - CProb p[256 + 2]; - SizeT inPos = 0, outPos = 0; + unsigned i; - const Byte *buffer, *bufferLim; - UInt32 range, code; - Byte prevByte = 0; + p->state = BCJ2_DEC_STATE_OK; + p->ip = 0; + p->temp[3] = 0; + p->range = 0; + p->code = 0; + for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++) + p->probs[i] = kBitModelTotal >> 1; +} - unsigned int i; - for (i = 0; i < sizeof(p) / sizeof(p[0]); i++) - p[i] = kBitModelTotal >> 1; +SRes Bcj2Dec_Decode(CBcj2Dec *p) +{ + if (p->range <= 5) + { + p->state = BCJ2_DEC_STATE_OK; + for (; p->range != 5; p->range++) + { + if (p->range == 1 && p->code != 0) + return SZ_ERROR_DATA; + + if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC]) + { + p->state = BCJ2_STREAM_RC; + return SZ_OK; + } - buffer = buf3; - bufferLim = buffer + size3; - RC_INIT2 + p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; + } + + if (p->code == 0xFFFFFFFF) + return SZ_ERROR_DATA; + + p->range = 0xFFFFFFFF; + } + else if (p->state >= BCJ2_DEC_STATE_ORIG_0) + { + while (p->state <= BCJ2_DEC_STATE_ORIG_3) + { + Byte *dest = p->dest; + if (dest == p->destLim) + return SZ_OK; + *dest = p->temp[p->state++ - BCJ2_DEC_STATE_ORIG_0]; + p->dest = dest + 1; + } + } - if (outSize == 0) - return SZ_OK; + /* + if (BCJ2_IS_32BIT_STREAM(p->state)) + { + const Byte *cur = p->bufs[p->state]; + if (cur == p->lims[p->state]) + return SZ_OK; + p->bufs[p->state] = cur + 4; + + { + UInt32 val; + Byte *dest; + SizeT rem; + + p->ip += 4; + val = GetBe32(cur) - p->ip; + dest = p->dest; + rem = p->destLim - dest; + if (rem < 4) + { + SizeT i; + SetUi32(p->temp, val); + for (i = 0; i < rem; i++) + dest[i] = p->temp[i]; + p->dest = dest + rem; + p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem; + return SZ_OK; + } + SetUi32(dest, val); + p->temp[3] = (Byte)(val >> 24); + p->dest = dest + 4; + p->state = BCJ2_DEC_STATE_OK; + } + } + */ for (;;) { - Byte b; - CProb *prob; - UInt32 bound; - UInt32 ttt; - - SizeT limit = size0 - inPos; - if (outSize - outPos < limit) - limit = outSize - outPos; - while (limit != 0) - { - Byte b = buf0[inPos]; - outBuf[outPos++] = b; - if (IsJ(prevByte, b)) - break; - inPos++; - prevByte = b; - limit--; - } - - if (limit == 0 || outPos == outSize) - break; - - b = buf0[inPos++]; - - if (b == 0xE8) - prob = p + prevByte; - else if (b == 0xE9) - prob = p + 256; - else - prob = p + 257; - - IF_BIT_0(prob) - { - UPDATE_0(prob) - prevByte = b; - } + if (BCJ2_IS_32BIT_STREAM(p->state)) + p->state = BCJ2_DEC_STATE_OK; else { - UInt32 dest; - const Byte *v; - UPDATE_1(prob) - if (b == 0xE8) + if (p->range < kTopValue) { - v = buf1; - if (size1 < 4) - return SZ_ERROR_DATA; - buf1 += 4; - size1 -= 4; + if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC]) + { + p->state = BCJ2_STREAM_RC; + return SZ_OK; + } + p->range <<= 8; + p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; } - else + { - v = buf2; - if (size2 < 4) - return SZ_ERROR_DATA; - buf2 += 4; - size2 -= 4; + const Byte *src = p->bufs[BCJ2_STREAM_MAIN]; + const Byte *srcLim; + Byte *dest; + SizeT num = p->lims[BCJ2_STREAM_MAIN] - src; + + if (num == 0) + { + p->state = BCJ2_STREAM_MAIN; + return SZ_OK; + } + + dest = p->dest; + if (num > (SizeT)(p->destLim - dest)) + { + num = p->destLim - dest; + if (num == 0) + { + p->state = BCJ2_DEC_STATE_ORIG; + return SZ_OK; + } + } + + srcLim = src + num; + + if (p->temp[3] == 0x0F && (src[0] & 0xF0) == 0x80) + *dest = src[0]; + else for (;;) + { + Byte b = *src; + *dest = b; + if (b != 0x0F) + { + if ((b & 0xFE) == 0xE8) + break; + dest++; + if (++src != srcLim) + continue; + break; + } + dest++; + if (++src == srcLim) + break; + if ((*src & 0xF0) != 0x80) + continue; + *dest = *src; + break; + } + + num = src - p->bufs[BCJ2_STREAM_MAIN]; + + if (src == srcLim) + { + p->temp[3] = src[-1]; + p->bufs[BCJ2_STREAM_MAIN] = src; + p->ip += (UInt32)num; + p->dest += num; + p->state = + p->bufs[BCJ2_STREAM_MAIN] == + p->lims[BCJ2_STREAM_MAIN] ? + (unsigned)BCJ2_STREAM_MAIN : + (unsigned)BCJ2_DEC_STATE_ORIG; + return SZ_OK; + } + + { + UInt32 bound, ttt; + CProb *prob; + Byte b = src[0]; + Byte prev = (Byte)(num == 0 ? p->temp[3] : src[-1]); + + p->temp[3] = b; + p->bufs[BCJ2_STREAM_MAIN] = src + 1; + num++; + p->ip += (UInt32)num; + p->dest += num; + + prob = p->probs + (unsigned)(b == 0xE8 ? 2 + (unsigned)prev : (b == 0xE9 ? 1 : 0)); + + _IF_BIT_0 + { + _UPDATE_0 + continue; + } + _UPDATE_1 + + } } - dest = (((UInt32)v[0] << 24) | ((UInt32)v[1] << 16) | - ((UInt32)v[2] << 8) | ((UInt32)v[3])) - ((UInt32)outPos + 4); - outBuf[outPos++] = (Byte)dest; - if (outPos == outSize) + } + + { + UInt32 val; + unsigned cj = (p->temp[3] == 0xE8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP; + const Byte *cur = p->bufs[cj]; + Byte *dest; + SizeT rem; + + if (cur == p->lims[cj]) + { + p->state = cj; break; - outBuf[outPos++] = (Byte)(dest >> 8); - if (outPos == outSize) + } + + val = GetBe32(cur); + p->bufs[cj] = cur + 4; + + p->ip += 4; + val -= p->ip; + dest = p->dest; + rem = p->destLim - dest; + + if (rem < 4) + { + SizeT i; + SetUi32(p->temp, val); + for (i = 0; i < rem; i++) + dest[i] = p->temp[i]; + p->dest = dest + rem; + p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem; break; - outBuf[outPos++] = (Byte)(dest >> 16); - if (outPos == outSize) - break; - outBuf[outPos++] = prevByte = (Byte)(dest >> 24); + } + + SetUi32(dest, val); + p->temp[3] = (Byte)(val >> 24); + p->dest = dest + 4; } } - return (outPos == outSize) ? SZ_OK : SZ_ERROR_DATA; + + if (p->range < kTopValue && p->bufs[BCJ2_STREAM_RC] != p->lims[BCJ2_STREAM_RC]) + { + p->range <<= 8; + p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; + } + + return SZ_OK; } diff --git a/lzma/C/Bcj2.h b/lzma/C/Bcj2.h index d9d857bc3..68893d2d1 100644 --- a/lzma/C/Bcj2.h +++ b/lzma/C/Bcj2.h @@ -1,38 +1,146 @@ -/* Bcj2.h -- Converter for x86 code (BCJ2) -2009-02-07 : Igor Pavlov : Public domain */ +/* Bcj2.h -- BCJ2 Converter for x86 code +2014-11-10 : Igor Pavlov : Public domain */ #ifndef __BCJ2_H #define __BCJ2_H -#include "Types.h" +#include "7zTypes.h" -#ifdef __cplusplus -extern "C" { -#endif +EXTERN_C_BEGIN + +#define BCJ2_NUM_STREAMS 4 + +enum +{ + BCJ2_STREAM_MAIN, + BCJ2_STREAM_CALL, + BCJ2_STREAM_JUMP, + BCJ2_STREAM_RC +}; + +enum +{ + BCJ2_DEC_STATE_ORIG_0 = BCJ2_NUM_STREAMS, + BCJ2_DEC_STATE_ORIG_1, + BCJ2_DEC_STATE_ORIG_2, + BCJ2_DEC_STATE_ORIG_3, + + BCJ2_DEC_STATE_ORIG, + BCJ2_DEC_STATE_OK +}; + +enum +{ + BCJ2_ENC_STATE_ORIG = BCJ2_NUM_STREAMS, + BCJ2_ENC_STATE_OK +}; + + +#define BCJ2_IS_32BIT_STREAM(s) ((s) == BCJ2_STREAM_CALL || (s) == BCJ2_STREAM_JUMP) /* -Conditions: - outSize <= FullOutputSize, - where FullOutputSize is full size of output stream of x86_2 filter. - -If buf0 overlaps outBuf, there are two required conditions: - 1) (buf0 >= outBuf) - 2) (buf0 + size0 >= outBuf + FullOutputSize). - -Returns: - SZ_OK - SZ_ERROR_DATA - Data error +CBcj2Dec / CBcj2Enc +bufs sizes: + BUF_SIZE(n) = lims[n] - bufs[n] +bufs sizes for BCJ2_STREAM_CALL and BCJ2_STREAM_JUMP must be mutliply of 4: + (BUF_SIZE(BCJ2_STREAM_CALL) & 3) == 0 + (BUF_SIZE(BCJ2_STREAM_JUMP) & 3) == 0 */ -int Bcj2_Decode( - const Byte *buf0, SizeT size0, - const Byte *buf1, SizeT size1, - const Byte *buf2, SizeT size2, - const Byte *buf3, SizeT size3, - Byte *outBuf, SizeT outSize); +/* +CBcj2Dec: +dest is allowed to overlap with bufs[BCJ2_STREAM_MAIN], with the following conditions: + bufs[BCJ2_STREAM_MAIN] >= dest && + bufs[BCJ2_STREAM_MAIN] - dest >= tempReserv + + BUF_SIZE(BCJ2_STREAM_CALL) + + BUF_SIZE(BCJ2_STREAM_JUMP) + tempReserv = 0 : for first call of Bcj2Dec_Decode + tempReserv = 4 : for any other calls of Bcj2Dec_Decode + overlap with offset = 1 is not allowed +*/ -#ifdef __cplusplus -} -#endif +typedef struct +{ + const Byte *bufs[BCJ2_NUM_STREAMS]; + const Byte *lims[BCJ2_NUM_STREAMS]; + Byte *dest; + const Byte *destLim; + + unsigned state; /* BCJ2_STREAM_MAIN has more priority than BCJ2_STATE_ORIG */ + + UInt32 ip; + Byte temp[4]; + UInt32 range; + UInt32 code; + UInt16 probs[2 + 256]; +} CBcj2Dec; + +void Bcj2Dec_Init(CBcj2Dec *p); + +/* Returns: SZ_OK or SZ_ERROR_DATA */ +SRes Bcj2Dec_Decode(CBcj2Dec *p); + +#define Bcj2Dec_IsFinished(_p_) ((_p_)->code == 0) + + + +typedef enum +{ + BCJ2_ENC_FINISH_MODE_CONTINUE, + BCJ2_ENC_FINISH_MODE_END_BLOCK, + BCJ2_ENC_FINISH_MODE_END_STREAM +} EBcj2Enc_FinishMode; + +typedef struct +{ + Byte *bufs[BCJ2_NUM_STREAMS]; + const Byte *lims[BCJ2_NUM_STREAMS]; + const Byte *src; + const Byte *srcLim; + + unsigned state; + EBcj2Enc_FinishMode finishMode; + + Byte prevByte; + + Byte cache; + UInt32 range; + UInt64 low; + UInt64 cacheSize; + + UInt32 ip; + + /* 32-bit ralative offset in JUMP/CALL commands is + - (mod 4 GB) in 32-bit mode + - signed Int32 in 64-bit mode + We use (mod 4 GB) check for fileSize. + Use fileSize up to 2 GB, if you want to support 32-bit and 64-bit code conversion. */ + UInt32 fileIp; + UInt32 fileSize; /* (fileSize <= ((UInt32)1 << 31)), 0 means no_limit */ + UInt32 relatLimit; /* (relatLimit <= ((UInt32)1 << 31)), 0 means desable_conversion */ + + UInt32 tempTarget; + unsigned tempPos; + Byte temp[4 * 2]; + + unsigned flushPos; + + UInt16 probs[2 + 256]; +} CBcj2Enc; + +void Bcj2Enc_Init(CBcj2Enc *p); +void Bcj2Enc_Encode(CBcj2Enc *p); + +#define Bcj2Enc_Get_InputData_Size(p) ((SizeT)((p)->srcLim - (p)->src) + (p)->tempPos) +#define Bcj2Enc_IsFinished(p) ((p)->flushPos == 5) + + +#define BCJ2_RELAT_LIMIT_NUM_BITS 26 +#define BCJ2_RELAT_LIMIT ((UInt32)1 << BCJ2_RELAT_LIMIT_NUM_BITS) + +/* limit for CBcj2Enc::fileSize variable */ +#define BCJ2_FileSize_MAX ((UInt32)1 << 31) + +EXTERN_C_END #endif diff --git a/lzma/C/Bra.c b/lzma/C/Bra.c index 2a0f147b2..976810c96 100644 --- a/lzma/C/Bra.c +++ b/lzma/C/Bra.c @@ -1,6 +1,8 @@ /* Bra.c -- Converters for RISC code 2010-04-16 : Igor Pavlov : Public domain */ +#include "Precomp.h" + #include "Bra.h" SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) diff --git a/lzma/C/Bra.h b/lzma/C/Bra.h index 9c91e332d..aba8dce14 100644 --- a/lzma/C/Bra.h +++ b/lzma/C/Bra.h @@ -1,14 +1,12 @@ /* Bra.h -- Branch converters for executables -2009-02-07 : Igor Pavlov : Public domain */ +2013-01-18 : Igor Pavlov : Public domain */ #ifndef __BRA_H #define __BRA_H -#include "Types.h" +#include "7zTypes.h" -#ifdef __cplusplus -extern "C" { -#endif +EXTERN_C_BEGIN /* These functions convert relative addresses to absolute addresses @@ -61,8 +59,6 @@ SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); -#ifdef __cplusplus -} -#endif +EXTERN_C_END #endif diff --git a/lzma/C/Bra86.c b/lzma/C/Bra86.c index 93566cb21..8dd3ed48d 100644 --- a/lzma/C/Bra86.c +++ b/lzma/C/Bra86.c @@ -1,85 +1,82 @@ /* Bra86.c -- Converter for x86 code (BCJ) -2008-10-04 : Igor Pavlov : Public domain */ +2013-11-12 : Igor Pavlov : Public domain */ + +#include "Precomp.h" #include "Bra.h" -#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF) - -const Byte kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0}; -const Byte kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3}; +#define Test86MSByte(b) ((((b) + 1) & 0xFE) == 0) SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding) { - SizeT bufferPos = 0, prevPosT; - UInt32 prevMask = *state & 0x7; + SizeT pos = 0; + UInt32 mask = *state & 7; if (size < 5) return 0; + size -= 4; ip += 5; - prevPosT = (SizeT)0 - 1; for (;;) { - Byte *p = data + bufferPos; - Byte *limit = data + size - 4; + Byte *p = data + pos; + const Byte *limit = data + size; for (; p < limit; p++) if ((*p & 0xFE) == 0xE8) break; - bufferPos = (SizeT)(p - data); - if (p >= limit) - break; - prevPosT = bufferPos - prevPosT; - if (prevPosT > 3) - prevMask = 0; - else + { - prevMask = (prevMask << ((int)prevPosT - 1)) & 0x7; - if (prevMask != 0) + SizeT d = (SizeT)(p - data - pos); + pos = (SizeT)(p - data); + if (p >= limit) { - Byte b = p[4 - kMaskToBitNumber[prevMask]]; - if (!kMaskToAllowedStatus[prevMask] || Test86MSByte(b)) + *state = (d > 2 ? 0 : mask >> (unsigned)d); + return pos; + } + if (d > 2) + mask = 0; + else + { + mask >>= (unsigned)d; + if (mask != 0 && (mask > 4 || mask == 3 || Test86MSByte(p[(mask >> 1) + 1]))) { - prevPosT = bufferPos; - prevMask = ((prevMask << 1) & 0x7) | 1; - bufferPos++; + mask = (mask >> 1) | 4; + pos++; continue; } } } - prevPosT = bufferPos; if (Test86MSByte(p[4])) { - UInt32 src = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]); - UInt32 dest; - for (;;) + UInt32 v = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]); + UInt32 cur = ip + (UInt32)pos; + pos += 5; + if (encoding) + v += cur; + else + v -= cur; + if (mask != 0) { - Byte b; - int index; - if (encoding) - dest = (ip + (UInt32)bufferPos) + src; - else - dest = src - (ip + (UInt32)bufferPos); - if (prevMask == 0) - break; - index = kMaskToBitNumber[prevMask] * 8; - b = (Byte)(dest >> (24 - index)); - if (!Test86MSByte(b)) - break; - src = dest ^ ((1 << (32 - index)) - 1); + unsigned sh = (mask & 6) << 2; + if (Test86MSByte((Byte)(v >> sh))) + { + v ^= (((UInt32)0x100 << sh) - 1); + if (encoding) + v += cur; + else + v -= cur; + } + mask = 0; } - p[4] = (Byte)(~(((dest >> 24) & 1) - 1)); - p[3] = (Byte)(dest >> 16); - p[2] = (Byte)(dest >> 8); - p[1] = (Byte)dest; - bufferPos += 5; + p[1] = (Byte)v; + p[2] = (Byte)(v >> 8); + p[3] = (Byte)(v >> 16); + p[4] = (Byte)(0 - ((v >> 24) & 1)); } else { - prevMask = ((prevMask << 1) & 0x7) | 1; - bufferPos++; + mask = (mask >> 1) | 4; + pos++; } } - prevPosT = bufferPos - prevPosT; - *state = ((prevPosT > 3) ? 0 : ((prevMask << ((int)prevPosT - 1)) & 0x7)); - return bufferPos; } diff --git a/lzma/C/BraIA64.c b/lzma/C/BraIA64.c new file mode 100644 index 000000000..fa60356b2 --- /dev/null +++ b/lzma/C/BraIA64.c @@ -0,0 +1,69 @@ +/* BraIA64.c -- Converter for IA-64 code +2013-11-12 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Bra.h" + +static const Byte kBranchTable[32] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 6, 6, 0, 0, 7, 7, + 4, 4, 0, 0, 4, 4, 0, 0 +}; + +SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +{ + SizeT i; + if (size < 16) + return 0; + size -= 16; + for (i = 0; i <= size; i += 16) + { + UInt32 instrTemplate = data[i] & 0x1F; + UInt32 mask = kBranchTable[instrTemplate]; + UInt32 bitPos = 5; + int slot; + for (slot = 0; slot < 3; slot++, bitPos += 41) + { + UInt32 bytePos, bitRes; + UInt64 instruction, instNorm; + int j; + if (((mask >> slot) & 1) == 0) + continue; + bytePos = (bitPos >> 3); + bitRes = bitPos & 0x7; + instruction = 0; + for (j = 0; j < 6; j++) + instruction += (UInt64)data[i + j + bytePos] << (8 * j); + + instNorm = instruction >> bitRes; + if (((instNorm >> 37) & 0xF) == 0x5 && ((instNorm >> 9) & 0x7) == 0) + { + UInt32 src = (UInt32)((instNorm >> 13) & 0xFFFFF); + UInt32 dest; + src |= ((UInt32)(instNorm >> 36) & 1) << 20; + + src <<= 4; + + if (encoding) + dest = ip + (UInt32)i + src; + else + dest = src - (ip + (UInt32)i); + + dest >>= 4; + + instNorm &= ~((UInt64)(0x8FFFFF) << 13); + instNorm |= ((UInt64)(dest & 0xFFFFF) << 13); + instNorm |= ((UInt64)(dest & 0x100000) << (36 - 20)); + + instruction &= (1 << bitRes) - 1; + instruction |= (instNorm << bitRes); + for (j = 0; j < 6; j++) + data[i + j + bytePos] = (Byte)(instruction >> (8 * j)); + } + } + } + return i; +} diff --git a/lzma/C/Compiler.h b/lzma/C/Compiler.h new file mode 100644 index 000000000..5bba7ee56 --- /dev/null +++ b/lzma/C/Compiler.h @@ -0,0 +1,32 @@ +/* Compiler.h +2015-08-02 : Igor Pavlov : Public domain */ + +#ifndef __7Z_COMPILER_H +#define __7Z_COMPILER_H + +#ifdef _MSC_VER + + #ifdef UNDER_CE + #define RPC_NO_WINDOWS_H + /* #pragma warning(disable : 4115) // '_RPC_ASYNC_STATE' : named type definition in parentheses */ + #pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union + #pragma warning(disable : 4214) // nonstandard extension used : bit field types other than int + #endif + + #if _MSC_VER >= 1300 + #pragma warning(disable : 4996) // This function or variable may be unsafe + #else + #pragma warning(disable : 4511) // copy constructor could not be generated + #pragma warning(disable : 4512) // assignment operator could not be generated + #pragma warning(disable : 4514) // unreferenced inline function has been removed + #pragma warning(disable : 4702) // unreachable code + #pragma warning(disable : 4710) // not inlined + #pragma warning(disable : 4786) // identifier was truncated to '255' characters in the debug information + #endif + +#endif + +#define UNUSED_VAR(x) (void)x; +/* #define UNUSED_VAR(x) x=x; */ + +#endif diff --git a/lzma/C/CpuArch.c b/lzma/C/CpuArch.c index d6ab3f7f8..bcb84cb2b 100644 --- a/lzma/C/CpuArch.c +++ b/lzma/C/CpuArch.c @@ -1,5 +1,7 @@ /* CpuArch.c -- CPU specific code -2010-10-26: Igor Pavlov : Public domain */ +2015-03-25: Igor Pavlov : Public domain */ + +#include "Precomp.h" #include "CpuArch.h" @@ -9,6 +11,10 @@ #define USE_ASM #endif +#if !defined(USE_ASM) && _MSC_VER >= 1500 +#include +#endif + #if defined(USE_ASM) && !defined(MY_CPU_AMD64) static UInt32 CheckFlag(UInt32 flag) { @@ -48,7 +54,7 @@ static UInt32 CheckFlag(UInt32 flag) #define CHECK_CPUID_IS_SUPPORTED #endif -static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d) +void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d) { #ifdef USE_ASM @@ -70,28 +76,20 @@ static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d) *c = c2; *d = d2; - #elif defined __PIC__ && defined __i386__ - - /* GCC or Clang WITH position-independent code generation, i386 only */ - - __asm__ __volatile__ ( - "xchgl %%ebx, %1\n" - "cpuid\n" - "xchgl %%ebx, %1\n" - : "=a" (*a) , - "=r" (*b) , - "=c" (*c) , - "=d" (*d) - : "0" (function)) ; - #else - /* GCC or Clang WITHOUT position-independent code generation, or x86_64 */ - __asm__ __volatile__ ( + #if defined(MY_CPU_X86) && defined(__PIC__) + "mov %%ebx, %%edi;" + "cpuid;" + "xchgl %%ebx, %%edi;" + : "=a" (*a) , + "=D" (*b) , + #else "cpuid" : "=a" (*a) , "=b" (*b) , + #endif "=c" (*c) , "=d" (*d) : "0" (function)) ; @@ -118,7 +116,7 @@ Bool x86cpuid_CheckAndRead(Cx86cpuid *p) return True; } -static UInt32 kVendors[][3] = +static const UInt32 kVendors[][3] = { { 0x756E6547, 0x49656E69, 0x6C65746E}, { 0x68747541, 0x69746E65, 0x444D4163}, @@ -146,12 +144,22 @@ Bool CPU_Is_InOrder() UInt32 family, model; if (!x86cpuid_CheckAndRead(&p)) return True; - family = x86cpuid_GetFamily(&p); - model = x86cpuid_GetModel(&p); + + family = x86cpuid_GetFamily(p.ver); + model = x86cpuid_GetModel(p.ver); + firm = x86cpuid_GetFirm(&p); + switch (firm) { - case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && model == 0x100C)); + case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && ( + /* In-Order Atom CPU */ + model == 0x1C /* 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 */ + || model == 0x26 /* 45 nm, Z6xx */ + || model == 0x27 /* 32 nm, Z2460 */ + || model == 0x35 /* 32 nm, Z2760 */ + || model == 0x36 /* 32 nm, N2xxx, D2xxx */ + ))); case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA))); case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF)); } @@ -159,6 +167,7 @@ Bool CPU_Is_InOrder() } #if !defined(MY_CPU_AMD64) && defined(_WIN32) +#include static Bool CPU_Sys_Is_SSE_Supported() { OSVERSIONINFO vi; diff --git a/lzma/C/CpuArch.h b/lzma/C/CpuArch.h index 1cd7c29c5..b31c2546c 100644 --- a/lzma/C/CpuArch.h +++ b/lzma/C/CpuArch.h @@ -1,27 +1,34 @@ /* CpuArch.h -- CPU specific code -2010-12-01: Igor Pavlov : Public domain */ +2015-12-01: Igor Pavlov : Public domain */ #ifndef __CPU_ARCH_H #define __CPU_ARCH_H -#include "Types.h" +#include "7zTypes.h" EXTERN_C_BEGIN /* MY_CPU_LE means that CPU is LITTLE ENDIAN. -If MY_CPU_LE is not defined, we don't know about that property of platform (it can be LITTLE ENDIAN). +MY_CPU_BE means that CPU is BIG ENDIAN. +If MY_CPU_LE and MY_CPU_BE are not defined, we don't know about ENDIANNESS of platform. MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses. -If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of platform. */ -#if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__) -#define MY_CPU_AMD64 +#if defined(_M_X64) \ + || defined(_M_AMD64) \ + || defined(__x86_64__) \ + || defined(__AMD64__) \ + || defined(__amd64__) + #define MY_CPU_AMD64 #endif -#if defined(MY_CPU_AMD64) || defined(_M_IA64) -#define MY_CPU_64BIT +#if defined(MY_CPU_AMD64) \ + || defined(_M_IA64) \ + || defined(__AARCH64EL__) \ + || defined(__AARCH64EB__) + #define MY_CPU_64BIT #endif #if defined(_M_IX86) || defined(__i386__) @@ -32,8 +39,13 @@ If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of pla #define MY_CPU_X86_OR_AMD64 #endif -#if defined(MY_CPU_X86) || defined(_M_ARM) -#define MY_CPU_32BIT +#if defined(MY_CPU_X86) \ + || defined(_M_ARM) \ + || defined(__ARMEL__) \ + || defined(__THUMBEL__) \ + || defined(__ARMEB__) \ + || defined(__THUMBEB__) + #define MY_CPU_32BIT #endif #if defined(_WIN32) && defined(_M_ARM) @@ -44,34 +56,63 @@ If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of pla #define MY_CPU_IA64_LE #endif -#if defined(MY_CPU_X86_OR_AMD64) -#define MY_CPU_LE_UNALIGN +#if defined(MY_CPU_X86_OR_AMD64) \ + || defined(MY_CPU_ARM_LE) \ + || defined(MY_CPU_IA64_LE) \ + || defined(__LITTLE_ENDIAN__) \ + || defined(__ARMEL__) \ + || defined(__THUMBEL__) \ + || defined(__AARCH64EL__) \ + || defined(__MIPSEL__) \ + || defined(__MIPSEL) \ + || defined(_MIPSEL) \ + || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) + #define MY_CPU_LE #endif -#if defined(MY_CPU_X86_OR_AMD64) || defined(MY_CPU_ARM_LE) || defined(MY_CPU_IA64_LE) || defined(__ARMEL__) || defined(__MIPSEL__) || defined(__LITTLE_ENDIAN__) -#define MY_CPU_LE -#endif - -#if defined(__BIG_ENDIAN__) || defined(__m68k__) || defined(__ARMEB__) || defined(__MIPSEB__) -#define MY_CPU_BE +#if defined(__BIG_ENDIAN__) \ + || defined(__ARMEB__) \ + || defined(__THUMBEB__) \ + || defined(__AARCH64EB__) \ + || defined(__MIPSEB__) \ + || defined(__MIPSEB) \ + || defined(_MIPSEB) \ + || defined(__m68k__) \ + || defined(__s390__) \ + || defined(__s390x__) \ + || defined(__zarch__) \ + || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) + #define MY_CPU_BE #endif #if defined(MY_CPU_LE) && defined(MY_CPU_BE) Stop_Compiling_Bad_Endian #endif + +#ifdef MY_CPU_LE + #if defined(MY_CPU_X86_OR_AMD64) \ + /* || defined(__AARCH64EL__) */ + #define MY_CPU_LE_UNALIGN + #endif +#endif + + #ifdef MY_CPU_LE_UNALIGN -#define GetUi16(p) (*(const UInt16 *)(p)) -#define GetUi32(p) (*(const UInt32 *)(p)) -#define GetUi64(p) (*(const UInt64 *)(p)) -#define SetUi16(p, d) *(UInt16 *)(p) = (d); -#define SetUi32(p, d) *(UInt32 *)(p) = (d); -#define SetUi64(p, d) *(UInt64 *)(p) = (d); +#define GetUi16(p) (*(const UInt16 *)(const void *)(p)) +#define GetUi32(p) (*(const UInt32 *)(const void *)(p)) +#define GetUi64(p) (*(const UInt64 *)(const void *)(p)) + +#define SetUi16(p, v) { *(UInt16 *)(p) = (v); } +#define SetUi32(p, v) { *(UInt32 *)(p) = (v); } +#define SetUi64(p, v) { *(UInt64 *)(p) = (v); } #else -#define GetUi16(p) (((const Byte *)(p))[0] | ((UInt16)((const Byte *)(p))[1] << 8)) +#define GetUi16(p) ( (UInt16) ( \ + ((const Byte *)(p))[0] | \ + ((UInt16)((const Byte *)(p))[1] << 8) )) #define GetUi32(p) ( \ ((const Byte *)(p))[0] | \ @@ -81,29 +122,43 @@ Stop_Compiling_Bad_Endian #define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32)) -#define SetUi16(p, d) { UInt32 _x_ = (d); \ - ((Byte *)(p))[0] = (Byte)_x_; \ - ((Byte *)(p))[1] = (Byte)(_x_ >> 8); } +#define SetUi16(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ + _ppp_[0] = (Byte)_vvv_; \ + _ppp_[1] = (Byte)(_vvv_ >> 8); } -#define SetUi32(p, d) { UInt32 _x_ = (d); \ - ((Byte *)(p))[0] = (Byte)_x_; \ - ((Byte *)(p))[1] = (Byte)(_x_ >> 8); \ - ((Byte *)(p))[2] = (Byte)(_x_ >> 16); \ - ((Byte *)(p))[3] = (Byte)(_x_ >> 24); } +#define SetUi32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ + _ppp_[0] = (Byte)_vvv_; \ + _ppp_[1] = (Byte)(_vvv_ >> 8); \ + _ppp_[2] = (Byte)(_vvv_ >> 16); \ + _ppp_[3] = (Byte)(_vvv_ >> 24); } -#define SetUi64(p, d) { UInt64 _x64_ = (d); \ - SetUi32(p, (UInt32)_x64_); \ - SetUi32(((Byte *)(p)) + 4, (UInt32)(_x64_ >> 32)); } +#define SetUi64(p, v) { Byte *_ppp2_ = (Byte *)(p); UInt64 _vvv2_ = (v); \ + SetUi32(_ppp2_ , (UInt32)_vvv2_); \ + SetUi32(_ppp2_ + 4, (UInt32)(_vvv2_ >> 32)); } #endif -#if defined(MY_CPU_LE_UNALIGN) && defined(_WIN64) && (_MSC_VER >= 1300) + +#if defined(MY_CPU_LE_UNALIGN) && /* defined(_WIN64) && */ (_MSC_VER >= 1300) + +/* Note: we use bswap instruction, that is unsupported in 386 cpu */ + +#include #pragma intrinsic(_byteswap_ulong) #pragma intrinsic(_byteswap_uint64) #define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p)) #define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p)) +#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = _byteswap_ulong(v) + +#elif defined(MY_CPU_LE_UNALIGN) && defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) + +#define GetBe32(p) __builtin_bswap32(*(const UInt32 *)(const Byte *)(p)) +#define GetBe64(p) __builtin_bswap64(*(const UInt64 *)(const Byte *)(p)) + +#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = __builtin_bswap32(v) + #else #define GetBe32(p) ( \ @@ -114,9 +169,19 @@ Stop_Compiling_Bad_Endian #define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4)) +#define SetBe32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ + _ppp_[0] = (Byte)(_vvv_ >> 24); \ + _ppp_[1] = (Byte)(_vvv_ >> 16); \ + _ppp_[2] = (Byte)(_vvv_ >> 8); \ + _ppp_[3] = (Byte)_vvv_; } + #endif -#define GetBe16(p) (((UInt16)((const Byte *)(p))[0] << 8) | ((const Byte *)(p))[1]) + +#define GetBe16(p) ( (UInt16) ( \ + ((UInt16)((const Byte *)(p))[0] << 8) | \ + ((const Byte *)(p))[1] )) + #ifdef MY_CPU_X86_OR_AMD64 @@ -138,12 +203,14 @@ enum CPU_FIRM_VIA }; +void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d); + Bool x86cpuid_CheckAndRead(Cx86cpuid *p); int x86cpuid_GetFirm(const Cx86cpuid *p); -#define x86cpuid_GetFamily(p) (((p)->ver >> 8) & 0xFF00F) -#define x86cpuid_GetModel(p) (((p)->ver >> 4) & 0xF00F) -#define x86cpuid_GetStepping(p) ((p)->ver & 0xF) +#define x86cpuid_GetFamily(ver) (((ver >> 16) & 0xFF0) | ((ver >> 8) & 0xF)) +#define x86cpuid_GetModel(ver) (((ver >> 12) & 0xF0) | ((ver >> 4) & 0xF)) +#define x86cpuid_GetStepping(ver) (ver & 0xF) Bool CPU_Is_InOrder(); Bool CPU_Is_Aes_Supported(); diff --git a/lzma/C/Delta.c b/lzma/C/Delta.c new file mode 100644 index 000000000..e3edd21ed --- /dev/null +++ b/lzma/C/Delta.c @@ -0,0 +1,64 @@ +/* Delta.c -- Delta converter +2009-05-26 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Delta.h" + +void Delta_Init(Byte *state) +{ + unsigned i; + for (i = 0; i < DELTA_STATE_SIZE; i++) + state[i] = 0; +} + +static void MyMemCpy(Byte *dest, const Byte *src, unsigned size) +{ + unsigned i; + for (i = 0; i < size; i++) + dest[i] = src[i]; +} + +void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size) +{ + Byte buf[DELTA_STATE_SIZE]; + unsigned j = 0; + MyMemCpy(buf, state, delta); + { + SizeT i; + for (i = 0; i < size;) + { + for (j = 0; j < delta && i < size; i++, j++) + { + Byte b = data[i]; + data[i] = (Byte)(b - buf[j]); + buf[j] = b; + } + } + } + if (j == delta) + j = 0; + MyMemCpy(state, buf + j, delta - j); + MyMemCpy(state + delta - j, buf, j); +} + +void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size) +{ + Byte buf[DELTA_STATE_SIZE]; + unsigned j = 0; + MyMemCpy(buf, state, delta); + { + SizeT i; + for (i = 0; i < size;) + { + for (j = 0; j < delta && i < size; i++, j++) + { + buf[j] = data[i] = (Byte)(buf[j] + data[i]); + } + } + } + if (j == delta) + j = 0; + MyMemCpy(state, buf + j, delta - j); + MyMemCpy(state + delta - j, buf, j); +} diff --git a/lzma/C/Delta.h b/lzma/C/Delta.h new file mode 100644 index 000000000..2fa54ad67 --- /dev/null +++ b/lzma/C/Delta.h @@ -0,0 +1,19 @@ +/* Delta.h -- Delta converter +2013-01-18 : Igor Pavlov : Public domain */ + +#ifndef __DELTA_H +#define __DELTA_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define DELTA_STATE_SIZE 256 + +void Delta_Init(Byte *state); +void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size); +void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size); + +EXTERN_C_END + +#endif diff --git a/lzma/C/LzFind.c b/lzma/C/LzFind.c index f6c9e66d5..c335d363c 100644 --- a/lzma/C/LzFind.c +++ b/lzma/C/LzFind.c @@ -1,5 +1,7 @@ /* LzFind.c -- Match finder for LZ algorithms -2009-04-22 : Igor Pavlov : Public domain */ +2015-10-15 : Igor Pavlov : Public domain */ + +#include "Precomp.h" #include @@ -9,8 +11,8 @@ #define kEmptyHashValue 0 #define kMaxValForNormalize ((UInt32)0xFFFFFFFF) #define kNormalizeStepMin (1 << 10) /* it must be power of 2 */ -#define kNormalizeMask (~(kNormalizeStepMin - 1)) -#define kMaxHistorySize ((UInt32)3 << 30) +#define kNormalizeMask (~(UInt32)(kNormalizeStepMin - 1)) +#define kMaxHistorySize ((UInt32)7 << 29) #define kStartMaxLen 3 @@ -19,7 +21,7 @@ static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc) if (!p->directInput) { alloc->Free(alloc, p->bufferBase); - p->bufferBase = 0; + p->bufferBase = NULL; } } @@ -33,17 +35,16 @@ static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *a p->blockSize = blockSize; return 1; } - if (p->bufferBase == 0 || p->blockSize != blockSize) + if (!p->bufferBase || p->blockSize != blockSize) { LzInWindow_Free(p, alloc); p->blockSize = blockSize; p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize); } - return (p->bufferBase != 0); + return (p->bufferBase != NULL); } Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } -Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; } UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } @@ -58,9 +59,12 @@ static void MatchFinder_ReadBlock(CMatchFinder *p) { if (p->streamEndWasReached || p->result != SZ_OK) return; + + /* We use (p->streamPos - p->pos) value. (p->streamPos < p->pos) is allowed. */ + if (p->directInput) { - UInt32 curSize = 0xFFFFFFFF - p->streamPos; + UInt32 curSize = 0xFFFFFFFF - (p->streamPos - p->pos); if (curSize > p->directInputRem) curSize = (UInt32)p->directInputRem; p->directInputRem -= curSize; @@ -69,12 +73,14 @@ static void MatchFinder_ReadBlock(CMatchFinder *p) p->streamEndWasReached = 1; return; } + for (;;) { Byte *dest = p->buffer + (p->streamPos - p->pos); size_t size = (p->bufferBase + p->blockSize - dest); if (size == 0) return; + p->result = p->stream->Read(p->stream, dest, &size); if (p->result != SZ_OK) return; @@ -92,8 +98,8 @@ static void MatchFinder_ReadBlock(CMatchFinder *p) void MatchFinder_MoveBlock(CMatchFinder *p) { memmove(p->bufferBase, - p->buffer - p->keepSizeBefore, - (size_t)(p->streamPos - p->pos + p->keepSizeBefore)); + p->buffer - p->keepSizeBefore, + (size_t)(p->streamPos - p->pos) + p->keepSizeBefore); p->buffer = p->bufferBase + p->keepSizeBefore; } @@ -133,15 +139,15 @@ static void MatchFinder_SetDefaultSettings(CMatchFinder *p) void MatchFinder_Construct(CMatchFinder *p) { UInt32 i; - p->bufferBase = 0; + p->bufferBase = NULL; p->directInput = 0; - p->hash = 0; + p->hash = NULL; MatchFinder_SetDefaultSettings(p); for (i = 0; i < 256; i++) { UInt32 r = i; - int j; + unsigned j; for (j = 0; j < 8; j++) r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); p->crc[i] = r; @@ -151,7 +157,7 @@ void MatchFinder_Construct(CMatchFinder *p) static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc) { alloc->Free(alloc, p->hash); - p->hash = 0; + p->hash = NULL; } void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc) @@ -160,11 +166,11 @@ void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc) LzInWindow_Free(p, alloc); } -static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc) +static CLzRef* AllocRefs(size_t num, ISzAlloc *alloc) { size_t sizeInBytes = (size_t)num * sizeof(CLzRef); if (sizeInBytes / sizeof(CLzRef) != num) - return 0; + return NULL; return (CLzRef *)alloc->Alloc(alloc, sizeInBytes); } @@ -173,19 +179,24 @@ int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, ISzAlloc *alloc) { UInt32 sizeReserv; + if (historySize > kMaxHistorySize) { MatchFinder_Free(p, alloc); return 0; } + sizeReserv = historySize >> 1; - if (historySize > ((UInt32)2 << 30)) - sizeReserv = historySize >> 2; + if (historySize >= ((UInt32)3 << 30)) sizeReserv = historySize >> 3; + else if (historySize >= ((UInt32)2 << 30)) sizeReserv = historySize >> 2; + sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19); p->keepSizeBefore = historySize + keepAddBufferBefore + 1; p->keepSizeAfter = matchMaxLen + keepAddBufferAfter; + /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */ + if (LzInWindow_Create(p, sizeReserv, alloc)) { UInt32 newCyclicBufferSize = historySize + 1; @@ -210,6 +221,7 @@ int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, hs = (1 << 24) - 1; else hs >>= 1; + /* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 1))) */ } } p->hashMask = hs; @@ -221,24 +233,32 @@ int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, } { - UInt32 prevSize = p->hashSizeSum + p->numSons; - UInt32 newSize; + size_t newSize; + size_t numSons; p->historySize = historySize; p->hashSizeSum = hs; p->cyclicBufferSize = newCyclicBufferSize; - p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize); - newSize = p->hashSizeSum + p->numSons; - if (p->hash != 0 && prevSize == newSize) + + numSons = newCyclicBufferSize; + if (p->btMode) + numSons <<= 1; + newSize = hs + numSons; + + if (p->hash && p->numRefs == newSize) return 1; + MatchFinder_FreeThisClassMemory(p, alloc); + p->numRefs = newSize; p->hash = AllocRefs(newSize, alloc); - if (p->hash != 0) + + if (p->hash) { p->son = p->hash + p->hashSizeSum; return 1; } } } + MatchFinder_Free(p, alloc); return 0; } @@ -247,9 +267,11 @@ static void MatchFinder_SetLimits(CMatchFinder *p) { UInt32 limit = kMaxValForNormalize - p->pos; UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos; + if (limit2 < limit) limit = limit2; limit2 = p->streamPos - p->pos; + if (limit2 <= p->keepSizeAfter) { if (limit2 > 0) @@ -257,8 +279,10 @@ static void MatchFinder_SetLimits(CMatchFinder *p) } else limit2 -= p->keepSizeAfter; + if (limit2 < limit) limit = limit2; + { UInt32 lenLimit = p->streamPos - p->pos; if (lenLimit > p->matchMaxLen) @@ -268,28 +292,39 @@ static void MatchFinder_SetLimits(CMatchFinder *p) p->posLimit = p->pos + limit; } -void MatchFinder_Init(CMatchFinder *p) +void MatchFinder_Init_2(CMatchFinder *p, int readData) { UInt32 i; - for (i = 0; i < p->hashSizeSum; i++) - p->hash[i] = kEmptyHashValue; + UInt32 *hash = p->hash; + UInt32 num = p->hashSizeSum; + for (i = 0; i < num; i++) + hash[i] = kEmptyHashValue; + p->cyclicBufferPos = 0; p->buffer = p->bufferBase; p->pos = p->streamPos = p->cyclicBufferSize; p->result = SZ_OK; p->streamEndWasReached = 0; - MatchFinder_ReadBlock(p); + + if (readData) + MatchFinder_ReadBlock(p); + MatchFinder_SetLimits(p); } +void MatchFinder_Init(CMatchFinder *p) +{ + MatchFinder_Init_2(p, True); +} + static UInt32 MatchFinder_GetSubValue(CMatchFinder *p) { return (p->pos - p->historySize - 1) & kNormalizeMask; } -void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) +void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems) { - UInt32 i; + size_t i; for (i = 0; i < numItems; i++) { UInt32 value = items[i]; @@ -304,7 +339,7 @@ void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) static void MatchFinder_Normalize(CMatchFinder *p) { UInt32 subValue = MatchFinder_GetSubValue(p); - MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons); + MatchFinder_Normalize3(subValue, p->hash, p->numRefs); MatchFinder_ReduceOffsets(p, subValue); } @@ -465,7 +500,7 @@ static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } #define GET_MATCHES_HEADER2(minLen, ret_op) \ - UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \ + UInt32 lenLimit; UInt32 hv; const Byte *cur; UInt32 curMatch; \ lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \ cur = p->buffer; @@ -481,13 +516,20 @@ static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } #define SKIP_FOOTER \ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS; +#define UPDATE_maxLen { \ + ptrdiff_t diff = (ptrdiff_t)0 - d2; \ + const Byte *c = cur + maxLen; \ + const Byte *lim = cur + lenLimit; \ + for (; c != lim; c++) if (*(c + diff) != *c) break; \ + maxLen = (UInt32)(c - cur); } + static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { UInt32 offset; GET_MATCHES_HEADER(2) HASH2_CALC; - curMatch = p->hash[hashValue]; - p->hash[hashValue] = p->pos; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; offset = 0; GET_MATCHES_FOOTER(offset, 1) } @@ -497,35 +539,38 @@ UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) UInt32 offset; GET_MATCHES_HEADER(3) HASH_ZIP_CALC; - curMatch = p->hash[hashValue]; - p->hash[hashValue] = p->pos; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; offset = 0; GET_MATCHES_FOOTER(offset, 2) } static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { - UInt32 hash2Value, delta2, maxLen, offset; + UInt32 h2, d2, maxLen, offset, pos; + UInt32 *hash; GET_MATCHES_HEADER(3) HASH3_CALC; - delta2 = p->pos - p->hash[hash2Value]; - curMatch = p->hash[kFix3HashSize + hashValue]; - - p->hash[hash2Value] = - p->hash[kFix3HashSize + hashValue] = p->pos; + hash = p->hash; + pos = p->pos; + d2 = pos - hash[h2]; + + curMatch = hash[kFix3HashSize + hv]; + + hash[h2] = pos; + hash[kFix3HashSize + hv] = pos; maxLen = 2; offset = 0; - if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) + + if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) { - for (; maxLen != lenLimit; maxLen++) - if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) - break; + UPDATE_maxLen distances[0] = maxLen; - distances[1] = delta2 - 1; + distances[1] = d2 - 1; offset = 2; if (maxLen == lenLimit) { @@ -533,44 +578,51 @@ static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) MOVE_POS_RET; } } + GET_MATCHES_FOOTER(offset, maxLen) } static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { - UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; + UInt32 h2, h3, d2, d3, maxLen, offset, pos; + UInt32 *hash; GET_MATCHES_HEADER(4) HASH4_CALC; - delta2 = p->pos - p->hash[ hash2Value]; - delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; - curMatch = p->hash[kFix4HashSize + hashValue]; - - p->hash[ hash2Value] = - p->hash[kFix3HashSize + hash3Value] = - p->hash[kFix4HashSize + hashValue] = p->pos; + hash = p->hash; + pos = p->pos; - maxLen = 1; + d2 = pos - hash[ h2]; + d3 = pos - hash[kFix3HashSize + h3]; + + curMatch = hash[kFix4HashSize + hv]; + + hash[ h2] = pos; + hash[kFix3HashSize + h3] = pos; + hash[kFix4HashSize + hv] = pos; + + maxLen = 0; offset = 0; - if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) + + if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) { distances[0] = maxLen = 2; - distances[1] = delta2 - 1; + distances[1] = d2 - 1; offset = 2; } - if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) + + if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur) { maxLen = 3; - distances[offset + 1] = delta3 - 1; + distances[offset + 1] = d3 - 1; offset += 2; - delta2 = delta3; + d2 = d3; } + if (offset != 0) { - for (; maxLen != lenLimit; maxLen++) - if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) - break; + UPDATE_maxLen distances[offset - 2] = maxLen; if (maxLen == lenLimit) { @@ -578,46 +630,131 @@ static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) MOVE_POS_RET; } } + if (maxLen < 3) maxLen = 3; + GET_MATCHES_FOOTER(offset, maxLen) } +/* +static UInt32 Bt5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos; + UInt32 *hash; + GET_MATCHES_HEADER(5) + + HASH5_CALC; + + hash = p->hash; + pos = p->pos; + + d2 = pos - hash[ h2]; + d3 = pos - hash[kFix3HashSize + h3]; + d4 = pos - hash[kFix4HashSize + h4]; + + curMatch = hash[kFix5HashSize + hv]; + + hash[ h2] = pos; + hash[kFix3HashSize + h3] = pos; + hash[kFix4HashSize + h4] = pos; + hash[kFix5HashSize + hv] = pos; + + maxLen = 0; + offset = 0; + + if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) + { + distances[0] = maxLen = 2; + distances[1] = d2 - 1; + offset = 2; + if (*(cur - d2 + 2) == cur[2]) + distances[0] = maxLen = 3; + else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + { + distances[2] = maxLen = 3; + distances[3] = d3 - 1; + offset = 4; + d2 = d3; + } + } + else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + { + distances[0] = maxLen = 3; + distances[1] = d3 - 1; + offset = 2; + d2 = d3; + } + + if (d2 != d4 && d4 < p->cyclicBufferSize + && *(cur - d4) == *cur + && *(cur - d4 + 3) == *(cur + 3)) + { + maxLen = 4; + distances[offset + 1] = d4 - 1; + offset += 2; + d2 = d4; + } + + if (offset != 0) + { + UPDATE_maxLen + distances[offset - 2] = maxLen; + if (maxLen == lenLimit) + { + SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); + MOVE_POS_RET; + } + } + + if (maxLen < 4) + maxLen = 4; + + GET_MATCHES_FOOTER(offset, maxLen) +} +*/ + static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { - UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; + UInt32 h2, h3, d2, d3, maxLen, offset, pos; + UInt32 *hash; GET_MATCHES_HEADER(4) HASH4_CALC; - delta2 = p->pos - p->hash[ hash2Value]; - delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; - curMatch = p->hash[kFix4HashSize + hashValue]; + hash = p->hash; + pos = p->pos; + + d2 = pos - hash[ h2]; + d3 = pos - hash[kFix3HashSize + h3]; + + curMatch = hash[kFix4HashSize + hv]; - p->hash[ hash2Value] = - p->hash[kFix3HashSize + hash3Value] = - p->hash[kFix4HashSize + hashValue] = p->pos; + hash[ h2] = pos; + hash[kFix3HashSize + h3] = pos; + hash[kFix4HashSize + hv] = pos; - maxLen = 1; + maxLen = 0; offset = 0; - if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) + + if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) { distances[0] = maxLen = 2; - distances[1] = delta2 - 1; + distances[1] = d2 - 1; offset = 2; } - if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) + + if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur) { maxLen = 3; - distances[offset + 1] = delta3 - 1; + distances[offset + 1] = d3 - 1; offset += 2; - delta2 = delta3; + d2 = d3; } + if (offset != 0) { - for (; maxLen != lenLimit; maxLen++) - if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) - break; + UPDATE_maxLen distances[offset - 2] = maxLen; if (maxLen == lenLimit) { @@ -625,22 +762,103 @@ static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) MOVE_POS_RET; } } + if (maxLen < 3) maxLen = 3; + offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), - distances + offset, maxLen) - (distances)); + distances + offset, maxLen) - (distances)); MOVE_POS_RET } +/* +static UInt32 Hc5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos + UInt32 *hash; + GET_MATCHES_HEADER(5) + + HASH5_CALC; + + hash = p->hash; + pos = p->pos; + + d2 = pos - hash[ h2]; + d3 = pos - hash[kFix3HashSize + h3]; + d4 = pos - hash[kFix4HashSize + h4]; + + curMatch = hash[kFix5HashSize + hv]; + + hash[ h2] = pos; + hash[kFix3HashSize + h3] = pos; + hash[kFix4HashSize + h4] = pos; + hash[kFix5HashSize + hv] = pos; + + maxLen = 0; + offset = 0; + + if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) + { + distances[0] = maxLen = 2; + distances[1] = d2 - 1; + offset = 2; + if (*(cur - d2 + 2) == cur[2]) + distances[0] = maxLen = 3; + else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + { + distances[2] = maxLen = 3; + distances[3] = d3 - 1; + offset = 4; + d2 = d3; + } + } + else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + { + distances[0] = maxLen = 3; + distances[1] = d3 - 1; + offset = 2; + d2 = d3; + } + + if (d2 != d4 && d4 < p->cyclicBufferSize + && *(cur - d4) == *cur + && *(cur - d4 + 3) == *(cur + 3)) + { + maxLen = 4; + distances[offset + 1] = d4 - 1; + offset += 2; + d2 = d4; + } + + if (offset != 0) + { + UPDATE_maxLen + distances[offset - 2] = maxLen; + if (maxLen == lenLimit) + { + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS_RET; + } + } + + if (maxLen < 4) + maxLen = 4; + + offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), + distances + offset, maxLen) - (distances)); + MOVE_POS_RET +} +*/ + UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { UInt32 offset; GET_MATCHES_HEADER(3) HASH_ZIP_CALC; - curMatch = p->hash[hashValue]; - p->hash[hashValue] = p->pos; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), - distances, 2) - (distances)); + distances, 2) - (distances)); MOVE_POS_RET } @@ -650,8 +868,8 @@ static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { SKIP_HEADER(2) HASH2_CALC; - curMatch = p->hash[hashValue]; - p->hash[hashValue] = p->pos; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; SKIP_FOOTER } while (--num != 0); @@ -663,8 +881,8 @@ void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { SKIP_HEADER(3) HASH_ZIP_CALC; - curMatch = p->hash[hashValue]; - p->hash[hashValue] = p->pos; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; SKIP_FOOTER } while (--num != 0); @@ -674,12 +892,14 @@ static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { - UInt32 hash2Value; + UInt32 h2; + UInt32 *hash; SKIP_HEADER(3) HASH3_CALC; - curMatch = p->hash[kFix3HashSize + hashValue]; - p->hash[hash2Value] = - p->hash[kFix3HashSize + hashValue] = p->pos; + hash = p->hash; + curMatch = hash[kFix3HashSize + hv]; + hash[h2] = + hash[kFix3HashSize + hv] = p->pos; SKIP_FOOTER } while (--num != 0); @@ -689,43 +909,90 @@ static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { - UInt32 hash2Value, hash3Value; + UInt32 h2, h3; + UInt32 *hash; SKIP_HEADER(4) HASH4_CALC; - curMatch = p->hash[kFix4HashSize + hashValue]; - p->hash[ hash2Value] = - p->hash[kFix3HashSize + hash3Value] = p->pos; - p->hash[kFix4HashSize + hashValue] = p->pos; + hash = p->hash; + curMatch = hash[kFix4HashSize + hv]; + hash[ h2] = + hash[kFix3HashSize + h3] = + hash[kFix4HashSize + hv] = p->pos; SKIP_FOOTER } while (--num != 0); } +/* +static void Bt5_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 h2, h3, h4; + UInt32 *hash; + SKIP_HEADER(5) + HASH5_CALC; + hash = p->hash; + curMatch = hash[kFix5HashSize + hv]; + hash[ h2] = + hash[kFix3HashSize + h3] = + hash[kFix4HashSize + h4] = + hash[kFix5HashSize + hv] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} +*/ + static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { - UInt32 hash2Value, hash3Value; + UInt32 h2, h3; + UInt32 *hash; SKIP_HEADER(4) HASH4_CALC; - curMatch = p->hash[kFix4HashSize + hashValue]; - p->hash[ hash2Value] = - p->hash[kFix3HashSize + hash3Value] = - p->hash[kFix4HashSize + hashValue] = p->pos; + hash = p->hash; + curMatch = hash[kFix4HashSize + hv]; + hash[ h2] = + hash[kFix3HashSize + h3] = + hash[kFix4HashSize + hv] = p->pos; p->son[p->cyclicBufferPos] = curMatch; MOVE_POS } while (--num != 0); } +/* +static void Hc5_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 h2, h3, h4; + UInt32 *hash; + SKIP_HEADER(5) + HASH5_CALC; + hash = p->hash; + curMatch = p->hash[kFix5HashSize + hv]; + hash[ h2] = + hash[kFix3HashSize + h3] = + hash[kFix4HashSize + h4] = + hash[kFix5HashSize + hv] = p->pos; + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS + } + while (--num != 0); +} +*/ + void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { SKIP_HEADER(3) HASH_ZIP_CALC; - curMatch = p->hash[hashValue]; - p->hash[hashValue] = p->pos; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; p->son[p->cyclicBufferPos] = curMatch; MOVE_POS } @@ -735,13 +1002,22 @@ void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) { vTable->Init = (Mf_Init_Func)MatchFinder_Init; - vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte; vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes; vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos; if (!p->btMode) { - vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; - vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; + /* if (p->numHashBytes <= 4) */ + { + vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; + } + /* + else + { + vTable->GetMatches = (Mf_GetMatches_Func)Hc5_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Hc5_MatchFinder_Skip; + } + */ } else if (p->numHashBytes == 2) { @@ -753,9 +1029,16 @@ void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches; vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip; } - else + else /* if (p->numHashBytes == 4) */ { vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; } + /* + else + { + vTable->GetMatches = (Mf_GetMatches_Func)Bt5_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Bt5_MatchFinder_Skip; + } + */ } diff --git a/lzma/C/LzFind.h b/lzma/C/LzFind.h index 7ebdfa446..2ff667377 100644 --- a/lzma/C/LzFind.h +++ b/lzma/C/LzFind.h @@ -1,14 +1,12 @@ /* LzFind.h -- Match finder for LZ algorithms -2009-04-22 : Igor Pavlov : Public domain */ +2015-10-15 : Igor Pavlov : Public domain */ #ifndef __LZ_FIND_H #define __LZ_FIND_H -#include "Types.h" +#include "7zTypes.h" -#ifdef __cplusplus -extern "C" { -#endif +EXTERN_C_BEGIN typedef UInt32 CLzRef; @@ -23,6 +21,11 @@ typedef struct _CMatchFinder UInt32 cyclicBufferPos; UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */ + Byte streamEndWasReached; + Byte btMode; + Byte bigHash; + Byte directInput; + UInt32 matchMaxLen; CLzRef *hash; CLzRef *son; @@ -31,30 +34,30 @@ typedef struct _CMatchFinder Byte *bufferBase; ISeqInStream *stream; - int streamEndWasReached; - + UInt32 blockSize; UInt32 keepSizeBefore; UInt32 keepSizeAfter; UInt32 numHashBytes; - int directInput; size_t directInputRem; - int btMode; - int bigHash; UInt32 historySize; UInt32 fixedHashSize; UInt32 hashSizeSum; - UInt32 numSons; SRes result; UInt32 crc[256]; + size_t numRefs; } CMatchFinder; #define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer) -#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)]) #define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos) +#define Inline_MatchFinder_IsFinishedOK(p) \ + ((p)->streamEndWasReached \ + && (p)->streamPos == (p)->pos \ + && (!(p)->directInput || (p)->directInputRem == 0)) + int MatchFinder_NeedMove(CMatchFinder *p); Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); void MatchFinder_MoveBlock(CMatchFinder *p); @@ -70,7 +73,7 @@ int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc); void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc); -void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems); +void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems); void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, @@ -84,7 +87,6 @@ Conditions: */ typedef void (*Mf_Init_Func)(void *object); -typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index); typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object); typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object); typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances); @@ -93,7 +95,6 @@ typedef void (*Mf_Skip_Func)(void *object, UInt32); typedef struct _IMatchFinder { Mf_Init_Func Init; - Mf_GetIndexByte_Func GetIndexByte; Mf_GetNumAvailableBytes_Func GetNumAvailableBytes; Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos; Mf_GetMatches_Func GetMatches; @@ -102,14 +103,15 @@ typedef struct _IMatchFinder void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable); +void MatchFinder_Init_2(CMatchFinder *p, int readData); void MatchFinder_Init(CMatchFinder *p); + UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); + void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); -#ifdef __cplusplus -} -#endif +EXTERN_C_END #endif diff --git a/lzma/C/LzFindMt.c b/lzma/C/LzFindMt.c index db95590c3..cb61e0953 100644 --- a/lzma/C/LzFindMt.c +++ b/lzma/C/LzFindMt.c @@ -1,11 +1,13 @@ /* LzFindMt.c -- multithreaded Match finder for LZ algorithms -2009-09-20 : Igor Pavlov : Public domain */ +2015-10-15 : Igor Pavlov : Public domain */ + +#include "Precomp.h" #include "LzHash.h" #include "LzFindMt.h" -void MtSync_Construct(CMtSync *p) +static void MtSync_Construct(CMtSync *p) { p->wasCreated = False; p->csWasInitialized = False; @@ -18,7 +20,7 @@ void MtSync_Construct(CMtSync *p) Semaphore_Construct(&p->filledSemaphore); } -void MtSync_GetNextBlock(CMtSync *p) +static void MtSync_GetNextBlock(CMtSync *p) { if (p->needStart) { @@ -46,7 +48,7 @@ void MtSync_GetNextBlock(CMtSync *p) /* MtSync_StopWriting must be called if Writing was started */ -void MtSync_StopWriting(CMtSync *p) +static void MtSync_StopWriting(CMtSync *p) { UInt32 myNumBlocks = p->numProcessedBlocks; if (!Thread_WasCreated(&p->thread) || p->needStart) @@ -69,7 +71,7 @@ void MtSync_StopWriting(CMtSync *p) p->needStart = True; } -void MtSync_Destruct(CMtSync *p) +static void MtSync_Destruct(CMtSync *p) { if (Thread_WasCreated(&p->thread)) { @@ -97,7 +99,7 @@ void MtSync_Destruct(CMtSync *p) #define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; } -static SRes MtSync_Create2(CMtSync *p, unsigned (MY_STD_CALL *startAddress)(void *), void *obj, UInt32 numBlocks) +static SRes MtSync_Create2(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj, UInt32 numBlocks) { if (p->wasCreated) return SZ_OK; @@ -119,7 +121,7 @@ static SRes MtSync_Create2(CMtSync *p, unsigned (MY_STD_CALL *startAddress)(void return SZ_OK; } -static SRes MtSync_Create(CMtSync *p, unsigned (MY_STD_CALL *startAddress)(void *), void *obj, UInt32 numBlocks) +static SRes MtSync_Create(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj, UInt32 numBlocks) { SRes res = MtSync_Create2(p, startAddress, obj, numBlocks); if (res != SZ_OK) @@ -132,20 +134,20 @@ void MtSync_Init(CMtSync *p) { p->needStart = True; } #define kMtMaxValForNormalize 0xFFFFFFFF #define DEF_GetHeads2(name, v, action) \ -static void GetHeads ## name(const Byte *p, UInt32 pos, \ -UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) \ -{ action; for (; numHeads != 0; numHeads--) { \ -const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++; } } + static void GetHeads ## name(const Byte *p, UInt32 pos, \ + UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) \ + { action; for (; numHeads != 0; numHeads--) { \ + const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++; } } #define DEF_GetHeads(name, v) DEF_GetHeads2(name, v, ;) -DEF_GetHeads2(2, (p[0] | ((UInt32)p[1] << 8)), hashMask = hashMask; crc = crc; ) +DEF_GetHeads2(2, (p[0] | ((UInt32)p[1] << 8)), UNUSED_VAR(hashMask); UNUSED_VAR(crc); ) DEF_GetHeads(3, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8)) & hashMask) DEF_GetHeads(4, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5)) & hashMask) DEF_GetHeads(4b, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ ((UInt32)p[3] << 16)) & hashMask) /* DEF_GetHeads(5, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5) ^ (crc[p[4]] << 3)) & hashMask) */ -void HashThreadFunc(CMatchFinderMt *mt) +static void HashThreadFunc(CMatchFinderMt *mt) { CMtSync *p = &mt->hashSync; for (;;) @@ -171,12 +173,12 @@ void HashThreadFunc(CMatchFinderMt *mt) CriticalSection_Enter(&mt->btSync.cs); CriticalSection_Enter(&mt->hashSync.cs); { - const Byte *beforePtr = MatchFinder_GetPointerToCurrentPos(mf); - const Byte *afterPtr; + const Byte *beforePtr = Inline_MatchFinder_GetPointerToCurrentPos(mf); + ptrdiff_t offset; MatchFinder_MoveBlock(mf); - afterPtr = MatchFinder_GetPointerToCurrentPos(mf); - mt->pointerToCurPos -= beforePtr - afterPtr; - mt->buffer -= beforePtr - afterPtr; + offset = beforePtr - Inline_MatchFinder_GetPointerToCurrentPos(mf); + mt->pointerToCurPos -= offset; + mt->buffer -= offset; } CriticalSection_Leave(&mt->btSync.cs); CriticalSection_Leave(&mt->hashSync.cs); @@ -190,7 +192,7 @@ void HashThreadFunc(CMatchFinderMt *mt) { UInt32 subValue = (mf->pos - mf->historySize - 1); MatchFinder_ReduceOffsets(mf, subValue); - MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, mf->hashMask + 1); + MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, (size_t)mf->hashMask + 1); } { UInt32 *heads = mt->hashBuf + ((numProcessedBlocks++) & kMtHashNumBlocksMask) * kMtHashBlockSize; @@ -215,7 +217,7 @@ void HashThreadFunc(CMatchFinderMt *mt) } } -void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p) +static void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p) { MtSync_GetNextBlock(&p->hashSync); p->hashBufPosLimit = p->hashBufPos = ((p->hashSync.numProcessedBlocks - 1) & kMtHashNumBlocksMask) * kMtHashBlockSize; @@ -231,7 +233,7 @@ void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p) #define NO_INLINE MY_FAST_CALL -Int32 NO_INLINE GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CLzRef *son, +static Int32 NO_INLINE GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CLzRef *son, UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, UInt32 *_distances, UInt32 _maxLen, const UInt32 *hash, Int32 limit, UInt32 size, UInt32 *posRes) { @@ -308,12 +310,14 @@ Int32 NO_INLINE GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CL #endif -void BtGetMatches(CMatchFinderMt *p, UInt32 *distances) +static void BtGetMatches(CMatchFinderMt *p, UInt32 *distances) { UInt32 numProcessed = 0; UInt32 curPos = 2; UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 2); + distances[1] = p->hashNumAvail; + while (curPos < limit) { if (p->hashBufPos == p->hashBufPosLimit) @@ -322,9 +326,11 @@ void BtGetMatches(CMatchFinderMt *p, UInt32 *distances) distances[1] = numProcessed + p->hashNumAvail; if (p->hashNumAvail >= p->numHashBytes) continue; + distances[0] = curPos + p->hashNumAvail; + distances += curPos; for (; p->hashNumAvail != 0; p->hashNumAvail--) - distances[curPos++] = 0; - break; + *distances++ = 0; + return; } { UInt32 size = p->hashBufPosLimit - p->hashBufPos; @@ -341,13 +347,14 @@ void BtGetMatches(CMatchFinderMt *p, UInt32 *distances) if (size2 < size) size = size2; } + #ifndef MFMT_GM_INLINE while (curPos < limit && size-- != 0) { UInt32 *startDistances = distances + curPos; UInt32 num = (UInt32)(GetMatchesSpec1(lenLimit, pos - p->hashBuf[p->hashBufPos++], - pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, - startDistances + 1, p->numHashBytes - 1) - startDistances); + pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, + startDistances + 1, p->numHashBytes - 1) - startDistances); *startDistances = num - 1; curPos += num; cyclicBufferPos++; @@ -358,7 +365,7 @@ void BtGetMatches(CMatchFinderMt *p, UInt32 *distances) { UInt32 posRes; curPos = limit - GetMatchesSpecN(lenLimit, pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, - distances + curPos, p->numHashBytes - 1, p->hashBuf + p->hashBufPos, (Int32)(limit - curPos) , size, &posRes); + distances + curPos, p->numHashBytes - 1, p->hashBuf + p->hashBufPos, (Int32)(limit - curPos), size, &posRes); p->hashBufPos += posRes - pos; cyclicBufferPos += posRes - pos; p->buffer += posRes - pos; @@ -374,10 +381,11 @@ void BtGetMatches(CMatchFinderMt *p, UInt32 *distances) p->cyclicBufferPos = cyclicBufferPos; } } + distances[0] = curPos; } -void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex) +static void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex) { CMtSync *sync = &p->hashSync; if (!sync->needStart) @@ -391,7 +399,7 @@ void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex) if (p->pos > kMtMaxValForNormalize - kMtBtBlockSize) { UInt32 subValue = p->pos - p->cyclicBufferSize; - MatchFinder_Normalize3(subValue, p->son, p->cyclicBufferSize * 2); + MatchFinder_Normalize3(subValue, p->son, (size_t)p->cyclicBufferSize * 2); p->pos -= subValue; } @@ -430,15 +438,15 @@ void BtThreadFunc(CMatchFinderMt *mt) void MatchFinderMt_Construct(CMatchFinderMt *p) { - p->hashBuf = 0; + p->hashBuf = NULL; MtSync_Construct(&p->hashSync); MtSync_Construct(&p->btSync); } -void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAlloc *alloc) +static void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAlloc *alloc) { alloc->Free(alloc, p->hashBuf); - p->hashBuf = 0; + p->hashBuf = NULL; } void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc) @@ -451,14 +459,15 @@ void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc) #define kHashBufferSize (kMtHashBlockSize * kMtHashNumBlocks) #define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks) -static unsigned MY_STD_CALL HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; } -static unsigned MY_STD_CALL BtThreadFunc2(void *p) +static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; } +static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE BtThreadFunc2(void *p) { Byte allocaDummy[0x180]; - int i = 0; + unsigned i = 0; for (i = 0; i < 16; i++) - allocaDummy[i] = (Byte)i; - BtThreadFunc((CMatchFinderMt *)p); + allocaDummy[i] = (Byte)0; + if (allocaDummy[0] == 0) + BtThreadFunc((CMatchFinderMt *)p); return 0; } @@ -469,10 +478,10 @@ SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddB p->historySize = historySize; if (kMtBtBlockSize <= matchMaxLen * 4) return SZ_ERROR_PARAM; - if (p->hashBuf == 0) + if (!p->hashBuf) { p->hashBuf = (UInt32 *)alloc->Alloc(alloc, (kHashBufferSize + kBtBufferSize) * sizeof(UInt32)); - if (p->hashBuf == 0) + if (!p->hashBuf) return SZ_ERROR_MEM; p->btBuf = p->hashBuf + kHashBufferSize; } @@ -492,8 +501,11 @@ void MatchFinderMt_Init(CMatchFinderMt *p) CMatchFinder *mf = p->MatchFinder; p->btBufPos = p->btBufPosLimit = 0; p->hashBufPos = p->hashBufPosLimit = 0; - MatchFinder_Init(mf); - p->pointerToCurPos = MatchFinder_GetPointerToCurrentPos(mf); + + /* Init without data reading. We don't want to read data in this thread */ + MatchFinder_Init_2(mf, False); + + p->pointerToCurPos = Inline_MatchFinder_GetPointerToCurrentPos(mf); p->btNumAvailBytes = 0; p->lzPos = p->historySize + 1; @@ -518,13 +530,13 @@ void MatchFinderMt_ReleaseStream(CMatchFinderMt *p) /* p->MatchFinder->ReleaseStream(); */ } -void MatchFinderMt_Normalize(CMatchFinderMt *p) +static void MatchFinderMt_Normalize(CMatchFinderMt *p) { MatchFinder_Normalize3(p->lzPos - p->historySize - 1, p->hash, p->fixedHashSize); p->lzPos = p->historySize + 1; } -void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p) +static void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p) { UInt32 blockIndex; MtSync_GetNextBlock(&p->btSync); @@ -536,34 +548,29 @@ void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p) MatchFinderMt_Normalize(p); } -const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p) +static const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p) { return p->pointerToCurPos; } #define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p); -UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p) +static UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p) { GET_NEXT_BLOCK_IF_REQUIRED; return p->btNumAvailBytes; } -Byte MatchFinderMt_GetIndexByte(CMatchFinderMt *p, Int32 index) +static UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) { - return p->pointerToCurPos[index]; -} - -UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) -{ - UInt32 hash2Value, curMatch2; + UInt32 h2, curMatch2; UInt32 *hash = p->hash; const Byte *cur = p->pointerToCurPos; UInt32 lzPos = p->lzPos; MT_HASH2_CALC - curMatch2 = hash[hash2Value]; - hash[hash2Value] = lzPos; + curMatch2 = hash[h2]; + hash[h2] = lzPos; if (curMatch2 >= matchMinPos) if (cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) @@ -571,23 +578,23 @@ UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) *distances++ = 2; *distances++ = lzPos - curMatch2 - 1; } + return distances; } -UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) +static UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) { - UInt32 hash2Value, hash3Value, curMatch2, curMatch3; + UInt32 h2, h3, curMatch2, curMatch3; UInt32 *hash = p->hash; const Byte *cur = p->pointerToCurPos; UInt32 lzPos = p->lzPos; MT_HASH3_CALC - curMatch2 = hash[ hash2Value]; - curMatch3 = hash[kFix3HashSize + hash3Value]; + curMatch2 = hash[ h2]; + curMatch3 = hash[kFix3HashSize + h3]; - hash[ hash2Value] = - hash[kFix3HashSize + hash3Value] = - lzPos; + hash[ h2] = lzPos; + hash[kFix3HashSize + h3] = lzPos; if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) { @@ -600,43 +607,45 @@ UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) distances[0] = 2; distances += 2; } + if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0]) { *distances++ = 3; *distances++ = lzPos - curMatch3 - 1; } + return distances; } /* -UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) +static UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) { - UInt32 hash2Value, hash3Value, hash4Value, curMatch2, curMatch3, curMatch4; + UInt32 h2, h3, h4, curMatch2, curMatch3, curMatch4; UInt32 *hash = p->hash; const Byte *cur = p->pointerToCurPos; UInt32 lzPos = p->lzPos; MT_HASH4_CALC - curMatch2 = hash[ hash2Value]; - curMatch3 = hash[kFix3HashSize + hash3Value]; - curMatch4 = hash[kFix4HashSize + hash4Value]; + curMatch2 = hash[ h2]; + curMatch3 = hash[kFix3HashSize + h3]; + curMatch4 = hash[kFix4HashSize + h4]; - hash[ hash2Value] = - hash[kFix3HashSize + hash3Value] = - hash[kFix4HashSize + hash4Value] = - lzPos; + hash[ h2] = lzPos; + hash[kFix3HashSize + h3] = lzPos; + hash[kFix4HashSize + h4] = lzPos; if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) { distances[1] = lzPos - curMatch2 - 1; if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2]) { - distances[0] = (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3; + distances[0] = (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3; return distances + 2; } distances[0] = 2; distances += 2; } + if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0]) { distances[1] = lzPos - curMatch3 - 1; @@ -658,13 +667,14 @@ UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) *distances++ = 4; *distances++ = lzPos - curMatch4 - 1; } + return distances; } */ #define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++; -UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances) +static UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances) { const UInt32 *btBuf = p->btBuf + p->btBufPos; UInt32 len = *btBuf++; @@ -682,7 +692,7 @@ UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances) return len; } -UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances) +static UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances) { const UInt32 *btBuf = p->btBuf + p->btBufPos; UInt32 len = *btBuf++; @@ -690,6 +700,7 @@ UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances) if (len == 0) { + /* change for bt5 ! */ if (p->btNumAvailBytes-- >= 4) len = (UInt32)(p->MixMatchesFunc(p, p->lzPos - p->historySize, distances) - (distances)); } @@ -705,7 +716,7 @@ UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances) *distances2++ = *btBuf++; } while ((len -= 2) != 0); - len = (UInt32)(distances2 - (distances)); + len = (UInt32)(distances2 - (distances)); } INCREASE_LZ_POS return len; @@ -715,41 +726,41 @@ UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances) #define SKIP_HEADER_MT(n) SKIP_HEADER2_MT if (p->btNumAvailBytes-- >= (n)) { const Byte *cur = p->pointerToCurPos; UInt32 *hash = p->hash; #define SKIP_FOOTER_MT } INCREASE_LZ_POS p->btBufPos += p->btBuf[p->btBufPos] + 1; } while (--num != 0); -void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num) +static void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num) { SKIP_HEADER2_MT { p->btNumAvailBytes--; SKIP_FOOTER_MT } -void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num) +static void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num) { SKIP_HEADER_MT(2) - UInt32 hash2Value; + UInt32 h2; MT_HASH2_CALC - hash[hash2Value] = p->lzPos; + hash[h2] = p->lzPos; SKIP_FOOTER_MT } -void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num) +static void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num) { SKIP_HEADER_MT(3) - UInt32 hash2Value, hash3Value; + UInt32 h2, h3; MT_HASH3_CALC - hash[kFix3HashSize + hash3Value] = - hash[ hash2Value] = + hash[kFix3HashSize + h3] = + hash[ h2] = p->lzPos; SKIP_FOOTER_MT } /* -void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num) +static void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num) { SKIP_HEADER_MT(4) - UInt32 hash2Value, hash3Value, hash4Value; + UInt32 h2, h3, h4; MT_HASH4_CALC - hash[kFix4HashSize + hash4Value] = - hash[kFix3HashSize + hash3Value] = - hash[ hash2Value] = + hash[kFix4HashSize + h4] = + hash[kFix3HashSize + h3] = + hash[ h2] = p->lzPos; SKIP_FOOTER_MT } @@ -758,11 +769,11 @@ void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num) void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable) { vTable->Init = (Mf_Init_Func)MatchFinderMt_Init; - vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinderMt_GetIndexByte; vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinderMt_GetNumAvailableBytes; vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinderMt_GetPointerToCurrentPos; vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches; - switch(p->MatchFinder->numHashBytes) + + switch (p->MatchFinder->numHashBytes) { case 2: p->GetHeadsFunc = GetHeads2; @@ -778,7 +789,6 @@ void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable) default: /* case 4: */ p->GetHeadsFunc = p->MatchFinder->bigHash ? GetHeads4b : GetHeads4; - /* p->GetHeadsFunc = GetHeads4; */ p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches3; vTable->Skip = (Mf_Skip_Func)MatchFinderMt3_Skip; break; diff --git a/lzma/C/LzFindMt.h b/lzma/C/LzFindMt.h index 17ed237d6..46b6924ad 100644 --- a/lzma/C/LzFindMt.h +++ b/lzma/C/LzFindMt.h @@ -1,5 +1,5 @@ /* LzFindMt.h -- multithreaded Match finder for LZ algorithms -2009-02-07 : Igor Pavlov : Public domain */ +2015-05-03 : Igor Pavlov : Public domain */ #ifndef __LZ_FIND_MT_H #define __LZ_FIND_MT_H @@ -7,9 +7,7 @@ #include "LzFind.h" #include "Threads.h" -#ifdef __cplusplus -extern "C" { -#endif +EXTERN_C_BEGIN #define kMtHashBlockSize (1 << 13) #define kMtHashNumBlocks (1 << 3) @@ -77,7 +75,7 @@ typedef struct _CMatchFinderMt UInt32 matchMaxLen; UInt32 numHashBytes; UInt32 pos; - Byte *buffer; + const Byte *buffer; UInt32 cyclicBufferPos; UInt32 cyclicBufferSize; /* it must be historySize + 1 */ UInt32 cutValue; @@ -98,8 +96,6 @@ SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddB void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable); void MatchFinderMt_ReleaseStream(CMatchFinderMt *p); -#ifdef __cplusplus -} -#endif +EXTERN_C_END #endif diff --git a/lzma/C/LzHash.h b/lzma/C/LzHash.h index b2f0e3c24..219144407 100644 --- a/lzma/C/LzHash.h +++ b/lzma/C/LzHash.h @@ -1,5 +1,5 @@ /* LzHash.h -- HASH functions for LZ algorithms -2009-02-07 : Igor Pavlov : Public domain */ +2015-04-12 : Igor Pavlov : Public domain */ #ifndef __LZ_HASH_H #define __LZ_HASH_H @@ -12,43 +12,46 @@ #define kFix4HashSize (kHash2Size + kHash3Size) #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) -#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8); +#define HASH2_CALC hv = cur[0] | ((UInt32)cur[1] << 8); #define HASH3_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ - hash2Value = temp & (kHash2Size - 1); \ - hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } + h2 = temp & (kHash2Size - 1); \ + hv = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } #define HASH4_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ - hash2Value = temp & (kHash2Size - 1); \ - hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ - hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; } + h2 = temp & (kHash2Size - 1); \ + temp ^= ((UInt32)cur[2] << 8); \ + h3 = temp & (kHash3Size - 1); \ + hv = (temp ^ (p->crc[cur[3]] << 5)) & p->hashMask; } #define HASH5_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ - hash2Value = temp & (kHash2Size - 1); \ - hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ - hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \ - hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \ - hash4Value &= (kHash4Size - 1); } + h2 = temp & (kHash2Size - 1); \ + temp ^= ((UInt32)cur[2] << 8); \ + h3 = temp & (kHash3Size - 1); \ + temp ^= (p->crc[cur[3]] << 5); \ + h4 = temp & (kHash4Size - 1); \ + hv = (temp ^ (p->crc[cur[4]] << 3)) & p->hashMask; } -/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */ -#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; +/* #define HASH_ZIP_CALC hv = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */ +#define HASH_ZIP_CALC hv = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; #define MT_HASH2_CALC \ - hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1); + h2 = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1); #define MT_HASH3_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ - hash2Value = temp & (kHash2Size - 1); \ - hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } + h2 = temp & (kHash2Size - 1); \ + h3 = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } #define MT_HASH4_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ - hash2Value = temp & (kHash2Size - 1); \ - hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ - hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); } + h2 = temp & (kHash2Size - 1); \ + temp ^= ((UInt32)cur[2] << 8); \ + h3 = temp & (kHash3Size - 1); \ + h4 = (temp ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); } #endif diff --git a/lzma/C/Lzma2Dec.c b/lzma/C/Lzma2Dec.c index 7c4eb4449..b6884571c 100644 --- a/lzma/C/Lzma2Dec.c +++ b/lzma/C/Lzma2Dec.c @@ -1,8 +1,10 @@ /* Lzma2Dec.c -- LZMA2 Decoder -2010-12-15 : Igor Pavlov : Public domain */ +2015-11-09 : Igor Pavlov : Public domain */ /* #define SHOW_DEBUG_INFO */ +#include "Precomp.h" + #ifdef SHOW_DEBUG_INFO #include #endif @@ -97,12 +99,12 @@ void Lzma2Dec_Init(CLzma2Dec *p) static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b) { - switch(p->state) + switch (p->state) { case LZMA2_STATE_CONTROL: p->control = b; - PRF(printf("\n %4X ", p->decoder.dicPos)); - PRF(printf(" %2X", b)); + PRF(printf("\n %4X ", (unsigned)p->decoder.dicPos)); + PRF(printf(" %2X", (unsigned)b)); if (p->control == 0) return LZMA2_STATE_FINISHED; if (LZMA2_IS_UNCOMPRESSED_STATE(p)) @@ -122,7 +124,7 @@ static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b) case LZMA2_STATE_UNPACK1: p->unpackSize |= (UInt32)b; p->unpackSize++; - PRF(printf(" %8d", p->unpackSize)); + PRF(printf(" %8u", (unsigned)p->unpackSize)); return (LZMA2_IS_UNCOMPRESSED_STATE(p)) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0; case LZMA2_STATE_PACK0: @@ -132,13 +134,13 @@ static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b) case LZMA2_STATE_PACK1: p->packSize |= (UInt32)b; p->packSize++; - PRF(printf(" %8d", p->packSize)); + PRF(printf(" %8u", (unsigned)p->packSize)); return LZMA2_IS_THERE_PROP(LZMA2_GET_LZMA_MODE(p)) ? LZMA2_STATE_PROP: (p->needInitProp ? LZMA2_STATE_ERROR : LZMA2_STATE_DATA); case LZMA2_STATE_PROP: { - int lc, lp; + unsigned lc, lp; if (b >= (9 * 5 * 5)) return LZMA2_STATE_ERROR; lc = b % 9; @@ -177,13 +179,16 @@ SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, while (p->state != LZMA2_STATE_FINISHED) { SizeT dicPos = p->decoder.dicPos; + if (p->state == LZMA2_STATE_ERROR) return SZ_ERROR_DATA; + if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY) { *status = LZMA_STATUS_NOT_FINISHED; return SZ_OK; } + if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT) { if (*srcLen == inSize) @@ -193,8 +198,15 @@ SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, } (*srcLen)++; p->state = Lzma2Dec_UpdateState(p, *src++); + + if (dicPos == dicLimit && p->state != LZMA2_STATE_FINISHED) + { + p->state = LZMA2_STATE_ERROR; + return SZ_ERROR_DATA; + } continue; } + { SizeT destSizeCur = dicLimit - dicPos; SizeT srcSizeCur = inSize - *srcLen; @@ -220,7 +232,10 @@ SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, if (initDic) p->needInitProp = p->needInitState = True; else if (p->needInitDic) + { + p->state = LZMA2_STATE_ERROR; return SZ_ERROR_DATA; + } p->needInitDic = False; LzmaDec_InitDicAndState(&p->decoder, initDic, False); } @@ -229,7 +244,10 @@ SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, srcSizeCur = destSizeCur; if (srcSizeCur == 0) + { + p->state = LZMA2_STATE_ERROR; return SZ_ERROR_DATA; + } LzmaDec_UpdateWithUncompressed(&p->decoder, src, srcSizeCur); @@ -245,17 +263,21 @@ SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, if (p->state == LZMA2_STATE_DATA) { - int mode = LZMA2_GET_LZMA_MODE(p); + unsigned mode = LZMA2_GET_LZMA_MODE(p); Bool initDic = (mode == 3); - Bool initState = (mode > 0); + Bool initState = (mode != 0); if ((!initDic && p->needInitDic) || (!initState && p->needInitState)) + { + p->state = LZMA2_STATE_ERROR; return SZ_ERROR_DATA; + } LzmaDec_InitDicAndState(&p->decoder, initDic, initState); p->needInitDic = False; p->needInitState = False; p->state = LZMA2_STATE_DATA_CONT; } + if (srcSizeCur > p->packSize) srcSizeCur = (SizeT)p->packSize; @@ -274,16 +296,22 @@ SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, if (srcSizeCur == 0 && outSizeProcessed == 0) { - if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK || - p->unpackSize != 0 || p->packSize != 0) + if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + || p->unpackSize != 0 + || p->packSize != 0) + { + p->state = LZMA2_STATE_ERROR; return SZ_ERROR_DATA; + } p->state = LZMA2_STATE_CONTROL; } + if (*status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) *status = LZMA_STATUS_NOT_FINISHED; } } } + *status = LZMA_STATUS_FINISHED_WITH_MARK; return SZ_OK; } diff --git a/lzma/C/Lzma2Dec.h b/lzma/C/Lzma2Dec.h index 827698dee..026cdefe9 100644 --- a/lzma/C/Lzma2Dec.h +++ b/lzma/C/Lzma2Dec.h @@ -1,14 +1,12 @@ /* Lzma2Dec.h -- LZMA2 Decoder -2009-05-03 : Igor Pavlov : Public domain */ +2015-05-13 : Igor Pavlov : Public domain */ #ifndef __LZMA2_DEC_H #define __LZMA2_DEC_H #include "LzmaDec.h" -#ifdef __cplusplus -extern "C" { -#endif +EXTERN_C_BEGIN /* ---------- State Interface ---------- */ @@ -17,7 +15,7 @@ typedef struct CLzmaDec decoder; UInt32 packSize; UInt32 unpackSize; - int state; + unsigned state; Byte control; Bool needInitDic; Bool needInitState; @@ -77,8 +75,6 @@ Returns: SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc); -#ifdef __cplusplus -} -#endif +EXTERN_C_END #endif diff --git a/lzma/C/LzmaDec.c b/lzma/C/LzmaDec.c index 72451d1ff..651d1f284 100644 --- a/lzma/C/LzmaDec.c +++ b/lzma/C/LzmaDec.c @@ -1,5 +1,7 @@ /* LzmaDec.c -- LZMA Decoder -2010-12-15 : Igor Pavlov : Public domain */ +2015-06-23 : Igor Pavlov : Public domain */ + +#include "Precomp.h" #include "LzmaDec.h" @@ -44,6 +46,13 @@ i -= 0x40; } #endif +#define NORMAL_LITER_DEC GET_BIT(prob + symbol, symbol) +#define MATCHED_LITER_DEC \ + matchByte <<= 1; \ + bit = (matchByte & offs); \ + probLit = prob + offs + bit + symbol; \ + GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) + #define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } #define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) @@ -105,14 +114,14 @@ #define Literal (RepLenCoder + kNumLenProbs) #define LZMA_BASE_SIZE 1846 -#define LZMA_LIT_SIZE 768 - -#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) +#define LZMA_LIT_SIZE 0x300 #if Literal != LZMA_BASE_SIZE StopCompilingDueBUG #endif +#define LzmaProps_GetNumProbs(p) (Literal + ((UInt32)LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) + #define LZMA_DIC_MIN (1 << 12) /* First LZMA-symbol is always decoded. @@ -124,8 +133,8 @@ Out: p->remainLen: < kMatchSpecLenStart : normal remain = kMatchSpecLenStart : finished - = kMatchSpecLenStart + 1 : Flush marker - = kMatchSpecLenStart + 2 : State Init Marker + = kMatchSpecLenStart + 1 : Flush marker (unused now) + = kMatchSpecLenStart + 2 : State Init Marker (unused now) */ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit) @@ -163,38 +172,62 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte unsigned symbol; UPDATE_0(prob); prob = probs + Literal; - if (checkDicSize != 0 || processedPos != 0) - prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + - (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); + if (processedPos != 0 || checkDicSize != 0) + prob += ((UInt32)LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + + (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); + processedPos++; if (state < kNumLitStates) { state -= (state < 4) ? state : 3; symbol = 1; - do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100); + #ifdef _LZMA_SIZE_OPT + do { NORMAL_LITER_DEC } while (symbol < 0x100); + #else + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + #endif } else { - unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + unsigned matchByte = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; unsigned offs = 0x100; state -= (state < 10) ? 3 : 6; symbol = 1; + #ifdef _LZMA_SIZE_OPT do { unsigned bit; CLzmaProb *probLit; - matchByte <<= 1; - bit = (matchByte & offs); - probLit = prob + offs + bit + symbol; - GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) + MATCHED_LITER_DEC } while (symbol < 0x100); + #else + { + unsigned bit; + CLzmaProb *probLit; + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + } + #endif } + dic[dicPos++] = (Byte)symbol; - processedPos++; continue; } - else + { UPDATE_1(prob); prob = probs + IsRep + state; @@ -217,7 +250,7 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte IF_BIT_0(prob) { UPDATE_0(prob); - dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; dicPos++; processedPos++; state = state < kNumLitStates ? 9 : 11; @@ -258,6 +291,8 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte state = state < kNumLitStates ? 8 : 11; prob = probs + RepLenCoder; } + + #ifdef _LZMA_SIZE_OPT { unsigned limit, offset; CLzmaProb *probLen = prob + LenChoice; @@ -290,6 +325,42 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte TREE_DECODE(probLen, limit, len); len += offset; } + #else + { + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenLow + (posState << kLenNumLowBits); + len = 1; + TREE_GET_BIT(probLen, len); + TREE_GET_BIT(probLen, len); + TREE_GET_BIT(probLen, len); + len -= 8; + } + else + { + UPDATE_1(probLen); + probLen = prob + LenChoice2; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenMid + (posState << kLenNumMidBits); + len = 1; + TREE_GET_BIT(probLen, len); + TREE_GET_BIT(probLen, len); + TREE_GET_BIT(probLen, len); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenHigh; + TREE_DECODE(probLen, (1 << kLenNumHighBits), len); + len += kLenNumLowSymbols + kLenNumMidSymbols; + } + } + } + #endif if (state >= kNumStates) { @@ -300,7 +371,7 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte if (distance >= kStartPosModelIndex) { unsigned posSlot = (unsigned)distance; - int numDirectBits = (int)(((distance >> 1) - 1)); + unsigned numDirectBits = (unsigned)(((distance >> 1) - 1)); distance = (2 | (distance & 1)); if (posSlot < kEndPosModelIndex) { @@ -359,6 +430,7 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte } } } + rep3 = rep2; rep2 = rep1; rep1 = rep0; @@ -366,26 +438,39 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte if (checkDicSize == 0) { if (distance >= processedPos) + { + p->dicPos = dicPos; return SZ_ERROR_DATA; + } } else if (distance >= checkDicSize) + { + p->dicPos = dicPos; return SZ_ERROR_DATA; + } state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; } len += kMatchMinLen; - if (limit == dicPos) - return SZ_ERROR_DATA; { - SizeT rem = limit - dicPos; - unsigned curLen = ((rem < len) ? (unsigned)rem : len); - SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0); + SizeT rem; + unsigned curLen; + SizeT pos; + + if ((rem = limit - dicPos) == 0) + { + p->dicPos = dicPos; + return SZ_ERROR_DATA; + } + + curLen = ((rem < len) ? (unsigned)rem : len); + pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0); processedPos += curLen; len -= curLen; - if (pos + curLen <= dicBufSize) + if (curLen <= dicBufSize - pos) { Byte *dest = dic + dicPos; ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; @@ -409,7 +494,9 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte } } while (dicPos < limit && buf < bufLimit); + NORMALIZE; + p->buf = buf; p->range = range; p->code = code; @@ -433,9 +520,10 @@ static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) SizeT dicPos = p->dicPos; SizeT dicBufSize = p->dicBufSize; unsigned len = p->remainLen; - UInt32 rep0 = p->reps[0]; - if (limit - dicPos < len) - len = (unsigned)(limit - dicPos); + SizeT rep0 = p->reps[0]; /* we use SizeT to avoid the BUG of VC14 for AMD64 */ + SizeT rem = limit - dicPos; + if (rem < len) + len = (unsigned)(rem); if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) p->checkDicSize = p->prop.dicSize; @@ -445,7 +533,7 @@ static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) while (len != 0) { len--; - dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; dicPos++; } p->dicPos = dicPos; @@ -463,17 +551,19 @@ static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte if (limit - p->dicPos > rem) limit2 = p->dicPos + rem; } + RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); - if (p->processedPos >= p->prop.dicSize) + + if (p->checkDicSize == 0 && p->processedPos >= p->prop.dicSize) p->checkDicSize = p->prop.dicSize; + LzmaDec_WriteRem(p, limit); } while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); if (p->remainLen > kMatchSpecLenStart) - { p->remainLen = kMatchSpecLenStart; - } + return 0; } @@ -490,12 +580,12 @@ static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inS UInt32 range = p->range; UInt32 code = p->code; const Byte *bufLimit = buf + inSize; - CLzmaProb *probs = p->probs; + const CLzmaProb *probs = p->probs; unsigned state = p->state; ELzmaDummy res; { - CLzmaProb *prob; + const CLzmaProb *prob; UInt32 bound; unsigned ttt; unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); @@ -509,9 +599,9 @@ static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inS prob = probs + Literal; if (p->checkDicSize != 0 || p->processedPos != 0) - prob += (LZMA_LIT_SIZE * - ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + - (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); + prob += ((UInt32)LZMA_LIT_SIZE * + ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + + (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); if (state < kNumLitStates) { @@ -521,13 +611,13 @@ static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inS else { unsigned matchByte = p->dic[p->dicPos - p->reps[0] + - ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)]; + (p->dicPos < p->reps[0] ? p->dicBufSize : 0)]; unsigned offs = 0x100; unsigned symbol = 1; do { unsigned bit; - CLzmaProb *probLit; + const CLzmaProb *probLit; matchByte <<= 1; bit = (matchByte & offs); probLit = prob + offs + bit + symbol; @@ -597,7 +687,7 @@ static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inS } { unsigned limit, offset; - CLzmaProb *probLen = prob + LenChoice; + const CLzmaProb *probLen = prob + LenChoice; IF_BIT_0_CHECK(probLen) { UPDATE_0_CHECK; @@ -637,7 +727,7 @@ static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inS TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); if (posSlot >= kStartPosModelIndex) { - int numDirectBits = ((posSlot >> 1) - 1); + unsigned numDirectBits = ((posSlot >> 1) - 1); /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ @@ -676,13 +766,6 @@ static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inS } -static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data) -{ - p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]); - p->range = 0xFFFFFFFF; - p->needFlush = 0; -} - void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) { p->needFlush = 1; @@ -707,8 +790,8 @@ void LzmaDec_Init(CLzmaDec *p) static void LzmaDec_InitStateReal(CLzmaDec *p) { - UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp)); - UInt32 i; + SizeT numProbs = LzmaProps_GetNumProbs(&p->prop); + SizeT i; CLzmaProb *probs = p->probs; for (i = 0; i < numProbs; i++) probs[i] = kBitModelTotal >> 1; @@ -730,7 +813,7 @@ SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *sr { int checkEndMarkNow; - if (p->needFlush != 0) + if (p->needFlush) { for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) p->tempBuf[p->tempBufSize++] = *src++; @@ -741,8 +824,13 @@ SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *sr } if (p->tempBuf[0] != 0) return SZ_ERROR_DATA; - - LzmaDec_InitRc(p, p->tempBuf); + p->code = + ((UInt32)p->tempBuf[1] << 24) + | ((UInt32)p->tempBuf[2] << 16) + | ((UInt32)p->tempBuf[3] << 8) + | ((UInt32)p->tempBuf[4]); + p->range = 0xFFFFFFFF; + p->needFlush = 0; p->tempBufSize = 0; } @@ -826,7 +914,16 @@ SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *sr p->buf = p->tempBuf; if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) return SZ_ERROR_DATA; - lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf)); + + { + unsigned kkk = (unsigned)(p->buf - p->tempBuf); + if (rem < kkk) + return SZ_ERROR_FAIL; /* some internal error */ + rem -= kkk; + if (lookAhead < rem) + return SZ_ERROR_FAIL; /* some internal error */ + lookAhead -= rem; + } (*srcLen) += lookAhead; src += lookAhead; inSize -= lookAhead; @@ -881,13 +978,13 @@ SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *sr void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) { alloc->Free(alloc, p->probs); - p->probs = 0; + p->probs = NULL; } static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) { alloc->Free(alloc, p->dic); - p->dic = 0; + p->dic = NULL; } void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) @@ -925,12 +1022,12 @@ SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) { UInt32 numProbs = LzmaProps_GetNumProbs(propNew); - if (p->probs == 0 || numProbs != p->numProbs) + if (!p->probs || numProbs != p->numProbs) { LzmaDec_FreeProbs(p, alloc); p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); p->numProbs = numProbs; - if (p->probs == 0) + if (!p->probs) return SZ_ERROR_MEM; } return SZ_OK; @@ -951,12 +1048,22 @@ SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAll SizeT dicBufSize; RINOK(LzmaProps_Decode(&propNew, props, propsSize)); RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); - dicBufSize = propNew.dicSize; - if (p->dic == 0 || dicBufSize != p->dicBufSize) + + { + UInt32 dictSize = propNew.dicSize; + SizeT mask = ((UInt32)1 << 12) - 1; + if (dictSize >= ((UInt32)1 << 30)) mask = ((UInt32)1 << 22) - 1; + else if (dictSize >= ((UInt32)1 << 22)) mask = ((UInt32)1 << 20) - 1;; + dicBufSize = ((SizeT)dictSize + mask) & ~mask; + if (dicBufSize < dictSize) + dicBufSize = dictSize; + } + + if (!p->dic || dicBufSize != p->dicBufSize) { LzmaDec_FreeDict(p, alloc); p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); - if (p->dic == 0) + if (!p->dic) { LzmaDec_FreeProbs(p, alloc); return SZ_ERROR_MEM; diff --git a/lzma/C/LzmaDec.h b/lzma/C/LzmaDec.h index 6741a644b..2633abeac 100644 --- a/lzma/C/LzmaDec.h +++ b/lzma/C/LzmaDec.h @@ -1,14 +1,12 @@ /* LzmaDec.h -- LZMA Decoder -2009-02-07 : Igor Pavlov : Public domain */ +2013-01-18 : Igor Pavlov : Public domain */ #ifndef __LZMA_DEC_H #define __LZMA_DEC_H -#include "Types.h" +#include "7zTypes.h" -#ifdef __cplusplus -extern "C" { -#endif +EXTERN_C_BEGIN /* #define _LZMA_PROB32 */ /* _LZMA_PROB32 can increase the speed on some CPUs, @@ -224,8 +222,6 @@ SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc); -#ifdef __cplusplus -} -#endif +EXTERN_C_END #endif diff --git a/lzma/C/LzmaEnc.c b/lzma/C/LzmaEnc.c index 870399d35..11de42c09 100644 --- a/lzma/C/LzmaEnc.c +++ b/lzma/C/LzmaEnc.c @@ -1,5 +1,7 @@ /* LzmaEnc.c -- LZMA Encoder -2011-01-27 : Igor Pavlov : Public domain */ +2015-11-08 : Igor Pavlov : Public domain */ + +#include "Precomp.h" #include @@ -18,9 +20,12 @@ #endif #ifdef SHOW_STAT -static int ttt = 0; +static unsigned g_STAT_OFFSET = 0; #endif +#define kMaxHistorySize ((UInt32)3 << 29) +/* #define kMaxHistorySize ((UInt32)7 << 29) */ + #define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1) #define kBlockSize (9 << 10) @@ -46,7 +51,7 @@ void LzmaEncProps_Init(CLzmaEncProps *p) { p->level = 5; p->dictSize = p->mc = 0; - p->reduceSize = (UInt32)(Int32)-1; + p->reduceSize = (UInt64)(Int64)-1; p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1; p->writeEndMark = 0; } @@ -56,24 +61,28 @@ void LzmaEncProps_Normalize(CLzmaEncProps *p) int level = p->level; if (level < 0) level = 5; p->level = level; + if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26))); if (p->dictSize > p->reduceSize) { unsigned i; - for (i = 15; i <= 30; i++) + for (i = 11; i <= 30; i++) { - if (p->reduceSize <= ((UInt32)2 << i)) { p->dictSize = ((UInt32)2 << i); break; } - if (p->reduceSize <= ((UInt32)3 << i)) { p->dictSize = ((UInt32)3 << i); break; } + if ((UInt32)p->reduceSize <= ((UInt32)2 << i)) { p->dictSize = ((UInt32)2 << i); break; } + if ((UInt32)p->reduceSize <= ((UInt32)3 << i)) { p->dictSize = ((UInt32)3 << i); break; } } } + if (p->lc < 0) p->lc = 3; if (p->lp < 0) p->lp = 0; if (p->pb < 0) p->pb = 2; + if (p->algo < 0) p->algo = (level < 5 ? 0 : 1); if (p->fb < 0) p->fb = (level < 7 ? 32 : 64); if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1); if (p->numHashBytes < 0) p->numHashBytes = 4; - if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1); + if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1); + if (p->numThreads < 0) p->numThreads = #ifndef _7ZIP_ST @@ -90,17 +99,18 @@ UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) return props.dictSize; } +#if (_MSC_VER >= 1400) +/* BSR code is fast for some new CPUs */ /* #define LZMA_LOG_BSR */ -/* Define it for Intel's CPU */ - +#endif #ifdef LZMA_LOG_BSR -#define kDicLogSizeMaxCompress 30 +#define kDicLogSizeMaxCompress 32 #define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); } -UInt32 GetPosSlot1(UInt32 pos) +static UInt32 GetPosSlot1(UInt32 pos) { UInt32 res; BSR2_RET(pos, res); @@ -111,27 +121,44 @@ UInt32 GetPosSlot1(UInt32 pos) #else -#define kNumLogBits (9 + (int)sizeof(size_t) / 2) +#define kNumLogBits (9 + sizeof(size_t) / 2) +/* #define kNumLogBits (11 + sizeof(size_t) / 8 * 3) */ + #define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) -void LzmaEnc_FastPosInit(Byte *g_FastPos) +static void LzmaEnc_FastPosInit(Byte *g_FastPos) { - int c = 2, slotFast; + unsigned slot; g_FastPos[0] = 0; g_FastPos[1] = 1; + g_FastPos += 2; - for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++) + for (slot = 2; slot < kNumLogBits * 2; slot++) { - UInt32 k = (1 << ((slotFast >> 1) - 1)); - UInt32 j; - for (j = 0; j < k; j++, c++) - g_FastPos[c] = (Byte)slotFast; + size_t k = ((size_t)1 << ((slot >> 1) - 1)); + size_t j; + for (j = 0; j < k; j++) + g_FastPos[j] = (Byte)slot; + g_FastPos += k; } } +/* we can use ((limit - pos) >> 31) only if (pos < ((UInt32)1 << 31)) */ +/* #define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \ (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \ res = p->g_FastPos[pos >> i] + (i * 2); } +*/ + +/* +#define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \ + (0 - (((((UInt32)1 << (kNumLogBits)) - 1) - (pos >> 6)) >> 31))); \ + res = p->g_FastPos[pos >> i] + (i * 2); } +*/ + +#define BSR2_RET(pos, res) { UInt32 i = (pos < (1 << (kNumLogBits + 6))) ? 6 : 6 + kNumLogBits - 1; \ + res = p->g_FastPos[pos >> i] + (i * 2); } + /* #define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \ p->g_FastPos[pos >> 6] + 12 : \ @@ -211,6 +238,7 @@ typedef struct #define kNumStates 12 + typedef struct { CLzmaProb choice; @@ -220,14 +248,16 @@ typedef struct CLzmaProb high[kLenNumHighSymbols]; } CLenEnc; + typedef struct { CLenEnc p; - UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal]; UInt32 tableSize; + UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal]; UInt32 counters[LZMA_NUM_PB_STATES_MAX]; } CLenPriceEnc; + typedef struct { UInt32 range; @@ -242,10 +272,14 @@ typedef struct SRes res; } CRangeEnc; + typedef struct { CLzmaProb *litProbs; + UInt32 state; + UInt32 reps[LZMA_NUM_REPS]; + CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; CLzmaProb isRep[kNumStates]; CLzmaProb isRepG0[kNumStates]; @@ -259,15 +293,49 @@ typedef struct CLenPriceEnc lenEnc; CLenPriceEnc repLenEnc; - - UInt32 reps[LZMA_NUM_REPS]; - UInt32 state; } CSaveState; + typedef struct { - IMatchFinder matchFinder; void *matchFinderObj; + IMatchFinder matchFinder; + + UInt32 optimumEndIndex; + UInt32 optimumCurrentIndex; + + UInt32 longestMatchLength; + UInt32 numPairs; + UInt32 numAvail; + + UInt32 numFastBytes; + UInt32 additionalOffset; + UInt32 reps[LZMA_NUM_REPS]; + UInt32 state; + + unsigned lc, lp, pb; + unsigned lpMask, pbMask; + unsigned lclp; + + CLzmaProb *litProbs; + + Bool fastMode; + Bool writeEndMark; + Bool finished; + Bool multiThread; + Bool needInit; + + UInt64 nowPos64; + + UInt32 matchPriceCount; + UInt32 alignPriceCount; + + UInt32 distTableSize; + + UInt32 dictSize; + SRes result; + + CRangeEnc rc; #ifndef _7ZIP_ST Bool mtMode; @@ -280,12 +348,6 @@ typedef struct Byte pad[128]; #endif - UInt32 optimumEndIndex; - UInt32 optimumCurrentIndex; - - UInt32 longestMatchLength; - UInt32 numPairs; - UInt32 numAvail; COptimal opt[kNumOpts]; #ifndef LZMA_LOG_BSR @@ -294,22 +356,10 @@ typedef struct UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits]; UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1]; - UInt32 numFastBytes; - UInt32 additionalOffset; - UInt32 reps[LZMA_NUM_REPS]; - UInt32 state; UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax]; UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances]; UInt32 alignPrices[kAlignTableSize]; - UInt32 alignPriceCount; - - UInt32 distTableSize; - - unsigned lc, lp, pb; - unsigned lpMask, pbMask; - - CLzmaProb *litProbs; CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; CLzmaProb isRep[kNumStates]; @@ -325,26 +375,14 @@ typedef struct CLenPriceEnc lenEnc; CLenPriceEnc repLenEnc; - unsigned lclp; - - Bool fastMode; - - CRangeEnc rc; - - Bool writeEndMark; - UInt64 nowPos64; - UInt32 matchPriceCount; - Bool finished; - Bool multiThread; - - SRes result; - UInt32 dictSize; - - int needInit; - CSaveState saveState; + + #ifndef _7ZIP_ST + Byte pad2[128]; + #endif } CLzmaEnc; + void LzmaEnc_SaveState(CLzmaEncHandle pp) { CLzmaEnc *p = (CLzmaEnc *)pp; @@ -368,7 +406,7 @@ void LzmaEnc_SaveState(CLzmaEncHandle pp) memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); memcpy(dest->reps, p->reps, sizeof(p->reps)); - memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb)); + memcpy(dest->litProbs, p->litProbs, ((UInt32)0x300 << p->lclp) * sizeof(CLzmaProb)); } void LzmaEnc_RestoreState(CLzmaEncHandle pp) @@ -394,7 +432,7 @@ void LzmaEnc_RestoreState(CLzmaEncHandle pp) memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); memcpy(dest->reps, p->reps, sizeof(p->reps)); - memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb)); + memcpy(dest->litProbs, p->litProbs, ((UInt32)0x300 << dest->lclp) * sizeof(CLzmaProb)); } SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) @@ -403,9 +441,13 @@ SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) CLzmaEncProps props = *props2; LzmaEncProps_Normalize(&props); - if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX || - props.dictSize > ((UInt32)1 << kDicLogSizeMaxCompress) || props.dictSize > ((UInt32)1 << 30)) + if (props.lc > LZMA_LC_MAX + || props.lp > LZMA_LP_MAX + || props.pb > LZMA_PB_MAX + || props.dictSize > ((UInt64)1 << kDicLogSizeMaxCompress) + || props.dictSize > kMaxHistorySize) return SZ_ERROR_PARAM; + p->dictSize = props.dictSize; { unsigned fb = props.fb; @@ -419,7 +461,7 @@ SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) p->lp = props.lp; p->pb = props.pb; p->fastMode = (props.algo == 0); - p->matchFinderBase.btMode = props.btMode; + p->matchFinderBase.btMode = (Byte)(props.btMode ? 1 : 0); { UInt32 numHashBytes = 4; if (props.btMode) @@ -463,8 +505,8 @@ static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, static void RangeEnc_Construct(CRangeEnc *p) { - p->outStream = 0; - p->bufBase = 0; + p->outStream = NULL; + p->bufBase = NULL; } #define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize) @@ -472,10 +514,10 @@ static void RangeEnc_Construct(CRangeEnc *p) #define RC_BUF_SIZE (1 << 16) static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc) { - if (p->bufBase == 0) + if (!p->bufBase) { p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE); - if (p->bufBase == 0) + if (!p->bufBase) return 0; p->bufLim = p->bufBase + RC_BUF_SIZE; } @@ -516,7 +558,7 @@ static void RangeEnc_FlushStream(CRangeEnc *p) static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p) { - if ((UInt32)p->low < (UInt32)0xFF000000 || (int)(p->low >> 32) != 0) + if ((UInt32)p->low < (UInt32)0xFF000000 || (unsigned)(p->low >> 32) != 0) { Byte temp = p->cache; do @@ -542,7 +584,7 @@ static void RangeEnc_FlushData(CRangeEnc *p) RangeEnc_ShiftLow(p); } -static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, int numBits) +static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, unsigned numBits) { do { @@ -605,7 +647,7 @@ static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, while (symbol < 0x10000); } -void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) +static void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) { UInt32 i; for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits)) @@ -641,7 +683,7 @@ void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) #define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits] #define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] -static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices) +static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, const UInt32 *ProbPrices) { UInt32 price = 0; symbol |= 0x100; @@ -654,7 +696,7 @@ static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *Pro return price; } -static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices) +static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, const UInt32 *ProbPrices) { UInt32 price = 0; UInt32 offs = 0x100; @@ -698,7 +740,7 @@ static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLeve } } -static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) +static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, const UInt32 *ProbPrices) { UInt32 price = 0; symbol |= (1 << numBitLevels); @@ -710,7 +752,7 @@ static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 s return price; } -static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) +static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, const UInt32 *ProbPrices) { UInt32 price = 0; UInt32 m = 1; @@ -761,7 +803,7 @@ static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posSt } } -static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices) +static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, const UInt32 *ProbPrices) { UInt32 a0 = GET_PRICE_0a(p->choice); UInt32 a1 = GET_PRICE_1a(p->choice); @@ -784,20 +826,20 @@ static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UIn prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices); } -static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices) +static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, const UInt32 *ProbPrices) { LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices); p->counters[posState] = p->tableSize; } -static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices) +static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, const UInt32 *ProbPrices) { UInt32 posState; for (posState = 0; posState < numPosStates; posState++) LenPriceEnc_UpdateTable(p, posState, ProbPrices); } -static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices) +static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, const UInt32 *ProbPrices) { LenEnc_Encode(&p->p, rc, symbol, posState); if (updatePrice) @@ -811,9 +853,10 @@ static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 static void MovePos(CLzmaEnc *p, UInt32 num) { #ifdef SHOW_STAT - ttt += num; - printf("\n MovePos %d", num); + g_STAT_OFFSET += num; + printf("\n MovePos %u", num); #endif + if (num != 0) { p->additionalOffset += num; @@ -826,28 +869,32 @@ static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes) UInt32 lenRes = 0, numPairs; p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches); + #ifdef SHOW_STAT - printf("\n i = %d numPairs = %d ", ttt, numPairs / 2); - ttt++; + printf("\n i = %u numPairs = %u ", g_STAT_OFFSET, numPairs / 2); + g_STAT_OFFSET++; { UInt32 i; for (i = 0; i < numPairs; i += 2) - printf("%2d %6d | ", p->matches[i], p->matches[i + 1]); + printf("%2u %6u | ", p->matches[i], p->matches[i + 1]); } #endif + if (numPairs > 0) { lenRes = p->matches[numPairs - 2]; if (lenRes == p->numFastBytes) { - const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; - UInt32 distance = p->matches[numPairs - 1] + 1; UInt32 numAvail = p->numAvail; if (numAvail > LZMA_MATCH_LEN_MAX) numAvail = LZMA_MATCH_LEN_MAX; { - const Byte *pby2 = pby - distance; - for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++); + const Byte *pbyCur = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + const Byte *pby = pbyCur + lenRes; + ptrdiff_t dif = (ptrdiff_t)-1 - p->matches[numPairs - 1]; + const Byte *pbyLim = pbyCur + numAvail; + for (; pby != pbyLim && *pby == pby[dif]; pby++); + lenRes = (UInt32)(pby - pbyCur); } } } @@ -932,7 +979,7 @@ static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur) return p->optimumCurrentIndex; } -#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300) +#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * (UInt32)0x300) static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) { @@ -976,7 +1023,7 @@ static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) UInt32 lenTest; const Byte *data2; reps[i] = p->reps[i]; - data2 = data - (reps[i] + 1); + data2 = data - reps[i] - 1; if (data[0] != data2[0] || data[1] != data2[1]) { repLens[i] = 0; @@ -1120,12 +1167,12 @@ static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) cur = 0; #ifdef SHOW_STAT2 - if (position >= 0) + /* if (position >= 0) */ { unsigned i; printf("\n pos = %4X", position); for (i = cur; i <= lenEnd; i++) - printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price); + printf("\nprice[%4X] = %u", position - cur + i, p->opt[i].price); } #endif @@ -1277,7 +1324,7 @@ static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) /* try Literal + rep0 */ UInt32 temp; UInt32 lenTest2; - const Byte *data2 = data - (reps[0] + 1); + const Byte *data2 = data - reps[0] - 1; UInt32 limit = p->numFastBytes + 1; if (limit > numAvailFull) limit = numAvailFull; @@ -1320,7 +1367,7 @@ static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) UInt32 lenTest; UInt32 lenTestTemp; UInt32 price; - const Byte *data2 = data - (reps[repIndex] + 1); + const Byte *data2 = data - reps[repIndex] - 1; if (data[0] != data2[0] || data[1] != data2[1]) continue; for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); @@ -1350,13 +1397,13 @@ static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) { UInt32 lenTest2 = lenTest + 1; UInt32 limit = lenTest2 + p->numFastBytes; - UInt32 nextRepMatchPrice; if (limit > numAvailFull) limit = numAvailFull; for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); lenTest2 -= lenTest + 1; if (lenTest2 >= 2) { + UInt32 nextRepMatchPrice; UInt32 state2 = kRepNextStates[state]; UInt32 posStateNext = (position + lenTest) & p->pbMask; UInt32 curAndLenCharPrice = @@ -1437,16 +1484,16 @@ static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) if (/*_maxMode && */lenTest == matches[offs]) { /* Try Match + Literal + Rep0 */ - const Byte *data2 = data - (curBack + 1); + const Byte *data2 = data - curBack - 1; UInt32 lenTest2 = lenTest + 1; UInt32 limit = lenTest2 + p->numFastBytes; - UInt32 nextRepMatchPrice; if (limit > numAvailFull) limit = numAvailFull; for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); lenTest2 -= lenTest + 1; if (lenTest2 >= 2) { + UInt32 nextRepMatchPrice; UInt32 state2 = kMatchNextStates[state]; UInt32 posStateNext = (position + lenTest) & p->pbMask; UInt32 curAndLenCharPrice = curAndLenPrice + @@ -1520,7 +1567,7 @@ static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes) for (i = 0; i < LZMA_NUM_REPS; i++) { UInt32 len; - const Byte *data2 = data - (p->reps[i] + 1); + const Byte *data2 = data - p->reps[i] - 1; if (data[0] != data2[0] || data[1] != data2[1]) continue; for (len = 2; len < numAvail && data[len] == data2[len]; len++); @@ -1589,7 +1636,7 @@ static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes) for (i = 0; i < LZMA_NUM_REPS; i++) { UInt32 len, limit; - const Byte *data2 = data - (p->reps[i] + 1); + const Byte *data2 = data - p->reps[i] - 1; if (data[0] != data2[0] || data[1] != data2[1]) continue; limit = mainLen - 1; @@ -1685,6 +1732,7 @@ void LzmaEnc_Construct(CLzmaEnc *p) { RangeEnc_Construct(&p->rc); MatchFinder_Construct(&p->matchFinderBase); + #ifndef _7ZIP_ST MatchFinderMt_Construct(&p->matchFinderMt); p->matchFinderMt.MatchFinder = &p->matchFinderBase; @@ -1701,15 +1749,15 @@ void LzmaEnc_Construct(CLzmaEnc *p) #endif LzmaEnc_InitPriceTables(p->ProbPrices); - p->litProbs = 0; - p->saveState.litProbs = 0; + p->litProbs = NULL; + p->saveState.litProbs = NULL; } CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc) { void *p; p = alloc->Alloc(alloc, sizeof(CLzmaEnc)); - if (p != 0) + if (p) LzmaEnc_Construct((CLzmaEnc *)p); return p; } @@ -1718,8 +1766,8 @@ void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc) { alloc->Free(alloc, p->litProbs); alloc->Free(alloc, p->saveState.litProbs); - p->litProbs = 0; - p->saveState.litProbs = 0; + p->litProbs = NULL; + p->saveState.litProbs = NULL; } void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) @@ -1727,6 +1775,7 @@ void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) #ifndef _7ZIP_ST MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); #endif + MatchFinder_Free(&p->matchFinderBase, allocBig); LzmaEnc_FreeLits(p, alloc); RangeEnc_Free(&p->rc, alloc); @@ -1763,7 +1812,7 @@ static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize ReadMatchDistances(p, &numPairs); RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0); p->state = kLiteralNextStates[p->state]; - curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset); + curByte = *(p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset); LitEnc_Encode(&p->rc, p->litProbs, curByte); p->additionalOffset--; nowPos32++; @@ -1780,7 +1829,7 @@ static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize len = GetOptimum(p, nowPos32, &pos); #ifdef SHOW_STAT2 - printf("\n pos = %4X, len = %d pos = %d", nowPos32, len, pos); + printf("\n pos = %4X, len = %u pos = %u", nowPos32, len, pos); #endif posState = nowPos32 & p->pbMask; @@ -1889,7 +1938,7 @@ static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize) break; } - else if (processed >= (1 << 15)) + else if (processed >= (1 << 17)) { p->nowPos64 += nowPos32 - startPos32; return CheckErrors(p); @@ -1905,22 +1954,21 @@ static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) { UInt32 beforeSize = kNumOpts; - Bool btMode; if (!RangeEnc_Alloc(&p->rc, alloc)) return SZ_ERROR_MEM; - btMode = (p->matchFinderBase.btMode != 0); + #ifndef _7ZIP_ST - p->mtMode = (p->multiThread && !p->fastMode && btMode); + p->mtMode = (p->multiThread && !p->fastMode && (p->matchFinderBase.btMode != 0)); #endif { unsigned lclp = p->lc + p->lp; - if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp) + if (!p->litProbs || !p->saveState.litProbs || p->lclp != lclp) { LzmaEnc_FreeLits(p, alloc); - p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); - p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); - if (p->litProbs == 0 || p->saveState.litProbs == 0) + p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, ((UInt32)0x300 << lclp) * sizeof(CLzmaProb)); + p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, ((UInt32)0x300 << lclp) * sizeof(CLzmaProb)); + if (!p->litProbs || !p->saveState.litProbs) { LzmaEnc_FreeLits(p, alloc); return SZ_ERROR_MEM; @@ -1929,7 +1977,7 @@ static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, I } } - p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit); + p->matchFinderBase.bigHash = (Byte)(p->dictSize > kBigHashDicLimit ? 1 : 0); if (beforeSize + p->dictSize < keepWindowSize) beforeSize = keepWindowSize - p->dictSize; @@ -1949,6 +1997,7 @@ static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, I p->matchFinderObj = &p->matchFinderBase; MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder); } + return SZ_OK; } @@ -1977,9 +2026,10 @@ void LzmaEnc_Init(CLzmaEnc *p) } { - UInt32 num = 0x300 << (p->lp + p->lc); + UInt32 num = (UInt32)0x300 << (p->lp + p->lc); + CLzmaProb *probs = p->litProbs; for (i = 0; i < num; i++) - p->litProbs[i] = kProbInitValue; + probs[i] = kProbInitValue; } { @@ -2086,10 +2136,11 @@ void LzmaEnc_Finish(CLzmaEncHandle pp) if (p->mtMode) MatchFinderMt_ReleaseStream(&p->matchFinderMt); #else - (void)pp; + UNUSED_VAR(pp); #endif } + typedef struct { ISeqOutStream funcTable; @@ -2119,12 +2170,14 @@ UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp) return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); } + const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp) { const CLzmaEnc *p = (CLzmaEnc *)pp; return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; } + SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) { @@ -2159,23 +2212,23 @@ SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, return res; } + static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) { SRes res = SZ_OK; #ifndef _7ZIP_ST Byte allocaDummy[0x300]; - int i = 0; - for (i = 0; i < 16; i++) - allocaDummy[i] = (Byte)i; + allocaDummy[0] = 0; + allocaDummy[1] = allocaDummy[0]; #endif for (;;) { res = LzmaEnc_CodeOneBlock(p, False, 0, 0); - if (res != SZ_OK || p->finished != 0) + if (res != SZ_OK || p->finished) break; - if (progress != 0) + if (progress) { res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc)); if (res != SZ_OK) @@ -2185,10 +2238,19 @@ static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) } } } + LzmaEnc_Finish(p); + + /* + if (res == S_OK && !Inline_MatchFinder_IsFinishedOK(&p->matchFinderBase)) + res = SZ_ERROR_FAIL; + } + */ + return res; } + SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) { @@ -2196,28 +2258,27 @@ SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *i return LzmaEnc_Encode2((CLzmaEnc *)pp, progress); } + SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) { CLzmaEnc *p = (CLzmaEnc *)pp; - int i; + unsigned i; UInt32 dictSize = p->dictSize; if (*size < LZMA_PROPS_SIZE) return SZ_ERROR_PARAM; *size = LZMA_PROPS_SIZE; props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc); - for (i = 11; i <= 30; i++) + if (dictSize >= ((UInt32)1 << 22)) { - if (dictSize <= ((UInt32)2 << i)) - { - dictSize = (2 << i); - break; - } - if (dictSize <= ((UInt32)3 << i)) - { - dictSize = (3 << i); - break; - } + UInt32 kDictMask = ((UInt32)1 << 20) - 1; + if (dictSize < (UInt32)0xFFFFFFFF - kDictMask) + dictSize = (dictSize + kDictMask) & ~kDictMask; + } + else for (i = 11; i <= 30; i++) + { + if (dictSize <= ((UInt32)2 << i)) { dictSize = (2 << i); break; } + if (dictSize <= ((UInt32)3 << i)) { dictSize = (3 << i); break; } } for (i = 0; i < 4; i++) @@ -2225,6 +2286,7 @@ SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) return SZ_OK; } + SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) { @@ -2233,19 +2295,22 @@ SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte CSeqOutStreamBuf outStream; - LzmaEnc_SetInputBuf(p, src, srcLen); - outStream.funcTable.Write = MyWrite; outStream.data = dest; outStream.rem = *destLen; outStream.overflow = False; p->writeEndMark = writeEndMark; - p->rc.outStream = &outStream.funcTable; + res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig); + if (res == SZ_OK) + { res = LzmaEnc_Encode2(p, progress); + if (res == SZ_OK && p->nowPos64 != srcLen) + res = SZ_ERROR_FAIL; + } *destLen -= outStream.rem; if (outStream.overflow) @@ -2253,13 +2318,14 @@ SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte return res; } + SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) { CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc); SRes res; - if (p == 0) + if (!p) return SZ_ERROR_MEM; res = LzmaEnc_SetProps(p, props); diff --git a/lzma/C/LzmaEnc.h b/lzma/C/LzmaEnc.h index 7573ba01b..c2806b45f 100644 --- a/lzma/C/LzmaEnc.h +++ b/lzma/C/LzmaEnc.h @@ -1,10 +1,10 @@ /* LzmaEnc.h -- LZMA Encoder -2011-01-27 : Igor Pavlov : Public domain */ +2013-01-18 : Igor Pavlov : Public domain */ #ifndef __LZMA_ENC_H #define __LZMA_ENC_H -#include "Types.h" +#include "7zTypes.h" EXTERN_C_BEGIN @@ -16,7 +16,7 @@ typedef struct _CLzmaEncProps UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version (1 << 12) <= dictSize <= (1 << 30) for 64-bit version default = (1 << 24) */ - UInt32 reduceSize; /* estimated size of data that will be compressed. default = 0xFFFFFFFF. + UInt64 reduceSize; /* estimated size of data that will be compressed. default = 0xFFFFFFFF. Encoder uses this value to reduce dictionary size */ int lc; /* 0 <= lc <= 8, default = 3 */ int lp; /* 0 <= lp <= 4, default = 0 */ diff --git a/lzma/C/Ppmd.h b/lzma/C/Ppmd.h new file mode 100644 index 000000000..4356dd1d8 --- /dev/null +++ b/lzma/C/Ppmd.h @@ -0,0 +1,85 @@ +/* Ppmd.h -- PPMD codec common code +2013-01-18 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +#ifndef __PPMD_H +#define __PPMD_H + +#include "CpuArch.h" + +EXTERN_C_BEGIN + +#ifdef MY_CPU_32BIT + #define PPMD_32BIT +#endif + +#define PPMD_INT_BITS 7 +#define PPMD_PERIOD_BITS 7 +#define PPMD_BIN_SCALE (1 << (PPMD_INT_BITS + PPMD_PERIOD_BITS)) + +#define PPMD_GET_MEAN_SPEC(summ, shift, round) (((summ) + (1 << ((shift) - (round)))) >> (shift)) +#define PPMD_GET_MEAN(summ) PPMD_GET_MEAN_SPEC((summ), PPMD_PERIOD_BITS, 2) +#define PPMD_UPDATE_PROB_0(prob) ((prob) + (1 << PPMD_INT_BITS) - PPMD_GET_MEAN(prob)) +#define PPMD_UPDATE_PROB_1(prob) ((prob) - PPMD_GET_MEAN(prob)) + +#define PPMD_N1 4 +#define PPMD_N2 4 +#define PPMD_N3 4 +#define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4) +#define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4) + +#pragma pack(push, 1) +/* Most compilers works OK here even without #pragma pack(push, 1), but some GCC compilers need it. */ + +/* SEE-contexts for PPM-contexts with masked symbols */ +typedef struct +{ + UInt16 Summ; /* Freq */ + Byte Shift; /* Speed of Freq change; low Shift is for fast change */ + Byte Count; /* Count to next change of Shift */ +} CPpmd_See; + +#define Ppmd_See_Update(p) if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \ + { (p)->Summ <<= 1; (p)->Count = (Byte)(3 << (p)->Shift++); } + +typedef struct +{ + Byte Symbol; + Byte Freq; + UInt16 SuccessorLow; + UInt16 SuccessorHigh; +} CPpmd_State; + +#pragma pack(pop) + +typedef + #ifdef PPMD_32BIT + CPpmd_State * + #else + UInt32 + #endif + CPpmd_State_Ref; + +typedef + #ifdef PPMD_32BIT + void * + #else + UInt32 + #endif + CPpmd_Void_Ref; + +typedef + #ifdef PPMD_32BIT + Byte * + #else + UInt32 + #endif + CPpmd_Byte_Ref; + +#define PPMD_SetAllBitsIn256Bytes(p) \ + { unsigned i; for (i = 0; i < 256 / sizeof(p[0]); i += 8) { \ + p[i+7] = p[i+6] = p[i+5] = p[i+4] = p[i+3] = p[i+2] = p[i+1] = p[i+0] = ~(size_t)0; }} + +EXTERN_C_END + +#endif diff --git a/lzma/C/Ppmd7.c b/lzma/C/Ppmd7.c new file mode 100644 index 000000000..7ef84d47b --- /dev/null +++ b/lzma/C/Ppmd7.c @@ -0,0 +1,710 @@ +/* Ppmd7.c -- PPMdH codec +2015-09-28 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +#include "Precomp.h" + +#include + +#include "Ppmd7.h" + +const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; +static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; + +#define MAX_FREQ 124 +#define UNIT_SIZE 12 + +#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE) +#define U2I(nu) (p->Units2Indx[(nu) - 1]) +#define I2U(indx) (p->Indx2Units[indx]) + +#ifdef PPMD_32BIT + #define REF(ptr) (ptr) +#else + #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base)) +#endif + +#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr)) + +#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref)) +#define STATS(ctx) Ppmd7_GetStats(p, ctx) +#define ONE_STATE(ctx) Ppmd7Context_OneState(ctx) +#define SUFFIX(ctx) CTX((ctx)->Suffix) + +typedef CPpmd7_Context * CTX_PTR; + +struct CPpmd7_Node_; + +typedef + #ifdef PPMD_32BIT + struct CPpmd7_Node_ * + #else + UInt32 + #endif + CPpmd7_Node_Ref; + +typedef struct CPpmd7_Node_ +{ + UInt16 Stamp; /* must be at offset 0 as CPpmd7_Context::NumStats. Stamp=0 means free */ + UInt16 NU; + CPpmd7_Node_Ref Next; /* must be at offset >= 4 */ + CPpmd7_Node_Ref Prev; +} CPpmd7_Node; + +#ifdef PPMD_32BIT + #define NODE(ptr) (ptr) +#else + #define NODE(offs) ((CPpmd7_Node *)(p->Base + (offs))) +#endif + +void Ppmd7_Construct(CPpmd7 *p) +{ + unsigned i, k, m; + + p->Base = 0; + + for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) + { + unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); + do { p->Units2Indx[k++] = (Byte)i; } while (--step); + p->Indx2Units[i] = (Byte)k; + } + + p->NS2BSIndx[0] = (0 << 1); + p->NS2BSIndx[1] = (1 << 1); + memset(p->NS2BSIndx + 2, (2 << 1), 9); + memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); + + for (i = 0; i < 3; i++) + p->NS2Indx[i] = (Byte)i; + for (m = i, k = 1; i < 256; i++) + { + p->NS2Indx[i] = (Byte)m; + if (--k == 0) + k = (++m) - 2; + } + + memset(p->HB2Flag, 0, 0x40); + memset(p->HB2Flag + 0x40, 8, 0x100 - 0x40); +} + +void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->Base); + p->Size = 0; + p->Base = 0; +} + +Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc) +{ + if (p->Base == 0 || p->Size != size) + { + Ppmd7_Free(p, alloc); + p->AlignOffset = + #ifdef PPMD_32BIT + (4 - size) & 3; + #else + 4 - (size & 3); + #endif + if ((p->Base = (Byte *)alloc->Alloc(alloc, p->AlignOffset + size + #ifndef PPMD_32BIT + + UNIT_SIZE + #endif + )) == 0) + return False; + p->Size = size; + } + return True; +} + +static void InsertNode(CPpmd7 *p, void *node, unsigned indx) +{ + *((CPpmd_Void_Ref *)node) = p->FreeList[indx]; + p->FreeList[indx] = REF(node); +} + +static void *RemoveNode(CPpmd7 *p, unsigned indx) +{ + CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]); + p->FreeList[indx] = *node; + return node; +} + +static void SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx) +{ + unsigned i, nu = I2U(oldIndx) - I2U(newIndx); + ptr = (Byte *)ptr + U2B(I2U(newIndx)); + if (I2U(i = U2I(nu)) != nu) + { + unsigned k = I2U(--i); + InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); + } + InsertNode(p, ptr, i); +} + +static void GlueFreeBlocks(CPpmd7 *p) +{ + #ifdef PPMD_32BIT + CPpmd7_Node headItem; + CPpmd7_Node_Ref head = &headItem; + #else + CPpmd7_Node_Ref head = p->AlignOffset + p->Size; + #endif + + CPpmd7_Node_Ref n = head; + unsigned i; + + p->GlueCount = 255; + + /* create doubly-linked list of free blocks */ + for (i = 0; i < PPMD_NUM_INDEXES; i++) + { + UInt16 nu = I2U(i); + CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i]; + p->FreeList[i] = 0; + while (next != 0) + { + CPpmd7_Node *node = NODE(next); + node->Next = n; + n = NODE(n)->Prev = next; + next = *(const CPpmd7_Node_Ref *)node; + node->Stamp = 0; + node->NU = (UInt16)nu; + } + } + NODE(head)->Stamp = 1; + NODE(head)->Next = n; + NODE(n)->Prev = head; + if (p->LoUnit != p->HiUnit) + ((CPpmd7_Node *)p->LoUnit)->Stamp = 1; + + /* Glue free blocks */ + while (n != head) + { + CPpmd7_Node *node = NODE(n); + UInt32 nu = (UInt32)node->NU; + for (;;) + { + CPpmd7_Node *node2 = NODE(n) + nu; + nu += node2->NU; + if (node2->Stamp != 0 || nu >= 0x10000) + break; + NODE(node2->Prev)->Next = node2->Next; + NODE(node2->Next)->Prev = node2->Prev; + node->NU = (UInt16)nu; + } + n = node->Next; + } + + /* Fill lists of free blocks */ + for (n = NODE(head)->Next; n != head;) + { + CPpmd7_Node *node = NODE(n); + unsigned nu; + CPpmd7_Node_Ref next = node->Next; + for (nu = node->NU; nu > 128; nu -= 128, node += 128) + InsertNode(p, node, PPMD_NUM_INDEXES - 1); + if (I2U(i = U2I(nu)) != nu) + { + unsigned k = I2U(--i); + InsertNode(p, node + k, nu - k - 1); + } + InsertNode(p, node, i); + n = next; + } +} + +static void *AllocUnitsRare(CPpmd7 *p, unsigned indx) +{ + unsigned i; + void *retVal; + if (p->GlueCount == 0) + { + GlueFreeBlocks(p); + if (p->FreeList[indx] != 0) + return RemoveNode(p, indx); + } + i = indx; + do + { + if (++i == PPMD_NUM_INDEXES) + { + UInt32 numBytes = U2B(I2U(indx)); + p->GlueCount--; + return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL); + } + } + while (p->FreeList[i] == 0); + retVal = RemoveNode(p, i); + SplitBlock(p, retVal, i, indx); + return retVal; +} + +static void *AllocUnits(CPpmd7 *p, unsigned indx) +{ + UInt32 numBytes; + if (p->FreeList[indx] != 0) + return RemoveNode(p, indx); + numBytes = U2B(I2U(indx)); + if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit)) + { + void *retVal = p->LoUnit; + p->LoUnit += numBytes; + return retVal; + } + return AllocUnitsRare(p, indx); +} + +#define MyMem12Cpy(dest, src, num) \ + { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \ + do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while (--n); } + +static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU) +{ + unsigned i0 = U2I(oldNU); + unsigned i1 = U2I(newNU); + if (i0 == i1) + return oldPtr; + if (p->FreeList[i1] != 0) + { + void *ptr = RemoveNode(p, i1); + MyMem12Cpy(ptr, oldPtr, newNU); + InsertNode(p, oldPtr, i0); + return ptr; + } + SplitBlock(p, oldPtr, i0, i1); + return oldPtr; +} + +#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16))) + +static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) +{ + (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF); + (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF); +} + +static void RestartModel(CPpmd7 *p) +{ + unsigned i, k, m; + + memset(p->FreeList, 0, sizeof(p->FreeList)); + p->Text = p->Base + p->AlignOffset; + p->HiUnit = p->Text + p->Size; + p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; + p->GlueCount = 0; + + p->OrderFall = p->MaxOrder; + p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; + p->PrevSuccess = 0; + + p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ + p->MinContext->Suffix = 0; + p->MinContext->NumStats = 256; + p->MinContext->SummFreq = 256 + 1; + p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */ + p->LoUnit += U2B(256 / 2); + p->MinContext->Stats = REF(p->FoundState); + for (i = 0; i < 256; i++) + { + CPpmd_State *s = &p->FoundState[i]; + s->Symbol = (Byte)i; + s->Freq = 1; + SetSuccessor(s, 0); + } + + for (i = 0; i < 128; i++) + for (k = 0; k < 8; k++) + { + UInt16 *dest = p->BinSumm[i] + k; + UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 2)); + for (m = 0; m < 64; m += 8) + dest[m] = val; + } + + for (i = 0; i < 25; i++) + for (k = 0; k < 16; k++) + { + CPpmd_See *s = &p->See[i][k]; + s->Summ = (UInt16)((5 * i + 10) << (s->Shift = PPMD_PERIOD_BITS - 4)); + s->Count = 4; + } +} + +void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder) +{ + p->MaxOrder = maxOrder; + RestartModel(p); + p->DummySee.Shift = PPMD_PERIOD_BITS; + p->DummySee.Summ = 0; /* unused */ + p->DummySee.Count = 64; /* unused */ +} + +static CTX_PTR CreateSuccessors(CPpmd7 *p, Bool skip) +{ + CPpmd_State upState; + CTX_PTR c = p->MinContext; + CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); + CPpmd_State *ps[PPMD7_MAX_ORDER]; + unsigned numPs = 0; + + if (!skip) + ps[numPs++] = p->FoundState; + + while (c->Suffix) + { + CPpmd_Void_Ref successor; + CPpmd_State *s; + c = SUFFIX(c); + if (c->NumStats != 1) + { + for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++); + } + else + s = ONE_STATE(c); + successor = SUCCESSOR(s); + if (successor != upBranch) + { + c = CTX(successor); + if (numPs == 0) + return c; + break; + } + ps[numPs++] = s; + } + + upState.Symbol = *(const Byte *)Ppmd7_GetPtr(p, upBranch); + SetSuccessor(&upState, upBranch + 1); + + if (c->NumStats == 1) + upState.Freq = ONE_STATE(c)->Freq; + else + { + UInt32 cf, s0; + CPpmd_State *s; + for (s = STATS(c); s->Symbol != upState.Symbol; s++); + cf = s->Freq - 1; + s0 = c->SummFreq - c->NumStats - cf; + upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0)))); + } + + do + { + /* Create Child */ + CTX_PTR c1; /* = AllocContext(p); */ + if (p->HiUnit != p->LoUnit) + c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); + else if (p->FreeList[0] != 0) + c1 = (CTX_PTR)RemoveNode(p, 0); + else + { + c1 = (CTX_PTR)AllocUnitsRare(p, 0); + if (!c1) + return NULL; + } + c1->NumStats = 1; + *ONE_STATE(c1) = upState; + c1->Suffix = REF(c); + SetSuccessor(ps[--numPs], REF(c1)); + c = c1; + } + while (numPs != 0); + + return c; +} + +static void SwapStates(CPpmd_State *t1, CPpmd_State *t2) +{ + CPpmd_State tmp = *t1; + *t1 = *t2; + *t2 = tmp; +} + +static void UpdateModel(CPpmd7 *p) +{ + CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState); + CTX_PTR c; + unsigned s0, ns; + + if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) + { + c = SUFFIX(p->MinContext); + + if (c->NumStats == 1) + { + CPpmd_State *s = ONE_STATE(c); + if (s->Freq < 32) + s->Freq++; + } + else + { + CPpmd_State *s = STATS(c); + if (s->Symbol != p->FoundState->Symbol) + { + do { s++; } while (s->Symbol != p->FoundState->Symbol); + if (s[0].Freq >= s[-1].Freq) + { + SwapStates(&s[0], &s[-1]); + s--; + } + } + if (s->Freq < MAX_FREQ - 9) + { + s->Freq += 2; + c->SummFreq += 2; + } + } + } + + if (p->OrderFall == 0) + { + p->MinContext = p->MaxContext = CreateSuccessors(p, True); + if (p->MinContext == 0) + { + RestartModel(p); + return; + } + SetSuccessor(p->FoundState, REF(p->MinContext)); + return; + } + + *p->Text++ = p->FoundState->Symbol; + successor = REF(p->Text); + if (p->Text >= p->UnitsStart) + { + RestartModel(p); + return; + } + + if (fSuccessor) + { + if (fSuccessor <= successor) + { + CTX_PTR cs = CreateSuccessors(p, False); + if (cs == NULL) + { + RestartModel(p); + return; + } + fSuccessor = REF(cs); + } + if (--p->OrderFall == 0) + { + successor = fSuccessor; + p->Text -= (p->MaxContext != p->MinContext); + } + } + else + { + SetSuccessor(p->FoundState, successor); + fSuccessor = REF(p->MinContext); + } + + s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - (p->FoundState->Freq - 1); + + for (c = p->MaxContext; c != p->MinContext; c = SUFFIX(c)) + { + unsigned ns1; + UInt32 cf, sf; + if ((ns1 = c->NumStats) != 1) + { + if ((ns1 & 1) == 0) + { + /* Expand for one UNIT */ + unsigned oldNU = ns1 >> 1; + unsigned i = U2I(oldNU); + if (i != U2I(oldNU + 1)) + { + void *ptr = AllocUnits(p, i + 1); + void *oldPtr; + if (!ptr) + { + RestartModel(p); + return; + } + oldPtr = STATS(c); + MyMem12Cpy(ptr, oldPtr, oldNU); + InsertNode(p, oldPtr, i); + c->Stats = STATS_REF(ptr); + } + } + c->SummFreq = (UInt16)(c->SummFreq + (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) & (c->SummFreq <= 8 * ns1))); + } + else + { + CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0); + if (!s) + { + RestartModel(p); + return; + } + *s = *ONE_STATE(c); + c->Stats = REF(s); + if (s->Freq < MAX_FREQ / 4 - 1) + s->Freq <<= 1; + else + s->Freq = MAX_FREQ - 4; + c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 3)); + } + cf = 2 * (UInt32)p->FoundState->Freq * (c->SummFreq + 6); + sf = (UInt32)s0 + c->SummFreq; + if (cf < 6 * sf) + { + cf = 1 + (cf > sf) + (cf >= 4 * sf); + c->SummFreq += 3; + } + else + { + cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf); + c->SummFreq = (UInt16)(c->SummFreq + cf); + } + { + CPpmd_State *s = STATS(c) + ns1; + SetSuccessor(s, successor); + s->Symbol = p->FoundState->Symbol; + s->Freq = (Byte)cf; + c->NumStats = (UInt16)(ns1 + 1); + } + } + p->MaxContext = p->MinContext = CTX(fSuccessor); +} + +static void Rescale(CPpmd7 *p) +{ + unsigned i, adder, sumFreq, escFreq; + CPpmd_State *stats = STATS(p->MinContext); + CPpmd_State *s = p->FoundState; + { + CPpmd_State tmp = *s; + for (; s != stats; s--) + s[0] = s[-1]; + *s = tmp; + } + escFreq = p->MinContext->SummFreq - s->Freq; + s->Freq += 4; + adder = (p->OrderFall != 0); + s->Freq = (Byte)((s->Freq + adder) >> 1); + sumFreq = s->Freq; + + i = p->MinContext->NumStats - 1; + do + { + escFreq -= (++s)->Freq; + s->Freq = (Byte)((s->Freq + adder) >> 1); + sumFreq += s->Freq; + if (s[0].Freq > s[-1].Freq) + { + CPpmd_State *s1 = s; + CPpmd_State tmp = *s1; + do + s1[0] = s1[-1]; + while (--s1 != stats && tmp.Freq > s1[-1].Freq); + *s1 = tmp; + } + } + while (--i); + + if (s->Freq == 0) + { + unsigned numStats = p->MinContext->NumStats; + unsigned n0, n1; + do { i++; } while ((--s)->Freq == 0); + escFreq += i; + p->MinContext->NumStats = (UInt16)(p->MinContext->NumStats - i); + if (p->MinContext->NumStats == 1) + { + CPpmd_State tmp = *stats; + do + { + tmp.Freq = (Byte)(tmp.Freq - (tmp.Freq >> 1)); + escFreq >>= 1; + } + while (escFreq > 1); + InsertNode(p, stats, U2I(((numStats + 1) >> 1))); + *(p->FoundState = ONE_STATE(p->MinContext)) = tmp; + return; + } + n0 = (numStats + 1) >> 1; + n1 = (p->MinContext->NumStats + 1) >> 1; + if (n0 != n1) + p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); + } + p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); + p->FoundState = STATS(p->MinContext); +} + +CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq) +{ + CPpmd_See *see; + unsigned nonMasked = p->MinContext->NumStats - numMasked; + if (p->MinContext->NumStats != 256) + { + see = p->See[p->NS2Indx[nonMasked - 1]] + + (nonMasked < (unsigned)SUFFIX(p->MinContext)->NumStats - p->MinContext->NumStats) + + 2 * (p->MinContext->SummFreq < 11 * p->MinContext->NumStats) + + 4 * (numMasked > nonMasked) + + p->HiBitsFlag; + { + unsigned r = (see->Summ >> see->Shift); + see->Summ = (UInt16)(see->Summ - r); + *escFreq = r + (r == 0); + } + } + else + { + see = &p->DummySee; + *escFreq = 1; + } + return see; +} + +static void NextContext(CPpmd7 *p) +{ + CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); + if (p->OrderFall == 0 && (Byte *)c > p->Text) + p->MinContext = p->MaxContext = c; + else + UpdateModel(p); +} + +void Ppmd7_Update1(CPpmd7 *p) +{ + CPpmd_State *s = p->FoundState; + s->Freq += 4; + p->MinContext->SummFreq += 4; + if (s[0].Freq > s[-1].Freq) + { + SwapStates(&s[0], &s[-1]); + p->FoundState = --s; + if (s->Freq > MAX_FREQ) + Rescale(p); + } + NextContext(p); +} + +void Ppmd7_Update1_0(CPpmd7 *p) +{ + p->PrevSuccess = (2 * p->FoundState->Freq > p->MinContext->SummFreq); + p->RunLength += p->PrevSuccess; + p->MinContext->SummFreq += 4; + if ((p->FoundState->Freq += 4) > MAX_FREQ) + Rescale(p); + NextContext(p); +} + +void Ppmd7_UpdateBin(CPpmd7 *p) +{ + p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 128 ? 1: 0)); + p->PrevSuccess = 1; + p->RunLength++; + NextContext(p); +} + +void Ppmd7_Update2(CPpmd7 *p) +{ + p->MinContext->SummFreq += 4; + if ((p->FoundState->Freq += 4) > MAX_FREQ) + Rescale(p); + p->RunLength = p->InitRL; + UpdateModel(p); +} diff --git a/lzma/C/Ppmd7.h b/lzma/C/Ppmd7.h new file mode 100644 index 000000000..96521c31f --- /dev/null +++ b/lzma/C/Ppmd7.h @@ -0,0 +1,140 @@ +/* Ppmd7.h -- PPMdH compression codec +2010-03-12 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +/* This code supports virtual RangeDecoder and includes the implementation +of RangeCoder from 7z, instead of RangeCoder from original PPMd var.H. +If you need the compatibility with original PPMd var.H, you can use external RangeDecoder */ + +#ifndef __PPMD7_H +#define __PPMD7_H + +#include "Ppmd.h" + +EXTERN_C_BEGIN + +#define PPMD7_MIN_ORDER 2 +#define PPMD7_MAX_ORDER 64 + +#define PPMD7_MIN_MEM_SIZE (1 << 11) +#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFF - 12 * 3) + +struct CPpmd7_Context_; + +typedef + #ifdef PPMD_32BIT + struct CPpmd7_Context_ * + #else + UInt32 + #endif + CPpmd7_Context_Ref; + +typedef struct CPpmd7_Context_ +{ + UInt16 NumStats; + UInt16 SummFreq; + CPpmd_State_Ref Stats; + CPpmd7_Context_Ref Suffix; +} CPpmd7_Context; + +#define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq) + +typedef struct +{ + CPpmd7_Context *MinContext, *MaxContext; + CPpmd_State *FoundState; + unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, HiBitsFlag; + Int32 RunLength, InitRL; /* must be 32-bit at least */ + + UInt32 Size; + UInt32 GlueCount; + Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart; + UInt32 AlignOffset; + + Byte Indx2Units[PPMD_NUM_INDEXES]; + Byte Units2Indx[128]; + CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES]; + Byte NS2Indx[256], NS2BSIndx[256], HB2Flag[256]; + CPpmd_See DummySee, See[25][16]; + UInt16 BinSumm[128][64]; +} CPpmd7; + +void Ppmd7_Construct(CPpmd7 *p); +Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc); +void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc); +void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder); +#define Ppmd7_WasAllocated(p) ((p)->Base != NULL) + + +/* ---------- Internal Functions ---------- */ + +extern const Byte PPMD7_kExpEscape[16]; + +#ifdef PPMD_32BIT + #define Ppmd7_GetPtr(p, ptr) (ptr) + #define Ppmd7_GetContext(p, ptr) (ptr) + #define Ppmd7_GetStats(p, ctx) ((ctx)->Stats) +#else + #define Ppmd7_GetPtr(p, offs) ((void *)((p)->Base + (offs))) + #define Ppmd7_GetContext(p, offs) ((CPpmd7_Context *)Ppmd7_GetPtr((p), (offs))) + #define Ppmd7_GetStats(p, ctx) ((CPpmd_State *)Ppmd7_GetPtr((p), ((ctx)->Stats))) +#endif + +void Ppmd7_Update1(CPpmd7 *p); +void Ppmd7_Update1_0(CPpmd7 *p); +void Ppmd7_Update2(CPpmd7 *p); +void Ppmd7_UpdateBin(CPpmd7 *p); + +#define Ppmd7_GetBinSumm(p) \ + &p->BinSumm[Ppmd7Context_OneState(p->MinContext)->Freq - 1][p->PrevSuccess + \ + p->NS2BSIndx[Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] + \ + (p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]) + \ + 2 * p->HB2Flag[Ppmd7Context_OneState(p->MinContext)->Symbol] + \ + ((p->RunLength >> 26) & 0x20)] + +CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *scale); + + +/* ---------- Decode ---------- */ + +typedef struct +{ + UInt32 (*GetThreshold)(void *p, UInt32 total); + void (*Decode)(void *p, UInt32 start, UInt32 size); + UInt32 (*DecodeBit)(void *p, UInt32 size0); +} IPpmd7_RangeDec; + +typedef struct +{ + IPpmd7_RangeDec p; + UInt32 Range; + UInt32 Code; + IByteIn *Stream; +} CPpmd7z_RangeDec; + +void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p); +Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p); +#define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0) + +int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc); + + +/* ---------- Encode ---------- */ + +typedef struct +{ + UInt64 Low; + UInt32 Range; + Byte Cache; + UInt64 CacheSize; + IByteOut *Stream; +} CPpmd7z_RangeEnc; + +void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p); +void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p); + +void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol); + +EXTERN_C_END + +#endif diff --git a/lzma/C/Ppmd7Dec.c b/lzma/C/Ppmd7Dec.c new file mode 100644 index 000000000..04b4b09e3 --- /dev/null +++ b/lzma/C/Ppmd7Dec.c @@ -0,0 +1,189 @@ +/* Ppmd7Dec.c -- PPMdH Decoder +2010-03-12 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +#include "Precomp.h" + +#include "Ppmd7.h" + +#define kTopValue (1 << 24) + +Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p) +{ + unsigned i; + p->Code = 0; + p->Range = 0xFFFFFFFF; + if (p->Stream->Read((void *)p->Stream) != 0) + return False; + for (i = 0; i < 4; i++) + p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); + return (p->Code < 0xFFFFFFFF); +} + +static UInt32 Range_GetThreshold(void *pp, UInt32 total) +{ + CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; + return (p->Code) / (p->Range /= total); +} + +static void Range_Normalize(CPpmd7z_RangeDec *p) +{ + if (p->Range < kTopValue) + { + p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); + p->Range <<= 8; + if (p->Range < kTopValue) + { + p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); + p->Range <<= 8; + } + } +} + +static void Range_Decode(void *pp, UInt32 start, UInt32 size) +{ + CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; + p->Code -= start * p->Range; + p->Range *= size; + Range_Normalize(p); +} + +static UInt32 Range_DecodeBit(void *pp, UInt32 size0) +{ + CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; + UInt32 newBound = (p->Range >> 14) * size0; + UInt32 symbol; + if (p->Code < newBound) + { + symbol = 0; + p->Range = newBound; + } + else + { + symbol = 1; + p->Code -= newBound; + p->Range -= newBound; + } + Range_Normalize(p); + return symbol; +} + +void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p) +{ + p->p.GetThreshold = Range_GetThreshold; + p->p.Decode = Range_Decode; + p->p.DecodeBit = Range_DecodeBit; +} + + +#define MASK(sym) ((signed char *)charMask)[sym] + +int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc) +{ + size_t charMask[256 / sizeof(size_t)]; + if (p->MinContext->NumStats != 1) + { + CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); + unsigned i; + UInt32 count, hiCnt; + if ((count = rc->GetThreshold(rc, p->MinContext->SummFreq)) < (hiCnt = s->Freq)) + { + Byte symbol; + rc->Decode(rc, 0, s->Freq); + p->FoundState = s; + symbol = s->Symbol; + Ppmd7_Update1_0(p); + return symbol; + } + p->PrevSuccess = 0; + i = p->MinContext->NumStats - 1; + do + { + if ((hiCnt += (++s)->Freq) > count) + { + Byte symbol; + rc->Decode(rc, hiCnt - s->Freq, s->Freq); + p->FoundState = s; + symbol = s->Symbol; + Ppmd7_Update1(p); + return symbol; + } + } + while (--i); + if (count >= p->MinContext->SummFreq) + return -2; + p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]; + rc->Decode(rc, hiCnt, p->MinContext->SummFreq - hiCnt); + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(s->Symbol) = 0; + i = p->MinContext->NumStats - 1; + do { MASK((--s)->Symbol) = 0; } while (--i); + } + else + { + UInt16 *prob = Ppmd7_GetBinSumm(p); + if (rc->DecodeBit(rc, *prob) == 0) + { + Byte symbol; + *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); + symbol = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol; + Ppmd7_UpdateBin(p); + return symbol; + } + *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); + p->InitEsc = PPMD7_kExpEscape[*prob >> 10]; + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0; + p->PrevSuccess = 0; + } + for (;;) + { + CPpmd_State *ps[256], *s; + UInt32 freqSum, count, hiCnt; + CPpmd_See *see; + unsigned i, num, numMasked = p->MinContext->NumStats; + do + { + p->OrderFall++; + if (!p->MinContext->Suffix) + return -1; + p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix); + } + while (p->MinContext->NumStats == numMasked); + hiCnt = 0; + s = Ppmd7_GetStats(p, p->MinContext); + i = 0; + num = p->MinContext->NumStats - numMasked; + do + { + int k = (int)(MASK(s->Symbol)); + hiCnt += (s->Freq & k); + ps[i] = s++; + i -= k; + } + while (i != num); + + see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum); + freqSum += hiCnt; + count = rc->GetThreshold(rc, freqSum); + + if (count < hiCnt) + { + Byte symbol; + CPpmd_State **pps = ps; + for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++); + s = *pps; + rc->Decode(rc, hiCnt - s->Freq, s->Freq); + Ppmd_See_Update(see); + p->FoundState = s; + symbol = s->Symbol; + Ppmd7_Update2(p); + return symbol; + } + if (count >= freqSum) + return -2; + rc->Decode(rc, hiCnt, freqSum - hiCnt); + see->Summ = (UInt16)(see->Summ + freqSum); + do { MASK(ps[--i]->Symbol) = 0; } while (i != 0); + } +} diff --git a/lzma/C/Precomp.h b/lzma/C/Precomp.h new file mode 100644 index 000000000..e8ff8b40e --- /dev/null +++ b/lzma/C/Precomp.h @@ -0,0 +1,10 @@ +/* Precomp.h -- StdAfx +2013-11-12 : Igor Pavlov : Public domain */ + +#ifndef __7Z_PRECOMP_H +#define __7Z_PRECOMP_H + +#include "Compiler.h" +/* #include "7zTypes.h" */ + +#endif diff --git a/lzma/C/Threads.c b/lzma/C/Threads.c index 4be44fb0f..ece07e618 100644 --- a/lzma/C/Threads.c +++ b/lzma/C/Threads.c @@ -1,7 +1,9 @@ /* Threads.c -- multithreading library -2009-09-20 : Igor Pavlov : Public domain */ +2014-09-21 : Igor Pavlov : Public domain */ -#ifndef _WIN32_WCE +#include "Precomp.h" + +#ifndef UNDER_CE #include #endif @@ -29,14 +31,21 @@ WRes Handle_WaitObject(HANDLE h) { return (WRes)WaitForSingleObject(h, INFINITE) WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param) { - unsigned threadId; /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */ - *p = - #ifdef UNDER_CE - CreateThread(0, 0, func, param, 0, &threadId); - #else - (HANDLE)_beginthreadex(NULL, 0, func, param, 0, &threadId); - #endif - /* maybe we must use errno here, but probably GetLastError() is also OK. */ + /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */ + + #ifdef UNDER_CE + + DWORD threadId; + *p = CreateThread(0, 0, func, param, 0, &threadId); + + #else + + unsigned threadId; + *p = (HANDLE)_beginthreadex(NULL, 0, func, param, 0, &threadId); + + #endif + + /* maybe we must use errno here, but probably GetLastError() is also OK. */ return HandleToWRes(*p); } diff --git a/lzma/C/Threads.h b/lzma/C/Threads.h index 6a7afa829..e927208d7 100644 --- a/lzma/C/Threads.h +++ b/lzma/C/Threads.h @@ -1,15 +1,17 @@ /* Threads.h -- multithreading library -2009-03-27 : Igor Pavlov : Public domain */ +2013-11-12 : Igor Pavlov : Public domain */ #ifndef __7Z_THREADS_H #define __7Z_THREADS_H -#include "Types.h" - -#ifdef __cplusplus -extern "C" { +#ifdef _WIN32 +#include #endif +#include "7zTypes.h" + +EXTERN_C_BEGIN + WRes HandlePtr_Close(HANDLE *h); WRes Handle_WaitObject(HANDLE h); @@ -18,7 +20,15 @@ typedef HANDLE CThread; #define Thread_WasCreated(p) (*(p) != NULL) #define Thread_Close(p) HandlePtr_Close(p) #define Thread_Wait(p) Handle_WaitObject(*(p)) -typedef unsigned THREAD_FUNC_RET_TYPE; + +typedef +#ifdef UNDER_CE + DWORD +#else + unsigned +#endif + THREAD_FUNC_RET_TYPE; + #define THREAD_FUNC_CALL_TYPE MY_STD_CALL #define THREAD_FUNC_DECL THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE typedef THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE * THREAD_FUNC_TYPE)(void *); @@ -52,8 +62,6 @@ WRes CriticalSection_Init(CCriticalSection *p); #define CriticalSection_Enter(p) EnterCriticalSection(p) #define CriticalSection_Leave(p) LeaveCriticalSection(p) -#ifdef __cplusplus -} -#endif +EXTERN_C_END #endif diff --git a/lzma/CMakeLists.txt b/lzma/CMakeLists.txt index 7cd330cc8..9c9de9152 100644 --- a/lzma/CMakeLists.txt +++ b/lzma/CMakeLists.txt @@ -6,21 +6,27 @@ if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE ) set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -fomit-frame-pointer" ) endif( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE ) +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_7ZIP_PPMD_SUPPPORT" ) + set( LZMA_FILES + C/7zArcIn.c C/7zBuf.c C/7zCrc.c C/7zCrcOpt.c C/7zDec.c - C/7zIn.c C/7zStream.c C/Bcj2.c C/Bra.c C/Bra86.c + C/BraIA64.c C/CpuArch.c + C/Delta.c C/LzFind.c C/Lzma2Dec.c C/LzmaDec.c - C/LzmaEnc.c ) + C/LzmaEnc.c + C/Ppmd7.c + C/Ppmd7Dec.c ) if( WIN32 ) set( LZMA_FILES ${LZMA_FILES} C/LzFindMt.c C/Threads.c ) diff --git a/lzma/history.txt b/lzma/history.txt index 36d01d7d9..6abb8248c 100644 --- a/lzma/history.txt +++ b/lzma/history.txt @@ -1,6 +1,62 @@ HISTORY of the LZMA SDK ----------------------- +15.12 2015-11-19 +------------------------- +- The BUG in C version of 7z decoder was fixed: + 7zDec.c : SzDecodeLzma2() + 7z decoder could mistakenly report about decoding error for some 7z archives + that use LZMA2 compression method. + The probability to get that mistaken decoding error report was about + one error per 16384 solid blocks for solid blocks larger than 16 KB (compressed size). +- The BUG (in 9.26-15.11) in C version of 7z decoder was fixed: + 7zArcIn.c : SzReadHeader2() + 7z decoder worked incorrectly for 7z archives that contain + empty solid blocks, that can be placed to 7z archive, if some file is + unavailable for reading during archive creation. + + +15.09 beta 2015-10-16 +------------------------- +- The BUG in LZMA / LZMA2 encoding code was fixed. + The BUG in LzFind.c::MatchFinder_ReadBlock() function. + If input data size is larger than (4 GiB - dictionary_size), + the following code worked incorrectly: + - LZMA : LzmaEnc_MemEncode(), LzmaEncode() : LZMA encoding functions + for compressing from memory to memory. + That BUG is not related to LZMA encoder version that works via streams. + - LZMA2 : multi-threaded version of LZMA2 encoder worked incorrectly, if + default value of chunk size (CLzma2EncProps::blockSize) is changed + to value larger than (4 GiB - dictionary_size). + + +9.38 beta 2015-01-03 +------------------------- +- The BUG in 9.31-9.37 was fixed: + IArchiveGetRawProps interface was disabled for 7z archives. +- The BUG in 9.26-9.36 was fixed: + Some code in CPP\7zip\Archive\7z\ worked correctly only under Windows. + + +9.36 beta 2014-12-26 +------------------------- +- The BUG in command line version was fixed: + 7-Zip created temporary archive in current folder during update archive + operation, if -w{Path} switch was not specified. + The fixed 7-Zip creates temporary archive in folder that contains updated archive. +- The BUG in 9.33-9.35 was fixed: + 7-Zip silently ignored file reading errors during 7z or gz archive creation, + and the created archive contained only part of file that was read before error. + The fixed 7-Zip stops archive creation and it reports about error. + + +9.35 beta 2014-12-07 +------------------------- +- 7zr.exe now support AES encryption. +- SFX mudules were added to LZMA SDK +- Some bugs were fixed. + + 9.21 beta 2011-04-11 ------------------------- - New class FString for file names at file systems. diff --git a/lzma/lzma.txt b/lzma/lzma.txt index 9d3cef003..4e74e8b5b 100644 --- a/lzma/lzma.txt +++ b/lzma/lzma.txt @@ -1,18 +1,27 @@ -LZMA SDK 9.22 -------------- +LZMA SDK 15.13 +-------------- -LZMA SDK provides the documentation, samples, header files, libraries, -and tools you need to develop applications that use LZMA compression. - -LZMA is default and general compression method of 7z format -in 7-Zip compression program (www.7-zip.org). LZMA provides high -compression ratio and very fast decompression. +LZMA SDK provides the documentation, samples, header files, +libraries, and tools you need to develop applications that +use 7z / LZMA / LZMA2 / XZ compression. LZMA is an improved version of famous LZ77 compression algorithm. It was improved in way of maximum increasing of compression ratio, keeping high decompression speed and low memory requirements for decompressing. +LZMA2 is a LZMA based compression method. LZMA2 provides better +multithreading support for compression than LZMA and some other improvements. + +7z is a file format for data compression and file archiving. +7z is a main file format for 7-Zip compression program (www.7-zip.org). +7z format supports different compression methods: LZMA, LZMA2 and others. +7z also supports AES-256 based encryption. + +XZ is a file format for data compression that uses LZMA2 compression. +XZ format provides additional features: SHA/CRC check, filters for +improved compression ratio, splitting to blocks and streams, + LICENSE @@ -24,8 +33,9 @@ Some code in LZMA SDK is based on public domain code from another developers: 1) PPMd var.H (2001): Dmitry Shkarin 2) SHA-256: Wei Dai (Crypto++ library) -You can copy, modify, distribute and perform LZMA SDK code, even for commercial purposes, -all without asking permission. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute the +original LZMA SDK code, either in source code form or as a compiled binary, for +any purpose, commercial or non-commercial, and by any means. LZMA SDK code is compatible with open source licenses, for example, you can include it to GNU GPL or GNU LGPL code. @@ -34,10 +44,20 @@ include it to GNU GPL or GNU LGPL code. LZMA SDK Contents ----------------- -LZMA SDK includes: + Source code: - - ANSI-C/C++/C#/Java source code for LZMA compressing and decompressing - - Compiled file->file LZMA compressing/decompressing program for Windows system + - C / C++ / C# / Java - LZMA compression and decompression + - C / C++ - LZMA2 compression and decompression + - C / C++ - XZ compression and decompression + - C - 7z decompression + - C++ - 7z compression and decompression + - C - small SFXs for installers (7z decompression) + - C++ - SFXs and SFXs for installers (7z decompression) + + Precomiled binaries: + + - console programs for lzma / 7z / xz compression and decompression + - SFX modules for installers. UNIX/Linux version @@ -51,70 +71,94 @@ In some UNIX/Linux versions you must compile LZMA with static libraries. To compile with static libraries, you can use LIB = -lm -static +Also you can use p7zip (port of 7-Zip for POSIX systems like Unix or Linux): + + http://p7zip.sourceforge.net/ + Files ---------------------- -lzma.txt - LZMA SDK description (this file) -7zFormat.txt - 7z Format description -7zC.txt - 7z ANSI-C Decoder description -methods.txt - Compression method IDs for .7z -lzma.exe - Compiled file->file LZMA encoder/decoder for Windows -7zr.exe - 7-Zip with 7z/lzma/xz support. -history.txt - history of the LZMA SDK +----- + +DOC/7zC.txt - 7z ANSI-C Decoder description +DOC/7zFormat.txt - 7z Format description +DOC/installer.txt - information about 7-Zip for installers +DOC/lzma.txt - LZMA compression description +DOC/lzma-sdk.txt - LZMA SDK description (this file) +DOC/lzma-history.txt - history of LZMA SDK +DOC/lzma-specification.txt - Specification of LZMA +DOC/Methods.txt - Compression method IDs for .7z + +bin/installer/ - example script to create installer that uses SFX module, + +bin/7zdec.exe - simplified 7z archive decoder +bin/7zr.exe - 7-Zip console program (reduced version) +bin/x64/7zr.exe - 7-Zip console program (reduced version) (x64 version) +bin/lzma.exe - file->file LZMA encoder/decoder for Windows +bin/7zS2.sfx - small SFX module for installers (GUI version) +bin/7zS2con.sfx - small SFX module for installers (Console version) +bin/7zSD.sfx - SFX module for installers. + + +7zDec.exe +--------- +7zDec.exe is simplified 7z archive decoder. +It supports only LZMA, LZMA2, and PPMd methods. +7zDec decodes whole solid block from 7z archive to RAM. +The RAM consumption can be high. + + Source code structure --------------------- -C/ - C files - 7zCrc*.* - CRC code - Alloc.* - Memory allocation functions - Bra*.* - Filters for x86, IA-64, ARM, ARM-Thumb, PowerPC and SPARC code - LzFind.* - Match finder for LZ (LZMA) encoders - LzFindMt.* - Match finder for LZ (LZMA) encoders for multithreading encoding - LzHash.h - Additional file for LZ match finder - LzmaDec.* - LZMA decoding - LzmaEnc.* - LZMA encoding - LzmaLib.* - LZMA Library for DLL calling - Types.h - Basic types for another .c files - Threads.* - The code for multithreading. - LzmaLib - LZMA Library (.DLL for Windows) - - LzmaUtil - LZMA Utility (file->file LZMA encoder/decoder). +Asm/ - asm files (optimized code for CRC calculation and Intel-AES encryption) - Archive - files related to archiving - 7z - 7z ANSI-C Decoder +C/ - C files (compression / decompression and other) + Util/ + 7z - 7z decoder program (decoding 7z files) + Lzma - LZMA program (file->file LZMA encoder/decoder). + LzmaLib - LZMA library (.DLL for Windows) + SfxSetup - small SFX module for installers CPP/ -- CPP files Common - common files for C++ projects Windows - common files for Windows related code - 7zip - files related to 7-Zip Project - - Common - common files for 7-Zip - - Compress - files related to compression/decompression + 7zip - files related to 7-Zip Archive - files related to archiving Common - common files for archive handling 7z - 7z C++ Encoder/Decoder - Bundles - Modules that are bundles of other modules + Bundles - Modules that are bundles of other modules (files) - Alone7z - 7zr.exe: Standalone version of 7z.exe that supports only 7z/LZMA/BCJ/BCJ2 - LzmaCon - lzma.exe: LZMA compression/decompression - Format7zR - 7zr.dll: Reduced version of 7za.dll: extracting/compressing to 7z/LZMA/BCJ/BCJ2 - Format7zExtractR - 7zxr.dll: Reduced version of 7zxa.dll: extracting from 7z/LZMA/BCJ/BCJ2. + Alone7z - 7zr.exe: Standalone 7-Zip console program (reduced version) + Format7zExtractR - 7zxr.dll: Reduced version of 7z DLL: extracting from 7z/LZMA/BCJ/BCJ2. + Format7zR - 7zr.dll: Reduced version of 7z DLL: extracting/compressing to 7z/LZMA/BCJ/BCJ2 + LzmaCon - lzma.exe: LZMA compression/decompression + LzmaSpec - example code for LZMA Specification + SFXCon - 7zCon.sfx: Console 7z SFX module + SFXSetup - 7zS.sfx: 7z SFX module for installers + SFXWin - 7z.sfx: GUI 7z SFX module - UI - User Interface files + Common - common files for 7-Zip + + Compress - files for compression/decompression + + Crypto - files for encryption / decompression + + UI - User Interface files - Client7z - Test application for 7za.dll, 7zr.dll, 7zxr.dll + Client7z - Test application for 7za.dll, 7zr.dll, 7zxr.dll Common - Common UI files - Console - Code for console archiver - + Console - Code for console program (7z.exe) + Explorer - Some code from 7-Zip Shell extension + FileManager - Some GUI code from 7-Zip File Manager + GUI - Some GUI code from 7-Zip CS/ - C# files @@ -134,8 +178,9 @@ Java/ - Java files RangeCoder - Range Coder (special code of compression/decompression) -C/C++ source code of LZMA SDK is part of 7-Zip project. -7-Zip source code can be downloaded from 7-Zip's SourceForge page: +Note: + Asm / C / C++ source code of LZMA SDK is part of 7-Zip's source code. + 7-Zip's source code can be downloaded from 7-Zip's SourceForge page: http://sourceforge.net/projects/sevenzip/ @@ -146,8 +191,8 @@ LZMA features - Variable dictionary size (up to 1 GB) - Estimated compressing speed: about 2 MB/s on 2 GHz CPU - Estimated decompressing speed: - - 20-30 MB/s on 2 GHz Core 2 or AMD Athlon 64 - - 1-2 MB/s on 200 MHz ARM, MIPS, PowerPC or other simple RISC + - 20-30 MB/s on modern 2 GHz cpu + - 1-2 MB/s on 200 MHz simple RISC cpu: (ARM, MIPS, PowerPC) - Small memory requirements for decompressing (16 KB + DictionarySize) - Small code size for decompressing: 5-8 KB @@ -156,7 +201,7 @@ implemented in any modern 32-bit CPU (or on 16-bit CPU with some conditions). Some critical operations that affect the speed of LZMA decompression: 1) 32*16 bit integer multiply - 2) Misspredicted branches (penalty mostly depends from pipeline length) + 2) Mispredicted branches (penalty mostly depends from pipeline length) 3) 32-bit shift and arithmetic operations The speed of LZMA decompressing mostly depends from CPU speed. @@ -304,298 +349,6 @@ compressible. For some ISAs (for example, for MIPS) it's impossible to get gain from such filter. -LZMA compressed file format ---------------------------- -Offset Size Description - 0 1 Special LZMA properties (lc,lp, pb in encoded form) - 1 4 Dictionary size (little endian) - 5 8 Uncompressed size (little endian). -1 means unknown size - 13 Compressed data - - -ANSI-C LZMA Decoder -~~~~~~~~~~~~~~~~~~~ - -Please note that interfaces for ANSI-C code were changed in LZMA SDK 4.58. -If you want to use old interfaces you can download previous version of LZMA SDK -from sourceforge.net site. - -To use ANSI-C LZMA Decoder you need the following files: -1) LzmaDec.h + LzmaDec.c + Types.h -LzmaUtil/LzmaUtil.c is example application that uses these files. - - -Memory requirements for LZMA decoding -------------------------------------- - -Stack usage of LZMA decoding function for local variables is not -larger than 200-400 bytes. - -LZMA Decoder uses dictionary buffer and internal state structure. -Internal state structure consumes - state_size = (4 + (1.5 << (lc + lp))) KB -by default (lc=3, lp=0), state_size = 16 KB. - - -How To decompress data ----------------------- - -LZMA Decoder (ANSI-C version) now supports 2 interfaces: -1) Single-call Decompressing -2) Multi-call State Decompressing (zlib-like interface) - -You must use external allocator: -Example: -void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); } -void SzFree(void *p, void *address) { p = p; free(address); } -ISzAlloc alloc = { SzAlloc, SzFree }; - -You can use p = p; operator to disable compiler warnings. - - -Single-call Decompressing -------------------------- -When to use: RAM->RAM decompressing -Compile files: LzmaDec.h + LzmaDec.c + Types.h -Compile defines: no defines -Memory Requirements: - - Input buffer: compressed size - - Output buffer: uncompressed size - - LZMA Internal Structures: state_size (16 KB for default settings) - -Interface: - int LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, - const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, - ELzmaStatus *status, ISzAlloc *alloc); - In: - dest - output data - destLen - output data size - src - input data - srcLen - input data size - propData - LZMA properties (5 bytes) - propSize - size of propData buffer (5 bytes) - finishMode - It has meaning only if the decoding reaches output limit (*destLen). - LZMA_FINISH_ANY - Decode just destLen bytes. - LZMA_FINISH_END - Stream must be finished after (*destLen). - You can use LZMA_FINISH_END, when you know that - current output buffer covers last bytes of stream. - alloc - Memory allocator. - - Out: - destLen - processed output size - srcLen - processed input size - - Output: - SZ_OK - status: - LZMA_STATUS_FINISHED_WITH_MARK - LZMA_STATUS_NOT_FINISHED - LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK - SZ_ERROR_DATA - Data error - SZ_ERROR_MEM - Memory allocation error - SZ_ERROR_UNSUPPORTED - Unsupported properties - SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). - - If LZMA decoder sees end_marker before reaching output limit, it returns OK result, - and output value of destLen will be less than output buffer size limit. - - You can use multiple checks to test data integrity after full decompression: - 1) Check Result and "status" variable. - 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. - 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. - You must use correct finish mode in that case. */ - - -Multi-call State Decompressing (zlib-like interface) ----------------------------------------------------- - -When to use: file->file decompressing -Compile files: LzmaDec.h + LzmaDec.c + Types.h - -Memory Requirements: - - Buffer for input stream: any size (for example, 16 KB) - - Buffer for output stream: any size (for example, 16 KB) - - LZMA Internal Structures: state_size (16 KB for default settings) - - LZMA dictionary (dictionary size is encoded in LZMA properties header) - -1) read LZMA properties (5 bytes) and uncompressed size (8 bytes, little-endian) to header: - unsigned char header[LZMA_PROPS_SIZE + 8]; - ReadFile(inFile, header, sizeof(header) - -2) Allocate CLzmaDec structures (state + dictionary) using LZMA properties - - CLzmaDec state; - LzmaDec_Constr(&state); - res = LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc); - if (res != SZ_OK) - return res; - -3) Init LzmaDec structure before any new LZMA stream. And call LzmaDec_DecodeToBuf in loop - - LzmaDec_Init(&state); - for (;;) - { - ... - int res = LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, - const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode); - ... - } - - -4) Free all allocated structures - LzmaDec_Free(&state, &g_Alloc); - -For full code example, look at C/LzmaUtil/LzmaUtil.c code. - - -How To compress data --------------------- - -Compile files: LzmaEnc.h + LzmaEnc.c + Types.h + -LzFind.c + LzFind.h + LzFindMt.c + LzFindMt.h + LzHash.h - -Memory Requirements: - - (dictSize * 11.5 + 6 MB) + state_size - -Lzma Encoder can use two memory allocators: -1) alloc - for small arrays. -2) allocBig - for big arrays. - -For example, you can use Large RAM Pages (2 MB) in allocBig allocator for -better compression speed. Note that Windows has bad implementation for -Large RAM Pages. -It's OK to use same allocator for alloc and allocBig. - - -Single-call Compression with callbacks --------------------------------------- - -Check C/LzmaUtil/LzmaUtil.c as example, - -When to use: file->file decompressing - -1) you must implement callback structures for interfaces: -ISeqInStream -ISeqOutStream -ICompressProgress -ISzAlloc - -static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } -static void SzFree(void *p, void *address) { p = p; MyFree(address); } -static ISzAlloc g_Alloc = { SzAlloc, SzFree }; - - CFileSeqInStream inStream; - CFileSeqOutStream outStream; - - inStream.funcTable.Read = MyRead; - inStream.file = inFile; - outStream.funcTable.Write = MyWrite; - outStream.file = outFile; - - -2) Create CLzmaEncHandle object; - - CLzmaEncHandle enc; - - enc = LzmaEnc_Create(&g_Alloc); - if (enc == 0) - return SZ_ERROR_MEM; - - -3) initialize CLzmaEncProps properties; - - LzmaEncProps_Init(&props); - - Then you can change some properties in that structure. - -4) Send LZMA properties to LZMA Encoder - - res = LzmaEnc_SetProps(enc, &props); - -5) Write encoded properties to header - - Byte header[LZMA_PROPS_SIZE + 8]; - size_t headerSize = LZMA_PROPS_SIZE; - UInt64 fileSize; - int i; - - res = LzmaEnc_WriteProperties(enc, header, &headerSize); - fileSize = MyGetFileLength(inFile); - for (i = 0; i < 8; i++) - header[headerSize++] = (Byte)(fileSize >> (8 * i)); - MyWriteFileAndCheck(outFile, header, headerSize) - -6) Call encoding function: - res = LzmaEnc_Encode(enc, &outStream.funcTable, &inStream.funcTable, - NULL, &g_Alloc, &g_Alloc); - -7) Destroy LZMA Encoder Object - LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc); - - -If callback function return some error code, LzmaEnc_Encode also returns that code -or it can return the code like SZ_ERROR_READ, SZ_ERROR_WRITE or SZ_ERROR_PROGRESS. - - -Single-call RAM->RAM Compression --------------------------------- - -Single-call RAM->RAM Compression is similar to Compression with callbacks, -but you provide pointers to buffers instead of pointers to stream callbacks: - -HRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, - CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, - ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); - -Return code: - SZ_OK - OK - SZ_ERROR_MEM - Memory allocation error - SZ_ERROR_PARAM - Incorrect paramater - SZ_ERROR_OUTPUT_EOF - output buffer overflow - SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) - - - -Defines -------- - -_LZMA_SIZE_OPT - Enable some optimizations in LZMA Decoder to get smaller executable code. - -_LZMA_PROB32 - It can increase the speed on some 32-bit CPUs, but memory usage for - some structures will be doubled in that case. - -_LZMA_UINT32_IS_ULONG - Define it if int is 16-bit on your compiler and long is 32-bit. - -_LZMA_NO_SYSTEM_SIZE_T - Define it if you don't want to use size_t type. - - -_7ZIP_PPMD_SUPPPORT - Define it if you don't want to support PPMD method in AMSI-C .7z decoder. - - -C++ LZMA Encoder/Decoder -~~~~~~~~~~~~~~~~~~~~~~~~ -C++ LZMA code use COM-like interfaces. So if you want to use it, -you can study basics of COM/OLE. -C++ LZMA code is just wrapper over ANSI-C code. - - -C++ Notes -~~~~~~~~~~~~~~~~~~~~~~~~ -If you use some C++ code folders in 7-Zip (for example, C++ code for .7z handling), -you must check that you correctly work with "new" operator. -7-Zip can be compiled with MSVC 6.0 that doesn't throw "exception" from "new" operator. -So 7-Zip uses "CPP\Common\NewHandler.cpp" that redefines "new" operator: -operator new(size_t size) -{ - void *p = ::malloc(size); - if (p == 0) - throw CNewException(); - return p; -} -If you use MSCV that throws exception for "new" operator, you can compile without -"NewHandler.cpp". So standard exception will be used. Actually some code of -7-Zip catches any exception in internal code and converts it to HRESULT code. -So you don't need to catch CNewException, if you call COM interfaces of 7-Zip. --- diff --git a/lzma/lzmalib.vcproj b/lzma/lzmalib.vcproj index 2736f31a6..f1e085f3d 100644 --- a/lzma/lzmalib.vcproj +++ b/lzma/lzmalib.vcproj @@ -1,12 +1,11 @@ + + @@ -303,10 +306,6 @@ RelativePath=".\C\7zDec.c" > - - @@ -323,10 +322,18 @@ RelativePath=".\C\Bra86.c" > + + + + @@ -347,6 +354,14 @@ RelativePath=".\C\LzmaEnc.c" > + + + + @@ -381,10 +396,18 @@ RelativePath=".\C\Bra.h" > + + + + @@ -409,6 +432,18 @@ RelativePath=".\C\LzmaEnc.h" > + + + + + + diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index e79ae196b..611a667af 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -203,7 +203,18 @@ Note: All fields default to false unless mentioned otherwise. // sound sequence thing in the sector will override this property. hidden = ; // if true this sector will not be drawn on the textured automap. waterzone = ; // Sector is under water and swimmable - moreids = ; // Additional sector IDs/tags, specified as a space separated list of numbers (e.g. "2 666 1003 4505") + moreids = ; // Additional sector IDs/tags, specified as a space separated list of numbers (e.g. "2 666 1003 4505") + damageamount = ; // Amount of damage inflicted by this sector, default = 0. If this is 0, all other damage properties will be ignored. + // Setting damage through these properties will override any damage set through 'special'. + // Setting damageamount to a negative value will create a healing sector. + damagetype = ; // Damage type for sector damage, Default = "None". (generic damage) + damageinterval = ; // Interval in tics between damage application, default = 32. + leakiness = ; // Probability of leaking through radiation suit (0 = never, 256 = always), default = 0. + damageterraineffect = ; // Will spawn a terrain splash when damage is inflicted. Default = false. + damagehazard = ; // Changes damage model to Strife's delayed damage for the given sector. Default = false. + floorterrain = ; // Sets the terrain for the sector's floor. Default = 'use the flat texture's terrain definition.' + ceilingterrain = ; // Sets the terrain for the sector's ceiling. Default = 'use the flat texture's terrain definition.' + * Note about dropactors @@ -377,6 +388,10 @@ Changed language describing the DIALOGUE lump to mention USDF as an option. 1.25 19.04.2015 Added 'moreids' for linedefs and sectors. +1.26 05.01.2016 +added clarification about character encoding +added sector damage properties. + =============================================================================== EOF =============================================================================== diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bd353a2ed..e161a85dd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -187,6 +187,7 @@ else( WIN32 ) if( GTK2_FOUND ) set( ZDOOM_LIBS ${ZDOOM_LIBS} ${GTK2_LIBRARIES} ) include_directories( ${GTK2_INCLUDE_DIRS} ) + link_directories( ${GTK2_LIBRARY_DIRS} ) else( GTK2_FOUND ) set( NO_GTK ON ) endif( GTK2_FOUND ) @@ -590,9 +591,7 @@ set( PLAT_WIN32_SOURCES set( PLAT_POSIX_SOURCES posix/i_cd.cpp posix/i_movie.cpp - posix/i_steam.cpp - posix/i_system.cpp - posix/st_start.cpp ) + posix/i_steam.cpp ) set( PLAT_SDL_SOURCES posix/sdl/crashcatcher.c posix/sdl/hardware.cpp @@ -600,8 +599,10 @@ set( PLAT_SDL_SOURCES posix/sdl/i_input.cpp posix/sdl/i_joystick.cpp posix/sdl/i_main.cpp + posix/sdl/i_system.cpp posix/sdl/i_timer.cpp - posix/sdl/sdlvideo.cpp ) + posix/sdl/sdlvideo.cpp + posix/sdl/st_start.cpp ) set( PLAT_OSX_SOURCES posix/osx/iwadpicker_cocoa.mm posix/osx/zdoom.icns ) @@ -610,8 +611,11 @@ set( PLAT_COCOA_SOURCES posix/cocoa/i_input.mm posix/cocoa/i_joystick.cpp posix/cocoa/i_main.mm + posix/cocoa/i_system.mm posix/cocoa/i_timer.cpp - posix/cocoa/i_video.mm ) + posix/cocoa/i_video.mm + posix/cocoa/st_console.mm + posix/cocoa/st_start.mm ) if( WIN32 ) set( SYSTEM_SOURCES_DIR win32 ) @@ -914,6 +918,7 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE nodebuild_extract.cpp nodebuild_gl.cpp nodebuild_utility.cpp + pathexpander.cpp p_3dfloors.cpp p_3dmidtex.cpp p_acs.cpp @@ -993,6 +998,8 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE wi_stuff.cpp zstrformat.cpp zstring.cpp + GuillotineBinPack.cpp + SkylineBinPack.cpp g_doom/a_doommisc.cpp g_heretic/a_hereticmisc.cpp g_hexen/a_hexenmisc.cpp @@ -1090,6 +1097,7 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE sound/music_fluidsynth_mididevice.cpp sound/music_softsynth_mididevice.cpp sound/music_timidity_mididevice.cpp + sound/music_wildmidi_mididevice.cpp sound/music_win_mididevice.cpp sound/oalsound.cpp sound/sndfile_decoder.cpp @@ -1133,6 +1141,11 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE timidity/playmidi.cpp timidity/resample.cpp timidity/timidity.cpp + wildmidi/file_io.cpp + wildmidi/gus_pat.cpp + wildmidi/reverb.cpp + wildmidi/wildmidi_lib.cpp + wildmidi/wm_error.cpp xlat/parse_xlat.cpp fragglescript/t_fspic.cpp fragglescript/t_func.cpp @@ -1270,6 +1283,8 @@ source_group("Audio Files\\OPL Synth" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURC source_group("Audio Files\\OPL Synth\\DOSBox" FILES oplsynth/dosbox/opl.cpp oplsynth/dosbox/opl.h) source_group("Audio Files\\Timidity\\Headers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/timidity/.+\\.h$") source_group("Audio Files\\Timidity\\Source" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/timidity/.+\\.cpp$") +source_group("Audio Files\\WildMidi\\Headers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/wildmidi/.+\\.h$") +source_group("Audio Files\\WildMidi\\Source" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/wildmidi/.+\\.cpp$") source_group("Decorate++" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/thingdef/.+") source_group("FraggleScript" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/fragglescript/.+") source_group("Games\\Doom Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_doom/.+") diff --git a/src/GuillotineBinPack.cpp b/src/GuillotineBinPack.cpp new file mode 100644 index 000000000..57dce4501 --- /dev/null +++ b/src/GuillotineBinPack.cpp @@ -0,0 +1,643 @@ +/** @file GuillotineBinPack.cpp + @author Jukka Jylänki + + @brief Implements different bin packer algorithms that use the GUILLOTINE data structure. + + This work is released to Public Domain, do whatever you want with it. +*/ + +#include +#include +#include "templates.h" +#include "GuillotineBinPack.h" + +using namespace std; + +GuillotineBinPack::GuillotineBinPack() +:binWidth(0), +binHeight(0) +{ +} + +GuillotineBinPack::GuillotineBinPack(int width, int height) +{ + Init(width, height); +} + +void GuillotineBinPack::Init(int width, int height) +{ + binWidth = width; + binHeight = height; + +#ifdef _DEBUG + disjointRects.Clear(); +#endif + + // Clear any memory of previously packed rectangles. + usedRectangles.Clear(); + + // We start with a single big free rectangle that spans the whole bin. + Rect n; + n.x = 0; + n.y = 0; + n.width = width; + n.height = height; + + freeRectangles.Clear(); + freeRectangles.Push(n); +} + +void GuillotineBinPack::Insert(TArray &rects, TArray &dst, bool merge, + FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod) +{ + dst.Clear(); + + // Remember variables about the best packing choice we have made so far during the iteration process. + int bestFreeRect = 0; + int bestRect = 0; + bool bestFlipped = false; + + // Pack rectangles one at a time until we have cleared the rects array of all rectangles. + // rects will get destroyed in the process. + while(rects.Size() > 0) + { + // Stores the penalty score of the best rectangle placement - bigger=worse, smaller=better. + int bestScore = INT_MAX; + + for(unsigned i = 0; i < freeRectangles.Size(); ++i) + { + for(unsigned j = 0; j < rects.Size(); ++j) + { + // If this rectangle is a perfect match, we pick it instantly. + if (rects[j].width == freeRectangles[i].width && rects[j].height == freeRectangles[i].height) + { + bestFreeRect = i; + bestRect = j; + bestFlipped = false; + bestScore = INT_MIN; + i = freeRectangles.Size(); // Force a jump out of the outer loop as well - we got an instant fit. + break; + } + // If flipping this rectangle is a perfect match, pick that then. + else if (rects[j].height == freeRectangles[i].width && rects[j].width == freeRectangles[i].height) + { + bestFreeRect = i; + bestRect = j; + bestFlipped = true; + bestScore = INT_MIN; + i = freeRectangles.Size(); // Force a jump out of the outer loop as well - we got an instant fit. + break; + } + // Try if we can fit the rectangle upright. + else if (rects[j].width <= freeRectangles[i].width && rects[j].height <= freeRectangles[i].height) + { + int score = ScoreByHeuristic(rects[j].width, rects[j].height, freeRectangles[i], rectChoice); + if (score < bestScore) + { + bestFreeRect = i; + bestRect = j; + bestFlipped = false; + bestScore = score; + } + } + // If not, then perhaps flipping sideways will make it fit? + else if (rects[j].height <= freeRectangles[i].width && rects[j].width <= freeRectangles[i].height) + { + int score = ScoreByHeuristic(rects[j].height, rects[j].width, freeRectangles[i], rectChoice); + if (score < bestScore) + { + bestFreeRect = i; + bestRect = j; + bestFlipped = true; + bestScore = score; + } + } + } + } + + // If we didn't manage to find any rectangle to pack, abort. + if (bestScore == INT_MAX) + return; + + // Otherwise, we're good to go and do the actual packing. + Rect newNode; + newNode.x = freeRectangles[bestFreeRect].x; + newNode.y = freeRectangles[bestFreeRect].y; + newNode.width = rects[bestRect].width; + newNode.height = rects[bestRect].height; + + if (bestFlipped) + std::swap(newNode.width, newNode.height); + + // Remove the free space we lost in the bin. + SplitFreeRectByHeuristic(freeRectangles[bestFreeRect], newNode, splitMethod); + freeRectangles.Delete(bestFreeRect); + + // Remove the rectangle we just packed from the input list. + rects.Delete(bestRect); + + // Perform a Rectangle Merge step if desired. + if (merge) + MergeFreeList(); + + // Remember the new used rectangle. + usedRectangles.Push(newNode); + + // Check that we're really producing correct packings here. +#ifdef _DEBUG + assert(disjointRects.Add(newNode) == true); +#endif + } +} + +/// @return True if r fits inside freeRect (possibly rotated). +bool Fits(const RectSize &r, const Rect &freeRect) +{ + return (r.width <= freeRect.width && r.height <= freeRect.height) || + (r.height <= freeRect.width && r.width <= freeRect.height); +} + +/// @return True if r fits perfectly inside freeRect, i.e. the leftover area is 0. +bool FitsPerfectly(const RectSize &r, const Rect &freeRect) +{ + return (r.width == freeRect.width && r.height == freeRect.height) || + (r.height == freeRect.width && r.width == freeRect.height); +} + +/* +// A helper function for GUILLOTINE-MAXFITTING. Counts how many rectangles fit into the given rectangle +// after it has been split. +void CountNumFitting(const Rect &freeRect, int width, int height, const TArray &rects, + int usedRectIndex, bool splitHorizontal, int &score1, int &score2) +{ + const int w = freeRect.width - width; + const int h = freeRect.height - height; + + Rect bottom; + bottom.x = freeRect.x; + bottom.y = freeRect.y + height; + bottom.height = h; + + Rect right; + right.x = freeRect.x + width; + right.y = freeRect.y; + right.width = w; + + if (splitHorizontal) + { + bottom.width = freeRect.width; + right.height = height; + } + else // Split vertically + { + bottom.width = width; + right.height = freeRect.height; + } + + int fitBottom = 0; + int fitRight = 0; + for(size_t i = 0; i < rects.size(); ++i) + if (i != usedRectIndex) + { + if (FitsPerfectly(rects[i], bottom)) + fitBottom |= 0x10000000; + if (FitsPerfectly(rects[i], right)) + fitRight |= 0x10000000; + + if (Fits(rects[i], bottom)) + ++fitBottom; + if (Fits(rects[i], right)) + ++fitRight; + } + + score1 = min(fitBottom, fitRight); + score2 = max(fitBottom, fitRight); +} +*/ +/* +// Implements GUILLOTINE-MAXFITTING, an experimental heuristic that's really cool but didn't quite work in practice. +void GuillotineBinPack::InsertMaxFitting(TArray &rects, TArray &dst, bool merge, + FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod) +{ + dst.clear(); + int bestRect = 0; + bool bestFlipped = false; + bool bestSplitHorizontal = false; + + // Pick rectangles one at a time and pack the one that leaves the most choices still open. + while(rects.size() > 0 && freeRectangles.size() > 0) + { + int bestScore1 = -1; + int bestScore2 = -1; + + ///\todo Different sort predicates. + clb::sort::QuickSort(&freeRectangles[0], freeRectangles.size(), CompareRectShortSide); + + Rect &freeRect = freeRectangles[0]; + + for(size_t j = 0; j < rects.size(); ++j) + { + int score1; + int score2; + + if (rects[j].width == freeRect.width && rects[j].height == freeRect.height) + { + bestRect = j; + bestFlipped = false; + bestScore1 = bestScore2 = std::numeric_limits::max(); + break; + } + else if (rects[j].width <= freeRect.width && rects[j].height <= freeRect.height) + { + CountNumFitting(freeRect, rects[j].width, rects[j].height, rects, j, false, score1, score2); + + if (score1 > bestScore1 || (score1 == bestScore1 && score2 > bestScore2)) + { + bestRect = j; + bestScore1 = score1; + bestScore2 = score2; + bestFlipped = false; + bestSplitHorizontal = false; + } + + CountNumFitting(freeRect, rects[j].width, rects[j].height, rects, j, true, score1, score2); + + if (score1 > bestScore1 || (score1 == bestScore1 && score2 > bestScore2)) + { + bestRect = j; + bestScore1 = score1; + bestScore2 = score2; + bestFlipped = false; + bestSplitHorizontal = true; + } + } + + if (rects[j].height == freeRect.width && rects[j].width == freeRect.height) + { + bestRect = j; + bestFlipped = true; + bestScore1 = bestScore2 = std::numeric_limits::max(); + break; + } + else if (rects[j].height <= freeRect.width && rects[j].width <= freeRect.height) + { + CountNumFitting(freeRect, rects[j].height, rects[j].width, rects, j, false, score1, score2); + + if (score1 > bestScore1 || (score1 == bestScore1 && score2 > bestScore2)) + { + bestRect = j; + bestScore1 = score1; + bestScore2 = score2; + bestFlipped = true; + bestSplitHorizontal = false; + } + + CountNumFitting(freeRect, rects[j].height, rects[j].width, rects, j, true, score1, score2); + + if (score1 > bestScore1 || (score1 == bestScore1 && score2 > bestScore2)) + { + bestRect = j; + bestScore1 = score1; + bestScore2 = score2; + bestFlipped = true; + bestSplitHorizontal = true; + } + } + } + + if (bestScore1 >= 0) + { + Rect newNode; + newNode.x = freeRect.x; + newNode.y = freeRect.y; + newNode.width = rects[bestRect].width; + newNode.height = rects[bestRect].height; + if (bestFlipped) + std::swap(newNode.width, newNode.height); + + assert(disjointRects.Disjoint(newNode)); + SplitFreeRectAlongAxis(freeRect, newNode, bestSplitHorizontal); + + rects.erase(rects.begin() + bestRect); + + if (merge) + MergeFreeList(); + + usedRectangles.push_back(newNode); +#ifdef _DEBUG + disjointRects.Add(newNode); +#endif + } + + freeRectangles.erase(freeRectangles.begin()); + } +} +*/ + +Rect GuillotineBinPack::Insert(int width, int height, bool merge, FreeRectChoiceHeuristic rectChoice, + GuillotineSplitHeuristic splitMethod) +{ + // Find where to put the new rectangle. + int freeNodeIndex = 0; + Rect newRect = FindPositionForNewNode(width, height, rectChoice, &freeNodeIndex); + + // Abort if we didn't have enough space in the bin. + if (newRect.height == 0) + return newRect; + + // Remove the space that was just consumed by the new rectangle. + SplitFreeRectByHeuristic(freeRectangles[freeNodeIndex], newRect, splitMethod); + freeRectangles.Delete(freeNodeIndex); + + // Perform a Rectangle Merge step if desired. + if (merge) + MergeFreeList(); + + // Remember the new used rectangle. + usedRectangles.Push(newRect); + + // Check that we're really producing correct packings here. +#ifdef _DEBUG + assert(disjointRects.Add(newRect) == true); +#endif + return newRect; +} + +/// Computes the ratio of used surface area to the total bin area. +float GuillotineBinPack::Occupancy() const +{ + ///\todo The occupancy rate could be cached/tracked incrementally instead + /// of looping through the list of packed rectangles here. + unsigned long usedSurfaceArea = 0; + for(unsigned i = 0; i < usedRectangles.Size(); ++i) + usedSurfaceArea += usedRectangles[i].width * usedRectangles[i].height; + + return (float)usedSurfaceArea / (binWidth * binHeight); +} + +/// Returns the heuristic score value for placing a rectangle of size width*height into freeRect. Does not try to rotate. +int GuillotineBinPack::ScoreByHeuristic(int width, int height, const Rect &freeRect, FreeRectChoiceHeuristic rectChoice) +{ + switch(rectChoice) + { + case RectBestAreaFit: return ScoreBestAreaFit(width, height, freeRect); + case RectBestShortSideFit: return ScoreBestShortSideFit(width, height, freeRect); + case RectBestLongSideFit: return ScoreBestLongSideFit(width, height, freeRect); + case RectWorstAreaFit: return ScoreWorstAreaFit(width, height, freeRect); + case RectWorstShortSideFit: return ScoreWorstShortSideFit(width, height, freeRect); + case RectWorstLongSideFit: return ScoreWorstLongSideFit(width, height, freeRect); + default: assert(false); return INT_MAX; + } +} + +int GuillotineBinPack::ScoreBestAreaFit(int width, int height, const Rect &freeRect) +{ + return freeRect.width * freeRect.height - width * height; +} + +int GuillotineBinPack::ScoreBestShortSideFit(int width, int height, const Rect &freeRect) +{ + int leftoverHoriz = abs(freeRect.width - width); + int leftoverVert = abs(freeRect.height - height); + int leftover = MIN(leftoverHoriz, leftoverVert); + return leftover; +} + +int GuillotineBinPack::ScoreBestLongSideFit(int width, int height, const Rect &freeRect) +{ + int leftoverHoriz = abs(freeRect.width - width); + int leftoverVert = abs(freeRect.height - height); + int leftover = MAX(leftoverHoriz, leftoverVert); + return leftover; +} + +int GuillotineBinPack::ScoreWorstAreaFit(int width, int height, const Rect &freeRect) +{ + return -ScoreBestAreaFit(width, height, freeRect); +} + +int GuillotineBinPack::ScoreWorstShortSideFit(int width, int height, const Rect &freeRect) +{ + return -ScoreBestShortSideFit(width, height, freeRect); +} + +int GuillotineBinPack::ScoreWorstLongSideFit(int width, int height, const Rect &freeRect) +{ + return -ScoreBestLongSideFit(width, height, freeRect); +} + +Rect GuillotineBinPack::FindPositionForNewNode(int width, int height, FreeRectChoiceHeuristic rectChoice, int *nodeIndex) +{ + Rect bestNode; + memset(&bestNode, 0, sizeof(Rect)); + + int bestScore = INT_MAX; + + /// Try each free rectangle to find the best one for placement. + for(unsigned i = 0; i < freeRectangles.Size(); ++i) + { + // If this is a perfect fit upright, choose it immediately. + if (width == freeRectangles[i].width && height == freeRectangles[i].height) + { + bestNode.x = freeRectangles[i].x; + bestNode.y = freeRectangles[i].y; + bestNode.width = width; + bestNode.height = height; + bestScore = INT_MIN; + *nodeIndex = i; +#ifdef _DEBUG + assert(disjointRects.Disjoint(bestNode)); +#endif + break; + } + // If this is a perfect fit sideways, choose it. +/* else if (height == freeRectangles[i].width && width == freeRectangles[i].height) + { + bestNode.x = freeRectangles[i].x; + bestNode.y = freeRectangles[i].y; + bestNode.width = height; + bestNode.height = width; + bestScore = INT_MIN; + *nodeIndex = i; + assert(disjointRects.Disjoint(bestNode)); + break; + } +*/ // Does the rectangle fit upright? + else if (width <= freeRectangles[i].width && height <= freeRectangles[i].height) + { + int score = ScoreByHeuristic(width, height, freeRectangles[i], rectChoice); + + if (score < bestScore) + { + bestNode.x = freeRectangles[i].x; + bestNode.y = freeRectangles[i].y; + bestNode.width = width; + bestNode.height = height; + bestScore = score; + *nodeIndex = i; +#ifdef _DEBUG + assert(disjointRects.Disjoint(bestNode)); +#endif + } + } + // Does the rectangle fit sideways? +/* else if (height <= freeRectangles[i].width && width <= freeRectangles[i].height) + { + int score = ScoreByHeuristic(height, width, freeRectangles[i], rectChoice); + + if (score < bestScore) + { + bestNode.x = freeRectangles[i].x; + bestNode.y = freeRectangles[i].y; + bestNode.width = height; + bestNode.height = width; + bestScore = score; + *nodeIndex = i; + assert(disjointRects.Disjoint(bestNode)); + } + } +*/ } + return bestNode; +} + +void GuillotineBinPack::SplitFreeRectByHeuristic(const Rect &freeRect, const Rect &placedRect, GuillotineSplitHeuristic method) +{ + // Compute the lengths of the leftover area. + const int w = freeRect.width - placedRect.width; + const int h = freeRect.height - placedRect.height; + + // Placing placedRect into freeRect results in an L-shaped free area, which must be split into + // two disjoint rectangles. This can be achieved with by splitting the L-shape using a single line. + // We have two choices: horizontal or vertical. + + // Use the given heuristic to decide which choice to make. + + bool splitHorizontal; + switch(method) + { + case SplitShorterLeftoverAxis: + // Split along the shorter leftover axis. + splitHorizontal = (w <= h); + break; + case SplitLongerLeftoverAxis: + // Split along the longer leftover axis. + splitHorizontal = (w > h); + break; + case SplitMinimizeArea: + // Maximize the larger area == minimize the smaller area. + // Tries to make the single bigger rectangle. + splitHorizontal = (placedRect.width * h > w * placedRect.height); + break; + case SplitMaximizeArea: + // Maximize the smaller area == minimize the larger area. + // Tries to make the rectangles more even-sized. + splitHorizontal = (placedRect.width * h <= w * placedRect.height); + break; + case SplitShorterAxis: + // Split along the shorter total axis. + splitHorizontal = (freeRect.width <= freeRect.height); + break; + case SplitLongerAxis: + // Split along the longer total axis. + splitHorizontal = (freeRect.width > freeRect.height); + break; + default: + splitHorizontal = true; + assert(false); + } + + // Perform the actual split. + SplitFreeRectAlongAxis(freeRect, placedRect, splitHorizontal); +} + +/// This function will add the two generated rectangles into the freeRectangles array. The caller is expected to +/// remove the original rectangle from the freeRectangles array after that. +void GuillotineBinPack::SplitFreeRectAlongAxis(const Rect &freeRect, const Rect &placedRect, bool splitHorizontal) +{ + // Form the two new rectangles. + Rect bottom; + bottom.x = freeRect.x; + bottom.y = freeRect.y + placedRect.height; + bottom.height = freeRect.height - placedRect.height; + + Rect right; + right.x = freeRect.x + placedRect.width; + right.y = freeRect.y; + right.width = freeRect.width - placedRect.width; + + if (splitHorizontal) + { + bottom.width = freeRect.width; + right.height = placedRect.height; + } + else // Split vertically + { + bottom.width = placedRect.width; + right.height = freeRect.height; + } + + // Add the new rectangles into the free rectangle pool if they weren't degenerate. + if (bottom.width > 0 && bottom.height > 0) + freeRectangles.Push(bottom); + if (right.width > 0 && right.height > 0) + freeRectangles.Push(right); + +#ifdef _DEBUG + assert(disjointRects.Disjoint(bottom)); + assert(disjointRects.Disjoint(right)); +#endif +} + +void GuillotineBinPack::MergeFreeList() +{ +#ifdef _DEBUG + DisjointRectCollection test; + for(unsigned i = 0; i < freeRectangles.Size(); ++i) + assert(test.Add(freeRectangles[i]) == true); +#endif + + // Do a Theta(n^2) loop to see if any pair of free rectangles could me merged into one. + // Note that we miss any opportunities to merge three rectangles into one. (should call this function again to detect that) + for(unsigned i = 0; i < freeRectangles.Size(); ++i) + for(unsigned j = i+1; j < freeRectangles.Size(); ++j) + { + if (freeRectangles[i].width == freeRectangles[j].width && freeRectangles[i].x == freeRectangles[j].x) + { + if (freeRectangles[i].y == freeRectangles[j].y + freeRectangles[j].height) + { + freeRectangles[i].y -= freeRectangles[j].height; + freeRectangles[i].height += freeRectangles[j].height; + freeRectangles.Delete(j); + --j; + } + else if (freeRectangles[i].y + freeRectangles[i].height == freeRectangles[j].y) + { + freeRectangles[i].height += freeRectangles[j].height; + freeRectangles.Delete(j); + --j; + } + } + else if (freeRectangles[i].height == freeRectangles[j].height && freeRectangles[i].y == freeRectangles[j].y) + { + if (freeRectangles[i].x == freeRectangles[j].x + freeRectangles[j].width) + { + freeRectangles[i].x -= freeRectangles[j].width; + freeRectangles[i].width += freeRectangles[j].width; + freeRectangles.Delete(j); + --j; + } + else if (freeRectangles[i].x + freeRectangles[i].width == freeRectangles[j].x) + { + freeRectangles[i].width += freeRectangles[j].width; + freeRectangles.Delete(j); + --j; + } + } + } + +#ifdef _DEBUG + test.Clear(); + for(unsigned i = 0; i < freeRectangles.Size(); ++i) + assert(test.Add(freeRectangles[i]) == true); +#endif +} diff --git a/src/GuillotineBinPack.h b/src/GuillotineBinPack.h new file mode 100644 index 000000000..54cd77a9e --- /dev/null +++ b/src/GuillotineBinPack.h @@ -0,0 +1,135 @@ +/** @file GuillotineBinPack.h + @author Jukka Jylänki + + @brief Implements different bin packer algorithms that use the GUILLOTINE data structure. + + This work is released to Public Domain, do whatever you want with it. +*/ +#pragma once + +#include "tarray.h" + +#include "Rect.h" + +/** GuillotineBinPack implements different variants of bin packer algorithms that use the GUILLOTINE data structure + to keep track of the free space of the bin where rectangles may be placed. */ +class GuillotineBinPack +{ +public: + /// The initial bin size will be (0,0). Call Init to set the bin size. + GuillotineBinPack(); + + /// Initializes a new bin of the given size. + GuillotineBinPack(int width, int height); + + /// (Re)initializes the packer to an empty bin of width x height units. Call whenever + /// you need to restart with a new bin. + void Init(int width, int height); + + /// Specifies the different choice heuristics that can be used when deciding which of the free subrectangles + /// to place the to-be-packed rectangle into. + enum FreeRectChoiceHeuristic + { + RectBestAreaFit, ///< -BAF + RectBestShortSideFit, ///< -BSSF + RectBestLongSideFit, ///< -BLSF + RectWorstAreaFit, ///< -WAF + RectWorstShortSideFit, ///< -WSSF + RectWorstLongSideFit ///< -WLSF + }; + + /// Specifies the different choice heuristics that can be used when the packer needs to decide whether to + /// subdivide the remaining free space in horizontal or vertical direction. + enum GuillotineSplitHeuristic + { + SplitShorterLeftoverAxis, ///< -SLAS + SplitLongerLeftoverAxis, ///< -LLAS + SplitMinimizeArea, ///< -MINAS, Try to make a single big rectangle at the expense of making the other small. + SplitMaximizeArea, ///< -MAXAS, Try to make both remaining rectangles as even-sized as possible. + SplitShorterAxis, ///< -SAS + SplitLongerAxis ///< -LAS + }; + + /// Inserts a single rectangle into the bin. The packer might rotate the rectangle, in which case the returned + /// struct will have the width and height values swapped. + /// @param merge If true, performs free Rectangle Merge procedure after packing the new rectangle. This procedure + /// tries to defragment the list of disjoint free rectangles to improve packing performance, but also takes up + /// some extra time. + /// @param rectChoice The free rectangle choice heuristic rule to use. + /// @param splitMethod The free rectangle split heuristic rule to use. + Rect Insert(int width, int height, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod); + + /// Inserts a list of rectangles into the bin. + /// @param rects The list of rectangles to add. This list will be destroyed in the packing process. + /// @param dst The outputted list of rectangles. Note that the indices will not correspond to the input indices. + /// @param merge If true, performs Rectangle Merge operations during the packing process. + /// @param rectChoice The free rectangle choice heuristic rule to use. + /// @param splitMethod The free rectangle split heuristic rule to use. + void Insert(TArray &rects, TArray &dst, bool merge, + FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod); + +// Implements GUILLOTINE-MAXFITTING, an experimental heuristic that's really cool but didn't quite work in practice. +// void InsertMaxFitting(TArray &rects, TArray &dst, bool merge, +// FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod); + + /// Computes the ratio of used/total surface area. 0.00 means no space is yet used, 1.00 means the whole bin is used. + float Occupancy() const; + + /// Returns the internal list of disjoint rectangles that track the free area of the bin. You may alter this vector + /// any way desired, as long as the end result still is a list of disjoint rectangles. + TArray &GetFreeRectangles() { return freeRectangles; } + + /// Returns the list of packed rectangles. You may alter this vector at will, for example, you can move a Rect from + /// this list to the Free Rectangles list to free up space on-the-fly, but notice that this causes fragmentation. + TArray &GetUsedRectangles() { return usedRectangles; } + + /// Performs a Rectangle Merge operation. This procedure looks for adjacent free rectangles and merges them if they + /// can be represented with a single rectangle. Takes up Theta(|freeRectangles|^2) time. + void MergeFreeList(); + +#ifdef _DEBUG + void DelDisjoint(const Rect &r) { disjointRects.Del(r); } +#endif + +private: + int binWidth; + int binHeight; + + /// Stores a list of all the rectangles that we have packed so far. This is used only to compute the Occupancy ratio, + /// so if you want to have the packer consume less memory, this can be removed. + TArray usedRectangles; + + /// Stores a list of rectangles that represents the free area of the bin. This rectangles in this list are disjoint. + TArray freeRectangles; + +#ifdef _DEBUG + /// Used to track that the packer produces proper packings. + DisjointRectCollection disjointRects; +#endif + + /// Goes through the list of free rectangles and finds the best one to place a rectangle of given size into. + /// Running time is Theta(|freeRectangles|). + /// @param nodeIndex [out] The index of the free rectangle in the freeRectangles array into which the new + /// rect was placed. + /// @return A Rect structure that represents the placement of the new rect into the best free rectangle. + Rect FindPositionForNewNode(int width, int height, FreeRectChoiceHeuristic rectChoice, int *nodeIndex); + + static int ScoreByHeuristic(int width, int height, const Rect &freeRect, FreeRectChoiceHeuristic rectChoice); + // The following functions compute (penalty) score values if a rect of the given size was placed into the + // given free rectangle. In these score values, smaller is better. + + static int ScoreBestAreaFit(int width, int height, const Rect &freeRect); + static int ScoreBestShortSideFit(int width, int height, const Rect &freeRect); + static int ScoreBestLongSideFit(int width, int height, const Rect &freeRect); + + static int ScoreWorstAreaFit(int width, int height, const Rect &freeRect); + static int ScoreWorstShortSideFit(int width, int height, const Rect &freeRect); + static int ScoreWorstLongSideFit(int width, int height, const Rect &freeRect); + + /// Splits the given L-shaped free rectangle into two new free rectangles after placedRect has been placed into it. + /// Determines the split axis by using the given heuristic. + void SplitFreeRectByHeuristic(const Rect &freeRect, const Rect &placedRect, GuillotineSplitHeuristic method); + + /// Splits the given L-shaped free rectangle into two new free rectangles along the given fixed split axis. + void SplitFreeRectAlongAxis(const Rect &freeRect, const Rect &placedRect, bool splitHorizontal); +}; diff --git a/src/Rect.h b/src/Rect.h new file mode 100644 index 000000000..8b7ba1e2a --- /dev/null +++ b/src/Rect.h @@ -0,0 +1,94 @@ +/** @file Rect.h + @author Jukka Jylänki + + This work is released to Public Domain, do whatever you want with it. +*/ +#pragma once + +#include + +struct RectSize +{ + int width; + int height; +}; + +struct Rect +{ + int x; + int y; + int width; + int height; +}; + +/// Performs a lexicographic compare on (rect short side, rect long side). +/// @return -1 if the smaller side of a is shorter than the smaller side of b, 1 if the other way around. +/// If they are equal, the larger side length is used as a tie-breaker. +/// If the rectangles are of same size, returns 0. +int CompareRectShortSide(const Rect &a, const Rect &b); + +/// Performs a lexicographic compare on (x, y, width, height). +int NodeSortCmp(const Rect &a, const Rect &b); + +/// Returns true if a is contained in b. +bool IsContainedIn(const Rect &a, const Rect &b); + +#ifdef _DEBUG +class DisjointRectCollection +{ +public: + TArray rects; + + bool Add(const Rect &r) + { + // Degenerate rectangles are ignored. + if (r.width == 0 || r.height == 0) + return true; + + if (!Disjoint(r)) + return false; + rects.Push(r); + return true; + } + + bool Del(const Rect &r) + { + for(unsigned i = 0; i < rects.Size(); ++i) + { + if(r.x == rects[i].x && r.y == rects[i].y && r.width == rects[i].width && r.height == rects[i].height) + { + rects.Delete(i); + return true; + } + } + return false; + } + + void Clear() + { + rects.Clear(); + } + + bool Disjoint(const Rect &r) const + { + // Degenerate rectangles are ignored. + if (r.width == 0 || r.height == 0) + return true; + + for(unsigned i = 0; i < rects.Size(); ++i) + if (!Disjoint(rects[i], r)) + return false; + return true; + } + + static bool Disjoint(const Rect &a, const Rect &b) + { + if (a.x + a.width <= b.x || + b.x + b.width <= a.x || + a.y + a.height <= b.y || + b.y + b.height <= a.y) + return true; + return false; + } +}; +#endif diff --git a/src/SkylineBinPack.cpp b/src/SkylineBinPack.cpp new file mode 100644 index 000000000..d63610370 --- /dev/null +++ b/src/SkylineBinPack.cpp @@ -0,0 +1,412 @@ +/** @file SkylineBinPack.cpp + @author Jukka Jylänki + + @brief Implements different bin packer algorithms that use the SKYLINE data structure. + + This work is released to Public Domain, do whatever you want with it. +*/ + +#include +#include +#include "templates.h" + +#include "SkylineBinPack.h" + +using namespace std; + +SkylineBinPack::SkylineBinPack() +:binWidth(0), +binHeight(0) +{ +} + +SkylineBinPack::SkylineBinPack(int width, int height, bool useWasteMap) +{ + Init(width, height, useWasteMap); +} + +void SkylineBinPack::Init(int width, int height, bool useWasteMap_) +{ + binWidth = width; + binHeight = height; + + useWasteMap = useWasteMap_; + +#ifdef _DEBUG + disjointRects.Clear(); +#endif + + usedSurfaceArea = 0; + skyLine.Clear(); + SkylineNode node; + node.x = 0; + node.y = 0; + node.width = binWidth; + skyLine.Push(node); + + if (useWasteMap) + { + wasteMap.Init(width, height); + wasteMap.GetFreeRectangles().Clear(); + } +} + +void SkylineBinPack::Insert(TArray &rects, TArray &dst) +{ + dst.Clear(); + + while(rects.Size() > 0) + { + Rect bestNode; + int bestScore1 = INT_MAX; + int bestScore2 = INT_MAX; + int bestSkylineIndex = -1; + int bestRectIndex = -1; + for(unsigned i = 0; i < rects.Size(); ++i) + { + Rect newNode; + int score1; + int score2; + int index; + newNode = FindPositionForNewNodeMinWaste(rects[i].width, rects[i].height, score2, score1, index); +#ifdef _DEBUG + assert(disjointRects.Disjoint(newNode)); +#endif + if (newNode.height != 0) + { + if (score1 < bestScore1 || (score1 == bestScore1 && score2 < bestScore2)) + { + bestNode = newNode; + bestScore1 = score1; + bestScore2 = score2; + bestSkylineIndex = index; + bestRectIndex = i; + } + } + } + + if (bestRectIndex == -1) + return; + + // Perform the actual packing. +#ifdef _DEBUG + assert(disjointRects.Disjoint(bestNode)); + disjointRects.Add(bestNode); +#endif + AddSkylineLevel(bestSkylineIndex, bestNode); + usedSurfaceArea += rects[bestRectIndex].width * rects[bestRectIndex].height; + rects.Delete(bestRectIndex); + dst.Push(bestNode); + } +} + +Rect SkylineBinPack::Insert(int width, int height) +{ + // First try to pack this rectangle into the waste map, if it fits. + Rect node = wasteMap.Insert(width, height, true, GuillotineBinPack::RectBestShortSideFit, + GuillotineBinPack::SplitMaximizeArea); +#ifdef _DEBUG + assert(disjointRects.Disjoint(node)); +#endif + + if (node.height != 0) + { + Rect newNode; + newNode.x = node.x; + newNode.y = node.y; + newNode.width = node.width; + newNode.height = node.height; + usedSurfaceArea += width * height; +#ifdef _DEBUG + assert(disjointRects.Disjoint(newNode)); + disjointRects.Add(newNode); +#endif + return newNode; + } + + return InsertBottomLeft(width, height); +} + +bool SkylineBinPack::RectangleFits(int skylineNodeIndex, int width, int height, int &y) const +{ + int x = skyLine[skylineNodeIndex].x; + if (x + width > binWidth) + return false; + int widthLeft = width; + int i = skylineNodeIndex; + y = skyLine[skylineNodeIndex].y; + while(widthLeft > 0) + { + y = MAX(y, skyLine[i].y); + if (y + height > binHeight) + return false; + widthLeft -= skyLine[i].width; + ++i; + assert(i < (int)skyLine.Size() || widthLeft <= 0); + } + return true; +} + +int SkylineBinPack::ComputeWastedArea(int skylineNodeIndex, int width, int height, int y) const +{ + int wastedArea = 0; + const int rectLeft = skyLine[skylineNodeIndex].x; + const int rectRight = rectLeft + width; + for(; skylineNodeIndex < (int)skyLine.Size() && skyLine[skylineNodeIndex].x < rectRight; ++skylineNodeIndex) + { + if (skyLine[skylineNodeIndex].x >= rectRight || skyLine[skylineNodeIndex].x + skyLine[skylineNodeIndex].width <= rectLeft) + break; + + int leftSide = skyLine[skylineNodeIndex].x; + int rightSide = MIN(rectRight, leftSide + skyLine[skylineNodeIndex].width); + assert(y >= skyLine[skylineNodeIndex].y); + wastedArea += (rightSide - leftSide) * (y - skyLine[skylineNodeIndex].y); + } + return wastedArea; +} + +bool SkylineBinPack::RectangleFits(int skylineNodeIndex, int width, int height, int &y, int &wastedArea) const +{ + bool fits = RectangleFits(skylineNodeIndex, width, height, y); + if (fits) + wastedArea = ComputeWastedArea(skylineNodeIndex, width, height, y); + + return fits; +} + +void SkylineBinPack::AddWasteMapArea(int skylineNodeIndex, int width, int height, int y) +{ + int wastedArea = 0; + const int rectLeft = skyLine[skylineNodeIndex].x; + const int rectRight = rectLeft + width; + for(; skylineNodeIndex < (int)skyLine.Size() && skyLine[skylineNodeIndex].x < rectRight; ++skylineNodeIndex) + { + if (skyLine[skylineNodeIndex].x >= rectRight || skyLine[skylineNodeIndex].x + skyLine[skylineNodeIndex].width <= rectLeft) + break; + + int leftSide = skyLine[skylineNodeIndex].x; + int rightSide = MIN(rectRight, leftSide + skyLine[skylineNodeIndex].width); + assert(y >= skyLine[skylineNodeIndex].y); + + Rect waste; + waste.x = leftSide; + waste.y = skyLine[skylineNodeIndex].y; + waste.width = rightSide - leftSide; + waste.height = y - skyLine[skylineNodeIndex].y; + +#ifdef _DEBUG + assert(disjointRects.Disjoint(waste)); +#endif + wasteMap.GetFreeRectangles().Push(waste); + } +} + +void SkylineBinPack::AddWaste(const Rect &waste) +{ + wasteMap.GetFreeRectangles().Push(waste); +#ifdef _DEBUG + disjointRects.Del(waste); + wasteMap.DelDisjoint(waste); +#endif +} + +void SkylineBinPack::AddSkylineLevel(int skylineNodeIndex, const Rect &rect) +{ + // First track all wasted areas and mark them into the waste map if we're using one. + if (useWasteMap) + AddWasteMapArea(skylineNodeIndex, rect.width, rect.height, rect.y); + + SkylineNode newNode; + newNode.x = rect.x; + newNode.y = rect.y + rect.height; + newNode.width = rect.width; + skyLine.Insert(skylineNodeIndex, newNode); + + assert(newNode.x + newNode.width <= binWidth); + assert(newNode.y <= binHeight); + + for(unsigned i = skylineNodeIndex+1; i < skyLine.Size(); ++i) + { + assert(skyLine[i-1].x <= skyLine[i].x); + + if (skyLine[i].x < skyLine[i-1].x + skyLine[i-1].width) + { + int shrink = skyLine[i-1].x + skyLine[i-1].width - skyLine[i].x; + + skyLine[i].x += shrink; + skyLine[i].width -= shrink; + + if (skyLine[i].width <= 0) + { + skyLine.Delete(i); + --i; + } + else + break; + } + else + break; + } + MergeSkylines(); +} + +void SkylineBinPack::MergeSkylines() +{ + for(unsigned i = 0; i < skyLine.Size()-1; ++i) + if (skyLine[i].y == skyLine[i+1].y) + { + skyLine[i].width += skyLine[i+1].width; + skyLine.Delete(i+1); + --i; + } +} + +Rect SkylineBinPack::InsertBottomLeft(int width, int height) +{ + int bestHeight; + int bestWidth; + int bestIndex; + Rect newNode = FindPositionForNewNodeBottomLeft(width, height, bestHeight, bestWidth, bestIndex); + + if (bestIndex != -1) + { +#ifdef _DEBUG + assert(disjointRects.Disjoint(newNode)); +#endif + // Perform the actual packing. + AddSkylineLevel(bestIndex, newNode); + + usedSurfaceArea += width * height; +#ifdef _DEBUG + disjointRects.Add(newNode); +#endif + } + else + memset(&newNode, 0, sizeof(Rect)); + + return newNode; +} + +Rect SkylineBinPack::FindPositionForNewNodeBottomLeft(int width, int height, int &bestHeight, int &bestWidth, int &bestIndex) const +{ + bestHeight = INT_MAX; + bestIndex = -1; + // Used to break ties if there are nodes at the same level. Then pick the narrowest one. + bestWidth = INT_MAX; + Rect newNode = { 0, 0, 0, 0 }; + for(unsigned i = 0; i < skyLine.Size(); ++i) + { + int y; + if (RectangleFits(i, width, height, y)) + { + if (y + height < bestHeight || (y + height == bestHeight && skyLine[i].width < bestWidth)) + { + bestHeight = y + height; + bestIndex = i; + bestWidth = skyLine[i].width; + newNode.x = skyLine[i].x; + newNode.y = y; + newNode.width = width; + newNode.height = height; +#ifdef _DEBUG + assert(disjointRects.Disjoint(newNode)); +#endif + } + } +/* if (RectangleFits(i, height, width, y)) + { + if (y + width < bestHeight || (y + width == bestHeight && skyLine[i].width < bestWidth)) + { + bestHeight = y + width; + bestIndex = i; + bestWidth = skyLine[i].width; + newNode.x = skyLine[i].x; + newNode.y = y; + newNode.width = height; + newNode.height = width; + assert(disjointRects.Disjoint(newNode)); + } + } +*/ } + + return newNode; +} + +Rect SkylineBinPack::InsertMinWaste(int width, int height) +{ + int bestHeight; + int bestWastedArea; + int bestIndex; + Rect newNode = FindPositionForNewNodeMinWaste(width, height, bestHeight, bestWastedArea, bestIndex); + + if (bestIndex != -1) + { +#ifdef _DEBUG + assert(disjointRects.Disjoint(newNode)); +#endif + // Perform the actual packing. + AddSkylineLevel(bestIndex, newNode); + + usedSurfaceArea += width * height; +#ifdef _DEBUG + disjointRects.Add(newNode); +#endif + } + else + memset(&newNode, 0, sizeof(newNode)); + + return newNode; +} + +Rect SkylineBinPack::FindPositionForNewNodeMinWaste(int width, int height, int &bestHeight, int &bestWastedArea, int &bestIndex) const +{ + bestHeight = INT_MAX; + bestWastedArea = INT_MAX; + bestIndex = -1; + Rect newNode; + memset(&newNode, 0, sizeof(newNode)); + for(unsigned i = 0; i < skyLine.Size(); ++i) + { + int y; + int wastedArea; + + if (RectangleFits(i, width, height, y, wastedArea)) + { + if (wastedArea < bestWastedArea || (wastedArea == bestWastedArea && y + height < bestHeight)) + { + bestHeight = y + height; + bestWastedArea = wastedArea; + bestIndex = i; + newNode.x = skyLine[i].x; + newNode.y = y; + newNode.width = width; + newNode.height = height; +#ifdef _DEBUG + assert(disjointRects.Disjoint(newNode)); +#endif + } + } +/* if (RectangleFits(i, height, width, y, wastedArea)) + { + if (wastedArea < bestWastedArea || (wastedArea == bestWastedArea && y + width < bestHeight)) + { + bestHeight = y + width; + bestWastedArea = wastedArea; + bestIndex = i; + newNode.x = skyLine[i].x; + newNode.y = y; + newNode.width = height; + newNode.height = width; + assert(disjointRects.Disjoint(newNode)); + } + }*/ + } + + return newNode; +} + +/// Computes the ratio of used surface area. +float SkylineBinPack::Occupancy() const +{ + return (float)usedSurfaceArea / (binWidth * binHeight); +} diff --git a/src/SkylineBinPack.h b/src/SkylineBinPack.h new file mode 100644 index 000000000..937c88de6 --- /dev/null +++ b/src/SkylineBinPack.h @@ -0,0 +1,91 @@ +/** @file SkylineBinPack.h + @author Jukka Jylänki + + @brief Implements different bin packer algorithms that use the SKYLINE data structure. + + This work is released to Public Domain, do whatever you want with it. +*/ +#pragma once + +#include "tarray.h" + +#include "Rect.h" +#include "GuillotineBinPack.h" + +/** Implements bin packing algorithms that use the SKYLINE data structure to store the bin contents. Uses + GuillotineBinPack as the waste map. */ +class SkylineBinPack +{ +public: + /// Instantiates a bin of size (0,0). Call Init to create a new bin. + SkylineBinPack(); + + /// Instantiates a bin of the given size. + SkylineBinPack(int binWidth, int binHeight, bool useWasteMap); + + /// (Re)initializes the packer to an empty bin of width x height units. Call whenever + /// you need to restart with a new bin. + void Init(int binWidth, int binHeight, bool useWasteMap); + + /// Inserts the given list of rectangles in an offline/batch mode, possibly rotated. + /// @param rects The list of rectangles to insert. This vector will be destroyed in the process. + /// @param dst [out] This list will contain the packed rectangles. The indices will not correspond to that of rects. + /// @param method The rectangle placement rule to use when packing. + void Insert(TArray &rects, TArray &dst); + + /// Inserts a single rectangle into the bin, possibly rotated. + Rect Insert(int width, int height); + + /// Adds a rectangle to the waste list. It must have been previously returned by + /// Insert or the results are undefined. + void AddWaste(const Rect &rect); + + /// Computes the ratio of used surface area to the total bin area. + float Occupancy() const; + +private: + int binWidth; + int binHeight; + +#ifdef _DEBUG + DisjointRectCollection disjointRects; +#endif + + /// Represents a single level (a horizontal line) of the skyline/horizon/envelope. + struct SkylineNode + { + /// The starting x-coordinate (leftmost). + int x; + + /// The y-coordinate of the skyline level line. + int y; + + /// The line width. The ending coordinate (inclusive) will be x+width-1. + int width; + }; + + TArray skyLine; + + unsigned long usedSurfaceArea; + + /// If true, we use the GuillotineBinPack structure to recover wasted areas into a waste map. + bool useWasteMap; + GuillotineBinPack wasteMap; + + Rect InsertBottomLeft(int width, int height); + Rect InsertMinWaste(int width, int height); + + Rect FindPositionForNewNodeBottomLeft(int width, int height, int &bestHeight, int &bestWidth, int &bestIndex) const; + Rect FindPositionForNewNodeMinWaste(int width, int height, int &bestHeight, int &bestWastedArea, int &bestIndex) const; + + bool RectangleFits(int skylineNodeIndex, int width, int height, int &y) const; + bool RectangleFits(int skylineNodeIndex, int width, int height, int &y, int &wastedArea) const; + int ComputeWastedArea(int skylineNodeIndex, int width, int height, int y) const; + + void AddWasteMapArea(int skylineNodeIndex, int width, int height, int y); + + void AddSkylineLevel(int skylineNodeIndex, const Rect &rect); + + /// Merges all skyline nodes that are at the same level. + void MergeSkylines(); +}; diff --git a/src/actor.h b/src/actor.h index 468dcc0c6..dc9c29e7c 100644 --- a/src/actor.h +++ b/src/actor.h @@ -588,6 +588,36 @@ enum AMETA_BloodType3, // AxeBlood replacement type }; +struct fixedvec3 +{ + fixed_t x, y, z; + + operator FVector3() + { + return FVector3(FIXED2FLOAT(x), FIXED2FLOAT(y), FIXED2FLOAT(z)); + } + + operator TVector3() + { + return TVector3(FIXED2DBL(x), FIXED2DBL(y), FIXED2DBL(z)); + } +}; + +struct fixedvec2 +{ + fixed_t x, y; + + operator FVector2() + { + return FVector2(FIXED2FLOAT(x), FIXED2FLOAT(y)); + } + + operator TVector2() + { + return TVector2(FIXED2DBL(x), FIXED2DBL(y)); + } +}; + struct FDropItem { FName Name; @@ -611,7 +641,8 @@ extern FDropItemPtrArray DropItemList; void FreeDropItemChain(FDropItem *chain); int StoreDropItemChain(FDropItem *chain); - +fixed_t P_AproxDistance (fixed_t dx, fixed_t dy); // since we cannot include p_local here... +angle_t R_PointToAngle2 (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2); // same reason here with r_defs.h // Map Object definition. @@ -813,12 +844,6 @@ public: return (flags & MF_COUNTKILL) && !(flags & MF_FRIENDLY); } - bool intersects(AActor *other) const - { - fixed_t blockdist = radius + other->radius; - return ( abs(x - other->x) < blockdist && abs(y - other->y) < blockdist); - } - PalEntry GetBloodColor() const { return (PalEntry)GetClass()->Meta.GetMetaInt(AMETA_BloodColor); @@ -853,6 +878,116 @@ public: return bloodcls; } + bool intersects(AActor *other) const + { + fixed_t blockdist = radius + other->radius; + return ( abs(X() - other->Y()) < blockdist && abs(Y() - other->Y()) < blockdist); + } + + // 'absolute' is reserved for a linked portal implementation which needs + // to distinguish between portal-aware and portal-unaware distance calculation. + fixed_t AproxDistance(AActor *other, bool absolute = false) + { + return P_AproxDistance(X() - other->X(), Y() - other->Y()); + } + + // same with 'ref' here. + fixed_t AproxDistance(fixed_t otherx, fixed_t othery, AActor *ref = NULL) + { + return P_AproxDistance(X() - otherx, Y() - othery); + } + + fixed_t AproxDistance(AActor *other, fixed_t xadd, fixed_t yadd, bool absolute = false) + { + return P_AproxDistance(X() - other->X() + xadd, Y() - other->Y() + yadd); + } + + fixed_t AproxDistance3D(AActor *other, bool absolute = false) + { + return P_AproxDistance(AproxDistance(other), Z() - other->Z()); + } + + // more precise, but slower version, being used in a few places + fixed_t Distance2D(AActor *other, bool absolute = false) + { + return xs_RoundToInt(FVector2(X() - other->X(), Y() - other->Y()).Length()); + } + + // a full 3D version of the above + fixed_t Distance3D(AActor *other, bool absolute = false) + { + return xs_RoundToInt(FVector3(X() - other->X(), Y() - other->Y(), Z() - other->Z()).Length()); + } + + angle_t AngleTo(AActor *other, bool absolute = false) const + { + return R_PointToAngle2(X(), Y(), other->X(), other->Y()); + } + + angle_t AngleTo(AActor *other, fixed_t oxofs, fixed_t oyofs, bool absolute = false) const + { + return R_PointToAngle2(X(), Y(), other->X() + oxofs, other->Y() + oyofs); + } + + fixed_t AngleTo(fixed_t otherx, fixed_t othery, AActor *ref = NULL) + { + return R_PointToAngle2(X(), Y(), otherx, othery); + } + + fixed_t AngleXYTo(fixed_t myx, fixed_t myy, AActor *other, bool absolute = false) + { + return R_PointToAngle2(myx, myy, other->X(), other->Y()); + } + + fixedvec2 Vec2To(AActor *other) const + { + fixedvec2 ret = { other->X() - X(), other->Y() - Y() }; + return ret; + } + + fixedvec3 Vec3To(AActor *other) const + { + fixedvec3 ret = { other->X() - X(), other->Y() - Y(), other->Z() - Z() }; + return ret; + } + + fixedvec2 Vec2Offset(fixed_t dx, fixed_t dy, bool absolute = false) const + { + fixedvec2 ret = { X() + dx, Y() + dy }; + return ret; + } + + + fixedvec2 Vec2Angle(fixed_t length, angle_t angle, bool absolute = false) const + { + fixedvec2 ret = { X() + FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]), + Y() + FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]) }; + return ret; + } + + fixedvec3 Vec3Offset(fixed_t dx, fixed_t dy, fixed_t dz, bool absolute = false) const + { + fixedvec3 ret = { X() + dx, Y() + dy, Z() + dz }; + return ret; + } + + fixedvec3 Vec3Angle(fixed_t length, angle_t angle, fixed_t dz, bool absolute = false) const + { + fixedvec3 ret = { X() + FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]), + Y() + FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]), Z() + dz }; + return ret; + } + + void Move(fixed_t dx, fixed_t dy, fixed_t dz) + { + SetOrigin(X() + dx, Y() + dy, Z() + dz, true); + } + + void SetOrigin(const fixedvec3 & npos, bool moving) + { + SetOrigin(npos.x, npos.y, npos.z, moving); + } + inline void SetFriendPlayer(player_t *player); bool IsVisibleToPlayer() const; @@ -871,9 +1006,10 @@ public: void CheckSectorTransition(sector_t *oldsec); // info for drawing -// NOTE: The first member variable *must* be x. - fixed_t x,y,z; +// NOTE: The first member variable *must* be snext. AActor *snext, **sprev; // links in sector (if needed) + fixedvec3 __pos; // double underscores so that it won't get used by accident. Access to this should be exclusively through the designated access functions. + angle_t angle; WORD sprite; // used to find patch_t and flip value BYTE frame; // sprite frame to draw @@ -896,6 +1032,7 @@ public: struct sector_t *floorsector; FTextureID floorpic; // contacted sec floorpic + int floorterrain; struct sector_t *ceilingsector; FTextureID ceilingpic; // contacted sec ceilingpic fixed_t radius, height; // for movement checking @@ -1069,7 +1206,7 @@ public: void LinkToWorld (sector_t *sector); void UnlinkFromWorld (); void AdjustFloorClip (); - void SetOrigin (fixed_t x, fixed_t y, fixed_t z); + void SetOrigin (fixed_t x, fixed_t y, fixed_t z, bool moving = false); bool InStateSequence(FState * newstate, FState * basestate); int GetTics(FState * newstate); bool SetState (FState *newstate, bool nofunction=false); @@ -1098,6 +1235,106 @@ public: } bool HasSpecialDeathStates () const; + + fixed_t X() const + { + return __pos.x; + } + fixed_t Y() const + { + return __pos.y; + } + fixed_t Z() const + { + return __pos.z; + } + fixedvec3 Pos() const + { + fixedvec3 ret = { X(), Y(), Z() }; + return ret; + } + fixedvec3 PosRelative(AActor *other) const + { + fixedvec3 ret = { X(), Y(), Z() }; + return ret; + } + fixedvec3 PosRelative(sector_t *sec) const + { + fixedvec3 ret = { X(), Y(), Z() }; + return ret; + } + fixedvec3 PosRelative(line_t *line) const + { + fixedvec3 ret = { X(), Y(), Z() }; + return ret; + } + fixed_t SoundX() const + { + return X(); + } + fixed_t SoundY() const + { + return Y(); + } + fixed_t SoundZ() const + { + return Z(); + } + fixedvec3 InterpolatedPosition(fixed_t ticFrac) const + { + fixedvec3 ret; + + ret.x = PrevX + FixedMul (ticFrac, X() - PrevX); + ret.y = PrevY + FixedMul (ticFrac, Y() - PrevY); + ret.z = PrevZ + FixedMul (ticFrac, Z() - PrevZ); + return ret; + } + fixedvec3 PosPlusZ(fixed_t zadd) const + { + fixedvec3 ret = { X(), Y(), Z() + zadd }; + return ret; + } + fixed_t Top() const + { + return Z() + height; + } + void SetZ(fixed_t newz, bool moving = true) + { + __pos.z = newz; + } + void AddZ(fixed_t newz, bool moving = true) + { + __pos.z += newz; + } + + // These are not for general use as they do not link the actor into the world! + void SetXY(fixed_t xx, fixed_t yy) + { + __pos.x = xx; + __pos.y = yy; + } + void SetXYZ(fixed_t xx, fixed_t yy, fixed_t zz) + { + __pos.x = xx; + __pos.y = yy; + __pos.z = zz; + } + void SetXY(const fixedvec2 &npos) + { + __pos.x = npos.x; + __pos.y = npos.y; + } + void SetXYZ(const fixedvec3 &npos) + { + __pos.x = npos.x; + __pos.y = npos.y; + __pos.z = npos.z; + } + void SetMovement(fixed_t x, fixed_t y, fixed_t z) + { + // not yet implemented + } + }; class FActorIterator @@ -1171,15 +1408,48 @@ inline AActor *Spawn (const PClass *type, fixed_t x, fixed_t y, fixed_t z, repla return AActor::StaticSpawn (type, x, y, z, allowreplacement); } +inline AActor *Spawn (const PClass *type, const fixedvec3 &pos, replace_t allowreplacement) +{ + return AActor::StaticSpawn (type, pos.x, pos.y, pos.z, allowreplacement); +} + AActor *Spawn (const char *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement); AActor *Spawn (FName classname, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement); +inline AActor *Spawn (const char *type, const fixedvec3 &pos, replace_t allowreplacement) +{ + return Spawn (type, pos.x, pos.y, pos.z, allowreplacement); +} + +inline AActor *Spawn (FName classname, const fixedvec3 &pos, replace_t allowreplacement) +{ + return Spawn (classname, pos.x, pos.y, pos.z, allowreplacement); +} + + template inline T *Spawn (fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement) { return static_cast(AActor::StaticSpawn (RUNTIME_CLASS(T), x, y, z, allowreplacement)); } +template +inline T *Spawn (const fixedvec3 &pos, replace_t allowreplacement) +{ + return static_cast(AActor::StaticSpawn (RUNTIME_CLASS(T), pos.x, pos.y, pos.z, allowreplacement)); +} + +inline fixedvec2 Vec2Angle(fixed_t length, angle_t angle) +{ + fixedvec2 ret = { FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]), + FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]) }; + return ret; +} + +inline fixedvec3 PosRelative(const fixedvec3 &pos, line_t *line, sector_t *refsec = NULL) +{ + return pos; +} void PrintMiscActorInfo(AActor * query); diff --git a/src/am_map.cpp b/src/am_map.cpp index 46a2d5a84..64d5420b0 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -998,8 +998,8 @@ void AM_restoreScaleAndLoc () } else { - m_x = (players[consoleplayer].camera->x >> FRACTOMAPBITS) - m_w/2; - m_y = (players[consoleplayer].camera->y >> FRACTOMAPBITS)- m_h/2; + m_x = (players[consoleplayer].camera->X() >> FRACTOMAPBITS) - m_w/2; + m_y = (players[consoleplayer].camera->Y() >> FRACTOMAPBITS)- m_h/2; } m_x2 = m_x + m_w; m_y2 = m_y + m_h; @@ -1249,8 +1249,8 @@ void AM_initVariables () if (playeringame[pnum]) break; assert(pnum >= 0 && pnum < MAXPLAYERS); - m_x = (players[pnum].camera->x >> FRACTOMAPBITS) - m_w/2; - m_y = (players[pnum].camera->y >> FRACTOMAPBITS) - m_h/2; + m_x = (players[pnum].camera->X() >> FRACTOMAPBITS) - m_w/2; + m_y = (players[pnum].camera->Y() >> FRACTOMAPBITS) - m_h/2; AM_changeWindowLoc(); // for saving & restoring @@ -1571,25 +1571,25 @@ void AM_doFollowPlayer () fixed_t sx, sy; if (players[consoleplayer].camera != NULL && - (f_oldloc.x != players[consoleplayer].camera->x || - f_oldloc.y != players[consoleplayer].camera->y)) + (f_oldloc.x != players[consoleplayer].camera->X() || + f_oldloc.y != players[consoleplayer].camera->Y())) { - m_x = (players[consoleplayer].camera->x >> FRACTOMAPBITS) - m_w/2; - m_y = (players[consoleplayer].camera->y >> FRACTOMAPBITS) - m_h/2; + m_x = (players[consoleplayer].camera->X() >> FRACTOMAPBITS) - m_w/2; + m_y = (players[consoleplayer].camera->Y() >> FRACTOMAPBITS) - m_h/2; m_x2 = m_x + m_w; m_y2 = m_y + m_h; // do the parallax parchment scrolling. - sx = (players[consoleplayer].camera->x - f_oldloc.x) >> FRACTOMAPBITS; - sy = (f_oldloc.y - players[consoleplayer].camera->y) >> FRACTOMAPBITS; + sx = (players[consoleplayer].camera->X() - f_oldloc.x) >> FRACTOMAPBITS; + sy = (f_oldloc.y - players[consoleplayer].camera->Y()) >> FRACTOMAPBITS; if (am_rotate == 1 || (am_rotate == 2 && viewactive)) { AM_rotate (&sx, &sy, players[consoleplayer].camera->angle - ANG90); } AM_ScrollParchment (sx, sy); - f_oldloc.x = players[consoleplayer].camera->x; - f_oldloc.y = players[consoleplayer].camera->y; + f_oldloc.x = players[consoleplayer].camera->X(); + f_oldloc.y = players[consoleplayer].camera->Y(); } } @@ -2071,17 +2071,17 @@ static bool AM_CheckSecret(line_t *line) { if (line->frontsector != NULL) { - if (line->frontsector->secretsector) + if (line->frontsector->wasSecret()) { - if (am_map_secrets!=0 && !(line->frontsector->special&SECRET_MASK)) return true; + if (am_map_secrets!=0 && !line->frontsector->isSecret()) return true; if (am_map_secrets==2 && !(line->flags & ML_SECRET)) return true; } } if (line->backsector != NULL) { - if (line->backsector->secretsector) + if (line->backsector->wasSecret()) { - if (am_map_secrets!=0 && !(line->backsector->special&SECRET_MASK)) return true; + if (am_map_secrets!=0 && !line->backsector->isSecret()) return true; if (am_map_secrets==2 && !(line->flags & ML_SECRET)) return true; } } @@ -2224,6 +2224,154 @@ bool AM_Check3DFloors(line_t *line) return false; } +// [TP] Check whether a sector can trigger a special that satisfies the provided function. +// If found, specialptr and argsptr will be filled by the special and the arguments +// If needUseActivated is true, the special must be activated by use. +bool AM_checkSectorActions (sector_t *sector, bool (*function)(int, int *), int *specialptr, int **argsptr, bool needUseActivated) +{ + for (ASectorAction* action = sector->SecActTarget; action; action = barrier_cast(action->tracer)) + { + if ((action->IsActivatedByUse() || false == needUseActivated) + && (*function)(action->special, action->args) + && action->CanTrigger (players[consoleplayer].mo)) + { + *specialptr = action->special; + *argsptr = action->args; + return true; + } + } + + return false; +} + +// [TP] Check whether there's a boundary on the provided line for a special that satisfies the provided function. +// It's a boundary if the line can activate the special or the line's bordering sectors can activate it. +// If found, specialptr and argsptr will be filled with special and args if given. +bool AM_checkSpecialBoundary (line_t &line, bool (*function)(int, int *), int *specialptr = NULL, int **argsptr = NULL) +{ + if (specialptr == NULL) + { + static int sink; + specialptr = &sink; + } + + if (argsptr == NULL) + { + static int *sink; + argsptr = &sink; + } + + // Check if the line special qualifies for this + if ((line.activation & SPAC_PlayerActivate) && (*function)(line.special, line.args)) + { + *specialptr = line.special; + *argsptr = line.args; + return true; + } + + // Check sector actions in the line's front sector -- the action has to be use-activated in order to + // show up if this is a one-sided line, because the player cannot trigger sector actions by crossing + // a one-sided line (since that's impossible, duh). + if (AM_checkSectorActions(line.frontsector, function, specialptr, argsptr, line.backsector == NULL)) + return true; + + // If it has a back sector, check sector actions in that. + return (line.backsector && AM_checkSectorActions(line.backsector, function, specialptr, argsptr, false)); +} + +bool AM_isTeleportSpecial (int special, int *) +{ + return (special == Teleport || + special == Teleport_NoFog || + special == Teleport_ZombieChanger || + special == Teleport_Line); +} + +bool AM_isTeleportBoundary (line_t &line) +{ + return AM_checkSpecialBoundary(line, &AM_isTeleportSpecial); +} + +bool AM_isExitSpecial (int special, int *) +{ + return (special == Teleport_NewMap || + special == Teleport_EndGame || + special == Exit_Normal || + special == Exit_Secret); +} + +bool AM_isExitBoundary (line_t& line) +{ + return AM_checkSpecialBoundary(line, &AM_isExitSpecial); +} + +bool AM_isTriggerSpecial (int special, int *) +{ + return LineSpecialsInfo[special] != NULL + && LineSpecialsInfo[special]->max_args >= 0 + && special != Door_Open + && special != Door_Close + && special != Door_CloseWaitOpen + && special != Door_Raise + && special != Door_Animated + && special != Generic_Door; +} + +bool AM_isTriggerBoundary (line_t &line) +{ + return AM_checkSpecialBoundary(line, &AM_isTriggerSpecial); +} + +bool AM_isLockSpecial (int special, int* args) +{ + return special == Door_LockedRaise + || special == ACS_LockedExecute + || special == ACS_LockedExecuteDoor + || (special == Door_Animated && args[3] != 0) + || (special == Generic_Door && args[4] != 0) + || (special == FS_Execute && args[2] != 0); +} + +bool AM_isLockBoundary (line_t &line, int *lockptr = NULL) +{ + if (lockptr == NULL) + { + static int sink; + lockptr = &sink; + } + + if (line.locknumber) + { + *lockptr = line.locknumber; + return true; + } + + int special; + int *args; + bool result = AM_checkSpecialBoundary(line, &AM_isLockSpecial, &special, &args); + + if (result) + { + switch (special) + { + case FS_Execute: + *lockptr = args[2]; + break; + + case Door_Animated: + case Door_LockedRaise: + *lockptr = args[3]; + break; + + default: + *lockptr = args[4]; + break; + } + } + + return result; +} + //============================================================================= // // Determines visible lines, draws them. @@ -2271,49 +2419,19 @@ void AM_drawWalls (bool allmap) AM_drawMline(&l, AMColors.SecretWallColor); else AM_drawMline(&l, AMColors.WallColor); - } - else if (lines[i].locknumber > 0 && AMColors.displayLocks) - { // [Dusk] specials w/ locknumbers - lock = lines[i].locknumber; - color = P_GetMapColorForLock(lock); - - AMColor c; - if (color >= 0) c.FromRGB(RPART(color), GPART(color), BPART(color)); - else c = AMColors[AMColors.LockedColor]; - - AM_drawMline (&l, c); - } - else if ((lines[i].special == Teleport || - lines[i].special == Teleport_NoFog || - lines[i].special == Teleport_ZombieChanger || - lines[i].special == Teleport_Line) && - (lines[i].activation & SPAC_PlayerActivate) && - AMColors.isValid(AMColors.IntraTeleportColor)) + } + else if (AM_isTeleportBoundary(lines[i]) && AMColors.isValid(AMColors.IntraTeleportColor)) { // intra-level teleporters AM_drawMline(&l, AMColors.IntraTeleportColor); } - else if ((lines[i].special == Teleport_NewMap || - lines[i].special == Teleport_EndGame || - lines[i].special == Exit_Normal || - lines[i].special == Exit_Secret) && - AMColors.isValid(AMColors.InterTeleportColor)) + else if (AM_isExitBoundary(lines[i]) && AMColors.isValid(AMColors.InterTeleportColor)) { // inter-level/game-ending teleporters AM_drawMline(&l, AMColors.InterTeleportColor); } - else if (lines[i].special == Door_LockedRaise || - lines[i].special == ACS_LockedExecute || - lines[i].special == ACS_LockedExecuteDoor || - (lines[i].special == Door_Animated && lines[i].args[3] != 0) || - (lines[i].special == Generic_Door && lines[i].args[4] != 0)) + else if (AM_isLockBoundary(lines[i], &lock)) { if (AMColors.displayLocks) { - int P_GetMapColorForLock(int lock); - - if (lines[i].special==Door_LockedRaise || lines[i].special==Door_Animated) - lock=lines[i].args[3]; - else lock=lines[i].args[4]; - color = P_GetMapColorForLock(lock); AMColor c; @@ -2328,16 +2446,9 @@ void AM_drawWalls (bool allmap) AM_drawMline (&l, AMColors.LockedColor); // locked special } } - else if (am_showtriggerlines && AMColors.isValid(AMColors.SpecialWallColor) - && LineSpecialsInfo[lines[i].special] != NULL - && LineSpecialsInfo[lines[i].special]->max_args >= 0 - && lines[i].special != Door_Open - && lines[i].special != Door_Close - && lines[i].special != Door_CloseWaitOpen - && lines[i].special != Door_Raise - && lines[i].special != Door_Animated - && lines[i].special != Generic_Door - && (lines[i].activation & SPAC_PlayerActivate)) + else if (am_showtriggerlines + && AMColors.isValid(AMColors.SpecialWallColor) + && AM_isTriggerBoundary(lines[i])) { AM_drawMline(&l, AMColors.SpecialWallColor); // wall with special non-door action the player can do } @@ -2501,8 +2612,8 @@ void AM_drawPlayers () mline_t *arrow; int numarrowlines; - pt.x = players[consoleplayer].camera->x >> FRACTOMAPBITS; - pt.y = players[consoleplayer].camera->y >> FRACTOMAPBITS; + pt.x = players[consoleplayer].camera->X() >> FRACTOMAPBITS; + pt.y = players[consoleplayer].camera->Y() >> FRACTOMAPBITS; if (am_rotate == 1 || (am_rotate == 2 && viewactive)) { angle = ANG90; @@ -2564,8 +2675,8 @@ void AM_drawPlayers () if (p->mo != NULL) { - pt.x = p->mo->x >> FRACTOMAPBITS; - pt.y = p->mo->y >> FRACTOMAPBITS; + pt.x = p->mo->X() >> FRACTOMAPBITS; + pt.y = p->mo->Y() >> FRACTOMAPBITS; angle = p->mo->angle; if (am_rotate == 1 || (am_rotate == 2 && viewactive)) @@ -2596,8 +2707,8 @@ void AM_drawKeys () while ((key = it.Next()) != NULL) { - p.x = key->x >> FRACTOMAPBITS; - p.y = key->y >> FRACTOMAPBITS; + p.x = key->X() >> FRACTOMAPBITS; + p.y = key->Y() >> FRACTOMAPBITS; angle = key->angle; if (am_rotate == 1 || (am_rotate == 2 && viewactive)) @@ -2641,8 +2752,8 @@ void AM_drawThings () { if (am_cheat > 0 || !(t->flags6 & MF6_NOTONAUTOMAP)) { - p.x = t->x >> FRACTOMAPBITS; - p.y = t->y >> FRACTOMAPBITS; + p.x = t->X() >> FRACTOMAPBITS; + p.y = t->Y() >> FRACTOMAPBITS; if (am_showthingsprites > 0 && t->sprite > 0) { @@ -2868,7 +2979,7 @@ void AM_drawAuthorMarkers () marked->subsector->flags & SSECF_DRAWN : marked->Sector->MoreFlags & SECF_DRAWN))) { - DrawMarker (tex, marked->x >> FRACTOMAPBITS, marked->y >> FRACTOMAPBITS, 0, + DrawMarker (tex, marked->X() >> FRACTOMAPBITS, marked->Y() >> FRACTOMAPBITS, 0, flip, mark->scaleX, mark->scaleY, mark->Translation, mark->alpha, mark->fillcolor, mark->RenderStyle); } diff --git a/src/b_func.cpp b/src/b_func.cpp index f93625612..eb86beba8 100644 --- a/src/b_func.cpp +++ b/src/b_func.cpp @@ -30,17 +30,17 @@ bool DBot::Reachable (AActor *rtarget) if (player->mo == rtarget) return false; - if ((rtarget->Sector->ceilingplane.ZatPoint (rtarget->x, rtarget->y) - - rtarget->Sector->floorplane.ZatPoint (rtarget->x, rtarget->y)) + if ((rtarget->Sector->ceilingplane.ZatPoint (rtarget) - + rtarget->Sector->floorplane.ZatPoint (rtarget)) < player->mo->height) //Where rtarget is, player->mo can't be. return false; sector_t *last_s = player->mo->Sector; - fixed_t last_z = last_s->floorplane.ZatPoint (player->mo->x, player->mo->y); - fixed_t estimated_dist = P_AproxDistance (player->mo->x - rtarget->x, player->mo->y - rtarget->y); + fixed_t last_z = last_s->floorplane.ZatPoint (player->mo); + fixed_t estimated_dist = player->mo->AproxDistance(rtarget); bool reachable = true; - FPathTraverse it(player->mo->x+player->mo->velx, player->mo->y+player->mo->vely, rtarget->x, rtarget->y, PT_ADDLINES|PT_ADDTHINGS); + FPathTraverse it(player->mo->X()+player->mo->velx, player->mo->Y()+player->mo->vely, rtarget->X(), rtarget->Y(), PT_ADDLINES|PT_ADDTHINGS); intercept_t *in; while ((in = it.Next())) { @@ -96,7 +96,7 @@ bool DBot::Reachable (AActor *rtarget) thing = in->d.thing; if (thing == player->mo) //Can't reach self in this case. continue; - if (thing == rtarget && (rtarget->Sector->floorplane.ZatPoint (rtarget->x, rtarget->y) <= (last_z+MAXMOVEHEIGHT))) + if (thing == rtarget && (rtarget->Sector->floorplane.ZatPoint (rtarget) <= (last_z+MAXMOVEHEIGHT))) { return true; } @@ -123,7 +123,7 @@ bool DBot::Check_LOS (AActor *to, angle_t vangle) if (vangle == 0) return false; //Looker seems to be blind. - return absangle(R_PointToAngle2 (player->mo->x, player->mo->y, to->x, to->y) - player->mo->angle) <= vangle/2; + return absangle(player->mo->AngleTo(to) - player->mo->angle) <= vangle/2; } //------------------------------------- @@ -165,10 +165,8 @@ void DBot::Dofire (ticcmd_t *cmd) //MAKEME: Decrease the rocket suicides even more. no_fire = true; - //angle = R_PointToAngle2(player->mo->x, player->mo->y, player->enemy->x, player->enemy->y); //Distance to enemy. - dist = P_AproxDistance ((player->mo->x + player->mo->velx) - (enemy->x + enemy->velx), - (player->mo->y + player->mo->vely) - (enemy->y + enemy->vely)); + dist = player->mo->AproxDistance(enemy, player->mo->velx - enemy->velx, player->mo->vely - enemy->vely); //FIRE EACH TYPE OF WEAPON DIFFERENT: Here should all the different weapons go. if (player->ReadyWeapon->WeaponFlags & WIF_MELEEWEAPON) @@ -219,17 +217,17 @@ void DBot::Dofire (ticcmd_t *cmd) } // prediction aiming shootmissile: - dist = P_AproxDistance (player->mo->x - enemy->x, player->mo->y - enemy->y); + dist = player->mo->AproxDistance (enemy); m = dist / GetDefaultByType (player->ReadyWeapon->ProjectileType)->Speed; - bglobal.SetBodyAt (enemy->x + enemy->velx*m*2, enemy->y + enemy->vely*m*2, enemy->z, 1); - angle = R_PointToAngle2 (player->mo->x, player->mo->y, bglobal.body1->x, bglobal.body1->y); + bglobal.SetBodyAt (enemy->X() + enemy->velx*m*2, enemy->Y() + enemy->vely*m*2, enemy->Z(), 1); + angle = player->mo->AngleTo(bglobal.body1); if (Check_LOS (enemy, SHOOTFOV)) no_fire = false; } else { //Other weapons, mostly instant hit stuff. - angle = R_PointToAngle2 (player->mo->x, player->mo->y, enemy->x, enemy->y); + angle = player->mo->AngleTo(enemy); aiming_penalty = 0; if (enemy->flags & MF_SHADOW) aiming_penalty += (pr_botdofire()%25)+10; @@ -265,7 +263,6 @@ shootmissile: cmd->ucmd.buttons |= BT_ATTACK; } //Prevents bot from jerking, when firing automatic things with low skill. - //player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, player->enemy->x, player->enemy->y); } bool FCajunMaster::IsLeader (player_t *player) @@ -331,8 +328,7 @@ AActor *DBot::Choose_Mate () { if (P_CheckSight (player->mo, client->mo, SF_IGNOREVISIBILITY)) { - test = P_AproxDistance (client->mo->x - player->mo->x, - client->mo->y - player->mo->y); + test = client->mo->AproxDistance(player->mo); if (test < closest_dist) { @@ -402,8 +398,7 @@ AActor *DBot::Find_enemy () if (Check_LOS (client->mo, vangle)) //Here's a strange one, when bot is standing still, the P_CheckSight within Check_LOS almost always returns false. tought it should be the same checksight as below but.. (below works) something must be fuckin wierd screded up. //if(P_CheckSight(player->mo, players[count].mo)) { - temp = P_AproxDistance (client->mo->x - player->mo->x, - client->mo->y - player->mo->y); + temp = client->mo->AproxDistance(player->mo); //Too dark? if (temp > DARK_DIST && @@ -432,7 +427,7 @@ void FCajunMaster::SetBodyAt (fixed_t x, fixed_t y, fixed_t z, int hostnum) { if (body1) { - body1->SetOrigin (x, y, z); + body1->SetOrigin (x, y, z, false); } else { @@ -443,7 +438,7 @@ void FCajunMaster::SetBodyAt (fixed_t x, fixed_t y, fixed_t z, int hostnum) { if (body2) { - body2->SetOrigin (x, y, z); + body2->SetOrigin (x, y, z, false); } else { @@ -464,16 +459,13 @@ void FCajunMaster::SetBodyAt (fixed_t x, fixed_t y, fixed_t z, int hostnum) //Emulates missile travel. Returns distance travelled. fixed_t FCajunMaster::FakeFire (AActor *source, AActor *dest, ticcmd_t *cmd) { - AActor *th = Spawn ("CajunTrace", source->x, source->y, source->z + 4*8*FRACUNIT, NO_REPLACE); + AActor *th = Spawn ("CajunTrace", source->PosPlusZ(4*8*FRACUNIT), NO_REPLACE); th->target = source; // where it came from float speed = (float)th->Speed; - FVector3 velocity; - velocity[0] = FIXED2FLOAT(dest->x - source->x); - velocity[1] = FIXED2FLOAT(dest->y - source->y); - velocity[2] = FIXED2FLOAT(dest->z - source->z); + TVector3 velocity = source->Vec3To(dest); velocity.MakeUnit(); th->velx = FLOAT2FIXED(velocity[0] * speed); th->vely = FLOAT2FIXED(velocity[1] * speed); @@ -484,8 +476,8 @@ fixed_t FCajunMaster::FakeFire (AActor *source, AActor *dest, ticcmd_t *cmd) while (dist < SAFE_SELF_MISDIST) { dist += th->Speed; - th->SetOrigin (th->x + th->velx, th->y + th->vely, th->z + th->velz); - if (!CleanAhead (th, th->x, th->y, cmd)) + th->Move(th->velx, th->vely, th->velz); + if (!CleanAhead (th, th->X(), th->Y(), cmd)) break; } th->Destroy (); @@ -499,30 +491,30 @@ angle_t DBot::FireRox (AActor *enemy, ticcmd_t *cmd) AActor *actor; int m; - bglobal.SetBodyAt (player->mo->x + FixedMul(player->mo->velx, 5*FRACUNIT), - player->mo->y + FixedMul(player->mo->vely, 5*FRACUNIT), - player->mo->z + (player->mo->height / 2), 2); + bglobal.SetBodyAt (player->mo->X() + FixedMul(player->mo->velx, 5*FRACUNIT), + player->mo->Y() + FixedMul(player->mo->vely, 5*FRACUNIT), + player->mo->Z() + (player->mo->height / 2), 2); actor = bglobal.body2; - dist = P_AproxDistance (actor->x-enemy->x, actor->y-enemy->y); + dist = actor->AproxDistance (enemy); if (dist < SAFE_SELF_MISDIST) return 0; //Predict. m = (((dist+1)/FRACUNIT) / GetDefaultByName("Rocket")->Speed); - bglobal.SetBodyAt (enemy->x + FixedMul(enemy->velx, (m+2*FRACUNIT)), - enemy->y + FixedMul(enemy->vely, (m+2*FRACUNIT)), ONFLOORZ, 1); + bglobal.SetBodyAt (enemy->X() + FixedMul(enemy->velx, (m+2*FRACUNIT)), + enemy->Y() + FixedMul(enemy->vely, (m+2*FRACUNIT)), ONFLOORZ, 1); //try the predicted location if (P_CheckSight (actor, bglobal.body1, SF_IGNOREVISIBILITY)) //See the predicted location, so give a test missile { FCheckPosition tm; - if (bglobal.SafeCheckPosition (player->mo, actor->x, actor->y, tm)) + if (bglobal.SafeCheckPosition (player->mo, actor->X(), actor->Y(), tm)) { if (bglobal.FakeFire (actor, bglobal.body1, cmd) >= SAFE_SELF_MISDIST) { - ang = R_PointToAngle2 (actor->x, actor->y, bglobal.body1->x, bglobal.body1->y); + ang = actor->AngleTo(bglobal.body1); return ang; } } @@ -532,7 +524,7 @@ angle_t DBot::FireRox (AActor *enemy, ticcmd_t *cmd) { if (bglobal.FakeFire (player->mo, enemy, cmd) >= SAFE_SELF_MISDIST) { - ang = R_PointToAngle2(player->mo->x, player->mo->y, enemy->x, enemy->y); + ang = player->mo->AngleTo(enemy); return ang; } } diff --git a/src/b_game.cpp b/src/b_game.cpp index e136f3f29..5f852d043 100644 --- a/src/b_game.cpp +++ b/src/b_game.cpp @@ -423,8 +423,8 @@ void FCajunMaster::RemoveAllBots (bool fromlist) } } } + FBehavior::StaticStartTypedScripts (SCRIPT_Disconnect, players[i].mo, true, i, true); ClearPlayer (i, !fromlist); - FBehavior::StaticStartTypedScripts (SCRIPT_Disconnect, NULL, true, i); } } diff --git a/src/b_move.cpp b/src/b_move.cpp index fd0405457..cee409265 100644 --- a/src/b_move.cpp +++ b/src/b_move.cpp @@ -35,7 +35,7 @@ void DBot::Roam (ticcmd_t *cmd) if (Reachable(dest)) { // Straight towards it. - angle = R_PointToAngle2(player->mo->x, player->mo->y, dest->x, dest->y); + angle = player->mo->AngleTo(dest); } else if (player->mo->movedir < 8) // turn towards movement direction if not there yet { @@ -67,8 +67,8 @@ bool DBot::Move (ticcmd_t *cmd) if ((unsigned)player->mo->movedir >= 8) I_Error ("Weird bot movedir!"); - tryx = player->mo->x + 8*xspeed[player->mo->movedir]; - tryy = player->mo->y + 8*yspeed[player->mo->movedir]; + tryx = player->mo->X() + 8*xspeed[player->mo->movedir]; + tryy = player->mo->Y() + 8*yspeed[player->mo->movedir]; try_ok = bglobal.CleanAhead (player->mo, tryx, tryy, cmd); @@ -124,9 +124,6 @@ bool DBot::TryWalk (ticcmd_t *cmd) void DBot::NewChaseDir (ticcmd_t *cmd) { - fixed_t deltax; - fixed_t deltay; - dirtype_t d[3]; int tdir; @@ -145,19 +142,18 @@ void DBot::NewChaseDir (ticcmd_t *cmd) olddir = (dirtype_t)player->mo->movedir; turnaround = opposite[olddir]; - deltax = dest->x - player->mo->x; - deltay = dest->y - player->mo->y; + fixedvec2 delta = player->mo->Vec2To(dest); - if (deltax > 10*FRACUNIT) + if (delta.x > 10*FRACUNIT) d[1] = DI_EAST; - else if (deltax < -10*FRACUNIT) + else if (delta.x < -10*FRACUNIT) d[1] = DI_WEST; else d[1] = DI_NODIR; - if (deltay < -10*FRACUNIT) + if (delta.y < -10*FRACUNIT) d[2] = DI_SOUTH; - else if (deltay > 10*FRACUNIT) + else if (delta.y > 10*FRACUNIT) d[2] = DI_NORTH; else d[2] = DI_NODIR; @@ -165,14 +161,14 @@ void DBot::NewChaseDir (ticcmd_t *cmd) // try direct route if (d[1] != DI_NODIR && d[2] != DI_NODIR) { - player->mo->movedir = diags[((deltay<0)<<1)+(deltax>0)]; + player->mo->movedir = diags[((delta.y<0)<<1)+(delta.x>0)]; if (player->mo->movedir != turnaround && TryWalk(cmd)) return; } // try other directions if (pr_botnewchasedir() > 200 - || abs(deltay)>abs(deltax)) + || abs(delta.y)>abs(delta.x)) { tdir=d[1]; d[1]=d[2]; @@ -282,7 +278,7 @@ bool FCajunMaster::CleanAhead (AActor *thing, fixed_t x, fixed_t y, ticcmd_t *cm if ( !(thing->flags & MF_TELEPORT) && - tm.ceilingz - thing->z < thing->height) + tm.ceilingz - thing->Z() < thing->height) return false; // mobj must lower itself to fit // jump out of water @@ -290,7 +286,7 @@ bool FCajunMaster::CleanAhead (AActor *thing, fixed_t x, fixed_t y, ticcmd_t *cm // maxstep=37*FRACUNIT; if ( !(thing->flags & MF_TELEPORT) && - (tm.floorz - thing->z > maxstep ) ) + (tm.floorz - thing->Z() > maxstep ) ) return false; // too big a step up @@ -346,28 +342,13 @@ void DBot::Pitch (AActor *target) double aim; double diff; - diff = target->z - player->mo->z; - aim = atan (diff / (double)P_AproxDistance (player->mo->x - target->x, player->mo->y - target->y)); + diff = target->Z() - player->mo->Z(); + aim = atan(diff / (double)player->mo->AproxDistance(target)); player->mo->pitch = -(int)(aim * ANGLE_180/M_PI); } //Checks if a sector is dangerous. bool FCajunMaster::IsDangerous (sector_t *sec) { - int special; - - return - sec->damage - || sec->special & DAMAGE_MASK - || (special = sec->special & 0xff, special == dLight_Strobe_Hurt) - || special == dDamage_Hellslime - || special == dDamage_Nukage - || special == dDamage_End - || special == dDamage_SuperHellslime - || special == dDamage_LavaWimpy - || special == dDamage_LavaHefty - || special == dScroll_EastLavaDamage - || special == sLight_Strobe_Hurt - || special == Damage_InstantDeath - || special == sDamage_SuperHellslime; + return sec->damageamount > 0; } diff --git a/src/b_think.cpp b/src/b_think.cpp index 34baeee9c..de74c04db 100644 --- a/src/b_think.cpp +++ b/src/b_think.cpp @@ -81,7 +81,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd) int r; stuck = false; - dist = dest ? P_AproxDistance(player->mo->x-dest->x, player->mo->y-dest->y) : 0; + dist = dest ? player->mo->AproxDistance(dest) : 0; if (missile && ((!missile->velx || !missile->vely) || !Check_LOS(missile, SHOOTFOV*3/2))) @@ -96,14 +96,14 @@ void DBot::ThinkForMove (ticcmd_t *cmd) player->mo->pitch += 80; //HOW TO MOVE: - if (missile && (P_AproxDistance(player->mo->x-missile->x, player->mo->y-missile->y)mo->AproxDistance(missile)mo->x, player->mo->y, missile->x, missile->y); + angle = player->mo->AngleTo(missile); cmd->ucmd.sidemove = sleft ? -SIDERUN : SIDERUN; cmd->ucmd.forwardmove = -FORWARDRUN; //Back IS best. - if ((P_AproxDistance(player->mo->x-oldx, player->mo->y-oldy)<50000) + if ((player->mo->AproxDistance(oldx, oldy)<50000) && t_strafe<=0) { t_strafe = 5; @@ -156,7 +156,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd) t_fight = AFTERTICS; if (t_strafe <= 0 && - (P_AproxDistance(player->mo->x-oldx, player->mo->y-oldy)<50000 + (player->mo->AproxDistance(oldx, oldy)<50000 || ((pr_botmove()%30)==10)) ) { @@ -165,10 +165,10 @@ void DBot::ThinkForMove (ticcmd_t *cmd) sleft = !sleft; } - angle = R_PointToAngle2(player->mo->x, player->mo->y, enemy->x, enemy->y); + angle = player->mo->AngleTo(enemy); if (player->ReadyWeapon == NULL || - P_AproxDistance(player->mo->x-enemy->x, player->mo->y-enemy->y) > + player->mo->AproxDistance(enemy) > player->ReadyWeapon->MoveCombatDist) { // If a monster, use lower speed (just for cooler apperance while strafing down doomed monster) @@ -206,9 +206,9 @@ void DBot::ThinkForMove (ticcmd_t *cmd) goto roam; } - angle = R_PointToAngle2(player->mo->x, player->mo->y, mate->x, mate->y); + angle = player->mo->AngleTo(mate); - matedist = P_AproxDistance(player->mo->x - mate->x, player->mo->y - mate->y); + matedist = player->mo->AproxDistance(mate); if (matedist > (FRIEND_DIST*2)) cmd->ucmd.forwardmove = FORWARDRUN; else if (matedist > FRIEND_DIST) @@ -241,7 +241,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd) (pr_botmove()%100)>skill.isp) && player->ReadyWeapon != NULL && !(player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON)) dest = enemy;//Dont let enemy kill the bot by supressive fire. So charge enemy. else //hide while t_fight, but keep view at enemy. - angle = R_PointToAngle2(player->mo->x, player->mo->y, enemy->x, enemy->y); + angle = player->mo->AngleTo(enemy); } //Just a monster, so kill it. else dest = enemy; @@ -303,8 +303,8 @@ void DBot::ThinkForMove (ticcmd_t *cmd) if (t_fight<(AFTERTICS/2)) player->mo->flags |= MF_DROPOFF; - oldx = player->mo->x; - oldy = player->mo->y; + oldx = player->mo->X(); + oldy = player->mo->Y(); } //BOT_WhatToGet diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index 0a9e4f0e3..3cfbf1c65 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -944,7 +944,7 @@ static void PrintFilteredActorList(const ActorTypeChecker IsActorType, const cha { Printf ("%s at (%d,%d,%d)\n", mo->GetClass()->TypeName.GetChars(), - mo->x >> FRACBITS, mo->y >> FRACBITS, mo->z >> FRACBITS); + mo->X() >> FRACBITS, mo->Y() >> FRACBITS, mo->Z() >> FRACBITS); } } } @@ -1084,7 +1084,7 @@ CCMD(currentpos) { AActor *mo = players[consoleplayer].mo; Printf("Current player position: (%1.3f,%1.3f,%1.3f), angle: %1.3f, floorheight: %1.3f, sector:%d, lightlevel: %d\n", - FIXED2FLOAT(mo->x), FIXED2FLOAT(mo->y), FIXED2FLOAT(mo->z), mo->angle/float(ANGLE_1), FIXED2FLOAT(mo->floorz), mo->Sector->sectornum, mo->Sector->lightlevel); + FIXED2FLOAT(mo->X()), FIXED2FLOAT(mo->Y()), FIXED2FLOAT(mo->Z()), mo->angle/float(ANGLE_1), FIXED2FLOAT(mo->floorz), mo->Sector->sectornum, mo->Sector->lightlevel); } //----------------------------------------------------------------------------- @@ -1106,11 +1106,8 @@ static void PrintSecretString(const char *string, bool thislevel) if (*string == ';') string++; if (thislevel && secnum >= 0 && secnum < numsectors) { - if (sectors[secnum].secretsector) - { - if ((sectors[secnum].special & SECRET_MASK)) colstr = TEXTCOLOR_RED; - else colstr = TEXTCOLOR_GREEN; - } + if (sectors[secnum].isSecret()) colstr = TEXTCOLOR_RED; + else if (sectors[secnum].wasSecret()) colstr = TEXTCOLOR_GREEN; else colstr = TEXTCOLOR_ORANGE; } } diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index bc0acc666..35abd13a8 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -3056,7 +3056,7 @@ bool ADehackedPickup::TryPickup (AActor *&toucher) { return false; } - RealPickup = static_cast(Spawn (type, x, y, z, NO_REPLACE)); + RealPickup = static_cast(Spawn (type, Pos(), NO_REPLACE)); if (RealPickup != NULL) { // The internally spawned item should never count towards statistics. diff --git a/src/d_net.cpp b/src/d_net.cpp index 780b89382..5e8a635d5 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2319,10 +2319,9 @@ void Net_DoCommand (int type, BYTE **stream, int player) else { const AActor *def = GetDefaultByType (typeinfo); - AActor *spawned = Spawn (typeinfo, - source->x + FixedMul (def->radius * 2 + source->radius, finecosine[source->angle>>ANGLETOFINESHIFT]), - source->y + FixedMul (def->radius * 2 + source->radius, finesine[source->angle>>ANGLETOFINESHIFT]), - source->z + 8 * FRACUNIT, ALLOW_REPLACE); + fixedvec3 spawnpos = source->Vec3Angle(def->radius * 2 + source->radius, source->angle, 8 * FRACUNIT); + + AActor *spawned = Spawn (typeinfo, spawnpos, ALLOW_REPLACE); if (spawned != NULL) { if (type == DEM_SUMMONFRIEND || type == DEM_SUMMONFRIEND2 || type == DEM_SUMMONMBF) @@ -2373,8 +2372,8 @@ void Net_DoCommand (int type, BYTE **stream, int player) s = ReadString (stream); - if (Trace (players[player].mo->x, players[player].mo->y, - players[player].mo->z + players[player].mo->height - (players[player].mo->height>>2), + if (Trace (players[player].mo->X(), players[player].mo->Y(), + players[player].mo->Top() - (players[player].mo->height>>2), players[player].mo->Sector, vx, vy, vz, 172*FRACUNIT, 0, ML_BLOCKEVERYTHING, players[player].mo, trace, TRACE_NoSky)) diff --git a/src/d_player.h b/src/d_player.h index e27bf1087..38879a63a 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -221,7 +221,11 @@ enum WF_WEAPONRELOADOK = 1 << 5, // [XA] Okay to reload this weapon. WF_WEAPONZOOMOK = 1 << 6, // [XA] Okay to use weapon zoom function. WF_REFIRESWITCHOK = 1 << 7, // Mirror WF_WEAPONSWITCHOK for A_ReFire -}; + WF_USER1OK = 1 << 8, // [MC] Allow pushing of custom state buttons 1-4 + WF_USER2OK = 1 << 9, + WF_USER3OK = 1 << 10, + WF_USER4OK = 1 << 11, +}; #define WPIECE1 1 #define WPIECE2 2 @@ -405,7 +409,7 @@ public: int lastkilltime; // [RH] For multikills BYTE multicount; BYTE spreecount; // [RH] Keep track of killing sprees - BYTE WeaponState; + WORD WeaponState; AWeapon *ReadyWeapon; AWeapon *PendingWeapon; // WP_NOCHANGE if not changing @@ -418,6 +422,8 @@ public: int killcount, itemcount, secretcount; // for intermission int damagecount, bonuscount;// for screen flashing int hazardcount; // for delayed Strife damage + int hazardinterval; // Frequency of damage infliction + FName hazardtype; // Damage type of last hazardous damage encounter. int poisoncount; // screen flash for poison damage FName poisontype; // type of poison damage to apply FName poisonpaintype; // type of Pain state to enter for poison damage diff --git a/src/dobject.cpp b/src/dobject.cpp index 191fa3c43..9d674d226 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -517,8 +517,8 @@ size_t DObject::StaticPointerSubstitution (DObject *old, DObject *notOld) #define SECTOR_CHECK(f,t) \ if (sectors[i].f.p == static_cast(old)) { sectors[i].f = static_cast(notOld); changed++; } SECTOR_CHECK( SoundTarget, AActor ); - SECTOR_CHECK( CeilingSkyBox, ASkyViewpoint ); - SECTOR_CHECK( FloorSkyBox, ASkyViewpoint ); + SECTOR_CHECK( SkyBoxes[sector_t::ceiling], ASkyViewpoint ); + SECTOR_CHECK( SkyBoxes[sector_t::floor], ASkyViewpoint ); SECTOR_CHECK( SecActTarget, ASectorAction ); SECTOR_CHECK( floordata, DSectorEffect ); SECTOR_CHECK( ceilingdata, DSectorEffect ); diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index d52962f11..3812c0b08 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -640,8 +640,8 @@ size_t DSectorMarker::PropagateMark() { sector_t *sec = §ors[SecNum + i]; GC::Mark(sec->SoundTarget); - GC::Mark(sec->CeilingSkyBox); - GC::Mark(sec->FloorSkyBox); + GC::Mark(sec->SkyBoxes[sector_t::ceiling]); + GC::Mark(sec->SkyBoxes[sector_t::floor]); GC::Mark(sec->SecActTarget); GC::Mark(sec->floordata); GC::Mark(sec->ceilingdata); diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index 7e05be8da..0945b1b4f 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -982,7 +982,7 @@ void FParser::SF_ObjX(void) } t_return.type = svt_fixed; // haleyjd: SoM's fixed-point fix - t_return.value.f = mo ? mo->x : 0; // null ptr check + t_return.value.f = mo ? mo->X() : 0; // null ptr check } //========================================================================== @@ -1005,7 +1005,7 @@ void FParser::SF_ObjY(void) } t_return.type = svt_fixed; // haleyjd - t_return.value.f = mo ? mo->y : 0; // null ptr check + t_return.value.f = mo ? mo->Y() : 0; // null ptr check } //========================================================================== @@ -1028,7 +1028,7 @@ void FParser::SF_ObjZ(void) } t_return.type = svt_fixed; // haleyjd - t_return.value.f = mo ? mo->z : 0; // null ptr check + t_return.value.f = mo ? mo->Z() : 0; // null ptr check } @@ -1466,8 +1466,8 @@ void FParser::SF_SetCamera(void) angle = t_argc < 2 ? newcamera->angle : (fixed_t)FixedToAngle(fixedvalue(t_argv[1])); newcamera->special1=newcamera->angle; - newcamera->special2=newcamera->z; - newcamera->z = t_argc < 3 ? (newcamera->z + (41 << FRACBITS)) : (intvalue(t_argv[2]) << FRACBITS); + newcamera->special2=newcamera->Z(); + newcamera->SetZ(t_argc < 3 ? (newcamera->Z() + (41 << FRACBITS)) : (intvalue(t_argv[2]) << FRACBITS)); newcamera->angle = angle; if(t_argc < 4) newcamera->pitch = 0; else @@ -1498,7 +1498,7 @@ void FParser::SF_ClearCamera(void) { player->camera=player->mo; cam->angle=cam->special1; - cam->z=cam->special2; + cam->SetZ(cam->special2); } } @@ -3065,7 +3065,7 @@ void FParser::SF_SetWeapon() void FParser::SF_MoveCamera(void) { fixed_t x, y, z; - fixed_t xdist, ydist, zdist, xydist, movespeed; + fixed_t zdist, xydist, movespeed; fixed_t xstep, ystep, zstep, targetheight; angle_t anglespeed, anglestep, angledist, targetangle, mobjangle, bigangle, smallangle; @@ -3097,9 +3097,8 @@ void FParser::SF_MoveCamera(void) anglespeed = (angle_t)FixedToAngle(fixedvalue(t_argv[5])); // figure out how big one step will be - xdist = target->x - cam->x; - ydist = target->y - cam->y; - zdist = targetheight - cam->z; + fixedvec2 dist = cam->Vec2To(target); + zdist = targetheight - cam->Z(); // Angle checking... // 90 @@ -3145,8 +3144,8 @@ void FParser::SF_MoveCamera(void) } // set step variables based on distance and speed - mobjangle = R_PointToAngle2(cam->x, cam->y, target->x, target->y); - xydist = R_PointToDist2(target->x - cam->x, target->y - cam->y); + mobjangle = cam->AngleTo(target); + xydist = cam->Distance2D(target); xstep = FixedMul(finecosine[mobjangle >> ANGLETOFINESHIFT], movespeed); ystep = FixedMul(finesine[mobjangle >> ANGLETOFINESHIFT], movespeed); @@ -3170,19 +3169,19 @@ void FParser::SF_MoveCamera(void) else anglestep = anglespeed; - if(abs(xstep) >= (abs(xdist) - 1)) - x = target->x; + if(abs(xstep) >= (abs(dist.x) - 1)) + x = cam->X() + dist.x; else { - x = cam->x + xstep; + x = cam->X() + xstep; moved = 1; } - if(abs(ystep) >= (abs(ydist) - 1)) - y = target->y; + if(abs(ystep) >= (abs(dist.y) - 1)) + y = cam->Y() + dist.y; else { - y = cam->y + ystep; + y = cam->Y() + ystep; moved = 1; } @@ -3190,7 +3189,7 @@ void FParser::SF_MoveCamera(void) z = targetheight; else { - z = cam->z + zstep; + z = cam->Z() + zstep; moved = 1; } @@ -3212,12 +3211,12 @@ void FParser::SF_MoveCamera(void) cam->radius=8; cam->height=8; - if ((x != cam->x || y != cam->y) && !P_TryMove(cam, x, y, true)) + if ((x != cam->X() || y != cam->Y()) && !P_TryMove(cam, x, y, true)) { Printf("Illegal camera move to (%f, %f)\n", x/65536.f, y/65536.f); return; } - cam->z = z; + cam->SetZ(z); t_return.type = svt_int; t_return.value.i = moved; @@ -3410,13 +3409,10 @@ void FParser::SF_SetObjPosition() if (!mobj) return; - mobj->UnlinkFromWorld(); - - mobj->x = intvalue(t_argv[1]) << FRACBITS; - if(t_argc >= 3) mobj->y = intvalue(t_argv[2]) << FRACBITS; - if(t_argc == 4) mobj->z = intvalue(t_argv[3]) << FRACBITS; - - mobj->LinkToWorld(); + mobj->SetOrigin( + fixedvalue(t_argv[1]), + (t_argc >= 3)? fixedvalue(t_argv[2]) : mobj->Y(), + (t_argc >= 4)? fixedvalue(t_argv[3]) : mobj->Z(), false); } } @@ -4285,7 +4281,7 @@ void FParser::SF_SpawnShot2(void) t_return.type = svt_mobj; - AActor *mo = Spawn (PClass, source->x, source->y, source->z+z, ALLOW_REPLACE); + AActor *mo = Spawn (PClass, source->PosPlusZ(z), ALLOW_REPLACE); if (mo) { S_Sound (mo, CHAN_VOICE, mo->SeeSound, 1, ATTN_NORM); @@ -4323,44 +4319,12 @@ void FParser::SF_KillInSector() //========================================================================== // // new for GZDoom: Sets a sector's type -// (Sure, this is not particularly useful. But having it made it possible -// to fix a few annoying bugs in some old maps ;) ) // //========================================================================== void FParser::SF_SectorType(void) { - int tagnum, secnum; - sector_t *sector; - - if (CheckArgs(1)) - { - tagnum = intvalue(t_argv[0]); - - // argv is sector tag - secnum = T_FindFirstSectorFromTag(tagnum); - - if(secnum < 0) - { script_error("sector not found with tagnum %i\n", tagnum); return;} - - sector = §ors[secnum]; - - if(t_argc > 1) - { - int i = -1; - int spec = intvalue(t_argv[1]); - - // set all sectors with tag - FSSectorTagIterator itr(tagnum); - while ((i = itr.Next()) >= 0) - { - sectors[i].special = spec; - } - } - - t_return.type = svt_int; - t_return.value.i = sector->special; - } + // I don't think this was ever used publicly so I'm not going to bother fixing it. } //========================================================================== diff --git a/src/fragglescript/t_load.cpp b/src/fragglescript/t_load.cpp index eedb68f7c..cd40d809a 100644 --- a/src/fragglescript/t_load.cpp +++ b/src/fragglescript/t_load.cpp @@ -87,7 +87,6 @@ DEFINE_MAP_OPTION(fs_nocheckposition, false) { FFsOptions *opt = info->GetOptData("fragglescript"); - parse.ParseAssign(); if (parse.CheckAssign()) { parse.sc.MustGetNumber(); diff --git a/src/g_doom/a_archvile.cpp b/src/g_doom/a_archvile.cpp index f24ff146e..304bb271a 100644 --- a/src/g_doom/a_archvile.cpp +++ b/src/g_doom/a_archvile.cpp @@ -52,7 +52,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Fire) void A_Fire(AActor *self, int height) { AActor *dest; - angle_t an; dest = self->tracer; if (dest == NULL || self->target == NULL) @@ -62,11 +61,8 @@ void A_Fire(AActor *self, int height) if (!P_CheckSight (self->target, dest, 0) ) return; - an = dest->angle >> ANGLETOFINESHIFT; - - self->SetOrigin (dest->x + FixedMul (24*FRACUNIT, finecosine[an]), - dest->y + FixedMul (24*FRACUNIT, finesine[an]), - dest->z + height); + fixedvec3 newpos = dest->Vec3Angle(24 * FRACUNIT, dest->angle, height); + self->SetOrigin(newpos, true); } @@ -86,8 +82,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileTarget) A_FaceTarget (self); - fog = Spawn (fire, self->target->x, self->target->y, - self->target->z, ALLOW_REPLACE); + fog = Spawn (fire, self->target->Pos(), ALLOW_REPLACE); self->tracer = fog; fog->target = self; @@ -117,7 +112,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileAttack) ACTION_PARAM_INT(flags,6); AActor *fire, *target; - angle_t an; if (NULL == (target = self->target)) return; @@ -139,15 +133,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileAttack) P_TraceBleed (newdam > 0 ? newdam : dmg, target); - an = self->angle >> ANGLETOFINESHIFT; fire = self->tracer; if (fire != NULL) { // move the fire between the vile and the player - fire->SetOrigin (target->x - FixedMul (24*FRACUNIT, finecosine[an]), - target->y - FixedMul (24*FRACUNIT, finesine[an]), - target->z); + fixedvec3 pos = target->Vec3Angle(-24 * FRACUNIT, self->angle, target->Z()); + fire->SetOrigin (pos, true); P_RadiusAttack (fire, self, blastdmg, blastrad, dmgtype, 0); } diff --git a/src/g_doom/a_bossbrain.cpp b/src/g_doom/a_bossbrain.cpp index a99ef9323..29bdd2be1 100644 --- a/src/g_doom/a_bossbrain.cpp +++ b/src/g_doom/a_bossbrain.cpp @@ -55,9 +55,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_BrainScream) { fixed_t x; - for (x = self->x - 196*FRACUNIT; x < self->x + 320*FRACUNIT; x += 8*FRACUNIT) + for (x = self->X() - 196*FRACUNIT; x < self->X() + 320*FRACUNIT; x += 8*FRACUNIT) { - BrainishExplosion (x, self->y - 320*FRACUNIT, + BrainishExplosion (x, self->Y() - 320*FRACUNIT, 128 + (pr_brainscream() << (FRACBITS + 1))); } S_Sound (self, CHAN_VOICE, "brain/death", 1, ATTN_NONE); @@ -65,9 +65,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_BrainScream) DEFINE_ACTION_FUNCTION(AActor, A_BrainExplode) { - fixed_t x = self->x + pr_brainexplode.Random2()*2048; + fixed_t x = self->X() + pr_brainexplode.Random2()*2048; fixed_t z = 128 + pr_brainexplode()*2*FRACUNIT; - BrainishExplosion (x, self->y, z); + BrainishExplosion (x, self->Y(), z); } DEFINE_ACTION_FUNCTION(AActor, A_BrainDie) @@ -140,11 +140,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BrainSpit) } else if (abs(spit->vely) > abs(spit->velx)) { - spit->special2 = (targ->y - self->y) / spit->vely; + spit->special2 = (targ->Y() - self->Y()) / spit->vely; } else { - spit->special2 = (targ->x - self->x) / spit->velx; + spit->special2 = (targ->X() - self->X()) / spit->velx; } // [GZ] Calculates when the projectile will have reached destination spit->special2 += level.maptime; @@ -185,7 +185,7 @@ static void SpawnFly(AActor *self, const PClass *spawntype, FSoundID sound) if (spawntype != NULL) { - fog = Spawn (spawntype, targ->x, targ->y, targ->z, ALLOW_REPLACE); + fog = Spawn (spawntype, targ->Pos(), ALLOW_REPLACE); if (fog != NULL) S_Sound (fog, CHAN_BODY, sound, 1, ATTN_NORM); } @@ -256,7 +256,7 @@ static void SpawnFly(AActor *self, const PClass *spawntype, FSoundID sound) spawntype = PClass::FindClass(SpawnName); if (spawntype != NULL) { - newmobj = Spawn (spawntype, targ->x, targ->y, targ->z, ALLOW_REPLACE); + newmobj = Spawn (spawntype, targ->Pos(), ALLOW_REPLACE); if (newmobj != NULL) { // Make the new monster hate what the boss eye hates @@ -275,7 +275,7 @@ static void SpawnFly(AActor *self, const PClass *spawntype, FSoundID sound) if (!(newmobj->ObjectFlags & OF_EuthanizeMe)) { // telefrag anything in this spot - P_TeleportMove (newmobj, newmobj->x, newmobj->y, newmobj->z, true); + P_TeleportMove (newmobj, newmobj->Pos(), true); } newmobj->flags4 |= MF4_BOSSSPAWNED; } diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index 899f1f7d5..4021ad206 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -59,10 +59,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Punch) if (linetarget) { S_Sound (self, CHAN_WEAPON, "*fist", 1, ATTN_NORM); - self->angle = R_PointToAngle2 (self->x, - self->y, - linetarget->x, - linetarget->y); + self->angle = self->AngleTo(linetarget); } } @@ -218,8 +215,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw) // turn to face target if (!(Flags & SF_NOTURN)) { - angle = R_PointToAngle2(self->x, self->y, - linetarget->x, linetarget->y); + angle = self->AngleTo(linetarget); if (angle - self->angle > ANG180) { if (angle - self->angle < (angle_t)(-ANG90 / 20)) @@ -616,8 +612,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray) if (linetarget != NULL) { - AActor *spray = Spawn(spraytype, linetarget->x, linetarget->y, - linetarget->z + (linetarget->height >> 2), ALLOW_REPLACE); + AActor *spray = Spawn(spraytype, linetarget->PosPlusZ(linetarget->height >> 2), ALLOW_REPLACE); int dmgFlags = 0; FName dmgType = NAME_BFGSplash; diff --git a/src/g_doom/a_fatso.cpp b/src/g_doom/a_fatso.cpp index 066e60468..9273febda 100644 --- a/src/g_doom/a_fatso.cpp +++ b/src/g_doom/a_fatso.cpp @@ -145,7 +145,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Mushroom) P_CheckSplash(self, 128<Pos(), NO_REPLACE); // We need something to aim at. AActor *master = (flags & MSF_DontHurt) ? (AActor*)(self->target) : self; target->height = self->height; for (i = -n; i <= n; i += 8) @@ -153,9 +153,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Mushroom) for (j = -n; j <= n; j += 8) { AActor *mo; - target->x = self->x + (i << FRACBITS); // Aim in many directions from source - target->y = self->y + (j << FRACBITS); - target->z = self->z + (P_AproxDistance(i,j) * vrange); // Aim up fairly high + target->SetXYZ( + self->X() + (i << FRACBITS), // Aim in many directions from source + self->Y() + (j << FRACBITS), + self->Z() + (P_AproxDistance(i,j) * vrange)); // Aim up fairly high if ((flags & MSF_Classic) || // Flag explicitely set, or no flags and compat options (flags == 0 && (self->state->DefineFlags & SDF_DEHACKED) && (i_compatflags & COMPATF_MUSHROOM))) { // Use old function for MBF compatibility diff --git a/src/g_doom/a_lostsoul.cpp b/src/g_doom/a_lostsoul.cpp index fdc0257cb..7dc9a1b8f 100644 --- a/src/g_doom/a_lostsoul.cpp +++ b/src/g_doom/a_lostsoul.cpp @@ -36,12 +36,12 @@ void A_SkullAttack(AActor *self, fixed_t speed) an = self->angle >> ANGLETOFINESHIFT; self->velx = FixedMul (speed, finecosine[an]); self->vely = FixedMul (speed, finesine[an]); - dist = P_AproxDistance (dest->x - self->x, dest->y - self->y); + dist = self->AproxDistance (dest); dist = dist / speed; if (dist < 1) dist = 1; - self->velz = (dest->z + (dest->height>>1) - self->z) / dist; + self->velz = (dest->Z() + (dest->height>>1) - self->Z()) / dist; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SkullAttack) diff --git a/src/g_doom/a_painelemental.cpp b/src/g_doom/a_painelemental.cpp index b52224c0c..69d6ef448 100644 --- a/src/g_doom/a_painelemental.cpp +++ b/src/g_doom/a_painelemental.cpp @@ -35,17 +35,14 @@ enum PA_Flags // void A_PainShootSkull (AActor *self, angle_t angle, const PClass *spawntype, int flags = 0, int limit = -1) { - fixed_t x, y, z; - AActor *other; - angle_t an; int prestep; if (spawntype == NULL) return; if (self->DamageType==NAME_Massacre) return; // [RH] check to make sure it's not too close to the ceiling - if (self->z + self->height + 8*FRACUNIT > self->ceilingz) + if (self->Top() + 8*FRACUNIT > self->ceilingz) { if (self->flags & MF_FLOAT) { @@ -76,47 +73,67 @@ void A_PainShootSkull (AActor *self, angle_t angle, const PClass *spawntype, int } // okay, there's room for another one - an = angle >> ANGLETOFINESHIFT; - prestep = 4*FRACUNIT + 3*(self->radius + GetDefaultByType(spawntype)->radius)/2; - - x = self->x + FixedMul (prestep, finecosine[an]); - y = self->y + FixedMul (prestep, finesine[an]); - z = self->z + 8*FRACUNIT; - - // Check whether the Lost Soul is being fired through a 1-sided // phares - // wall or an impassible line, or a "monsters can't cross" line.// | - // If it is, then we don't allow the spawn. // V - FBoundingBox box(MIN(self->x, x), MIN(self->y, y), MAX(self->x, x), MAX(self->y, y)); - FBlockLinesIterator it(box); - line_t *ld; + // NOTE: The following code contains some advance work for line-to-line portals which is currenty inactive. - while ((ld = it.Next())) + fixedvec2 dist = Vec2Angle(prestep, angle); + fixedvec3 pos = self->Vec3Offset(dist.x, dist.y, 8 * FRACUNIT, true); + fixedvec3 src = self->Pos(); + + for (int i = 0; i < 2; i++) { - if (!(ld->flags & ML_TWOSIDED) || - (ld->flags & (ML_BLOCKING|ML_BLOCKMONSTERS|ML_BLOCKEVERYTHING))) + // Check whether the Lost Soul is being fired through a 1-sided // phares + // wall or an impassible line, or a "monsters can't cross" line.// | + // If it is, then we don't allow the spawn. // V + + FBoundingBox box(MIN(src.x, pos.x), MIN(src.y, pos.y), MAX(src.x, pos.x), MAX(src.y, pos.y)); + FBlockLinesIterator it(box); + line_t *ld; + bool inportal = false; + + while ((ld = it.Next())) { - if (!(box.Left() > ld->bbox[BOXRIGHT] || - box.Right() < ld->bbox[BOXLEFT] || - box.Top() < ld->bbox[BOXBOTTOM] || - box.Bottom() > ld->bbox[BOXTOP])) + if (ld->isLinePortal() && i == 0) { - if (P_PointOnLineSide(self->x,self->y,ld) != P_PointOnLineSide(x,y,ld)) - return; // line blocks trajectory // ^ + if (P_PointOnLineSidePrecise(src.x, src.y, ld) == 0 && + P_PointOnLineSidePrecise(pos.x, pos.y, ld) == 1) + { + // crossed a portal line from front to back, we need to repeat the check on the other side as well. + inportal = true; + } + } + else if (!(ld->flags & ML_TWOSIDED) || + (ld->flags & (ML_BLOCKING | ML_BLOCKMONSTERS | ML_BLOCKEVERYTHING))) + { + if (!(box.Left() > ld->bbox[BOXRIGHT] || + box.Right() < ld->bbox[BOXLEFT] || + box.Top() < ld->bbox[BOXBOTTOM] || + box.Bottom() > ld->bbox[BOXTOP])) + { + if (P_PointOnLineSidePrecise(src.x, src.y, ld) != P_PointOnLineSidePrecise(pos.x, pos.y, ld)) + return; // line blocks trajectory // ^ + } } } + if (!inportal) break; + + // recalculate position and redo the check on the other side of the portal + pos = self->Vec3Offset(dist.x, dist.y, 8 * FRACUNIT, false); + src.x = pos.x - dist.x; + src.y = pos.y - dist.y; + } - other = Spawn (spawntype, x, y, z, ALLOW_REPLACE); + other = Spawn (spawntype, pos.x, pos.y, pos.z, ALLOW_REPLACE); // Check to see if the new Lost Soul's z value is above the // ceiling of its new sector, or below the floor. If so, kill it. - if ((other->z > - (other->Sector->ceilingplane.ZatPoint (other->x, other->y) - other->height)) || - (other->z < other->Sector->floorplane.ZatPoint (other->x, other->y))) + if ((other->Z() > + (other->Sector->HighestCeiling(other) - other->height)) || + (other->Z() < other->Sector->LowestFloor(other))) { // kill it immediately P_DamageMobj (other, self, self, TELEFRAG_DAMAGE, NAME_None);// ^ @@ -125,7 +142,7 @@ void A_PainShootSkull (AActor *self, angle_t angle, const PClass *spawntype, int // Check for movements. - if (!P_CheckPosition (other, other->x, other->y)) + if (!P_CheckPosition (other, other->Pos())) { // kill it immediately P_DamageMobj (other, self, self, TELEFRAG_DAMAGE, NAME_None); diff --git a/src/g_doom/a_revenant.cpp b/src/g_doom/a_revenant.cpp index 0600a59eb..9b8821fb4 100644 --- a/src/g_doom/a_revenant.cpp +++ b/src/g_doom/a_revenant.cpp @@ -26,13 +26,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkelMissile) return; A_FaceTarget (self); - missile = P_SpawnMissileZ (self, self->z + 48*FRACUNIT, + missile = P_SpawnMissileZ (self, self->Z() + 48*FRACUNIT, self->target, PClass::FindClass("RevenantTracer")); if (missile != NULL) { - missile->x += missile->velx; - missile->y += missile->vely; + missile->SetOrigin(missile->Vec3Offset(missile->velx, missile->vely, 0), false); missile->tracer = self->target; } } @@ -60,10 +59,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer) return; // spawn a puff of smoke behind the rocket - P_SpawnPuff (self, PClass::FindClass(NAME_BulletPuff), self->x, self->y, self->z, 0, 3); + P_SpawnPuff (self, PClass::FindClass(NAME_BulletPuff), self->X(), self->Y(), self->Z(), 0, 3); - smoke = Spawn ("RevenantTracerSmoke", self->x - self->velx, - self->y - self->vely, self->z, ALLOW_REPLACE); + smoke = Spawn ("RevenantTracerSmoke", self->Vec3Offset(-self->velx, -self->vely, 0), ALLOW_REPLACE); smoke->velz = FRACUNIT; smoke->tics -= pr_tracer()&3; @@ -77,7 +75,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer) return; // change angle - exact = R_PointToAngle2 (self->x, self->y, dest->x, dest->y); + exact = self->AngleTo(dest); if (exact != self->angle) { @@ -102,21 +100,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer) if (!(self->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER))) { // change slope - dist = P_AproxDistance (dest->x - self->x, - dest->y - self->y); - - dist = dist / self->Speed; + dist = self->AproxDistance (dest) / self->Speed; if (dist < 1) dist = 1; if (dest->height >= 56*FRACUNIT) { - slope = (dest->z+40*FRACUNIT - self->z) / dist; + slope = (dest->Z()+40*FRACUNIT - self->Z()) / dist; } else { - slope = (dest->z + self->height*2/3 - self->z) / dist; + slope = (dest->Z() + self->height*2/3 - self->Z()) / dist; } if (slope < self->velz) diff --git a/src/g_doom/a_scriptedmarine.cpp b/src/g_doom/a_scriptedmarine.cpp index be39b545b..6e75d80e6 100644 --- a/src/g_doom/a_scriptedmarine.cpp +++ b/src/g_doom/a_scriptedmarine.cpp @@ -276,7 +276,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Saw) S_Sound (self, CHAN_WEAPON, hitsound, 1, ATTN_NORM); // turn to face target - angle = R_PointToAngle2 (self->x, self->y, linetarget->x, linetarget->y); + angle = self->AngleTo(linetarget); if (angle - self->angle > ANG180) { if (angle - self->angle < (angle_t)(-ANG90/20)) @@ -326,7 +326,8 @@ static void MarinePunch(AActor *self, int damagemul) if (linetarget) { S_Sound (self, CHAN_WEAPON, "*fist", 1, ATTN_NORM); - self->angle = R_PointToAngle2 (self->x, self->y, linetarget->x, linetarget->y); + self->angle = self->AngleTo(linetarget); + } } diff --git a/src/g_doomedmap.cpp b/src/g_doomedmap.cpp index 08d5aa2e2..42157101d 100644 --- a/src/g_doomedmap.cpp +++ b/src/g_doomedmap.cpp @@ -81,7 +81,7 @@ struct MapinfoEdMapItem { FName classname; // DECORATE is read after MAPINFO so we do not have the actual classes available here yet. short special; - bool argsdefined; + signed char argsdefined; int args[5]; // These are for error reporting. We must store the file information because it's no longer available when these items get resolved. FString filename; @@ -181,14 +181,14 @@ void FMapInfoParser::ParseDoomEdNums() editem.special = -1; } memset(editem.args, 0, sizeof(editem.args)); - editem.argsdefined = false; + editem.argsdefined = 0; int minargs = 0; int maxargs = 5; FString specialname; if (sc.CheckString(",")) { - editem.argsdefined = true; // mark args as used - if this is done we need to prevent assignment of map args in P_SpawnMapThing. + editem.argsdefined = 5; // mark args as used - if this is done we need to prevent assignment of map args in P_SpawnMapThing. if (editem.special < 0) editem.special = 0; if (!sc.CheckNumber()) { @@ -221,7 +221,14 @@ void FMapInfoParser::ParseDoomEdNums() editem.args[i] = sc.Number; i++; if (!sc.CheckString(",")) break; + // special check for the ambient sounds which combine the arg being set here with the ones on the mapthing. + if (sc.CheckString("+")) + { + editem.argsdefined = i; + break; + } sc.MustGetNumber(); + } if (specialname.IsNotEmpty() && (i < minargs || i > maxargs)) { diff --git a/src/g_game.cpp b/src/g_game.cpp index 8101ca23d..799a4e7aa 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1176,7 +1176,7 @@ void G_Ticker () } if (players[i].mo) { - DWORD sum = rngsum + players[i].mo->x + players[i].mo->y + players[i].mo->z + DWORD sum = rngsum + players[i].mo->X() + players[i].mo->Y() + players[i].mo->Z() + players[i].mo->angle + players[i].mo->pitch; sum ^= players[i].health; consistancy[i][buf] = sum; @@ -1435,13 +1435,13 @@ bool G_CheckSpot (int playernum, FPlayerStart *mthing) if (!players[playernum].mo) { // first spawn of level, before corpses for (i = 0; i < playernum; i++) - if (players[i].mo && players[i].mo->x == x && players[i].mo->y == y) + if (players[i].mo && players[i].mo->X() == x && players[i].mo->Y() == y) return false; return true; } - oldz = players[playernum].mo->z; // [RH] Need to save corpse's z-height - players[playernum].mo->z = z; // [RH] Checks are now full 3-D + oldz = players[playernum].mo->Z(); // [RH] Need to save corpse's z-height + players[playernum].mo->SetZ(z); // [RH] Checks are now full 3-D // killough 4/2/98: fix bug where P_CheckPosition() uses a non-solid // corpse to detect collisions with other players in DM starts @@ -1453,7 +1453,7 @@ bool G_CheckSpot (int playernum, FPlayerStart *mthing) players[playernum].mo->flags |= MF_SOLID; i = P_CheckPosition(players[playernum].mo, x, y); players[playernum].mo->flags &= ~MF_SOLID; - players[playernum].mo->z = oldz; // [RH] Restore corpse's height + players[playernum].mo->SetZ(oldz); // [RH] Restore corpse's height if (!i) return false; @@ -1479,8 +1479,7 @@ static fixed_t PlayersRangeFromSpot (FPlayerStart *spot) if (!playeringame[i] || !players[i].mo || players[i].health <= 0) continue; - distance = P_AproxDistance (players[i].mo->x - spot->x, - players[i].mo->y - spot->y); + distance = players[i].mo->AproxDistance (spot->x, spot->y); if (distance < closest) closest = distance; @@ -1713,6 +1712,8 @@ void G_DoPlayerPop(int playernum) // [RH] Make the player disappear FBehavior::StaticStopMyScripts(players[playernum].mo); + // [RH] Let the scripts know the player left + FBehavior::StaticStartTypedScripts(SCRIPT_Disconnect, players[playernum].mo, true, playernum, true); if (players[playernum].mo != NULL) { P_DisconnectEffect(players[playernum].mo); @@ -1726,8 +1727,6 @@ void G_DoPlayerPop(int playernum) players[playernum].mo = NULL; players[playernum].camera = NULL; } - // [RH] Let the scripts know the player left - FBehavior::StaticStartTypedScripts(SCRIPT_Disconnect, NULL, true, playernum); } void G_ScreenShot (char *filename) @@ -1931,9 +1930,6 @@ void G_DoLoadGame () } G_ReadSnapshots (png); - STAT_Read(png); - FRandom::StaticReadRNGState (png); - P_ReadACSDefereds (png); // load a base level savegamerestore = true; // Use the player actors in the savegame @@ -1943,6 +1939,9 @@ void G_DoLoadGame () delete[] map; savegamerestore = false; + STAT_Read(png); + FRandom::StaticReadRNGState(png); + P_ReadACSDefereds(png); P_ReadACSVars(png); NextSkill = -1; diff --git a/src/g_heretic/a_chicken.cpp b/src/g_heretic/a_chicken.cpp index 082774a3d..329b4d264 100644 --- a/src/g_heretic/a_chicken.cpp +++ b/src/g_heretic/a_chicken.cpp @@ -45,7 +45,7 @@ void AChickenPlayer::MorphPlayerThink () { // Twitch view angle angle += pr_chickenplayerthink.Random2 () << 19; } - if ((z <= floorz) && (pr_chickenplayerthink() < 32)) + if ((Z() <= floorz) && (pr_chickenplayerthink() < 32)) { // Jump and noise velz += JumpZ; @@ -100,7 +100,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Feathers) } for (i = 0; i < count; i++) { - mo = Spawn("Feather", self->x, self->y, self->z+20*FRACUNIT, NO_REPLACE); + mo = Spawn("Feather", self->PosPlusZ(20*FRACUNIT), NO_REPLACE); mo->target = self; mo->velx = pr_feathers.Random2() << 8; mo->vely = pr_feathers.Random2() << 8; @@ -178,8 +178,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL1) P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true, &linetarget); if (linetarget) { - player->mo->angle = R_PointToAngle2 (player->mo->x, - player->mo->y, linetarget->x, linetarget->y); + player->mo->angle = player->mo->AngleTo(linetarget); } P_PlayPeck (player->mo); player->chickenPeck = 12; @@ -211,8 +210,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL2) P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true, &linetarget); if (linetarget) { - player->mo->angle = R_PointToAngle2 (player->mo->x, - player->mo->y, linetarget->x, linetarget->y); + player->mo->angle = player->mo->AngleTo(linetarget); } P_PlayPeck (player->mo); player->chickenPeck = 12; diff --git a/src/g_heretic/a_dsparil.cpp b/src/g_heretic/a_dsparil.cpp index e4d86c83a..bb3cfb0c5 100644 --- a/src/g_heretic/a_dsparil.cpp +++ b/src/g_heretic/a_dsparil.cpp @@ -78,17 +78,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_Srcr1Attack) const PClass *fx = PClass::FindClass("SorcererFX1"); if (self->health > (self->SpawnHealth()/3)*2) { // Spit one fireball - P_SpawnMissileZ (self, self->z + 48*FRACUNIT, self->target, fx ); + P_SpawnMissileZ (self, self->Z() + 48*FRACUNIT, self->target, fx ); } else { // Spit three fireballs - mo = P_SpawnMissileZ (self, self->z + 48*FRACUNIT, self->target, fx); + mo = P_SpawnMissileZ (self, self->Z() + 48*FRACUNIT, self->target, fx); if (mo != NULL) { velz = mo->velz; angle = mo->angle; - P_SpawnMissileAngleZ (self, self->z + 48*FRACUNIT, fx, angle-ANGLE_1*3, velz); - P_SpawnMissileAngleZ (self, self->z + 48*FRACUNIT, fx, angle+ANGLE_1*3, velz); + P_SpawnMissileAngleZ (self, self->Z() + 48*FRACUNIT, fx, angle-ANGLE_1*3, velz); + P_SpawnMissileAngleZ (self, self->Z() + 48*FRACUNIT, fx, angle+ANGLE_1*3, velz); } if (self->health < self->SpawnHealth()/3) { // Maybe attack again @@ -116,7 +116,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcererRise) AActor *mo; self->flags &= ~MF_SOLID; - mo = Spawn("Sorcerer2", self->x, self->y, self->z, ALLOW_REPLACE); + mo = Spawn("Sorcerer2", self->Pos(), ALLOW_REPLACE); mo->Translation = self->Translation; mo->SetState (mo->FindState("Rise")); mo->angle = self->angle; @@ -140,20 +140,20 @@ void P_DSparilTeleport (AActor *actor) DSpotState *state = DSpotState::GetSpotState(); if (state == NULL) return; - spot = state->GetSpotWithMinMaxDistance(PClass::FindClass("BossSpot"), actor->x, actor->y, 128*FRACUNIT, 0); + spot = state->GetSpotWithMinMaxDistance(PClass::FindClass("BossSpot"), actor->X(), actor->Y(), 128*FRACUNIT, 0); if (spot == NULL) return; - prevX = actor->x; - prevY = actor->y; - prevZ = actor->z; - if (P_TeleportMove (actor, spot->x, spot->y, spot->z, false)) + prevX = actor->X(); + prevY = actor->Y(); + prevZ = actor->Z(); + if (P_TeleportMove (actor, spot->Pos(), false)) { mo = Spawn("Sorcerer2Telefade", prevX, prevY, prevZ, ALLOW_REPLACE); if (mo) mo->Translation = actor->Translation; S_Sound (mo, CHAN_BODY, "misc/teleport", 1, ATTN_NORM); actor->SetState (actor->FindState("Teleport")); S_Sound (actor, CHAN_BODY, "misc/teleport", 1, ATTN_NORM); - actor->z = actor->floorz; + actor->SetZ(actor->floorz, false); actor->angle = spot->angle; actor->velx = actor->vely = actor->velz = 0; } @@ -237,7 +237,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BlueSpark) for (i = 0; i < 2; i++) { - mo = Spawn("Sorcerer2FXSpark", self->x, self->y, self->z, ALLOW_REPLACE); + mo = Spawn("Sorcerer2FXSpark", self->Pos(), ALLOW_REPLACE); mo->velx = pr_bluespark.Random2() << 9; mo->vely = pr_bluespark.Random2() << 9; mo->velz = FRACUNIT + (pr_bluespark()<<8); @@ -254,10 +254,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_GenWizard) { AActor *mo; - mo = Spawn("Wizard", self->x, self->y, self->z, ALLOW_REPLACE); + mo = Spawn("Wizard", self->Pos(), ALLOW_REPLACE); if (mo != NULL) { - mo->z -= mo->GetDefault()->height/2; + mo->AddZ(-mo->GetDefault()->height / 2, false); if (!P_TestMobjLocation (mo)) { // Didn't fit mo->ClearCounters(); @@ -272,7 +272,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_GenWizard) self->flags &= ~MF_MISSILE; mo->master = self->target; // Heretic did not offset it by TELEFOGHEIGHT, so I won't either. - Spawn (self->x, self->y, self->z, ALLOW_REPLACE); + Spawn (self->Pos(), ALLOW_REPLACE); } } } diff --git a/src/g_heretic/a_hereticartifacts.cpp b/src/g_heretic/a_hereticartifacts.cpp index 651e3609c..322869f19 100644 --- a/src/g_heretic/a_hereticartifacts.cpp +++ b/src/g_heretic/a_hereticartifacts.cpp @@ -47,8 +47,8 @@ bool AArtiTomeOfPower::Use (bool pickup) DEFINE_ACTION_FUNCTION(AActor, A_TimeBomb) { - self->z += 32*FRACUNIT; - self->PrevZ = self->z; // no interpolation! + self->AddZ(32*FRACUNIT, false); + self->PrevZ = self->Z(); // no interpolation! self->RenderStyle = STYLE_Add; self->alpha = FRACUNIT; P_RadiusAttack (self, self->target, 128, 128, self->DamageType, RADF_HURTSOURCE); @@ -69,9 +69,7 @@ bool AArtiTimeBomb::Use (bool pickup) { angle_t angle = Owner->angle >> ANGLETOFINESHIFT; AActor *mo = Spawn("ActivatedTimeBomb", - Owner->x + 24*finecosine[angle], - Owner->y + 24*finesine[angle], - Owner->z - Owner->floorclip, ALLOW_REPLACE); + Vec3Angle(24*FRACUNIT, Owner->angle, - Owner->floorclip), ALLOW_REPLACE); mo->target = Owner; return true; } diff --git a/src/g_heretic/a_hereticimp.cpp b/src/g_heretic/a_hereticimp.cpp index 221fe49fb..71c9debc4 100644 --- a/src/g_heretic/a_hereticimp.cpp +++ b/src/g_heretic/a_hereticimp.cpp @@ -41,12 +41,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_ImpExplode) self->flags &= ~MF_NOGRAVITY; - chunk = Spawn("HereticImpChunk1", self->x, self->y, self->z, ALLOW_REPLACE); + chunk = Spawn("HereticImpChunk1", self->Pos(), ALLOW_REPLACE); chunk->velx = pr_imp.Random2 () << 10; chunk->vely = pr_imp.Random2 () << 10; chunk->velz = 9*FRACUNIT; - chunk = Spawn("HereticImpChunk2", self->x, self->y, self->z, ALLOW_REPLACE); + chunk = Spawn("HereticImpChunk2", self->Pos(), ALLOW_REPLACE); chunk->velx = pr_imp.Random2 () << 10; chunk->vely = pr_imp.Random2 () << 10; chunk->velz = 9*FRACUNIT; diff --git a/src/g_heretic/a_hereticmisc.cpp b/src/g_heretic/a_hereticmisc.cpp index 279635482..09c3d4253 100644 --- a/src/g_heretic/a_hereticmisc.cpp +++ b/src/g_heretic/a_hereticmisc.cpp @@ -57,7 +57,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PodPain) } for (count = chance > 240 ? 2 : 1; count; count--) { - goo = Spawn(gootype, self->x, self->y, self->z + 48*FRACUNIT, ALLOW_REPLACE); + goo = Spawn(gootype, self->PosPlusZ(48*FRACUNIT), ALLOW_REPLACE); goo->target = self; goo->velx = pr_podpain.Random2() << 9; goo->vely = pr_podpain.Random2() << 9; @@ -100,15 +100,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MakePod) AActor *mo; fixed_t x; fixed_t y; - fixed_t z; if (self->special1 == MAX_GEN_PODS) { // Too many generated pods return; } - x = self->x; - y = self->y; - z = self->z; + x = self->X(); + y = self->Y(); mo = Spawn(podtype, x, y, ONFLOORZ, ALLOW_REPLACE); if (!P_CheckPosition (mo, x, y)) { // Didn't fit @@ -165,8 +163,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_VolcanoBlast) count = 1 + (pr_blast() % 3); for (i = 0; i < count; i++) { - blast = Spawn("VolcanoBlast", self->x, self->y, - self->z + 44*FRACUNIT, ALLOW_REPLACE); + blast = Spawn("VolcanoBlast", self->PosPlusZ(44*FRACUNIT), ALLOW_REPLACE); blast->target = self; angle = pr_blast () << 24; blast->angle = angle; @@ -191,17 +188,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_VolcBallImpact) AActor *tiny; angle_t angle; - if (self->z <= self->floorz) + if (self->Z() <= self->floorz) { self->flags |= MF_NOGRAVITY; self->gravity = FRACUNIT; - self->z += 28*FRACUNIT; + self->AddZ(28*FRACUNIT); //self->velz = 3*FRACUNIT; } P_RadiusAttack (self, self->target, 25, 25, NAME_Fire, RADF_HURTSOURCE); for (i = 0; i < 4; i++) { - tiny = Spawn("VolcanoTBlast", self->x, self->y, self->z, ALLOW_REPLACE); + tiny = Spawn("VolcanoTBlast", self->Pos(), ALLOW_REPLACE); tiny->target = self; angle = i*ANG90; tiny->angle = angle; diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp index afc4f6007..ba216a8ba 100644 --- a/src/g_heretic/a_hereticweaps.cpp +++ b/src/g_heretic/a_hereticweaps.cpp @@ -90,8 +90,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StaffAttack) { //S_StartSound(player->mo, sfx_stfhit); // turn to face target - self->angle = R_PointToAngle2 (self->x, - self->y, linetarget->x, linetarget->y); + self->angle = self->AngleTo(linetarget); } } @@ -307,8 +306,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack) S_Sound (self, CHAN_AUTO, "weapons/gauntletshit", 1, ATTN_NORM); } // turn to face target - angle = R_PointToAngle2 (self->x, self->y, - linetarget->x, linetarget->y); + angle = self->AngleTo(linetarget); if (angle-self->angle > ANG180) { if ((int)(angle-self->angle) < -ANG90/20) @@ -384,14 +382,13 @@ void FireMacePL1B (AActor *actor) if (!weapon->DepleteAmmo (weapon->bAltFire)) return; } - ball = Spawn("MaceFX2", actor->x, actor->y, actor->z + 28*FRACUNIT - - actor->floorclip, ALLOW_REPLACE); + ball = Spawn("MaceFX2", actor->PosPlusZ(28*FRACUNIT - actor->floorclip), ALLOW_REPLACE); ball->velz = 2*FRACUNIT+/*((player->lookdir)<<(FRACBITS-5))*/ finetangent[FINEANGLES/4-(actor->pitch>>ANGLETOFINESHIFT)]; angle = actor->angle; ball->target = actor; ball->angle = angle; - ball->z += 2*finetangent[FINEANGLES/4-(actor->pitch>>ANGLETOFINESHIFT)]; + ball->AddZ(2*finetangent[FINEANGLES/4-(actor->pitch>>ANGLETOFINESHIFT)]); angle >>= ANGLETOFINESHIFT; ball->velx = (actor->velx>>1) + FixedMul(ball->Speed, finecosine[angle]); ball->vely = (actor->vely>>1) + FixedMul(ball->Speed, finesine[angle]); @@ -510,10 +507,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_MaceBallImpact2) if (self->flags & MF_INBOUNCE) { - fixed_t floordist = self->z - self->floorz; - fixed_t ceildist = self->ceilingz - self->z; + fixed_t floordist = self->Z() - self->floorz; + fixed_t ceildist = self->ceilingz - self->Z(); fixed_t vel; + // NOTE: The assumptions being made here about the plane to use for bouncing off are dead wrong. + // http://forum.zdoom.org/viewtopic.php?f=2&t=50449 if (floordist <= ceildist) { vel = MulScale32 (self->velz, self->Sector->floorplane.c); @@ -531,7 +530,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MaceBallImpact2) self->velz = (self->velz * 192) >> 8; self->SetState (self->SpawnState); - tiny = Spawn("MaceFX3", self->x, self->y, self->z, ALLOW_REPLACE); + tiny = Spawn("MaceFX3", self->Pos(), ALLOW_REPLACE); angle = self->angle+ANG90; tiny->target = self->target; tiny->angle = angle; @@ -541,7 +540,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MaceBallImpact2) tiny->velz = self->velz; P_CheckMissileSpawn (tiny, self->radius); - tiny = Spawn("MaceFX3", self->x, self->y, self->z, ALLOW_REPLACE); + tiny = Spawn("MaceFX3", self->Pos(), ALLOW_REPLACE); angle = self->angle-ANG90; tiny->target = self->target; tiny->angle = angle; @@ -613,17 +612,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeathBallImpact) bool newAngle; AActor *linetarget; - if ((self->z <= self->floorz) && P_HitFloor (self)) + if ((self->Z() <= self->floorz) && P_HitFloor (self)) { // Landed in some sort of liquid self->Destroy (); return; } if (self->flags & MF_INBOUNCE) { - fixed_t floordist = self->z - self->floorz; - fixed_t ceildist = self->ceilingz - self->z; + fixed_t floordist = self->Z() - self->floorz; + fixed_t ceildist = self->ceilingz - self->Z(); fixed_t vel; + // NOTE: The assumptions being made here about the plane to use for bouncing off are dead wrong. + // http://forum.zdoom.org/viewtopic.php?f=2&t=50449 if (floordist <= ceildist) { vel = MulScale32 (self->velz, self->Sector->floorplane.c); @@ -648,8 +649,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeathBallImpact) } else { // Seek - angle = R_PointToAngle2(self->x, self->y, - target->x, target->y); + self->angle = self->AngleTo(target); newAngle = true; } } @@ -662,8 +662,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeathBallImpact) if (linetarget && self->target != linetarget) { self->tracer = linetarget; - angle = R_PointToAngle2 (self->x, self->y, - linetarget->x, linetarget->y); + angle = self->AngleTo(linetarget); newAngle = true; break; } @@ -724,7 +723,7 @@ void ABlasterFX1::Effect () { if (pr_bfx1t() < 64) { - Spawn("BlasterSmoke", x, y, MAX (z - 8 * FRACUNIT, floorz), ALLOW_REPLACE); + Spawn("BlasterSmoke", X(), Y(), MAX (Z() - 8 * FRACUNIT, floorz), ALLOW_REPLACE); } } @@ -803,7 +802,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnRippers) for(i = 0; i < 8; i++) { - ripper = Spawn (self->x, self->y, self->z, ALLOW_REPLACE); + ripper = Spawn (self->Pos(), ALLOW_REPLACE); angle = i*ANG45; ripper->target = self->target; ripper->angle = angle; @@ -1011,8 +1010,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_AddPlayerRain) DEFINE_ACTION_FUNCTION(AActor, A_SkullRodStorm) { - fixed_t x; - fixed_t y; AActor *mo; ARainTracker *tracker; @@ -1043,20 +1040,21 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullRodStorm) { // Fudge rain frequency return; } - x = self->x + ((pr_storm()&127) - 64) * FRACUNIT; - y = self->y + ((pr_storm()&127) - 64) * FRACUNIT; - mo = Spawn (x, y, ONCEILINGZ, ALLOW_REPLACE); + fixedvec2 pos = self->Vec2Offset( + ((pr_storm()&127) - 64) * FRACUNIT, + ((pr_storm()&127) - 64) * FRACUNIT); + mo = Spawn (pos.x, pos.y, ONCEILINGZ, ALLOW_REPLACE); // We used bouncecount to store the 3D floor index in A_HideInCeiling if (!mo) return; fixed_t newz; if (self->bouncecount >= 0 && (unsigned)self->bouncecount < self->Sector->e->XFloor.ffloors.Size()) - newz = self->Sector->e->XFloor.ffloors[self->bouncecount]->bottom.plane->ZatPoint(x, y);// - 40 * FRACUNIT; + newz = self->Sector->e->XFloor.ffloors[self->bouncecount]->bottom.plane->ZatPoint(pos.x, pos.y);// - 40 * FRACUNIT; else - newz = self->Sector->ceilingplane.ZatPoint(x, y); - int moceiling = P_Find3DFloor(NULL, x, y, newz, false, false, newz); + newz = self->Sector->ceilingplane.ZatPoint(pos.x, pos.y); + int moceiling = P_Find3DFloor(NULL, pos.x, pos.y, newz, false, false, newz); if (moceiling >= 0) - mo->z = newz - mo->height; + mo->SetZ(newz - mo->height, false); mo->Translation = multiplayer ? TRANSLATION(TRANSLATION_PlayersExtra,self->special2) : 0; mo->target = self->target; @@ -1078,7 +1076,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullRodStorm) DEFINE_ACTION_FUNCTION(AActor, A_RainImpact) { - if (self->z > self->floorz) + if (self->Z() > self->floorz) { self->SetState (self->FindState("NotFloor")); } @@ -1103,15 +1101,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_HideInCeiling) F3DFloor * rover = self->Sector->e->XFloor.ffloors[i]; if(!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue; - if ((foo = rover->bottom.plane->ZatPoint(self->x, self->y)) >= (self->z + self->height)) + if ((foo = rover->bottom.plane->ZatPoint(self)) >= (self->Top())) { - self->z = foo + 4*FRACUNIT; + self->SetZ(foo + 4*FRACUNIT, false); self->bouncecount = i; return; } } self->bouncecount = -1; - self->z = self->ceilingz + 4*FRACUNIT; + self->SetZ(self->ceilingz + 4*FRACUNIT, false); } // --- Phoenix Rod ---------------------------------------------------------- @@ -1229,13 +1227,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_PhoenixPuff) //[RH] Heretic never sets the target for seeking //P_SeekerMissile (self, ANGLE_1*5, ANGLE_1*10); - puff = Spawn("PhoenixPuff", self->x, self->y, self->z, ALLOW_REPLACE); + puff = Spawn("PhoenixPuff", self->Pos(), ALLOW_REPLACE); angle = self->angle + ANG90; angle >>= ANGLETOFINESHIFT; puff->velx = FixedMul (FRACUNIT*13/10, finecosine[angle]); puff->vely = FixedMul (FRACUNIT*13/10, finesine[angle]); puff->velz = 0; - puff = Spawn("PhoenixPuff", self->x, self->y, self->z, ALLOW_REPLACE); + puff = Spawn("PhoenixPuff", self->Pos(), ALLOW_REPLACE); angle = self->angle - ANG90; angle >>= ANGLETOFINESHIFT; puff->velx = FixedMul (FRACUNIT*13/10, finecosine[angle]); @@ -1273,7 +1271,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL2) { AActor *mo; angle_t angle; - fixed_t x, y, z; fixed_t slope; FSoundID soundid; @@ -1296,12 +1293,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL2) return; } angle = self->angle; - x = self->x + (pr_fp2.Random2() << 9); - y = self->y + (pr_fp2.Random2() << 9); - z = self->z + 26*FRACUNIT + finetangent[FINEANGLES/4-(self->pitch>>ANGLETOFINESHIFT)]; - z -= self->floorclip; + + fixed_t xo = (pr_fp2.Random2() << 9); + fixed_t yo = (pr_fp2.Random2() << 9); + fixedvec3 pos = self->Vec3Offset(xo, yo, + 26*FRACUNIT + finetangent[FINEANGLES/4-(self->pitch>>ANGLETOFINESHIFT)] - self->floorclip); + slope = finetangent[FINEANGLES/4-(self->pitch>>ANGLETOFINESHIFT)] + (FRACUNIT/10); - mo = Spawn("PhoenixFX2", x, y, z, ALLOW_REPLACE); + mo = Spawn("PhoenixFX2", pos, ALLOW_REPLACE); mo->target = self; mo->angle = angle; mo->velx = self->velx + FixedMul (mo->Speed, finecosine[angle>>ANGLETOFINESHIFT]); diff --git a/src/g_heretic/a_ironlich.cpp b/src/g_heretic/a_ironlich.cpp index dba16b622..206ba5e8b 100644 --- a/src/g_heretic/a_ironlich.cpp +++ b/src/g_heretic/a_ironlich.cpp @@ -91,8 +91,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichAttack) P_TraceBleed (newdam > 0 ? newdam : damage, target, self); return; } - dist = P_AproxDistance (self->x-target->x, self->y-target->y) - > 8*64*FRACUNIT; + dist = self->AproxDistance (target) > 8*64*FRACUNIT; randAttack = pr_atk (); if (randAttack < atkResolve1[dist]) { // Ice ball @@ -107,8 +106,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichAttack) baseFire->SetState (baseFire->FindState("NoGrow")); for (i = 0; i < 5; i++) { - fire = Spawn("HeadFX3", baseFire->x, baseFire->y, - baseFire->z, ALLOW_REPLACE); + fire = Spawn("HeadFX3", baseFire->Pos(), ALLOW_REPLACE); if (i == 0) { S_Sound (self, CHAN_BODY, "ironlich/attack1", 1, ATTN_NORM); @@ -129,7 +127,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichAttack) mo = P_SpawnMissile (self, target, RUNTIME_CLASS(AWhirlwind)); if (mo != NULL) { - mo->z -= 32*FRACUNIT; + mo->AddZ(-32*FRACUNIT, false); mo->tracer = target; mo->special1 = 60; mo->special2 = 50; // Timer for active sound @@ -181,7 +179,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichIceImpact) for (i = 0; i < 8; i++) { - shard = Spawn("HeadFX2", self->x, self->y, self->z, ALLOW_REPLACE); + shard = Spawn("HeadFX2", self->Pos(), ALLOW_REPLACE); angle = i*ANG45; shard->target = self->target; shard->angle = angle; @@ -202,7 +200,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichIceImpact) DEFINE_ACTION_FUNCTION(AActor, A_LichFireGrow) { self->health--; - self->z += 9*FRACUNIT; + self->AddZ(9*FRACUNIT); if (self->health == 0) { self->Damage = self->GetDefault()->Damage; diff --git a/src/g_heretic/a_knight.cpp b/src/g_heretic/a_knight.cpp index 18280326a..0ae5a240a 100644 --- a/src/g_heretic/a_knight.cpp +++ b/src/g_heretic/a_knight.cpp @@ -22,11 +22,10 @@ static FRandom pr_knightatk ("KnightAttack"); DEFINE_ACTION_FUNCTION(AActor, A_DripBlood) { AActor *mo; - fixed_t x, y; - x = self->x + (pr_dripblood.Random2 () << 11); - y = self->y + (pr_dripblood.Random2 () << 11); - mo = Spawn ("Blood", x, y, self->z, ALLOW_REPLACE); + fixed_t xo = (pr_dripblood.Random2() << 11); + fixed_t yo = (pr_dripblood.Random2() << 11); + mo = Spawn ("Blood", self->Vec3Offset(xo, yo, 0), ALLOW_REPLACE); mo->velx = pr_dripblood.Random2 () << 10; mo->vely = pr_dripblood.Random2 () << 10; mo->gravity = FRACUNIT/8; @@ -56,10 +55,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_KnightAttack) S_Sound (self, CHAN_BODY, self->AttackSound, 1, ATTN_NORM); if (self->flags & MF_SHADOW || pr_knightatk () < 40) { // Red axe - P_SpawnMissileZ (self, self->z + 36*FRACUNIT, self->target, PClass::FindClass("RedAxe")); + P_SpawnMissileZ (self, self->Z() + 36*FRACUNIT, self->target, PClass::FindClass("RedAxe")); return; } // Green axe - P_SpawnMissileZ (self, self->z + 36*FRACUNIT, self->target, PClass::FindClass("KnightAxe")); + P_SpawnMissileZ (self, self->Z() + 36*FRACUNIT, self->target, PClass::FindClass("KnightAxe")); } diff --git a/src/g_hexen/a_bats.cpp b/src/g_hexen/a_bats.cpp index eda5692ae..8edb68cee 100644 --- a/src/g_hexen/a_bats.cpp +++ b/src/g_hexen/a_bats.cpp @@ -84,6 +84,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_BatMove) } // Handle Z movement - self->z = self->target->z + 16*finesine[self->args[0] << BOBTOFINESHIFT]; + self->SetZ(self->target->Z() + 16*finesine[self->args[0] << BOBTOFINESHIFT]); self->args[0] = (self->args[0]+3)&63; } diff --git a/src/g_hexen/a_bishop.cpp b/src/g_hexen/a_bishop.cpp index 08faee955..167fae568 100644 --- a/src/g_hexen/a_bishop.cpp +++ b/src/g_hexen/a_bishop.cpp @@ -140,7 +140,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopSpawnBlur) self->SetState (self->MissileState); } } - mo = Spawn ("BishopBlur", self->x, self->y, self->z, ALLOW_REPLACE); + mo = Spawn ("BishopBlur", self->Pos(), ALLOW_REPLACE); if (mo) { mo->angle = self->angle; @@ -155,9 +155,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopSpawnBlur) DEFINE_ACTION_FUNCTION(AActor, A_BishopChase) { - self->z -= finesine[self->special2 << BOBTOFINESHIFT] * 4; + fixed_t newz = self->Z() - finesine[self->special2 << BOBTOFINESHIFT] * 4; self->special2 = (self->special2 + 4) & 63; - self->z += finesine[self->special2 << BOBTOFINESHIFT] * 4; + newz += finesine[self->special2 << BOBTOFINESHIFT] * 4; + self->SetZ(newz); } //============================================================================ @@ -170,7 +171,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopPuff) { AActor *mo; - mo = Spawn ("BishopPuff", self->x, self->y, self->z + 40*FRACUNIT, ALLOW_REPLACE); + mo = Spawn ("BishopPuff", self->PosPlusZ(40*FRACUNIT), ALLOW_REPLACE); if (mo) { mo->velz = FRACUNIT/2; @@ -192,10 +193,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopPainBlur) self->SetState (self->FindState ("Blur")); return; } - fixed_t x = self->x + (pr_pain.Random2()<<12); - fixed_t y = self->y + (pr_pain.Random2()<<12); - fixed_t z = self->z + (pr_pain.Random2()<<11); - mo = Spawn ("BishopPainBlur", x, y, z, ALLOW_REPLACE); + fixed_t xo = (pr_pain.Random2() << 12); + fixed_t yo = (pr_pain.Random2() << 12); + fixed_t zo = (pr_pain.Random2() << 11); + mo = Spawn ("BishopPainBlur", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); if (mo) { mo->angle = self->angle; diff --git a/src/g_hexen/a_blastradius.cpp b/src/g_hexen/a_blastradius.cpp index a78b0b4c8..c7d962e12 100644 --- a/src/g_hexen/a_blastradius.cpp +++ b/src/g_hexen/a_blastradius.cpp @@ -26,25 +26,26 @@ void BlastActor (AActor *victim, fixed_t strength, fixed_t speed, AActor * Owner { angle_t angle,ang; AActor *mo; - fixed_t x,y,z; + fixedvec3 pos; if (!victim->SpecialBlastHandling (Owner, strength)) { return; } - angle = R_PointToAngle2 (Owner->x, Owner->y, victim->x, victim->y); + angle = Owner->AngleTo(victim); angle >>= ANGLETOFINESHIFT; victim->velx = FixedMul (speed, finecosine[angle]); victim->vely = FixedMul (speed, finesine[angle]); // Spawn blast puff - ang = R_PointToAngle2 (victim->x, victim->y, Owner->x, Owner->y); + ang = victim->AngleTo(Owner); ang >>= ANGLETOFINESHIFT; - x = victim->x + FixedMul (victim->radius+FRACUNIT, finecosine[ang]); - y = victim->y + FixedMul (victim->radius+FRACUNIT, finesine[ang]); - z = victim->z - victim->floorclip + (victim->height>>1); - mo = Spawn (blasteffect, x, y, z, ALLOW_REPLACE); + pos = victim->Vec3Offset( + FixedMul (victim->radius+FRACUNIT, finecosine[ang]), + FixedMul (victim->radius+FRACUNIT, finesine[ang]), + -victim->floorclip + (victim->height>>1)); + mo = Spawn (blasteffect, pos, ALLOW_REPLACE); if (mo) { mo->velx = victim->velx; @@ -141,7 +142,7 @@ DEFINE_ACTION_FUNCTION_PARAMS (AActor, A_Blast) { // Must be monster, player, missile, touchy or vulnerable continue; } - dist = P_AproxDistance (self->x - mo->x, self->y - mo->y); + dist = self->AproxDistance (mo); if (dist > radius) { // Out of range continue; diff --git a/src/g_hexen/a_clericflame.cpp b/src/g_hexen/a_clericflame.cpp index 0fe482ede..d2bc98329 100644 --- a/src/g_hexen/a_clericflame.cpp +++ b/src/g_hexen/a_clericflame.cpp @@ -48,12 +48,12 @@ void ACFlameMissile::Effect () if (!--special1) { special1 = 4; - newz = z-12*FRACUNIT; + newz = Z()-12*FRACUNIT; if (newz < floorz) { newz = floorz; } - AActor *mo = Spawn ("CFlameFloor", x, y, newz, ALLOW_REPLACE); + AActor *mo = Spawn ("CFlameFloor", X(), Y(), newz, ALLOW_REPLACE); if (mo) { mo->angle = angle; @@ -123,9 +123,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_CFlameMissile) { an = (i*ANG45)>>ANGLETOFINESHIFT; an90 = (i*ANG45+ANG90)>>ANGLETOFINESHIFT; - mo = Spawn ("CircleFlame", BlockingMobj->x+FixedMul(dist, finecosine[an]), - BlockingMobj->y+FixedMul(dist, finesine[an]), - BlockingMobj->z+5*FRACUNIT, ALLOW_REPLACE); + mo = Spawn ("CircleFlame", BlockingMobj->Vec3Offset( + FixedMul(dist, finecosine[an]), + FixedMul(dist, finesine[an]), + 5*FRACUNIT), ALLOW_REPLACE); if (mo) { mo->angle = an<vely = mo->special2 = FixedMul(FLAMESPEED, finesine[an]); mo->tics -= pr_missile()&3; } - mo = Spawn ("CircleFlame", BlockingMobj->x-FixedMul(dist, finecosine[an]), - BlockingMobj->y-FixedMul(dist, finesine[an]), - BlockingMobj->z+5*FRACUNIT, ALLOW_REPLACE); + mo = Spawn ("CircleFlame", BlockingMobj->Vec3Offset( + -FixedMul(dist, finecosine[an]), + -FixedMul(dist, finesine[an]), + 5*FRACUNIT), ALLOW_REPLACE); if(mo) { mo->angle = ANG180+(an<flags3&MF3_ISMONSTER && pr_spiritslam() < 128) { @@ -136,7 +136,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolyAttack2) for (j = 0; j < 4; j++) { - mo = Spawn (self->x, self->y, self->z, ALLOW_REPLACE); + mo = Spawn (self->Pos(), ALLOW_REPLACE); if (!mo) { continue; @@ -157,7 +157,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolyAttack2) mo->special2 = ((FINEANGLES/2 + i) << 16) + FINEANGLES/2 + pr_holyatk2(8 << BOBTOFINESHIFT); break; } - mo->z = self->z; + mo->SetZ(self->Z()); mo->angle = self->angle+(ANGLE_45+ANGLE_45/2)-ANGLE_45*j; P_ThrustMobj(mo, mo->angle, mo->Speed); mo->target = self->target; @@ -188,11 +188,11 @@ void SpawnSpiritTail (AActor *spirit) AActor *tail, *next; int i; - tail = Spawn ("HolyTail", spirit->x, spirit->y, spirit->z, ALLOW_REPLACE); + tail = Spawn ("HolyTail", spirit->Pos(), ALLOW_REPLACE); tail->target = spirit; // parent for (i = 1; i < 3; i++) { - next = Spawn ("HolyTailTrail", spirit->x, spirit->y, spirit->z, ALLOW_REPLACE); + next = Spawn ("HolyTailTrail", spirit->Pos(), ALLOW_REPLACE); tail->tracer = next; tail = next; } @@ -262,28 +262,26 @@ static void CHolyTailFollow (AActor *actor, fixed_t dist) child = actor->tracer; if (child) { - an = R_PointToAngle2(actor->x, actor->y, child->x, - child->y)>>ANGLETOFINESHIFT; - oldDistance = P_AproxDistance (child->x-actor->x, child->y-actor->y); - if (P_TryMove (child, actor->x+FixedMul(dist, finecosine[an]), - actor->y+FixedMul(dist, finesine[an]), true)) + an = actor->AngleTo(child) >> ANGLETOFINESHIFT; + oldDistance = child->AproxDistance (actor); + if (P_TryMove (child, actor->X()+FixedMul(dist, finecosine[an]), + actor->Y()+FixedMul(dist, finesine[an]), true)) { - newDistance = P_AproxDistance (child->x-actor->x, - child->y-actor->y)-FRACUNIT; + newDistance = child->AproxDistance (actor)-FRACUNIT; if (oldDistance < FRACUNIT) { - if (child->z < actor->z) + if (child->Z() < actor->Z()) { - child->z = actor->z-dist; + child->SetZ(actor->Z()-dist); } else { - child->z = actor->z+dist; + child->SetZ(actor->Z()+dist); } } else { - child->z = actor->z + Scale (newDistance, child->z-actor->z, oldDistance); + child->SetZ(actor->Z() + Scale (newDistance, child->Z()-actor->Z(), oldDistance)); } } } @@ -330,10 +328,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolyTail) else { if (P_TryMove (self, - parent->x - 14*finecosine[parent->angle>>ANGLETOFINESHIFT], - parent->y - 14*finesine[parent->angle>>ANGLETOFINESHIFT], true)) + parent->X() - 14*finecosine[parent->angle>>ANGLETOFINESHIFT], + parent->Y() - 14*finesine[parent->angle>>ANGLETOFINESHIFT], true)) { - self->z = parent->z-5*FRACUNIT; + self->SetZ(parent->Z()-5*FRACUNIT); } CHolyTailFollow (self, 10*FRACUNIT); } @@ -409,11 +407,11 @@ static void CHolySeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax) actor->velx = FixedMul (actor->Speed, finecosine[angle]); actor->vely = FixedMul (actor->Speed, finesine[angle]); if (!(level.time&15) - || actor->z > target->z+(target->height) - || actor->z+actor->height < target->z) + || actor->Z() > target->Top() + || actor->Top() < target->Z()) { - newZ = target->z+((pr_holyseeker()*target->height)>>8); - deltaZ = newZ-actor->z; + newZ = target->Z()+((pr_holyseeker()*target->height)>>8); + deltaZ = newZ - actor->Z(); if (abs(deltaZ) > 15*FRACUNIT) { if (deltaZ > 0) @@ -425,7 +423,7 @@ static void CHolySeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax) deltaZ = -15*FRACUNIT; } } - dist = P_AproxDistance (target->x-actor->x, target->y-actor->y); + dist = actor->AproxDistance (target); dist = dist / actor->Speed; if (dist < 1) { @@ -444,22 +442,24 @@ static void CHolySeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax) void CHolyWeave (AActor *actor, FRandom &pr_random) { - fixed_t newX, newY; + fixed_t newX, newY, newZ; int weaveXY, weaveZ; int angle; weaveXY = actor->special2 >> 16; weaveZ = actor->special2 & FINEMASK; angle = (actor->angle + ANG90) >> ANGLETOFINESHIFT; - newX = actor->x - FixedMul(finecosine[angle], finesine[weaveXY] * 32); - newY = actor->y - FixedMul(finesine[angle], finesine[weaveXY] * 32); + newX = actor->X() - FixedMul(finecosine[angle], finesine[weaveXY] * 32); + newY = actor->Y() - FixedMul(finesine[angle], finesine[weaveXY] * 32); weaveXY = (weaveXY + pr_random(5 << BOBTOFINESHIFT)) & FINEMASK; newX += FixedMul(finecosine[angle], finesine[weaveXY] * 32); newY += FixedMul(finesine[angle], finesine[weaveXY] * 32); P_TryMove(actor, newX, newY, true); - actor->z -= finesine[weaveZ] * 16; + newZ = actor->Z(); + newZ -= finesine[weaveZ] * 16; weaveZ = (weaveZ + pr_random(5 << BOBTOFINESHIFT)) & FINEMASK; - actor->z += finesine[weaveZ] * 16; + newZ += finesine[weaveZ] * 16; + actor->SetZ(newZ); actor->special2 = weaveZ + (weaveXY << 16); } @@ -523,7 +523,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ClericAttack) { if (!self->target) return; - AActor * missile = P_SpawnMissileZ (self, self->z + 40*FRACUNIT, self->target, PClass::FindClass ("HolyMissile")); + AActor * missile = P_SpawnMissileZ (self, self->Z() + 40*FRACUNIT, self->target, PClass::FindClass ("HolyMissile")); if (missile != NULL) missile->tracer = NULL; // No initial target S_Sound (self, CHAN_WEAPON, "HolySymbolFire", 1, ATTN_NORM); } diff --git a/src/g_hexen/a_clericstaff.cpp b/src/g_hexen/a_clericstaff.cpp index b397fc12b..eeda968fa 100644 --- a/src/g_hexen/a_clericstaff.cpp +++ b/src/g_hexen/a_clericstaff.cpp @@ -73,7 +73,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck) P_LineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, PClass::FindClass ("CStaffPuff"), false, &linetarget); if (linetarget != NULL) { - pmo->angle = R_PointToAngle2 (pmo->x, pmo->y, linetarget->x, linetarget->y); + pmo->angle = pmo->AngleTo(linetarget); if (((linetarget->player && (!linetarget->IsTeammate (pmo) || level.teamdamage != 0))|| linetarget->flags3&MF3_ISMONSTER) && (!(linetarget->flags2&(MF2_DORMANT|MF2_INVULNERABLE)))) { @@ -103,7 +103,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck) P_LineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, PClass::FindClass ("CStaffPuff"), false, &linetarget); if (linetarget != NULL) { - pmo->angle = R_PointToAngle2 (pmo->x, pmo->y, linetarget->x, linetarget->y); + pmo->angle = pmo->AngleTo(linetarget); if ((linetarget->player && (!linetarget->IsTeammate (pmo) || level.teamdamage != 0)) || linetarget->flags3&MF3_ISMONSTER) { newLife = player->health+(damage>>4); diff --git a/src/g_hexen/a_dragon.cpp b/src/g_hexen/a_dragon.cpp index fdf2428af..9dc577aa9 100644 --- a/src/g_hexen/a_dragon.cpp +++ b/src/g_hexen/a_dragon.cpp @@ -59,28 +59,21 @@ static void DragonSeek (AActor *actor, angle_t thresh, angle_t turnMax) angle = actor->angle>>ANGLETOFINESHIFT; actor->velx = FixedMul (actor->Speed, finecosine[angle]); actor->vely = FixedMul (actor->Speed, finesine[angle]); - if (actor->z+actor->height < target->z || - target->z+target->height < actor->z) + dist = actor->AproxDistance (target) / actor->Speed; + if (actor->Top() < target->Z() || + target->Top() < actor->Z()) { - dist = P_AproxDistance(target->x-actor->x, target->y-actor->y); - dist = dist/actor->Speed; if (dist < 1) { dist = 1; } - actor->velz = (target->z - actor->z)/dist; - } - else - { - dist = P_AproxDistance (target->x-actor->x, target->y-actor->y); - dist = dist/actor->Speed; + actor->velz = (target->Z() - actor->Z())/dist; } if (target->flags&MF_SHOOTABLE && pr_dragonseek() < 64) { // attack the destination mobj if it's attackable AActor *oldTarget; - if (absangle(actor->angle-R_PointToAngle2(actor->x, actor->y, - target->x, target->y)) < ANGLE_45/2) + if (absangle(actor->angle - actor->AngleTo(target)) < ANGLE_45/2) { oldTarget = actor->target; actor->target = target; @@ -105,8 +98,7 @@ static void DragonSeek (AActor *actor, angle_t thresh, angle_t turnMax) { AActor *bestActor = NULL; bestAngle = ANGLE_MAX; - angleToTarget = R_PointToAngle2(actor->x, actor->y, - actor->target->x, actor->target->y); + angleToTarget = actor->AngleTo(actor->target); for (i = 0; i < 5; i++) { if (!target->args[i]) @@ -119,8 +111,7 @@ static void DragonSeek (AActor *actor, angle_t thresh, angle_t turnMax) { continue; } - angleToSpot = R_PointToAngle2(actor->x, actor->y, - mo->x, mo->y); + angleToSpot = actor->AngleTo(mo); if (absangle(angleToSpot-angleToTarget) < bestAngle) { bestAngle = absangle(angleToSpot-angleToTarget); @@ -196,8 +187,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonFlight) self->target = NULL; return; } - angle = R_PointToAngle2(self->x, self->y, self->target->x, - self->target->y); + angle = self->AngleTo(self->target); if (absangle(self->angle-angle) < ANGLE_45/2 && self->CheckMeleeRange()) { int damage = pr_dragonflight.HitDice (8); @@ -262,11 +252,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonFX2) delay = 16+(pr_dragonfx2()>>3); for (i = 1+(pr_dragonfx2()&3); i; i--) { - fixed_t x = self->x+((pr_dragonfx2()-128)<<14); - fixed_t y = self->y+((pr_dragonfx2()-128)<<14); - fixed_t z = self->z+((pr_dragonfx2()-128)<<12); + fixed_t xo = ((pr_dragonfx2() - 128) << 14); + fixed_t yo = ((pr_dragonfx2() - 128) << 14); + fixed_t zo = ((pr_dragonfx2() - 128) << 12); - mo = Spawn ("DragonExplosion", x, y, z, ALLOW_REPLACE); + mo = Spawn ("DragonExplosion", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); if (mo) { mo->tics = delay+(pr_dragonfx2()&3)*i*2; @@ -298,7 +288,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonPain) DEFINE_ACTION_FUNCTION(AActor, A_DragonCheckCrash) { - if (self->z <= self->floorz) + if (self->Z() <= self->floorz) { self->SetState (self->FindState ("Crash")); } diff --git a/src/g_hexen/a_fighterplayer.cpp b/src/g_hexen/a_fighterplayer.cpp index 5df183901..82cb8bd05 100644 --- a/src/g_hexen/a_fighterplayer.cpp +++ b/src/g_hexen/a_fighterplayer.cpp @@ -30,7 +30,7 @@ void AdjustPlayerAngle (AActor *pmo, AActor *linetarget) angle_t angle; int difference; - angle = R_PointToAngle2 (pmo->x, pmo->y, linetarget->x, linetarget->y); + angle = pmo->AngleTo(linetarget); difference = (int)angle - (int)pmo->angle; if (abs(difference) > MAX_ANGLE_ADJUST) { diff --git a/src/g_hexen/a_fighterquietus.cpp b/src/g_hexen/a_fighterquietus.cpp index 846b30281..cd3f65607 100644 --- a/src/g_hexen/a_fighterquietus.cpp +++ b/src/g_hexen/a_fighterquietus.cpp @@ -36,7 +36,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DropWeaponPieces) const PClass *cls = j==0? p1 : j==1? p2 : p3; if (cls) { - AActor *piece = Spawn (cls, self->x, self->y, self->z, ALLOW_REPLACE); + AActor *piece = Spawn (cls, self->Pos(), ALLOW_REPLACE); if (piece != NULL) { piece->velx = self->velx + finecosine[fineang]; @@ -112,10 +112,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_FSwordFlames) for (i = 1+(pr_fswordflame()&3); i; i--) { - fixed_t x = self->x+((pr_fswordflame()-128)<<12); - fixed_t y = self->y+((pr_fswordflame()-128)<<12); - fixed_t z = self->z+((pr_fswordflame()-128)<<11); - Spawn ("FSwordFlame", x, y, z, ALLOW_REPLACE); + fixed_t xo = ((pr_fswordflame() - 128) << 12); + fixed_t yo = ((pr_fswordflame() - 128) << 12); + fixed_t zo = ((pr_fswordflame() - 128) << 11); + Spawn ("FSwordFlame", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); } } diff --git a/src/g_hexen/a_firedemon.cpp b/src/g_hexen/a_firedemon.cpp index c588dd2ae..40f03abbf 100644 --- a/src/g_hexen/a_firedemon.cpp +++ b/src/g_hexen/a_firedemon.cpp @@ -32,7 +32,6 @@ static FRandom pr_firedemonsplotch ("FiredSplotch"); void A_FiredSpawnRock (AActor *actor) { AActor *mo; - int x,y,z; const PClass *rtype; switch (pr_firedemonrock() % 5) @@ -55,10 +54,10 @@ void A_FiredSpawnRock (AActor *actor) break; } - x = actor->x + ((pr_firedemonrock() - 128) << 12); - y = actor->y + ((pr_firedemonrock() - 128) << 12); - z = actor->z + ( pr_firedemonrock() << 11); - mo = Spawn (rtype, x, y, z, ALLOW_REPLACE); + fixed_t xo = ((pr_firedemonrock() - 128) << 12); + fixed_t yo = ((pr_firedemonrock() - 128) << 12); + fixed_t zo = (pr_firedemonrock() << 11); + mo = Spawn (rtype, actor->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); if (mo) { mo->target = actor; @@ -97,7 +96,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FiredRocks) DEFINE_ACTION_FUNCTION(AActor, A_SmBounce) { // give some more velocity (x,y,&z) - self->z = self->floorz + FRACUNIT; + self->SetZ(self->floorz + FRACUNIT); self->velz = (2*FRACUNIT) + (pr_smbounce() << 10); self->velx = pr_smbounce()%3<vely = pr_smbounce()%3<threshold) self->threshold--; // Float up and down - self->z += finesine[weaveindex << BOBTOFINESHIFT] * 8; + self->AddZ(finesine[weaveindex << BOBTOFINESHIFT] * 8); self->special1 = (weaveindex + 2) & 63; // Ensure it stays above certain height - if (self->z < self->floorz + (64*FRACUNIT)) + if (self->Z() < self->floorz + (64*FRACUNIT)) { - self->z += 2*FRACUNIT; + self->AddZ(2*FRACUNIT); } if(!self->target || !(self->target->flags&MF_SHOOTABLE)) @@ -158,12 +157,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_FiredChase) { self->special2 = 0; self->velx = self->vely = 0; - dist = P_AproxDistance (self->x - target->x, self->y - target->y); + dist = self->AproxDistance (target); if (dist < FIREDEMON_ATTACK_RANGE) { if (pr_firedemonchase() < 30) { - ang = R_PointToAngle2 (self->x, self->y, target->x, target->y); + ang = self->AngleTo(target); if (pr_firedemonchase() < 128) ang += ANGLE_90; else @@ -219,14 +218,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_FiredSplotch) { AActor *mo; - mo = Spawn ("FireDemonSplotch1", self->x, self->y, self->z, ALLOW_REPLACE); + mo = Spawn ("FireDemonSplotch1", self->Pos(), ALLOW_REPLACE); if (mo) { mo->velx = (pr_firedemonsplotch() - 128) << 11; mo->vely = (pr_firedemonsplotch() - 128) << 11; mo->velz = (pr_firedemonsplotch() << 10) + FRACUNIT*3; } - mo = Spawn ("FireDemonSplotch2", self->x, self->y, self->z, ALLOW_REPLACE); + mo = Spawn ("FireDemonSplotch2", self->Pos(), ALLOW_REPLACE); if (mo) { mo->velx = (pr_firedemonsplotch() - 128) << 11; diff --git a/src/g_hexen/a_flechette.cpp b/src/g_hexen/a_flechette.cpp index 1a9461ae8..ef8e27ca1 100644 --- a/src/g_hexen/a_flechette.cpp +++ b/src/g_hexen/a_flechette.cpp @@ -51,10 +51,10 @@ bool AArtiPoisonBag1::Use (bool pickup) angle_t angle = Owner->angle >> ANGLETOFINESHIFT; AActor *mo; - mo = Spawn ("PoisonBag", - Owner->x+16*finecosine[angle], - Owner->y+24*finesine[angle], Owner->z- - Owner->floorclip+8*FRACUNIT, ALLOW_REPLACE); + mo = Spawn ("PoisonBag", Owner->Vec3Offset( + 16*finecosine[angle], + 24*finesine[angle], + -Owner->floorclip+8*FRACUNIT), ALLOW_REPLACE); if (mo) { mo->target = Owner; @@ -79,10 +79,10 @@ bool AArtiPoisonBag2::Use (bool pickup) angle_t angle = Owner->angle >> ANGLETOFINESHIFT; AActor *mo; - mo = Spawn ("FireBomb", - Owner->x+16*finecosine[angle], - Owner->y+24*finesine[angle], Owner->z- - Owner->floorclip+8*FRACUNIT, ALLOW_REPLACE); + mo = Spawn ("FireBomb", Owner->Vec3Offset( + 16*finecosine[angle], + 24*finesine[angle], + -Owner->floorclip+8*FRACUNIT), ALLOW_REPLACE); if (mo) { mo->target = Owner; @@ -106,8 +106,7 @@ bool AArtiPoisonBag3::Use (bool pickup) { AActor *mo; - mo = Spawn("ThrowingBomb", Owner->x, Owner->y, - Owner->z-Owner->floorclip+35*FRACUNIT + (Owner->player? Owner->player->crouchoffset : 0), ALLOW_REPLACE); + mo = Spawn("ThrowingBomb", Owner->PosPlusZ(-Owner->floorclip+35*FRACUNIT + (Owner->player? Owner->player->crouchoffset : 0)), ALLOW_REPLACE); if (mo) { mo->angle = Owner->angle + (((pr_poisonbag()&7) - 4) << 24); @@ -133,7 +132,7 @@ bool AArtiPoisonBag3::Use (bool pickup) mo->velz = FixedMul(speed, finesine[modpitch]); mo->velx = FixedMul(xyscale, finecosine[angle]) + (Owner->velx >> 1); mo->vely = FixedMul(xyscale, finesine[angle]) + (Owner->vely >> 1); - mo->z += FixedMul(mo->Speed, finesine[orgpitch]); + mo->AddZ(FixedMul(mo->Speed, finesine[orgpitch])); mo->target = Owner; mo->tics -= pr_poisonbag()&3; @@ -159,7 +158,7 @@ bool AArtiPoisonBagGiver::Use (bool pickup) const PClass *MissileType = PClass::FindClass((ENamedName) this->GetClass()->Meta.GetMetaInt (ACMETA_MissileName, NAME_None)); if (MissileType != NULL) { - AActor *mo = Spawn (MissileType, Owner->x, Owner->y, Owner->z, ALLOW_REPLACE); + AActor *mo = Spawn (MissileType, Owner->Pos(), ALLOW_REPLACE); if (mo != NULL) { if (mo->IsKindOf(RUNTIME_CLASS(AInventory))) @@ -385,7 +384,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_PoisonBagInit) { AActor *mo; - mo = Spawn (self->x, self->y, self->z+28*FRACUNIT, ALLOW_REPLACE); + mo = Spawn (self->PosPlusZ(28*FRACUNIT), ALLOW_REPLACE); if (mo) { mo->target = self->target; @@ -422,7 +421,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_PoisonBagDamage) P_RadiusAttack (self, self->target, 4, 40, self->DamageType, RADF_HURTSOURCE); bobIndex = self->special2; - self->z += finesine[bobIndex << BOBTOFINESHIFT] >> 1; + self->AddZ(finesine[bobIndex << BOBTOFINESHIFT] >> 1); self->special2 = (bobIndex + 1) & 63; } @@ -456,7 +455,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckThrowBomb2) < (3*3)/(2*2)) { self->SetState (self->SpawnState + 6); - self->z = self->floorz; + self->SetZ(self->floorz); self->velz = 0; self->BounceFlags = BOUNCE_None; self->flags &= ~MF_MISSILE; diff --git a/src/g_hexen/a_flies.cpp b/src/g_hexen/a_flies.cpp index 3c677d5cb..05c4ef94c 100644 --- a/src/g_hexen/a_flies.cpp +++ b/src/g_hexen/a_flies.cpp @@ -79,11 +79,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_FlyBuzz) return; } - angle_t ang = R_PointToAngle2(self->x, self->y, targ->x, targ->y); + angle_t ang = self->AngleTo(targ); self->angle = ang; self->args[0]++; ang >>= ANGLETOFINESHIFT; - if (!P_TryMove(self, self->x + 6 * finecosine[ang], self->y + 6 * finesine[ang], true)) + if (!P_TryMove(self, self->X() + 6 * finecosine[ang], self->Y() + 6 * finesine[ang], true)) { self->SetIdle(true); return; @@ -94,7 +94,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FlyBuzz) self->vely += (pr_fly() - 128) << BOBTOFINESHIFT; } int zrand = pr_fly(); - if (targ->z + 5*FRACUNIT < self->z && zrand > 150) + if (targ->Z() + 5*FRACUNIT < self->Z() && zrand > 150) { zrand = -zrand; } diff --git a/src/g_hexen/a_fog.cpp b/src/g_hexen/a_fog.cpp index 6bafd383c..a427daa47 100644 --- a/src/g_hexen/a_fog.cpp +++ b/src/g_hexen/a_fog.cpp @@ -41,7 +41,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FogSpawn) self->special1 = self->args[2]; // Reset frequency count - mo = Spawn (fogs[pr_fogspawn()%3], self->x, self->y, self->z, ALLOW_REPLACE); + mo = Spawn (fogs[pr_fogspawn()%3], self->Pos(), ALLOW_REPLACE); if (mo) { @@ -80,7 +80,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FogMove) if ((self->args[3] % 4) == 0) { weaveindex = self->special2; - self->z += finesine[weaveindex << BOBTOFINESHIFT] * 4; + self->AddZ(finesine[weaveindex << BOBTOFINESHIFT] * 4); self->special2 = (weaveindex + 1) & 63; } diff --git a/src/g_hexen/a_healingradius.cpp b/src/g_hexen/a_healingradius.cpp index b827f666b..d1d39ddd4 100644 --- a/src/g_hexen/a_healingradius.cpp +++ b/src/g_hexen/a_healingradius.cpp @@ -37,7 +37,7 @@ bool AArtiHealingRadius::Use (bool pickup) if (playeringame[i] && players[i].mo != NULL && players[i].mo->health > 0 && - P_AproxDistance (players[i].mo->x - Owner->x, players[i].mo->y - Owner->y) <= HEAL_RADIUS_DIST) + players[i].mo->AproxDistance (Owner) <= HEAL_RADIUS_DIST) { // Q: Is it worth it to make this selectable as a player property? // A: Probably not - but it sure doesn't hurt. diff --git a/src/g_hexen/a_heresiarch.cpp b/src/g_hexen/a_heresiarch.cpp index 9ca0a70e8..e2b8c9ed2 100644 --- a/src/g_hexen/a_heresiarch.cpp +++ b/src/g_hexen/a_heresiarch.cpp @@ -232,7 +232,6 @@ void ASorcBall1::DoFireSpell () DEFINE_ACTION_FUNCTION(AActor, A_SorcSpinBalls) { AActor *mo; - fixed_t z; self->SpawnState += 2; // [RH] Don't spawn balls again A_SlowBalls(self); @@ -240,17 +239,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcSpinBalls) self->args[3] = SORC_NORMAL; self->args[4] = SORCBALL_INITIAL_SPEED; // Initial orbit speed self->special1 = ANGLE_1; - z = self->z - self->floorclip + self->height; + + fixedvec3 pos = self->PosPlusZ(-self->floorclip + self->height); - mo = Spawn("SorcBall1", self->x, self->y, z, NO_REPLACE); + mo = Spawn("SorcBall1", pos, NO_REPLACE); if (mo) { mo->target = self; mo->special2 = SORCFX4_RAPIDFIRE_TIME; } - mo = Spawn("SorcBall2", self->x, self->y, z, NO_REPLACE); + mo = Spawn("SorcBall2", pos, NO_REPLACE); if (mo) mo->target = self; - mo = Spawn("SorcBall3", self->x, self->y, z, NO_REPLACE); + mo = Spawn("SorcBall3", pos, NO_REPLACE); if (mo) mo->target = self; } @@ -271,7 +271,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcBallOrbit) } ASorcBall *actor; - int x,y; angle_t angle, baseangle; int mode = self->target->args[3]; AHeresiarch *parent = barrier_cast(self->target); @@ -370,9 +369,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcBallOrbit) S_Sound (actor, CHAN_BODY, "SorcererBallWoosh", 1, ATTN_NORM); } actor->special1 = angle; // Set previous angle - x = parent->x + FixedMul(dist, finecosine[angle]); - y = parent->y + FixedMul(dist, finesine[angle]); - actor->SetOrigin (x, y, parent->z - parent->floorclip + parent->height); + + fixedvec3 pos = parent->Vec3Offset( + FixedMul(dist, finecosine[angle]), + FixedMul(dist, finesine[angle]), + -parent->floorclip + parent->height); + actor->SetOrigin (pos, true); actor->floorz = parent->floorz; actor->ceilingz = parent->ceilingz; } @@ -540,8 +542,7 @@ void ASorcBall2::CastSorcererSpell () AActor *parent = target; AActor *mo; - fixed_t z = parent->z - parent->floorclip + SORC_DEFENSE_HEIGHT*FRACUNIT; - mo = Spawn("SorcFX2", x, y, z, ALLOW_REPLACE); + mo = Spawn("SorcFX2", PosPlusZ(-parent->floorclip + SORC_DEFENSE_HEIGHT*FRACUNIT), ALLOW_REPLACE); parent->flags2 |= MF2_REFLECTIVE|MF2_INVULNERABLE; parent->args[0] = SORC_DEFENSE_TIME; if (mo) mo->target = parent; @@ -665,10 +666,9 @@ void A_SorcOffense2(AActor *actor) if (mo) { mo->special2 = 35*5/2; // 5 seconds - dist = P_AproxDistance(dest->x - mo->x, dest->y - mo->y); - dist = dist/mo->Speed; + dist = mo->AproxDistance(dest) / mo->Speed; if(dist < 1) dist = 1; - mo->velz = (dest->z - mo->z) / dist; + mo->velz = (dest->Z() - mo->Z()) / dist; } } @@ -696,23 +696,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcBossAttack) DEFINE_ACTION_FUNCTION(AActor, A_SpawnFizzle) { - fixed_t x,y,z; fixed_t dist = 5*FRACUNIT; - angle_t angle = self->angle >> ANGLETOFINESHIFT; fixed_t speed = self->Speed; angle_t rangle; AActor *mo; int ix; - x = self->x + FixedMul(dist,finecosine[angle]); - y = self->y + FixedMul(dist,finesine[angle]); - z = self->z - self->floorclip + (self->height>>1); + fixedvec3 pos = self->Vec3Angle(dist, self->angle, -self->floorclip + (self->height >> 1)); for (ix=0; ix<5; ix++) { - mo = Spawn("SorcSpark1", x, y, z, ALLOW_REPLACE); + mo = Spawn("SorcSpark1", pos, ALLOW_REPLACE); if (mo) { - rangle = angle + ((pr_heresiarch()%5) << 1); + rangle = (self->angle >> ANGLETOFINESHIFT) + ((pr_heresiarch()%5) << 1); mo->velx = FixedMul(pr_heresiarch()%speed, finecosine[rangle]); mo->vely = FixedMul(pr_heresiarch()%speed, finesine[rangle]); mo->velz = FRACUNIT*2; @@ -756,7 +752,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcFX2Split) { AActor *mo; - mo = Spawn(self->GetClass(), self->x, self->y, self->z, NO_REPLACE); + mo = Spawn(self->GetClass(), self->Pos(), NO_REPLACE); if (mo) { mo->target = self->target; @@ -764,7 +760,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcFX2Split) mo->special1 = self->angle; // Set angle mo->SetState (mo->FindState("Orbit")); } - mo = Spawn(self->GetClass(), self->x, self->y, self->z, NO_REPLACE); + mo = Spawn(self->GetClass(), self->Pos(), NO_REPLACE); if (mo) { mo->target = self->target; @@ -786,7 +782,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcFX2Split) DEFINE_ACTION_FUNCTION(AActor, A_SorcFX2Orbit) { angle_t angle; - fixed_t x,y,z; + fixedvec3 pos; AActor *parent = self->target; // [RH] If no parent, then disappear @@ -819,26 +815,28 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcFX2Orbit) { self->special1 += ANGLE_1*10; angle = ((angle_t)self->special1) >> ANGLETOFINESHIFT; - x = parent->x + FixedMul(dist, finecosine[angle]); - y = parent->y + FixedMul(dist, finesine[angle]); - z = parent->z - parent->floorclip + SORC_DEFENSE_HEIGHT*FRACUNIT; - z += FixedMul(15*FRACUNIT,finecosine[angle]); + pos = parent->Vec3Offset( + FixedMul(dist, finecosine[angle]), + FixedMul(dist, finesine[angle]), + parent->floorclip + SORC_DEFENSE_HEIGHT*FRACUNIT); + pos.z += FixedMul(15*FRACUNIT,finecosine[angle]); // Spawn trailer - Spawn("SorcFX2T1", x, y, z, ALLOW_REPLACE); + Spawn("SorcFX2T1", pos, ALLOW_REPLACE); } else // Clock wise { self->special1 -= ANGLE_1*10; angle = ((angle_t)self->special1) >> ANGLETOFINESHIFT; - x = parent->x + FixedMul(dist, finecosine[angle]); - y = parent->y + FixedMul(dist, finesine[angle]); - z = parent->z - parent->floorclip + SORC_DEFENSE_HEIGHT*FRACUNIT; - z += FixedMul(20*FRACUNIT,finesine[angle]); + pos = parent->Vec3Offset( + FixedMul(dist, finecosine[angle]), + FixedMul(dist, finesine[angle]), + parent->floorclip + SORC_DEFENSE_HEIGHT*FRACUNIT); + pos.z += FixedMul(20*FRACUNIT,finesine[angle]); // Spawn trailer - Spawn("SorcFX2T1", x, y, z, ALLOW_REPLACE); + Spawn("SorcFX2T1", pos, ALLOW_REPLACE); } - self->SetOrigin (x, y, z); + self->SetOrigin (pos, true); self->floorz = parent->floorz; self->ceilingz = parent->ceilingz; } @@ -854,7 +852,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcFX2Orbit) DEFINE_ACTION_FUNCTION(AActor, A_SpawnBishop) { AActor *mo; - mo = Spawn("Bishop", self->x, self->y, self->z, ALLOW_REPLACE); + mo = Spawn("Bishop", self->Pos(), ALLOW_REPLACE); if (mo) { if (!P_TestMobjLocation(mo)) @@ -879,7 +877,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnBishop) DEFINE_ACTION_FUNCTION(AActor, A_SorcererBishopEntry) { - Spawn("SorcFX3Explosion", self->x, self->y, self->z, ALLOW_REPLACE); + Spawn("SorcFX3Explosion", self->Pos(), ALLOW_REPLACE); S_Sound (self, CHAN_VOICE, self->SeeSound, 1, ATTN_NORM); } diff --git a/src/g_hexen/a_hexenspecialdecs.cpp b/src/g_hexen/a_hexenspecialdecs.cpp index 9d0c098fe..b79d9f2c2 100644 --- a/src/g_hexen/a_hexenspecialdecs.cpp +++ b/src/g_hexen/a_hexenspecialdecs.cpp @@ -60,7 +60,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_PotteryExplode) for(i = (pr_pottery()&3)+3; i; i--) { - mo = Spawn ("PotteryBit", self->x, self->y, self->z, ALLOW_REPLACE); + mo = Spawn ("PotteryBit", self->Pos(), ALLOW_REPLACE); if (mo) { mo->SetState (mo->SpawnState + (pr_pottery()%5)); @@ -77,7 +77,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_PotteryExplode) if (!((level.flags2 & LEVEL2_NOMONSTERS) || (dmflags & DF_NO_MONSTERS)) || !(GetDefaultByType (type)->flags3 & MF3_ISMONSTER)) { // Only spawn monsters if not -nomonsters - Spawn (type, self->x, self->y, self->z, ALLOW_REPLACE); + Spawn (type, self->Pos(), ALLOW_REPLACE); } } } @@ -109,8 +109,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_PotteryCheck) if (playeringame[i]) { AActor *pmo = players[i].mo; - if (P_CheckSight (self, pmo) && (absangle(R_PointToAngle2 (pmo->x, - pmo->y, self->x, self->y) - pmo->angle) <= ANGLE_45)) + if (P_CheckSight (self, pmo) && (absangle(pmo->AngleTo(self) - pmo->angle) <= ANGLE_45)) { // Previous state (pottery bit waiting state) self->SetState (self->state - 1); return; @@ -133,7 +132,7 @@ IMPLEMENT_CLASS (AZCorpseLynchedNoHeart) void AZCorpseLynchedNoHeart::PostBeginPlay () { Super::PostBeginPlay (); - Spawn ("BloodPool", x, y, floorz, ALLOW_REPLACE); + Spawn ("BloodPool", X(), Y(), floorz, ALLOW_REPLACE); } //============================================================================ @@ -146,7 +145,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CorpseBloodDrip) { if (pr_drip() <= 128) { - Spawn ("CorpseBloodDrip", self->x, self->y, self->z + self->height/2, ALLOW_REPLACE); + Spawn ("CorpseBloodDrip", self->PosPlusZ(self->height/2), ALLOW_REPLACE); } } @@ -163,7 +162,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CorpseExplode) for (i = (pr_foo()&3)+3; i; i--) { - mo = Spawn ("CorpseBit", self->x, self->y, self->z, ALLOW_REPLACE); + mo = Spawn ("CorpseBit", self->Pos(), ALLOW_REPLACE); if (mo) { mo->SetState (mo->SpawnState + (pr_foo()%3)); @@ -173,7 +172,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CorpseExplode) } } // Spawn a skull - mo = Spawn ("CorpseBit", self->x, self->y, self->z, ALLOW_REPLACE); + mo = Spawn ("CorpseBit", self->Pos(), ALLOW_REPLACE); if (mo) { mo->SetState (mo->SpawnState + 3); @@ -198,10 +197,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_LeafSpawn) for (i = (pr_leaf()&3)+1; i; i--) { + fixed_t xo = (pr_leaf.Random2() << 14); + fixed_t yo = (pr_leaf.Random2() << 14); + fixed_t zo = (pr_leaf() << 14); mo = Spawn (pr_leaf()&1 ? PClass::FindClass ("Leaf1") : PClass::FindClass ("Leaf2"), - self->x + (pr_leaf.Random2()<<14), - self->y + (pr_leaf.Random2()<<14), - self->z + (pr_leaf()<<14), ALLOW_REPLACE); + self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); + if (mo) { P_ThrustMobj (mo, self->angle, (pr_leaf()<<9)+3*FRACUNIT); @@ -278,9 +279,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_SoAExplode) for (i = 0; i < 10; i++) { - mo = Spawn ("ZArmorChunk", self->x+((pr_soaexplode()-128)<<12), - self->y+((pr_soaexplode()-128)<<12), - self->z+(pr_soaexplode()*self->height/256), ALLOW_REPLACE); + fixed_t xo = ((pr_soaexplode() - 128) << 12); + fixed_t yo = ((pr_soaexplode() - 128) << 12); + fixed_t zo = (pr_soaexplode()*self->height / 256); + mo = Spawn ("ZArmorChunk", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); if (mo) { mo->SetState (mo->SpawnState + i); @@ -296,7 +298,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SoAExplode) if (!((level.flags2 & LEVEL2_NOMONSTERS) || (dmflags & DF_NO_MONSTERS)) || !(GetDefaultByType (type)->flags3 & MF3_ISMONSTER)) { // Only spawn monsters if not -nomonsters - Spawn (type, self->x, self->y, self->z, ALLOW_REPLACE); + Spawn (type, self->Pos(), ALLOW_REPLACE); } } S_Sound (self, CHAN_BODY, self->DeathSound, 1, ATTN_NORM); diff --git a/src/g_hexen/a_iceguy.cpp b/src/g_hexen/a_iceguy.cpp index 9d8360d4d..75be577bf 100644 --- a/src/g_hexen/a_iceguy.cpp +++ b/src/g_hexen/a_iceguy.cpp @@ -35,10 +35,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_IceGuyLook) dist = ((pr_iceguylook()-128)*self->radius)>>7; an = (self->angle+ANG90)>>ANGLETOFINESHIFT; - Spawn (WispTypes[pr_iceguylook()&1], - self->x+FixedMul(dist, finecosine[an]), - self->y+FixedMul(dist, finesine[an]), - self->z+60*FRACUNIT, ALLOW_REPLACE); + Spawn(WispTypes[pr_iceguylook() & 1], self->Vec3Offset( + FixedMul(dist, finecosine[an]), + FixedMul(dist, finesine[an]), + 60 * FRACUNIT), ALLOW_REPLACE); } } @@ -60,10 +60,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_IceGuyChase) dist = ((pr_iceguychase()-128)*self->radius)>>7; an = (self->angle+ANG90)>>ANGLETOFINESHIFT; - mo = Spawn (WispTypes[pr_iceguychase()&1], - self->x+FixedMul(dist, finecosine[an]), - self->y+FixedMul(dist, finesine[an]), - self->z+60*FRACUNIT, ALLOW_REPLACE); + mo = Spawn(WispTypes[pr_iceguychase() & 1], self->Vec3Offset( + FixedMul(dist, finecosine[an]), + FixedMul(dist, finesine[an]), + 60 * FRACUNIT), ALLOW_REPLACE); if (mo) { mo->velx = self->velx; @@ -82,22 +82,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_IceGuyChase) DEFINE_ACTION_FUNCTION(AActor, A_IceGuyAttack) { - fixed_t an; - if(!self->target) { return; } - an = (self->angle+ANG90)>>ANGLETOFINESHIFT; - P_SpawnMissileXYZ(self->x+FixedMul(self->radius>>1, - finecosine[an]), self->y+FixedMul(self->radius>>1, - finesine[an]), self->z+40*FRACUNIT, self, self->target, - PClass::FindClass ("IceGuyFX")); - an = (self->angle-ANG90)>>ANGLETOFINESHIFT; - P_SpawnMissileXYZ(self->x+FixedMul(self->radius>>1, - finecosine[an]), self->y+FixedMul(self->radius>>1, - finesine[an]), self->z+40*FRACUNIT, self, self->target, - PClass::FindClass ("IceGuyFX")); + P_SpawnMissileXYZ(self->Vec3Angle(self->radius>>1, self->angle+ANG90, 40*FRACUNIT), self, self->target, PClass::FindClass ("IceGuyFX")); + P_SpawnMissileXYZ(self->Vec3Angle(self->radius>>1, self->angle-ANG90, 40*FRACUNIT), self, self->target, PClass::FindClass ("IceGuyFX")); S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM); } @@ -129,7 +119,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_IceGuyMissileExplode) for (i = 0; i < 8; i++) { - mo = P_SpawnMissileAngleZ (self, self->z+3*FRACUNIT, + mo = P_SpawnMissileAngleZ (self, self->Z()+3*FRACUNIT, PClass::FindClass("IceGuyFX2"), i*ANG45, (fixed_t)(-0.3*FRACUNIT)); if (mo) { diff --git a/src/g_hexen/a_korax.cpp b/src/g_hexen/a_korax.cpp index 5323fb851..fb833fded 100644 --- a/src/g_hexen/a_korax.cpp +++ b/src/g_hexen/a_korax.cpp @@ -97,7 +97,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_KoraxChase) spot = iterator.Next (); if (spot != NULL) { - P_Teleport (self, spot->x, spot->y, ONFLOORZ, spot->angle, true, true, false); + P_Teleport (self, spot->X(), spot->Y(), ONFLOORZ, spot->angle, true, true, false); } P_StartScript (self, NULL, 249, NULL, NULL, 0, 0); @@ -136,7 +136,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_KoraxChase) self->tracer = spot; if (spot) { - P_Teleport (self, spot->x, spot->y, ONFLOORZ, spot->angle, true, true, false); + P_Teleport (self, spot->X(), spot->Y(), ONFLOORZ, spot->angle, true, true, false); } } } @@ -248,7 +248,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_KoraxMissile) DEFINE_ACTION_FUNCTION(AActor, A_KoraxCommand) { - fixed_t x,y,z; angle_t ang; int numcommands; @@ -256,10 +255,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_KoraxCommand) // Shoot stream of lightning to ceiling ang = (self->angle - ANGLE_90) >> ANGLETOFINESHIFT; - x = self->x + KORAX_COMMAND_OFFSET * finecosine[ang]; - y = self->y + KORAX_COMMAND_OFFSET * finesine[ang]; - z = self->z + KORAX_COMMAND_HEIGHT*FRACUNIT; - Spawn("KoraxBolt", x, y, z, ALLOW_REPLACE); + fixedvec3 pos = self->Vec3Offset( + KORAX_COMMAND_OFFSET * finecosine[ang], + KORAX_COMMAND_OFFSET * finesine[ang], + KORAX_COMMAND_HEIGHT*FRACUNIT); + Spawn("KoraxBolt", pos, ALLOW_REPLACE); if (self->health <= (self->SpawnHealth() >> 1)) { @@ -310,14 +310,13 @@ void KoraxFire (AActor *actor, const PClass *type, int arm) }; angle_t ang; - fixed_t x,y,z; - ang = (actor->angle + (arm < 3 ? -KORAX_DELTAANGLE : KORAX_DELTAANGLE)) - >> ANGLETOFINESHIFT; - x = actor->x + extension[arm] * finecosine[ang]; - y = actor->y + extension[arm] * finesine[ang]; - z = actor->z - actor->floorclip + armheight[arm]; - P_SpawnKoraxMissile (x, y, z, actor, actor->target, type); + ang = (actor->angle + (arm < 3 ? -KORAX_DELTAANGLE : KORAX_DELTAANGLE)) >> ANGLETOFINESHIFT; + fixedvec3 pos = actor->Vec3Offset( + extension[arm] * finecosine[ang], + extension[arm] * finesine[ang], + -actor->floorclip + armheight[arm]); + P_SpawnKoraxMissile (pos.x, pos.y, pos.z, actor, actor->target, type); } //============================================================================ @@ -372,11 +371,11 @@ void A_KSpiritSeeker (AActor *actor, angle_t thresh, angle_t turnMax) actor->vely = FixedMul (actor->Speed, finesine[angle]); if (!(level.time&15) - || actor->z > target->z+(target->GetDefault()->height) - || actor->z+actor->height < target->z) + || actor->Z() > target->Z()+(target->GetDefault()->height) + || actor->Top() < target->Z()) { - newZ = target->z+((pr_kspiritseek()*target->GetDefault()->height)>>8); - deltaZ = newZ-actor->z; + newZ = target->Z()+((pr_kspiritseek()*target->GetDefault()->height)>>8); + deltaZ = newZ-actor->Z(); if (abs(deltaZ) > 15*FRACUNIT) { if(deltaZ > 0) @@ -388,8 +387,7 @@ void A_KSpiritSeeker (AActor *actor, angle_t thresh, angle_t turnMax) deltaZ = -15*FRACUNIT; } } - dist = P_AproxDistance (target->x-actor->x, target->y-actor->y); - dist = dist/actor->Speed; + dist = actor->AproxDistance (target) / actor->Speed; if (dist < 1) { dist = 1; @@ -454,11 +452,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_KBoltRaise) fixed_t z; // Spawn a child upward - z = self->z + KORAX_BOLT_HEIGHT; + z = self->Z() + KORAX_BOLT_HEIGHT; if ((z + KORAX_BOLT_HEIGHT) < self->ceilingz) { - mo = Spawn("KoraxBolt", self->x, self->y, z, ALLOW_REPLACE); + mo = Spawn("KoraxBolt", self->X(), self->Y(), z, ALLOW_REPLACE); if (mo) { mo->special1 = KORAX_BOLT_LIFETIME; @@ -486,7 +484,7 @@ AActor *P_SpawnKoraxMissile (fixed_t x, fixed_t y, fixed_t z, z -= source->floorclip; th = Spawn (type, x, y, z, ALLOW_REPLACE); th->target = source; // Originator - an = R_PointToAngle2(x, y, dest->x, dest->y); + an = source->AngleXYTo(x, y, dest); if (dest->flags & MF_SHADOW) { // Invisible target an += pr_kmissile.Random2()<<21; @@ -495,12 +493,11 @@ AActor *P_SpawnKoraxMissile (fixed_t x, fixed_t y, fixed_t z, an >>= ANGLETOFINESHIFT; th->velx = FixedMul (th->Speed, finecosine[an]); th->vely = FixedMul (th->Speed, finesine[an]); - dist = P_AproxDistance (dest->x - x, dest->y - y); - dist = dist/th->Speed; + dist = dest->AproxDistance (x, y, source) / th->Speed; if (dist < 1) { dist = 1; } - th->velz = (dest->z-z+(30*FRACUNIT))/dist; + th->velz = (dest->Z()-z+(30*FRACUNIT))/dist; return (P_CheckMissileSpawn(th, source->radius) ? th : NULL); } diff --git a/src/g_hexen/a_magecone.cpp b/src/g_hexen/a_magecone.cpp index 6356fbb2f..f9d98c78f 100644 --- a/src/g_hexen/a_magecone.cpp +++ b/src/g_hexen/a_magecone.cpp @@ -120,7 +120,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ShedShard) // every so many calls, spawn a new missile in its set directions if (spawndir & SHARDSPAWN_LEFT) { - mo = P_SpawnMissileAngleZSpeed (self, self->z, RUNTIME_CLASS(AFrostMissile), self->angle+(ANG45/9), + mo = P_SpawnMissileAngleZSpeed (self, self->Z(), RUNTIME_CLASS(AFrostMissile), self->angle+(ANG45/9), 0, (20+2*spermcount)<target); if (mo) { @@ -132,7 +132,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ShedShard) } if (spawndir & SHARDSPAWN_RIGHT) { - mo = P_SpawnMissileAngleZSpeed (self, self->z, RUNTIME_CLASS(AFrostMissile), self->angle-(ANG45/9), + mo = P_SpawnMissileAngleZSpeed (self, self->Z(), RUNTIME_CLASS(AFrostMissile), self->angle-(ANG45/9), 0, (20+2*spermcount)<target); if (mo) { @@ -144,7 +144,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ShedShard) } if (spawndir & SHARDSPAWN_UP) { - mo = P_SpawnMissileAngleZSpeed (self, self->z+8*FRACUNIT, RUNTIME_CLASS(AFrostMissile), self->angle, + mo = P_SpawnMissileAngleZSpeed (self, self->Z()+8*FRACUNIT, RUNTIME_CLASS(AFrostMissile), self->angle, 0, (15+2*spermcount)<target); if (mo) { @@ -159,7 +159,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ShedShard) } if (spawndir & SHARDSPAWN_DOWN) { - mo = P_SpawnMissileAngleZSpeed (self, self->z-4*FRACUNIT, RUNTIME_CLASS(AFrostMissile), self->angle, + mo = P_SpawnMissileAngleZSpeed (self, self->Z()-4*FRACUNIT, RUNTIME_CLASS(AFrostMissile), self->angle, 0, (15+2*spermcount)<target); if (mo) { diff --git a/src/g_hexen/a_magelightning.cpp b/src/g_hexen/a_magelightning.cpp index 9953cf1d0..c1dd7d7d0 100644 --- a/src/g_hexen/a_magelightning.cpp +++ b/src/g_hexen/a_magelightning.cpp @@ -151,12 +151,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightningClip) { return; } - self->z = self->floorz; + self->SetZ(self->floorz); target = self->lastenemy->tracer; } else if (self->flags3 & MF3_CEILINGHUGGER) { - self->z = self->ceilingz-self->height; + self->SetZ(self->ceilingz-self->height); target = self->tracer; } if (self->flags3 & MF3_FLOORHUGGER) @@ -190,7 +190,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightningClip) } else { - self->angle = R_PointToAngle2(self->x, self->y, target->x, target->y); + self->angle = self->AngleTo(target); self->velx = 0; self->vely = 0; P_ThrustMobj (self, self->angle, self->Speed>>1); @@ -227,10 +227,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightningZap) else { deltaZ = -10*FRACUNIT; - } - mo = Spawn(lightning, self->x+((pr_zap()-128)*self->radius/256), - self->y+((pr_zap()-128)*self->radius/256), - self->z+deltaZ, ALLOW_REPLACE); + } + fixed_t xo = ((pr_zap() - 128)*self->radius / 256); + fixed_t yo = ((pr_zap() - 128)*self->radius / 256); + + mo = Spawn(lightning, self->Vec3Offset(xo, yo, deltaZ), ALLOW_REPLACE); if (mo) { mo->lastenemy = self; @@ -329,7 +330,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LastZap) AActor *mo; - mo = Spawn(lightning, self->x, self->y, self->z, ALLOW_REPLACE); + mo = Spawn(lightning, self->Pos(), ALLOW_REPLACE); if (mo) { mo->SetState (mo->FindState (NAME_Death)); diff --git a/src/g_hexen/a_magestaff.cpp b/src/g_hexen/a_magestaff.cpp index 97a658a15..4df037fc2 100644 --- a/src/g_hexen/a_magestaff.cpp +++ b/src/g_hexen/a_magestaff.cpp @@ -140,8 +140,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_MStaffAttack) P_AimLineAttack (self, angle, PLAYERMISSILERANGE, &linetarget, ANGLE_1*32); if (linetarget == NULL) { - BlockCheckLine.x = self->x; - BlockCheckLine.y = self->y; + BlockCheckLine.x = self->X(); + BlockCheckLine.y = self->Y(); BlockCheckLine.dx = -finesine[angle >> ANGLETOFINESHIFT]; BlockCheckLine.dy = -finecosine[angle >> ANGLETOFINESHIFT]; linetarget = P_BlockmapSearch (self, 10, FrontBlockCheck); @@ -202,7 +202,7 @@ static AActor *FrontBlockCheck (AActor *mo, int index, void *) { if (link->Me != mo) { - if (P_PointOnDivlineSide (link->Me->x, link->Me->y, &BlockCheckLine) == 0 && + if (P_PointOnDivlineSide (link->Me->X(), link->Me->Y(), &BlockCheckLine) == 0 && mo->IsOkayToAttack (link->Me)) { return link->Me; @@ -222,7 +222,7 @@ void MStaffSpawn2 (AActor *actor, angle_t angle) { AActor *mo; - mo = P_SpawnMissileAngleZ (actor, actor->z+40*FRACUNIT, + mo = P_SpawnMissileAngleZ (actor, actor->Z()+40*FRACUNIT, RUNTIME_CLASS(AMageStaffFX2), angle, 0); if (mo) { diff --git a/src/g_hexen/a_pig.cpp b/src/g_hexen/a_pig.cpp index 437a336a3..21d141b0c 100644 --- a/src/g_hexen/a_pig.cpp +++ b/src/g_hexen/a_pig.cpp @@ -96,7 +96,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SnoutAttack) DEFINE_ACTION_FUNCTION(AActor, A_PigPain) { CALL_ACTION(A_Pain, self); - if (self->z <= self->floorz) + if (self->Z() <= self->floorz) { self->velz = FRACUNIT*7/2; } diff --git a/src/g_hexen/a_serpent.cpp b/src/g_hexen/a_serpent.cpp index cf552897f..39b4382e3 100644 --- a/src/g_hexen/a_serpent.cpp +++ b/src/g_hexen/a_serpent.cpp @@ -202,9 +202,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentSpawnGibs) for (int i = countof(GibTypes)-1; i >= 0; --i) { - mo = Spawn (GibTypes[i], - self->x+((pr_serpentgibs()-128)<<12), - self->y+((pr_serpentgibs()-128)<<12), + fixedvec2 pos = self->Vec2Offset( + ((pr_serpentgibs() - 128) << 12), + ((pr_serpentgibs() - 128) << 12)); + + mo = Spawn (GibTypes[i], pos.x, pos.y, self->floorz+FRACUNIT, ALLOW_REPLACE); if (mo) { @@ -256,7 +258,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DelayGib) DEFINE_ACTION_FUNCTION(AActor, A_SerpentHeadCheck) { - if (self->z <= self->floorz) + if (self->Z() <= self->floorz) { if (Terrains[P_GetThingFloorType(self)].IsLiquid) { diff --git a/src/g_hexen/a_spike.cpp b/src/g_hexen/a_spike.cpp index 9c9f9ab20..90729a77d 100644 --- a/src/g_hexen/a_spike.cpp +++ b/src/g_hexen/a_spike.cpp @@ -95,7 +95,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ThrustInitDn) self->flags2 = MF2_NOTELEPORT|MF2_FLOORCLIP; self->renderflags = RF_INVISIBLE; static_cast(self)->DirtClump = - Spawn("DirtClump", self->x, self->y, self->z, ALLOW_REPLACE); + Spawn("DirtClump", self->Pos(), ALLOW_REPLACE); } @@ -140,7 +140,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ThrustLower) DEFINE_ACTION_FUNCTION(AActor, A_ThrustImpale) { AActor *thing; - FBlockThingsIterator it(FBoundingBox(self->x, self->y, self->radius)); + FBlockThingsIterator it(FBoundingBox(self->X(), self->Y(), self->radius)); while ((thing = it.Next())) { if (!thing->intersects(self)) diff --git a/src/g_hexen/a_summon.cpp b/src/g_hexen/a_summon.cpp index cbb8a3854..0fffb6e4c 100644 --- a/src/g_hexen/a_summon.cpp +++ b/src/g_hexen/a_summon.cpp @@ -51,13 +51,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_Summon) { AMinotaurFriend *mo; - mo = Spawn (self->x, self->y, self->z, ALLOW_REPLACE); + mo = Spawn (self->Pos(), ALLOW_REPLACE); if (mo) { if (P_TestMobjLocation(mo) == false || !self->tracer) { // Didn't fit - change back to artifact mo->Destroy (); - AActor *arti = Spawn (self->x, self->y, self->z, ALLOW_REPLACE); + AActor *arti = Spawn (self->Pos(), ALLOW_REPLACE); if (arti) arti->flags |= MF_DROPPED; return; } @@ -76,7 +76,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Summon) } // Make smoke puff - Spawn ("MinotaurSmoke", self->x, self->y, self->z, ALLOW_REPLACE); + Spawn ("MinotaurSmoke", self->Pos(), ALLOW_REPLACE); S_Sound (self, CHAN_VOICE, mo->ActiveSound, 1, ATTN_NORM); } } diff --git a/src/g_hexen/a_teleportother.cpp b/src/g_hexen/a_teleportother.cpp index 2bf99640b..14edd7519 100644 --- a/src/g_hexen/a_teleportother.cpp +++ b/src/g_hexen/a_teleportother.cpp @@ -51,7 +51,7 @@ static void TeloSpawn (AActor *source, const char *type) { AActor *fx; - fx = Spawn (type, source->x, source->y, source->z, ALLOW_REPLACE); + fx = Spawn (type, source->Pos(), ALLOW_REPLACE); if (fx) { fx->special1 = TELEPORT_LIFE; // Lifetime countdown diff --git a/src/g_hexen/a_wraith.cpp b/src/g_hexen/a_wraith.cpp index b339f14be..3bbe567ac 100644 --- a/src/g_hexen/a_wraith.cpp +++ b/src/g_hexen/a_wraith.cpp @@ -29,12 +29,12 @@ static FRandom pr_wraithfx4 ("WraithFX4"); DEFINE_ACTION_FUNCTION(AActor, A_WraithInit) { - self->z += 48<AddZ(48<z + self->height > self->ceilingz) + if (self->Top() > self->ceilingz) { - self->z = self->ceilingz - self->height; + self->SetZ(self->ceilingz - self->height); } self->special1 = 0; // index into floatbob @@ -110,7 +110,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_WraithFX2) for (i = 2; i; --i) { - mo = Spawn ("WraithFX2", self->x, self->y, self->z, ALLOW_REPLACE); + mo = Spawn ("WraithFX2", self->Pos(), ALLOW_REPLACE); if(mo) { if (pr_wraithfx2 ()<128) @@ -147,12 +147,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_WraithFX3) while (numdropped-- > 0) { - mo = Spawn ("WraithFX3", self->x, self->y, self->z, ALLOW_REPLACE); + fixed_t xo = (pr_wraithfx3() - 128) << 11; + fixed_t yo = (pr_wraithfx3() - 128) << 11; + fixed_t zo = pr_wraithfx3() << 10; + + mo = Spawn ("WraithFX3", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); if (mo) { - mo->x += (pr_wraithfx3()-128)<<11; - mo->y += (pr_wraithfx3()-128)<<11; - mo->z += (pr_wraithfx3()<<10); + mo->floorz = self->floorz; + mo->ceilingz = self->ceilingz; mo->target = self; } } @@ -195,23 +198,29 @@ void A_WraithFX4 (AActor *self) if (spawn4) { - mo = Spawn ("WraithFX4", self->x, self->y, self->z, ALLOW_REPLACE); + fixed_t xo = (pr_wraithfx4() - 128) << 12; + fixed_t yo = (pr_wraithfx4() - 128) << 12; + fixed_t zo = (pr_wraithfx4() << 10); + + mo = Spawn ("WraithFX4", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); if (mo) { - mo->x += (pr_wraithfx4()-128)<<12; - mo->y += (pr_wraithfx4()-128)<<12; - mo->z += (pr_wraithfx4()<<10); + mo->floorz = self->floorz; + mo->ceilingz = self->ceilingz; mo->target = self; } } if (spawn5) { - mo = Spawn ("WraithFX5", self->x, self->y, self->z, ALLOW_REPLACE); + fixed_t xo = (pr_wraithfx4() - 128) << 11; + fixed_t yo = (pr_wraithfx4() - 128) << 11; + fixed_t zo = (pr_wraithfx4()<<10); + + mo = Spawn ("WraithFX5", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); if (mo) { - mo->x += (pr_wraithfx4()-128)<<11; - mo->y += (pr_wraithfx4()-128)<<11; - mo->z += (pr_wraithfx4()<<10); + mo->floorz = self->floorz; + mo->ceilingz = self->ceilingz; mo->target = self; } } @@ -226,7 +235,7 @@ void A_WraithFX4 (AActor *self) DEFINE_ACTION_FUNCTION(AActor, A_WraithChase) { int weaveindex = self->special1; - self->z += finesine[weaveindex << BOBTOFINESHIFT] * 8; + self->AddZ(finesine[weaveindex << BOBTOFINESHIFT] * 8); self->special1 = (weaveindex + 2) & 63; // if (self->floorclip > 0) // { diff --git a/src/g_level.cpp b/src/g_level.cpp index aba58e810..43a07a475 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1220,9 +1220,7 @@ void G_FinishTravel () pawn->angle = pawndup->angle; pawn->pitch = pawndup->pitch; } - pawn->x = pawndup->x; - pawn->y = pawndup->y; - pawn->z = pawndup->z; + pawn->SetXYZ(pawndup->X(), pawndup->Y(), pawndup->Z()); pawn->velx = pawndup->velx; pawn->vely = pawndup->vely; pawn->velz = pawndup->velz; @@ -1232,6 +1230,7 @@ void G_FinishTravel () pawn->dropoffz = pawndup->dropoffz; pawn->floorsector = pawndup->floorsector; pawn->floorpic = pawndup->floorpic; + pawn->floorterrain = pawndup->floorterrain; pawn->ceilingsector = pawndup->ceilingsector; pawn->ceilingpic = pawndup->ceilingpic; pawn->floorclip = pawndup->floorclip; diff --git a/src/g_raven/a_minotaur.cpp b/src/g_raven/a_minotaur.cpp index 0f9d9cd55..5e2edd634 100644 --- a/src/g_raven/a_minotaur.cpp +++ b/src/g_raven/a_minotaur.cpp @@ -185,9 +185,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurDecide) { S_Sound (self, CHAN_WEAPON, "minotaur/sight", 1, ATTN_NORM); } - dist = P_AproxDistance (self->x-target->x, self->y-target->y); - if (target->z+target->height > self->z - && target->z+target->height < self->z+self->height + dist = self->AproxDistance (target); + if (target->Top() > self->Z() + && target->Top() < self->Top() && dist < (friendly ? 16*64*FRACUNIT : 8*64*FRACUNIT) && dist > 1*64*FRACUNIT && pr_minotaurdecide() < 150) @@ -205,7 +205,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurDecide) self->vely = FixedMul (MNTR_CHARGE_SPEED, finesine[angle]); self->special1 = TICRATE/2; // Charge duration } - else if (target->z == target->floorz + else if (target->Z() == target->floorz && dist < 9*64*FRACUNIT && pr_minotaurdecide() < (friendly ? 100 : 220)) { // Floor fire attack @@ -244,7 +244,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurCharge) { type = PClass::FindClass ("PunchPuff"); } - puff = Spawn (type, self->x, self->y, self->z, ALLOW_REPLACE); + puff = Spawn (type, self->Pos(), ALLOW_REPLACE); puff->velz = 2*FRACUNIT; self->special1--; } @@ -285,7 +285,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk2) P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); return; } - z = self->z + 40*FRACUNIT; + z = self->Z() + 40*FRACUNIT; const PClass *fx = PClass::FindClass("MinotaurFX1"); if (fx) { @@ -367,12 +367,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk3) DEFINE_ACTION_FUNCTION(AActor, A_MntrFloorFire) { AActor *mo; - fixed_t x, y; - self->z = self->floorz; - x = self->x + (pr_fire.Random2 () << 10); - y = self->y + (pr_fire.Random2 () << 10); - mo = Spawn("MinotaurFX3", x, y, self->floorz, ALLOW_REPLACE); + self->SetZ(self->floorz); + fixedvec2 pos = self->Vec2Offset( + (pr_fire.Random2 () << 10), + (pr_fire.Random2 () << 10)); + mo = Spawn("MinotaurFX3", pos.x, pos.y, self->floorz, ALLOW_REPLACE); mo->target = self->target; mo->velx = 1; // Force block checking P_CheckMissileSpawn (mo, self->radius); @@ -390,7 +390,7 @@ void P_MinotaurSlam (AActor *source, AActor *target) fixed_t thrust; int damage; - angle = R_PointToAngle2 (source->x, source->y, target->x, target->y); + angle = source->AngleTo(target); angle >>= ANGLETOFINESHIFT; thrust = 16*FRACUNIT+(pr_minotaurslam()<<10); target->velx += FixedMul (thrust, finecosine[angle]); @@ -489,7 +489,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurLook) mo = player->mo; if (mo == master) continue; if (mo->health <= 0) continue; - dist = P_AproxDistance(self->x - mo->x, self->y - mo->y); + dist = self->AproxDistance(mo); if (dist > MINOTAUR_LOOK_DIST) continue; self->target = mo; break; @@ -514,7 +514,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurLook) if (!(mo->flags3 & MF3_ISMONSTER)) continue; if (mo->health <= 0) continue; if (!(mo->flags & MF_SHOOTABLE)) continue; - dist = P_AproxDistance (self->x - mo->x, self->y - mo->y); + dist = self->AproxDistance(mo); if (dist > MINOTAUR_LOOK_DIST) continue; if ((mo == master) || (mo == self)) continue; if ((mo->flags5 & MF5_SUMMONEDMONSTER) && (mo->tracer == master)) continue; diff --git a/src/g_shared/a_action.cpp b/src/g_shared/a_action.cpp index 1149bc2c3..e4b683e97 100644 --- a/src/g_shared/a_action.cpp +++ b/src/g_shared/a_action.cpp @@ -262,14 +262,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeathChunks) i = (pr_freeze.Random2()) % (numChunks/4); for (i = MAX (24, numChunks + i); i >= 0; i--) { - mo = Spawn("IceChunk", - self->x + (((pr_freeze()-128)*self->radius)>>7), - self->y + (((pr_freeze()-128)*self->radius)>>7), - self->z + (pr_freeze()*self->height/255), ALLOW_REPLACE); + fixed_t xo = (((pr_freeze() - 128)*self->radius) >> 7); + fixed_t yo = (((pr_freeze() - 128)*self->radius) >> 7); + fixed_t zo = (pr_freeze()*self->height / 255); + mo = Spawn("IceChunk", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); if (mo) { mo->SetState (mo->SpawnState + (pr_freeze()%3)); - mo->velz = FixedDiv(mo->z - self->z, self->height)<<2; + mo->velz = FixedDiv(mo->Z() - self->Z(), self->height)<<2; mo->velx = pr_freeze.Random2 () << (FRACBITS-7); mo->vely = pr_freeze.Random2 () << (FRACBITS-7); CALL_ACTION(A_IceSetTics, mo); // set a random tic wait @@ -279,11 +279,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeathChunks) } if (self->player) { // attach the player's view to a chunk of ice - AActor *head = Spawn("IceChunkHead", self->x, self->y, - self->z + self->player->mo->ViewHeight, ALLOW_REPLACE); + AActor *head = Spawn("IceChunkHead", self->PosPlusZ(self->player->mo->ViewHeight), ALLOW_REPLACE); if (head != NULL) { - head->velz = FixedDiv(head->z - self->z, self->height)<<2; + head->velz = FixedDiv(head->Z() - self->Z(), self->height)<<2; head->velx = pr_freeze.Random2 () << (FRACBITS-7); head->vely = pr_freeze.Random2 () << (FRACBITS-7); head->health = self->health; diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index 2be2e179d..faa5392b7 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -965,7 +965,7 @@ void APowerFlight::InitEffect () Super::InitEffect(); Owner->flags2 |= MF2_FLY; Owner->flags |= MF_NOGRAVITY; - if (Owner->z <= Owner->floorz) + if (Owner->Z() <= Owner->floorz) { Owner->velz = 4*FRACUNIT; // thrust the player in the air a bit } @@ -1012,7 +1012,7 @@ void APowerFlight::EndEffect () if (!(Owner->flags7 & MF7_FLYCHEAT)) { - if (Owner->z != Owner->floorz) + if (Owner->Z() != Owner->floorz) { Owner->player->centering = true; } @@ -1250,7 +1250,7 @@ void APowerSpeed::DoEffect () if (P_AproxDistance (Owner->velx, Owner->vely) <= 12*FRACUNIT) return; - AActor *speedMo = Spawn (Owner->x, Owner->y, Owner->z, NO_REPLACE); + AActor *speedMo = Spawn (Owner->Pos(), NO_REPLACE); if (speedMo) { speedMo->angle = Owner->angle; diff --git a/src/g_shared/a_bridge.cpp b/src/g_shared/a_bridge.cpp index 4caa56287..27dbb0c6b 100644 --- a/src/g_shared/a_bridge.cpp +++ b/src/g_shared/a_bridge.cpp @@ -100,19 +100,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_BridgeOrbit) // Set default values // Every five tics, Hexen moved the ball 3/256th of a revolution. int rotationspeed = ANGLE_45/32*3/5; - int rotationradius = ORBIT_RADIUS; + int rotationradius = ORBIT_RADIUS * FRACUNIT; // If the bridge is custom, set non-default values if any. // Set angular speed; 1--128: counterclockwise rotation ~=1--180°; 129--255: clockwise rotation ~= 180--1° if (self->target->args[3] > 128) rotationspeed = ANGLE_45/32 * (self->target->args[3]-256) / TICRATE; else if (self->target->args[3] > 0) rotationspeed = ANGLE_45/32 * (self->target->args[3]) / TICRATE; // Set rotation radius - if (self->target->args[4]) rotationradius = ((self->target->args[4] * self->target->radius) / (100 * FRACUNIT)); + if (self->target->args[4]) rotationradius = ((self->target->args[4] * self->target->radius) / 100); self->angle += rotationspeed; - self->x = self->target->x + rotationradius * finecosine[self->angle >> ANGLETOFINESHIFT]; - self->y = self->target->y + rotationradius * finesine[self->angle >> ANGLETOFINESHIFT]; - self->z = self->target->z; + self->SetOrigin(self->target->Vec3Angle(rotationradius, self->angle, 0), true); + self->floorz = self->target->floorz; + self->ceilingz = self->target->ceilingz; } @@ -120,16 +120,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BridgeInit) { angle_t startangle; AActor *ball; - fixed_t cx, cy, cz; ACTION_PARAM_START(1); ACTION_PARAM_CLASS(balltype, 0); if (balltype == NULL) balltype = PClass::FindClass("BridgeBall"); - cx = self->x; - cy = self->y; - cz = self->z; startangle = pr_orbit() << 24; // Spawn triad into world -- may be more than a triad now. @@ -137,7 +133,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BridgeInit) for (int i = 0; i < ballcount; i++) { - ball = Spawn(balltype, cx, cy, cz, ALLOW_REPLACE); + ball = Spawn(balltype, self->Pos(), ALLOW_REPLACE); ball->angle = startangle + (ANGLE_45/32) * (256/ballcount) * i; ball->target = self; CALL_ACTION(A_BridgeOrbit, ball); diff --git a/src/g_shared/a_camera.cpp b/src/g_shared/a_camera.cpp index 24363851e..61a155ea7 100644 --- a/src/g_shared/a_camera.cpp +++ b/src/g_shared/a_camera.cpp @@ -176,11 +176,10 @@ void AAimingCamera::Tick () } if (MaxPitchChange) { // Aim camera's pitch; use floats for precision - float dx = FIXED2FLOAT(x - tracer->x); - float dy = FIXED2FLOAT(y - tracer->y); - float dz = FIXED2FLOAT(z - tracer->z - tracer->height/2); - float dist = (float)sqrt (dx*dx + dy*dy); - float ang = dist != 0.f ? (float)atan2 (dz, dist) : 0; + TVector2 vect = tracer->Vec2To(this); + double dz = FIXED2DBL(Z() - tracer->Z() - tracer->height/2); + double dist = vect.Length(); + double ang = dist != 0.f ? atan2 (dz, dist) : 0; int desiredpitch = (angle_t)(ang * 2147483648.f / PI); if (abs (desiredpitch - pitch) < MaxPitchChange) { diff --git a/src/g_shared/a_debris.cpp b/src/g_shared/a_debris.cpp index e6fc79b0a..f60e71595 100644 --- a/src/g_shared/a_debris.cpp +++ b/src/g_shared/a_debris.cpp @@ -31,22 +31,18 @@ IMPLEMENT_CLASS(AGlassShard) void P_SpawnDirt (AActor *actor, fixed_t radius) { - fixed_t x,y,z; const PClass *dtype = NULL; AActor *mo; - angle_t angle; - angle = pr_dirt()<<5; // <<24 >>19 - x = actor->x + FixedMul(radius,finecosine[angle]); - y = actor->y + FixedMul(radius,finesine[angle]); - z = actor->z + (pr_dirt()<<9) + FRACUNIT; + fixed_t zo = (pr_dirt() << 9) + FRACUNIT; + fixedvec3 pos = actor->Vec3Angle(radius, pr_dirt() << 24, zo); char fmt[8]; mysnprintf(fmt, countof(fmt), "Dirt%d", 1 + pr_dirt()%6); dtype = PClass::FindClass(fmt); if (dtype) { - mo = Spawn (dtype, x, y, z, ALLOW_REPLACE); + mo = Spawn (dtype, pos, ALLOW_REPLACE); if (mo) { mo->velz = pr_dirt()<<10; diff --git a/src/g_shared/a_decals.cpp b/src/g_shared/a_decals.cpp index 29fcbf8cb..64921d647 100644 --- a/src/g_shared/a_decals.cpp +++ b/src/g_shared/a_decals.cpp @@ -91,7 +91,7 @@ DBaseDecal::DBaseDecal (int statnum, fixed_t z) DBaseDecal::DBaseDecal (const AActor *basis) : DThinker(STAT_DECAL), - WallNext(0), WallPrev(0), LeftDistance(0), Z(basis->z), ScaleX(basis->scaleX), ScaleY(basis->scaleY), + WallNext(0), WallPrev(0), LeftDistance(0), Z(basis->Z()), ScaleX(basis->scaleX), ScaleY(basis->scaleY), Alpha(basis->alpha), AlphaColor(basis->fillcolor), Translation(basis->Translation), PicNum(basis->picnum), RenderFlags(basis->renderflags), RenderStyle(basis->RenderStyle) { @@ -817,22 +817,22 @@ void ADecal::BeginPlay () { if (!tpl->PicNum.Exists()) { - Printf("Decal actor at (%d,%d) does not have a valid texture\n", x>>FRACBITS, y>>FRACBITS); + Printf("Decal actor at (%d,%d) does not have a valid texture\n", X()>>FRACBITS, Y()>>FRACBITS); } else { // Look for a wall within 64 units behind the actor. If none can be // found, then no decal is created, and this actor is destroyed // without effectively doing anything. - if (NULL == ShootDecal(tpl, this, Sector, x, y, z, angle + ANGLE_180, 64*FRACUNIT, true)) + if (NULL == ShootDecal(tpl, this, Sector, X(), Y(), Z(), angle + ANGLE_180, 64*FRACUNIT, true)) { - DPrintf ("Could not find a wall to stick decal to at (%d,%d)\n", x>>FRACBITS, y>>FRACBITS); + DPrintf ("Could not find a wall to stick decal to at (%d,%d)\n", X()>>FRACBITS, Y()>>FRACBITS); } } } else { - DPrintf ("Decal actor at (%d,%d) does not have a good template\n", x>>FRACBITS, y>>FRACBITS); + DPrintf ("Decal actor at (%d,%d) does not have a good template\n", X()>>FRACBITS, Y()>>FRACBITS); } // This actor doesn't need to stick around anymore. Destroy(); diff --git a/src/g_shared/a_fastprojectile.cpp b/src/g_shared/a_fastprojectile.cpp index c019fcbf6..ae7f6a58b 100644 --- a/src/g_shared/a_fastprojectile.cpp +++ b/src/g_shared/a_fastprojectile.cpp @@ -25,10 +25,10 @@ void AFastProjectile::Tick () fixed_t zfrac; int changexy; - PrevX = x; - PrevY = y; - PrevZ = z; - fixed_t oldz = z; + PrevX = X(); + PrevY = Y(); + PrevZ = Z(); + fixed_t oldz = Z(); PrevAngle = angle; if (!(flags5 & MF5_NOTIMEFREEZE)) @@ -57,7 +57,7 @@ void AFastProjectile::Tick () } // Handle movement - if (velx || vely || (z != floorz) || velz) + if (velx || vely || (Z() != floorz) || velz) { xfrac = velx >> shift; yfrac = vely >> shift; @@ -73,14 +73,14 @@ void AFastProjectile::Tick () tm.LastRipped = NULL; // [RH] Do rip damage each step, like Hexen } - if (!P_TryMove (this, x + xfrac,y + yfrac, true, NULL, tm)) + if (!P_TryMove (this, X() + xfrac,Y() + yfrac, true, NULL, tm)) { // Blocked move if (!(flags3 & MF3_SKYEXPLODE)) { if (tm.ceilingline && tm.ceilingline->backsector && tm.ceilingline->backsector->GetTexture(sector_t::ceiling) == skyflatnum && - z >= tm.ceilingline->backsector->ceilingplane.ZatPoint (x, y)) + Z() >= tm.ceilingline->backsector->ceilingplane.ZatPoint (this)) { // Hack to prevent missiles exploding against the sky. // Does not handle sky floors. @@ -99,10 +99,10 @@ void AFastProjectile::Tick () return; } } - z += zfrac; + AddZ(zfrac); UpdateWaterLevel (oldz); - oldz = z; - if (z <= floorz) + oldz = Z(); + if (Z() <= floorz) { // Hit the floor if (floorpic == skyflatnum && !(flags3 & MF3_SKYEXPLODE)) @@ -113,12 +113,12 @@ void AFastProjectile::Tick () return; } - z = floorz; + SetZ(floorz); P_HitFloor (this); P_ExplodeMissile (this, NULL, NULL); return; } - if (z + height > ceilingz) + if (Top() > ceilingz) { // Hit the ceiling if (ceilingpic == skyflatnum && !(flags3 & MF3_SKYEXPLODE)) @@ -127,7 +127,7 @@ void AFastProjectile::Tick () return; } - z = ceilingz - height; + SetZ(ceilingz - height); P_ExplodeMissile (this, NULL, NULL); return; } @@ -160,7 +160,7 @@ void AFastProjectile::Effect() FName name = (ENamedName) this->GetClass()->Meta.GetMetaInt (ACMETA_MissileName, NAME_None); if (name != NAME_None) { - fixed_t hitz = z-8*FRACUNIT; + fixed_t hitz = Z()-8*FRACUNIT; if (hitz < floorz) { @@ -172,7 +172,7 @@ void AFastProjectile::Effect() const PClass *trail = PClass::FindClass(name); if (trail != NULL) { - AActor *act = Spawn (trail, x, y, hitz, ALLOW_REPLACE); + AActor *act = Spawn (trail, X(), Y(), hitz, ALLOW_REPLACE); if (act != NULL) { act->angle = this->angle; diff --git a/src/g_shared/a_lightning.cpp b/src/g_shared/a_lightning.cpp index e7c598d3e..33d51c02d 100644 --- a/src/g_shared/a_lightning.cpp +++ b/src/g_shared/a_lightning.cpp @@ -139,7 +139,7 @@ void DLightningThinker::LightningFlash () for (i = numsectors, j = 0; i > 0; --i, ++j, ++tempSec) { // allow combination of the lightning sector specials with bit masks - int special = tempSec->special & 0xff; + int special = tempSec->special; if (tempSec->GetTexture(sector_t::ceiling) == skyflatnum || special == Light_IndoorLightning1 || special == Light_IndoorLightning2 diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 4da6eb67b..bc63f7bf0 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -77,7 +77,7 @@ bool P_MorphPlayer (player_t *activator, player_t *p, const PClass *spawntype, i return false; } - morphed = static_cast(Spawn (spawntype, actor->x, actor->y, actor->z, NO_REPLACE)); + morphed = static_cast(Spawn (spawntype, actor->Pos(), NO_REPLACE)); EndAllPowerupEffects(actor->Inventory); DObject::StaticPointerSubstitution (actor, morphed); if ((actor->tid != 0) && (style & MORPH_NEWTIDBEHAVIOUR)) @@ -105,7 +105,7 @@ bool P_MorphPlayer (player_t *activator, player_t *p, const PClass *spawntype, i morphed->flags |= actor->flags & (MF_SHADOW|MF_NOGRAVITY); morphed->flags2 |= actor->flags2 & MF2_FLY; morphed->flags3 |= actor->flags3 & MF3_GHOST; - AActor *eflash = Spawn(((enter_flash) ? enter_flash : RUNTIME_CLASS(ATeleportFog)), actor->x, actor->y, actor->z + TELEFOGHEIGHT, ALLOW_REPLACE); + AActor *eflash = Spawn(((enter_flash) ? enter_flash : RUNTIME_CLASS(ATeleportFog)), actor->PosPlusZ(TELEFOGHEIGHT), ALLOW_REPLACE); actor->player = NULL; actor->flags &= ~(MF_SOLID|MF_SHOOTABLE); actor->flags |= MF_UNMORPHED; @@ -192,7 +192,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, } mo = barrier_cast(pmo->tracer); - mo->SetOrigin (pmo->x, pmo->y, pmo->z); + mo->SetOrigin (pmo->Pos(), false); mo->flags |= MF_SOLID; pmo->flags &= ~MF_SOLID; if (!force && !P_TestMobjLocation (mo)) @@ -310,7 +310,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, AActor *eflash = NULL; if (exit_flash != NULL) { - eflash = Spawn(exit_flash, pmo->x + 20*finecosine[angle], pmo->y + 20*finesine[angle], pmo->z + TELEFOGHEIGHT, ALLOW_REPLACE); + eflash = Spawn(exit_flash, pmo->Vec3Offset(20*finecosine[angle], 20*finesine[angle], TELEFOGHEIGHT), ALLOW_REPLACE); if (eflash) eflash->target = mo; } mo->SetupWeaponSlots(); // Use original class's weapon slots. @@ -381,7 +381,7 @@ bool P_MorphMonster (AActor *actor, const PClass *spawntype, int duration, int s return false; } - morphed = static_cast(Spawn (spawntype, actor->x, actor->y, actor->z, NO_REPLACE)); + morphed = static_cast(Spawn (spawntype, actor->Pos(), NO_REPLACE)); DObject::StaticPointerSubstitution (actor, morphed); morphed->tid = actor->tid; morphed->angle = actor->angle; @@ -410,7 +410,7 @@ bool P_MorphMonster (AActor *actor, const PClass *spawntype, int duration, int s actor->flags &= ~(MF_SOLID|MF_SHOOTABLE); actor->flags |= MF_UNMORPHED; actor->renderflags |= RF_INVISIBLE; - AActor *eflash = Spawn(((enter_flash) ? enter_flash : RUNTIME_CLASS(ATeleportFog)), actor->x, actor->y, actor->z + TELEFOGHEIGHT, ALLOW_REPLACE); + AActor *eflash = Spawn(((enter_flash) ? enter_flash : RUNTIME_CLASS(ATeleportFog)), actor->PosPlusZ(TELEFOGHEIGHT), ALLOW_REPLACE); if (eflash) eflash->target = morphed; return true; @@ -436,7 +436,7 @@ bool P_UndoMonsterMorph (AMorphedMonster *beast, bool force) return false; } actor = beast->UnmorphedMe; - actor->SetOrigin (beast->x, beast->y, beast->z); + actor->SetOrigin (beast->Pos(), false); actor->flags |= MF_SOLID; beast->flags &= ~MF_SOLID; ActorFlags6 beastflags6 = beast->flags6; @@ -472,7 +472,7 @@ bool P_UndoMonsterMorph (AMorphedMonster *beast, bool force) DObject::StaticPointerSubstitution (beast, actor); const PClass *exit_flash = beast->MorphExitFlash; beast->Destroy (); - AActor *eflash = Spawn(exit_flash, beast->x, beast->y, beast->z + TELEFOGHEIGHT, ALLOW_REPLACE); + AActor *eflash = Spawn(exit_flash, beast->PosPlusZ(TELEFOGHEIGHT), ALLOW_REPLACE); if (eflash) eflash->target = actor; return true; diff --git a/src/g_shared/a_movingcamera.cpp b/src/g_shared/a_movingcamera.cpp index 0f847fa41..fe4526e16 100644 --- a/src/g_shared/a_movingcamera.cpp +++ b/src/g_shared/a_movingcamera.cpp @@ -282,7 +282,7 @@ void APathFollower::Activate (AActor *activator) if (CurrNode != NULL) { NewNode (); - SetOrigin (CurrNode->x, CurrNode->y, CurrNode->z); + SetOrigin (CurrNode->Pos(), false); Time = 0.f; HoldTime = 0; bJustStepped = true; @@ -302,9 +302,7 @@ void APathFollower::Tick () if (CurrNode->args[2]) { HoldTime = level.time + CurrNode->args[2] * TICRATE / 8; - x = CurrNode->x; - y = CurrNode->y; - z = CurrNode->z; + SetXYZ(CurrNode->X(), CurrNode->Y(), CurrNode->Z()); } } @@ -362,31 +360,33 @@ bool APathFollower::Interpolate () if ((args[2] & 8) && Time > 0.f) { - dx = x; - dy = y; - dz = z; + dx = X(); + dy = Y(); + dz = Z(); } if (CurrNode->Next==NULL) return false; UnlinkFromWorld (); + fixed_t x, y, z; if (args[2] & 1) { // linear - x = FLOAT2FIXED(Lerp (FIXED2FLOAT(CurrNode->x), FIXED2FLOAT(CurrNode->Next->x))); - y = FLOAT2FIXED(Lerp (FIXED2FLOAT(CurrNode->y), FIXED2FLOAT(CurrNode->Next->y))); - z = FLOAT2FIXED(Lerp (FIXED2FLOAT(CurrNode->z), FIXED2FLOAT(CurrNode->Next->z))); + x = FLOAT2FIXED(Lerp (FIXED2FLOAT(CurrNode->X()), FIXED2FLOAT(CurrNode->Next->X()))); + y = FLOAT2FIXED(Lerp (FIXED2FLOAT(CurrNode->Y()), FIXED2FLOAT(CurrNode->Next->Y()))); + z = FLOAT2FIXED(Lerp (FIXED2FLOAT(CurrNode->Z()), FIXED2FLOAT(CurrNode->Next->Z()))); } else { // spline if (CurrNode->Next->Next==NULL) return false; - x = FLOAT2FIXED(Splerp (FIXED2FLOAT(PrevNode->x), FIXED2FLOAT(CurrNode->x), - FIXED2FLOAT(CurrNode->Next->x), FIXED2FLOAT(CurrNode->Next->Next->x))); - y = FLOAT2FIXED(Splerp (FIXED2FLOAT(PrevNode->y), FIXED2FLOAT(CurrNode->y), - FIXED2FLOAT(CurrNode->Next->y), FIXED2FLOAT(CurrNode->Next->Next->y))); - z = FLOAT2FIXED(Splerp (FIXED2FLOAT(PrevNode->z), FIXED2FLOAT(CurrNode->z), - FIXED2FLOAT(CurrNode->Next->z), FIXED2FLOAT(CurrNode->Next->Next->z))); + x = FLOAT2FIXED(Splerp (FIXED2FLOAT(PrevNode->X()), FIXED2FLOAT(CurrNode->X()), + FIXED2FLOAT(CurrNode->Next->X()), FIXED2FLOAT(CurrNode->Next->Next->X()))); + y = FLOAT2FIXED(Splerp (FIXED2FLOAT(PrevNode->Y()), FIXED2FLOAT(CurrNode->Y()), + FIXED2FLOAT(CurrNode->Next->Y()), FIXED2FLOAT(CurrNode->Next->Next->Y()))); + z = FLOAT2FIXED(Splerp (FIXED2FLOAT(PrevNode->Z()), FIXED2FLOAT(CurrNode->Z()), + FIXED2FLOAT(CurrNode->Next->Z()), FIXED2FLOAT(CurrNode->Next->Next->Z()))); } + SetXYZ(x, y, z); LinkToWorld (); if (args[2] & 6) @@ -395,9 +395,9 @@ bool APathFollower::Interpolate () { if (args[2] & 1) { // linear - dx = CurrNode->Next->x - CurrNode->x; - dy = CurrNode->Next->y - CurrNode->y; - dz = CurrNode->Next->z - CurrNode->z; + dx = CurrNode->Next->X() - CurrNode->X(); + dy = CurrNode->Next->Y() - CurrNode->Y(); + dz = CurrNode->Next->Z() - CurrNode->Z(); } else if (Time > 0.f) { // spline @@ -422,6 +422,7 @@ bool APathFollower::Interpolate () x -= dx; y -= dy; z -= dz; + SetXYZ(x, y, z); } if (args[2] & 2) { // adjust yaw @@ -548,11 +549,11 @@ bool AActorMover::Interpolate () if (Super::Interpolate ()) { - fixed_t savedz = tracer->z; - tracer->z = z; - if (!P_TryMove (tracer, x, y, true)) + fixed_t savedz = tracer->Z(); + tracer->SetZ(Z()); + if (!P_TryMove (tracer, X(), Y(), true)) { - tracer->z = savedz; + tracer->SetZ(savedz); return false; } @@ -589,9 +590,9 @@ void AActorMover::Activate (AActor *activator) // Don't let the renderer interpolate between the actor's // old position and its new position. Interpolate (); - tracer->PrevX = tracer->x; - tracer->PrevY = tracer->y; - tracer->PrevZ = tracer->z; + tracer->PrevX = tracer->X(); + tracer->PrevY = tracer->Y(); + tracer->PrevZ = tracer->Z(); tracer->PrevAngle = tracer->angle; } @@ -667,15 +668,15 @@ bool AMovingCamera::Interpolate () if (Super::Interpolate ()) { - angle = R_PointToAngle2 (x, y, tracer->x, tracer->y); + angle = AngleTo(tracer, true); if (args[2] & 4) { // Also aim camera's pitch; use floats for precision - float dx = FIXED2FLOAT(x - tracer->x); - float dy = FIXED2FLOAT(y - tracer->y); - float dz = FIXED2FLOAT(z - tracer->z - tracer->height/2); - float dist = (float)sqrt (dx*dx + dy*dy); - float ang = dist != 0.f ? (float)atan2 (dz, dist) : 0; + double dx = FIXED2DBL(X() - tracer->X()); + double dy = FIXED2DBL(Y() - tracer->Y()); + double dz = FIXED2DBL(Z() - tracer->Z() - tracer->height/2); + double dist = sqrt (dx*dx + dy*dy); + double ang = dist != 0.f ? atan2 (dz, dist) : 0; pitch = (angle_t)(ang * 2147483648.f / PI); } diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index eb2831024..9fe31db22 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -331,7 +331,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialDoomThing) { self->SetState (self->SpawnState); S_Sound (self, CHAN_VOICE, "misc/spawn", 1, ATTN_IDLE); - Spawn ("ItemFog", self->x, self->y, self->z, ALLOW_REPLACE); + Spawn ("ItemFog", self->Pos(), ALLOW_REPLACE); } } @@ -351,19 +351,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialPosition) _y = self->SpawnPoint[1]; self->UnlinkFromWorld(); - self->x = _x; - self->y = _y; + self->SetXY(_x, _y); self->LinkToWorld(true); sec = self->Sector; - self->z = self->dropoffz = self->floorz = sec->floorplane.ZatPoint(_x, _y); self->ceilingz = sec->ceilingplane.ZatPoint(_x, _y); + self->SetZ(self->floorz); P_FindFloorCeiling(self, FFCF_ONLYSPAWNPOS); if (self->flags & MF_SPAWNCEILING) { - self->z = self->ceilingz - self->height - self->SpawnPoint[2]; + self->SetZ(self->ceilingz - self->height - self->SpawnPoint[2]); } else if (self->flags2 & MF2_SPAWNFLOAT) { @@ -371,33 +370,33 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialPosition) if (space > 48*FRACUNIT) { space -= 40*FRACUNIT; - self->z = ((space * pr_restore())>>8) + self->floorz + 40*FRACUNIT; + self->SetZ(((space * pr_restore())>>8) + self->floorz + 40*FRACUNIT); } else { - self->z = self->floorz; + self->SetZ(self->floorz); } } else { - self->z = self->SpawnPoint[2] + self->floorz; + self->SetZ(self->SpawnPoint[2] + self->floorz); } // Redo floor/ceiling check, in case of 3D floors P_FindFloorCeiling(self, FFCF_SAMESECTOR | FFCF_ONLY3DFLOORS | FFCF_3DRESTRICT); - if (self->z < self->floorz) + if (self->Z() < self->floorz) { // Do not reappear under the floor, even if that's where we were for the // initial spawn. - self->z = self->floorz; + self->SetZ(self->floorz); } - if ((self->flags & MF_SOLID) && (self->z + self->height > self->ceilingz)) + if ((self->flags & MF_SOLID) && (self->Top() > self->ceilingz)) { // Do the same for the ceiling. - self->z = self->ceilingz - self->height; + self->SetZ(self->ceilingz - self->height); } // Do not interpolate from the position the actor was at when it was // picked up, in case that is different from where it is now. - self->PrevX = self->x; - self->PrevY = self->y; - self->PrevZ = self->z; + self->PrevX = self->X(); + self->PrevY = self->Y(); + self->PrevZ = self->Z(); } int AInventory::StaticLastMessageTic; @@ -728,8 +727,7 @@ AInventory *AInventory::CreateTossable () flags &= ~(MF_SPECIAL|MF_SOLID); return this; } - copy = static_cast(Spawn (GetClass(), Owner->x, - Owner->y, Owner->z, NO_REPLACE)); + copy = static_cast(Spawn (GetClass(), Owner->Pos(), NO_REPLACE)); if (copy != NULL) { copy->MaxAmount = MaxAmount; @@ -994,7 +992,7 @@ void AInventory::Touch (AActor *toucher) // This is the only situation when a pickup flash should ever play. if (PickupFlash != NULL && !ShouldStay()) { - Spawn(PickupFlash, x, y, z, ALLOW_REPLACE); + Spawn(PickupFlash, Pos(), ALLOW_REPLACE); } if (!(ItemFlags & IF_QUIET)) @@ -1290,8 +1288,8 @@ bool AInventory::DoRespawn () if (state != NULL) spot = state->GetRandomSpot(SpawnPointClass); if (spot != NULL) { - SetOrigin (spot->x, spot->y, spot->z); - z = floorz; + SetOrigin (spot->Pos(), false); + SetZ(floorz); } } return true; diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index 74b10206b..413b01db3 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -305,8 +305,7 @@ public: virtual FState *GetReadyState (); virtual FState *GetAtkState (bool hold); virtual FState *GetAltAtkState (bool hold); - virtual FState *GetRelState (); - virtual FState *GetZoomState (); + virtual FState *GetStateForButtonName (FName button); virtual void PostMorphWeapon (); virtual void EndPowerup (); diff --git a/src/g_shared/a_quake.cpp b/src/g_shared/a_quake.cpp index 3c8d704aa..94a375d3e 100644 --- a/src/g_shared/a_quake.cpp +++ b/src/g_shared/a_quake.cpp @@ -129,9 +129,9 @@ void DEarthquake::Tick () AActor *victim = players[i].mo; fixed_t dist; - dist = P_AproxDistance (victim->x - m_Spot->x, victim->y - m_Spot->y); + dist = m_Spot->AproxDistance (victim, true); // Check if in damage radius - if (dist < m_DamageRadius && victim->z <= victim->floorz) + if (dist < m_DamageRadius && victim->Z() <= victim->floorz) { if (pr_quake() < 50) { @@ -242,8 +242,7 @@ int DEarthquake::StaticGetQuakeIntensities(AActor *victim, FQuakeJiggers &jigger { if (quake->m_Spot != NULL) { - fixed_t dist = P_AproxDistance (victim->x - quake->m_Spot->x, - victim->y - quake->m_Spot->y); + fixed_t dist = quake->m_Spot->AproxDistance (victim, true); if (dist < quake->m_TremorRadius) { ++count; diff --git a/src/g_shared/a_randomspawner.cpp b/src/g_shared/a_randomspawner.cpp index 7d000f3d4..2ba445b7b 100644 --- a/src/g_shared/a_randomspawner.cpp +++ b/src/g_shared/a_randomspawner.cpp @@ -91,7 +91,7 @@ class ARandomSpawner : public AActor // So now we can spawn the dropped item. if (di == NULL || bouncecount >= MAX_RANDOMSPAWNERS_RECURSION) // Prevents infinite recursions { - Spawn("Unknown", x, y, z, NO_REPLACE); // Show that there's a problem. + Spawn("Unknown", Pos(), NO_REPLACE); // Show that there's a problem. Destroy(); return; } @@ -144,9 +144,9 @@ class ARandomSpawner : public AActor if (this->flags & MF_MISSILE && target && target->target) // Attempting to spawn a missile. { if ((tracer == NULL) && (flags2 & MF2_SEEKERMISSILE)) tracer = target->target; - newmobj = P_SpawnMissileXYZ(x, y, z, target, target->target, cls, false); + newmobj = P_SpawnMissileXYZ(Pos(), target, target->target, cls, false); } - else newmobj = Spawn(cls, x, y, z, NO_REPLACE); + else newmobj = Spawn(cls, Pos(), NO_REPLACE); if (newmobj != NULL) { // copy everything relevant @@ -179,7 +179,7 @@ class ARandomSpawner : public AActor // Handle special altitude flags if (newmobj->flags & MF_SPAWNCEILING) { - newmobj->z = newmobj->ceilingz - newmobj->height - SpawnPoint[2]; + newmobj->SetZ(newmobj->ceilingz - newmobj->height - SpawnPoint[2]); } else if (newmobj->flags2 & MF2_SPAWNFLOAT) { @@ -187,9 +187,9 @@ class ARandomSpawner : public AActor if (space > 48*FRACUNIT) { space -= 40*FRACUNIT; - newmobj->z = MulScale8 (space, pr_randomspawn()) + newmobj->floorz + 40*FRACUNIT; + newmobj->SetZ(MulScale8 (space, pr_randomspawn()) + newmobj->floorz + 40*FRACUNIT); } - newmobj->z += SpawnPoint[2]; + newmobj->AddZ(SpawnPoint[2]); } if (newmobj->flags & MF_MISSILE) P_CheckMissileSpawn(newmobj, 0); diff --git a/src/g_shared/a_sectoraction.cpp b/src/g_shared/a_sectoraction.cpp index 570818e19..bb582dd28 100644 --- a/src/g_shared/a_sectoraction.cpp +++ b/src/g_shared/a_sectoraction.cpp @@ -39,6 +39,14 @@ IMPLEMENT_CLASS (ASectorAction) +ASectorAction::ASectorAction (bool activatedByUse) : + ActivatedByUse (activatedByUse) {} + +bool ASectorAction::IsActivatedByUse() const +{ + return ActivatedByUse; +} + void ASectorAction::Destroy () { // Remove ourself from this sector's list of actions @@ -102,12 +110,17 @@ bool ASectorAction::DoTriggerAction (AActor *triggerer, int activationType) return false; } +bool ASectorAction::CanTrigger (AActor *triggerer) const +{ + return special && + ((triggerer->player && !(flags & MF_FRIENDLY)) || + ((flags & MF_AMBUSH) && (triggerer->flags2 & MF2_MCROSS)) || + ((flags2 & MF2_DORMANT) && (triggerer->flags2 & MF2_PCROSS))); +} + bool ASectorAction::CheckTrigger (AActor *triggerer) const { - if (special && - ((triggerer->player && !(flags & MF_FRIENDLY)) || - ((flags & MF_AMBUSH) && (triggerer->flags2 & MF2_MCROSS)) || - ((flags2 & MF2_DORMANT) && (triggerer->flags2 & MF2_PCROSS)))) + if (CanTrigger(triggerer)) { bool res = !!P_ExecuteSpecial(special, NULL, triggerer, false, args[0], args[1], args[2], args[3], args[4]); @@ -196,6 +209,7 @@ class ASecActUse : public ASectorAction { DECLARE_CLASS (ASecActUse, ASectorAction) public: + ASecActUse() : ASectorAction (true) {} bool DoTriggerAction (AActor *triggerer, int activationType); }; @@ -214,6 +228,7 @@ class ASecActUseWall : public ASectorAction { DECLARE_CLASS (ASecActUseWall, ASectorAction) public: + ASecActUseWall() : ASectorAction (true) {} bool DoTriggerAction (AActor *triggerer, int activationType); }; diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h index 2688249ea..8a1c31307 100644 --- a/src/g_shared/a_sharedglobal.h +++ b/src/g_shared/a_sharedglobal.h @@ -100,6 +100,20 @@ public: TObjPtr Mate; }; +// For an EE compatible linedef based definition. +class ASkyCamCompat : public ASkyViewpoint +{ + DECLARE_CLASS (ASkyCamCompat, ASkyViewpoint) + +public: + void BeginPlay () + { + // Do not call the SkyViewpoint's super method because it would trash our setup + AActor::BeginPlay(); + } +}; + + class AStackPoint : public ASkyViewpoint { DECLARE_CLASS (AStackPoint, ASkyViewpoint) diff --git a/src/g_shared/a_skies.cpp b/src/g_shared/a_skies.cpp index 54661ea14..a8c8ebd55 100644 --- a/src/g_shared/a_skies.cpp +++ b/src/g_shared/a_skies.cpp @@ -37,6 +37,7 @@ #include "p_local.h" #include "p_lnspec.h" #include "farchive.h" +#include "r_sky.h" // arg0 = Visibility*4 for this skybox @@ -66,13 +67,13 @@ void ASkyViewpoint::Destroy () // remove all sector references to ourselves. for (int i = 0; i linecount; i++) - { - refline = Sector->lines[i]; - if (refline->special == Sector_SetPortal && refline->args[1] == 2) - { - // We found the setup linedef for this skybox, so let's use it for our init. - int skybox_id = refline->args[0]; - - // Then, change the alpha - alpha = refline->args[4]; - - // Finally, skyboxify all tagged sectors - // This involves changing their texture to the sky flat, because while - // EE works with any texture for its skybox portals, ZDoom doesn't. - FSectorTagIterator it(skybox_id); - int secnum; - while ((secnum = it.Next()) >= 0) - { - // plane: 0=floor, 1=ceiling, 2=both - if (refline->args[2] == 1 || refline->args[2] == 2) - { - sectors[secnum].CeilingSkyBox = this; - sectors[secnum].SetTexture(sector_t::ceiling, skyflatnum, false); - } - if (refline->args[2] == 0 || refline->args[2] == 2) - { - sectors[secnum].FloorSkyBox = this; - sectors[secnum].SetTexture(sector_t::floor, skyflatnum, false); - } - } - } - } - } - // Do not call the SkyViewpoint's super method because it would trash our setup - AActor::BeginPlay(); -} //--------------------------------------------------------------------------- @@ -185,12 +129,12 @@ void ASkyPicker::PostBeginPlay () { if (0 == (args[1] & 2)) { - Sector->CeilingSkyBox = box; + Sector->SkyBoxes[sector_t::ceiling] = box; if (box == NULL) Sector->MoreFlags |= SECF_NOCEILINGSKYBOX; // sector should ignore the level's default skybox } if (0 == (args[1] & 1)) { - Sector->FloorSkyBox = box; + Sector->SkyBoxes[sector_t::floor] = box; if (box == NULL) Sector->MoreFlags |= SECF_NOFLOORSKYBOX; // sector should ignore the level's default skybox } } diff --git a/src/g_shared/a_spark.cpp b/src/g_shared/a_spark.cpp index 18b27d9ff..eee842f36 100644 --- a/src/g_shared/a_spark.cpp +++ b/src/g_shared/a_spark.cpp @@ -50,6 +50,6 @@ IMPLEMENT_CLASS (ASpark) void ASpark::Activate (AActor *activator) { Super::Activate (activator); - P_DrawSplash (args[0] ? args[0] : 32, x, y, z, angle, 1); + P_DrawSplash (args[0] ? args[0] : 32, X(), Y(), Z(), angle, 1); S_Sound (this, CHAN_AUTO, "world/spark", 1, ATTN_STATIC); } diff --git a/src/g_shared/a_specialspot.cpp b/src/g_shared/a_specialspot.cpp index fbfbbf550..1d2747ceb 100644 --- a/src/g_shared/a_specialspot.cpp +++ b/src/g_shared/a_specialspot.cpp @@ -158,7 +158,7 @@ struct FSpotList while (true) { - distance = P_AproxDistance(Spots[i]->x - x, Spots[i]->y - y); + distance = Spots[i]->AproxDistance(x, y); if ((distance >= mindist) && ((maxdist == 0) || (distance <= maxdist))) break; @@ -423,12 +423,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnSingleItem) return; } - AActor *spawned = Spawn(cls, self->x, self->y, self->z, ALLOW_REPLACE); + AActor *spawned = Spawn(cls, self->Pos(), ALLOW_REPLACE); if (spawned) { - spawned->SetOrigin (spot->x, spot->y, spot->z); - spawned->z = spawned->floorz; + spawned->SetOrigin (spot->Pos(), false); + spawned->SetZ(spawned->floorz); // We want this to respawn. if (!(self->flags & MF_DROPPED)) { diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index fae232557..9c71ab0ea 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -683,25 +683,15 @@ FState *AWeapon::GetAltAtkState (bool hold) //=========================================================================== // -// AWeapon :: GetRelState +// AWeapon :: GetStateForButtonName // //=========================================================================== -FState *AWeapon::GetRelState () +FState *AWeapon::GetStateForButtonName (FName button) { - return FindState(NAME_Reload); + return FindState(button); } -//=========================================================================== -// -// AWeapon :: GetZoomState -// -//=========================================================================== - -FState *AWeapon::GetZoomState () -{ - return FindState(NAME_Zoom); -} /* Weapon giver ***********************************************************/ diff --git a/src/g_shared/sbar_mugshot.cpp b/src/g_shared/sbar_mugshot.cpp index b8f419ef0..ea1c8528e 100644 --- a/src/g_shared/sbar_mugshot.cpp +++ b/src/g_shared/sbar_mugshot.cpp @@ -366,7 +366,7 @@ int FMugShot::UpdateState(player_t *player, StateFlags stateflags) if (player->mo != NULL) { // The next 12 lines are from the Doom statusbar code. - badguyangle = R_PointToAngle2(player->mo->x, player->mo->y, player->attacker->x, player->attacker->y); + badguyangle = player->mo->AngleTo(player->attacker); if (badguyangle > player->mo->angle) { // whether right or left diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index b2f1184ea..0fe8a4588 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -826,9 +826,9 @@ static void DrawCoordinates(player_t * CPlayer) if (!map_point_coordinates || !automapactive) { - x=CPlayer->mo->x; - y=CPlayer->mo->y; - z=CPlayer->mo->z; + x=CPlayer->mo->X(); + y=CPlayer->mo->Y(); + z=CPlayer->mo->Z(); } else { diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index b74350633..bd2946f2a 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -1286,8 +1286,8 @@ void DBaseStatusBar::Draw (EHudState state) y -= height * 2; } - value = &CPlayer->mo->z; - for (i = 2, value = &CPlayer->mo->z; i >= 0; y -= height, --value, --i) + fixedvec3 pos = CPlayer->mo->Pos(); + for (i = 2, value = &pos.z; i >= 0; y -= height, --value, --i) { mysnprintf (line, countof(line), "%c: %d", labels[i], *value >> FRACBITS); screen->DrawText (SmallFont, CR_GREEN, xpos, y, line, diff --git a/src/g_strife/a_alienspectres.cpp b/src/g_strife/a_alienspectres.cpp index 2b9f499e9..c6339f33d 100644 --- a/src/g_strife/a_alienspectres.cpp +++ b/src/g_strife/a_alienspectres.cpp @@ -22,7 +22,7 @@ AActor *P_SpawnSubMissile (AActor *source, const PClass *type, AActor *target); DEFINE_ACTION_FUNCTION(AActor, A_SpectreChunkSmall) { - AActor *foo = Spawn("AlienChunkSmall", self->x, self->y, self->z + 10*FRACUNIT, ALLOW_REPLACE); + AActor *foo = Spawn("AlienChunkSmall", self->PosPlusZ(10*FRACUNIT), ALLOW_REPLACE); if (foo != NULL) { @@ -40,7 +40,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpectreChunkSmall) DEFINE_ACTION_FUNCTION(AActor, A_SpectreChunkLarge) { - AActor *foo = Spawn("AlienChunkLarge", self->x, self->y, self->z + 10*FRACUNIT, ALLOW_REPLACE); + AActor *foo = Spawn("AlienChunkLarge", self->PosPlusZ(10*FRACUNIT), ALLOW_REPLACE); if (foo != NULL) { @@ -62,7 +62,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Spectre3Attack) if (self->target == NULL) return; - AActor *foo = Spawn("SpectralLightningV2", self->x, self->y, self->z + 32*FRACUNIT, ALLOW_REPLACE); + AActor *foo = Spawn("SpectralLightningV2", self->PosPlusZ(32*FRACUNIT), ALLOW_REPLACE); foo->velz = -12*FRACUNIT; foo->target = self; diff --git a/src/g_strife/a_coin.cpp b/src/g_strife/a_coin.cpp index dd3610039..36b531001 100644 --- a/src/g_strife/a_coin.cpp +++ b/src/g_strife/a_coin.cpp @@ -80,22 +80,22 @@ AInventory *ACoin::CreateTossable () if (Amount >= 50) { Amount -= 50; - tossed = static_cast(Spawn("Gold50", Owner->x, Owner->y, Owner->z, NO_REPLACE)); + tossed = static_cast(Spawn("Gold50", Owner->Pos(), NO_REPLACE)); } else if (Amount >= 25) { Amount -= 25; - tossed = static_cast(Spawn("Gold25", Owner->x, Owner->y, Owner->z, NO_REPLACE)); + tossed = static_cast(Spawn("Gold25", Owner->Pos(), NO_REPLACE)); } else if (Amount >= 10) { Amount -= 10; - tossed = static_cast(Spawn("Gold10", Owner->x, Owner->y, Owner->z, NO_REPLACE)); + tossed = static_cast(Spawn("Gold10", Owner->Pos(), NO_REPLACE)); } else if (Amount > 1 || (ItemFlags & IF_KEEPDEPLETED)) { Amount -= 1; - tossed = static_cast(Spawn("Coin", Owner->x, Owner->y, Owner->z, NO_REPLACE)); + tossed = static_cast(Spawn("Coin", Owner->Pos(), NO_REPLACE)); } else // Amount == 1 && !(ItemFlags & IF_KEEPDEPLETED) { diff --git a/src/g_strife/a_crusader.cpp b/src/g_strife/a_crusader.cpp index 7ef0b24a1..8655e10bc 100644 --- a/src/g_strife/a_crusader.cpp +++ b/src/g_strife/a_crusader.cpp @@ -11,9 +11,9 @@ static bool CrusaderCheckRange (AActor *self) { - if (P_CheckSight (self, self->target) && self->reactiontime == 0) + if (self->reactiontime == 0 && P_CheckSight (self, self->target)) { - return P_AproxDistance (self->x - self->target->x, self->y - self->target->y) < 264*FRACUNIT; + return self->AproxDistance (self->target) < 264*FRACUNIT; } return false; } @@ -27,18 +27,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_CrusaderChoose) { A_FaceTarget (self); self->angle -= ANGLE_180/16; - P_SpawnMissileZAimed (self, self->z + 40*FRACUNIT, self->target, PClass::FindClass("FastFlameMissile")); + P_SpawnMissileZAimed (self, self->Z() + 40*FRACUNIT, self->target, PClass::FindClass("FastFlameMissile")); } else { if (P_CheckMissileRange (self)) { A_FaceTarget (self); - P_SpawnMissileZAimed (self, self->z + 56*FRACUNIT, self->target, PClass::FindClass("CrusaderMissile")); + P_SpawnMissileZAimed (self, self->Z() + 56*FRACUNIT, self->target, PClass::FindClass("CrusaderMissile")); self->angle -= ANGLE_45/32; - P_SpawnMissileZAimed (self, self->z + 40*FRACUNIT, self->target, PClass::FindClass("CrusaderMissile")); + P_SpawnMissileZAimed (self, self->Z() + 40*FRACUNIT, self->target, PClass::FindClass("CrusaderMissile")); self->angle += ANGLE_45/16; - P_SpawnMissileZAimed (self, self->z + 40*FRACUNIT, self->target, PClass::FindClass("CrusaderMissile")); + P_SpawnMissileZAimed (self, self->Z() + 40*FRACUNIT, self->target, PClass::FindClass("CrusaderMissile")); self->angle -= ANGLE_45/16; self->reactiontime += 15; } @@ -49,7 +49,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CrusaderChoose) DEFINE_ACTION_FUNCTION(AActor, A_CrusaderSweepLeft) { self->angle += ANGLE_90/16; - AActor *misl = P_SpawnMissileZAimed (self, self->z + 48*FRACUNIT, self->target, PClass::FindClass("FastFlameMissile")); + AActor *misl = P_SpawnMissileZAimed (self, self->Z() + 48*FRACUNIT, self->target, PClass::FindClass("FastFlameMissile")); if (misl != NULL) { misl->velz += FRACUNIT; @@ -59,7 +59,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CrusaderSweepLeft) DEFINE_ACTION_FUNCTION(AActor, A_CrusaderSweepRight) { self->angle -= ANGLE_90/16; - AActor *misl = P_SpawnMissileZAimed (self, self->z + 48*FRACUNIT, self->target, PClass::FindClass("FastFlameMissile")); + AActor *misl = P_SpawnMissileZAimed (self, self->Z() + 48*FRACUNIT, self->target, PClass::FindClass("FastFlameMissile")); if (misl != NULL) { misl->velz += FRACUNIT; diff --git a/src/g_strife/a_entityboss.cpp b/src/g_strife/a_entityboss.cpp index fafb3b862..04b586b67 100644 --- a/src/g_strife/a_entityboss.cpp +++ b/src/g_strife/a_entityboss.cpp @@ -24,7 +24,7 @@ void A_SpectralMissile (AActor *self, const char *missilename) { if (self->target != NULL) { - AActor *missile = P_SpawnMissileXYZ (self->x, self->y, self->z + 32*FRACUNIT, + AActor *missile = P_SpawnMissileXYZ (self->PosPlusZ(32*FRACUNIT), self, self->target, PClass::FindClass(missilename), false); if (missile != NULL) { @@ -70,7 +70,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_EntityAttack) DEFINE_ACTION_FUNCTION(AActor, A_SpawnEntity) { - AActor *entity = Spawn("EntityBoss", self->x, self->y, self->z + 70*FRACUNIT, ALLOW_REPLACE); + AActor *entity = Spawn("EntityBoss", self->PosPlusZ(70*FRACUNIT), ALLOW_REPLACE); if (entity != NULL) { entity->angle = self->angle; @@ -89,13 +89,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_EntityDeath) AActor *spot = self->tracer; if (spot == NULL) spot = self; - fixed_t SpawnX = spot->x; - fixed_t SpawnY = spot->y; - fixed_t SpawnZ = spot->z + (self->tracer? 70*FRACUNIT : 0); + fixedvec3 pos = spot->Vec3Angle(secondRadius, self->angle, self->tracer? 70*FRACUNIT : 0); an = self->angle >> ANGLETOFINESHIFT; - second = Spawn("EntitySecond", SpawnX + FixedMul (secondRadius, finecosine[an]), - SpawnY + FixedMul (secondRadius, finesine[an]), SpawnZ, ALLOW_REPLACE); + second = Spawn("EntitySecond", pos, ALLOW_REPLACE); second->CopyFriendliness(self, true); //second->target = self->target; A_FaceTarget (second); @@ -103,18 +100,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_EntityDeath) second->velx += FixedMul (finecosine[an], 320000); second->vely += FixedMul (finesine[an], 320000); + pos = spot->Vec3Angle(secondRadius, self->angle + ANGLE_90, self->tracer? 70*FRACUNIT : 0); an = (self->angle + ANGLE_90) >> ANGLETOFINESHIFT; - second = Spawn("EntitySecond", SpawnX + FixedMul (secondRadius, finecosine[an]), - SpawnY + FixedMul (secondRadius, finesine[an]), SpawnZ, ALLOW_REPLACE); + second = Spawn("EntitySecond", pos, ALLOW_REPLACE); second->CopyFriendliness(self, true); //second->target = self->target; second->velx = FixedMul (secondRadius, finecosine[an]) << 2; second->vely = FixedMul (secondRadius, finesine[an]) << 2; A_FaceTarget (second); + pos = spot->Vec3Angle(secondRadius, self->angle - ANGLE_90, self->tracer? 70*FRACUNIT : 0); an = (self->angle - ANGLE_90) >> ANGLETOFINESHIFT; - second = Spawn("EntitySecond", SpawnX + FixedMul (secondRadius, finecosine[an]), - SpawnY + FixedMul (secondRadius, finesine[an]), SpawnZ, ALLOW_REPLACE); + second = Spawn("EntitySecond", pos, ALLOW_REPLACE); second->CopyFriendliness(self, true); //second->target = self->target; second->velx = FixedMul (secondRadius, finecosine[an]) << 2; diff --git a/src/g_strife/a_inquisitor.cpp b/src/g_strife/a_inquisitor.cpp index 70ca805f8..b93933422 100644 --- a/src/g_strife/a_inquisitor.cpp +++ b/src/g_strife/a_inquisitor.cpp @@ -20,7 +20,7 @@ bool InquisitorCheckDistance (AActor *self) { if (self->reactiontime == 0 && P_CheckSight (self, self->target)) { - return P_AproxDistance (self->x - self->target->x, self->y - self->target->y) < 264*FRACUNIT; + return self->AproxDistance (self->target) < 264*FRACUNIT; } return false; } @@ -35,9 +35,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_InquisitorDecide) { self->SetState (self->FindState("Grenade")); } - if (self->target->z != self->z) + if (self->target->Z() != self->Z()) { - if (self->z + self->height + 54*FRACUNIT < self->ceilingz) + if (self->Top() + 54*FRACUNIT < self->ceilingz) { self->SetState (self->FindState("Jump")); } @@ -53,20 +53,20 @@ DEFINE_ACTION_FUNCTION(AActor, A_InquisitorAttack) A_FaceTarget (self); - self->z += 32*FRACUNIT; + self->AddZ(32*FRACUNIT); self->angle -= ANGLE_45/32; - proj = P_SpawnMissileZAimed (self, self->z, self->target, PClass::FindClass("InquisitorShot")); + proj = P_SpawnMissileZAimed (self, self->Z(), self->target, PClass::FindClass("InquisitorShot")); if (proj != NULL) { proj->velz += 9*FRACUNIT; } self->angle += ANGLE_45/16; - proj = P_SpawnMissileZAimed (self, self->z, self->target, PClass::FindClass("InquisitorShot")); + proj = P_SpawnMissileZAimed (self, self->Z(), self->target, PClass::FindClass("InquisitorShot")); if (proj != NULL) { proj->velz += 16*FRACUNIT; } - self->z -= 32*FRACUNIT; + self->AddZ(-32*FRACUNIT); } DEFINE_ACTION_FUNCTION(AActor, A_InquisitorJump) @@ -79,19 +79,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_InquisitorJump) return; S_Sound (self, CHAN_ITEM|CHAN_LOOP, "inquisitor/jump", 1, ATTN_NORM); - self->z += 64*FRACUNIT; + self->AddZ(64*FRACUNIT); A_FaceTarget (self); an = self->angle >> ANGLETOFINESHIFT; speed = self->Speed * 2/3; self->velx += FixedMul (speed, finecosine[an]); self->vely += FixedMul (speed, finesine[an]); - dist = P_AproxDistance (self->target->x - self->x, self->target->y - self->y); + dist = self->AproxDistance (self->target); dist /= speed; if (dist < 1) { dist = 1; } - self->velz = (self->target->z - self->z) / dist; + self->velz = (self->target->Z() - self->Z()) / dist; self->reactiontime = 60; self->flags |= MF_NOGRAVITY; } @@ -102,7 +102,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_InquisitorCheckLand) if (self->reactiontime < 0 || self->velx == 0 || self->vely == 0 || - self->z <= self->floorz) + self->Z() <= self->floorz) { self->SetState (self->SeeState); self->reactiontime = 0; @@ -119,7 +119,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_InquisitorCheckLand) DEFINE_ACTION_FUNCTION(AActor, A_TossArm) { - AActor *foo = Spawn("InquisitorArm", self->x, self->y, self->z + 24*FRACUNIT, ALLOW_REPLACE); + AActor *foo = Spawn("InquisitorArm", self->PosPlusZ(24*FRACUNIT), ALLOW_REPLACE); foo->angle = self->angle - ANGLE_90 + (pr_inq.Random2() << 22); foo->velx = FixedMul (foo->Speed, finecosine[foo->angle >> ANGLETOFINESHIFT]) >> 3; foo->vely = FixedMul (foo->Speed, finesine[foo->angle >> ANGLETOFINESHIFT]) >> 3; diff --git a/src/g_strife/a_loremaster.cpp b/src/g_strife/a_loremaster.cpp index d984bbdd3..1b12c2436 100644 --- a/src/g_strife/a_loremaster.cpp +++ b/src/g_strife/a_loremaster.cpp @@ -21,16 +21,14 @@ IMPLEMENT_CLASS (ALoreShot) int ALoreShot::DoSpecialDamage (AActor *victim, int damage, FName damagetype) { - FVector3 thrust; if (victim != NULL && target != NULL && !(victim->flags7 & MF7_DONTTHRUST)) { - thrust.X = float(target->x - victim->x); - thrust.Y = float(target->y - victim->y); - thrust.Z = float(target->z - victim->z); - + fixedvec3 fixthrust = victim->Vec3To(target); + TVector3 thrust(fixthrust.x, fixthrust.y, fixthrust.z); + thrust.MakeUnit(); - thrust *= float((255*50*FRACUNIT) / (victim->Mass ? victim->Mass : 1)); + thrust *= double((255*50*FRACUNIT) / (victim->Mass ? victim->Mass : 1)); victim->velx += fixed_t(thrust.X); victim->vely += fixed_t(thrust.Y); @@ -42,7 +40,7 @@ int ALoreShot::DoSpecialDamage (AActor *victim, int damage, FName damagetype) DEFINE_ACTION_FUNCTION(AActor, A_LoremasterChain) { S_Sound (self, CHAN_BODY, "loremaster/active", 1, ATTN_NORM); - Spawn("LoreShot2", self->x, self->y, self->z, ALLOW_REPLACE); - Spawn("LoreShot2", self->x - (self->velx >> 1), self->y - (self->vely >> 1), self->z - (self->velz >> 1), ALLOW_REPLACE); - Spawn("LoreShot2", self->x - self->velx, self->y - self->vely, self->z - self->velz, ALLOW_REPLACE); + Spawn("LoreShot2", self->Pos(), ALLOW_REPLACE); + Spawn("LoreShot2", self->Vec3Offset(-(self->velx >> 1), -(self->vely >> 1), -(self->velz >> 1)), ALLOW_REPLACE); + Spawn("LoreShot2", self->Vec3Offset(-self->velx, -self->vely, -self->velz), ALLOW_REPLACE); } diff --git a/src/g_strife/a_programmer.cpp b/src/g_strife/a_programmer.cpp index 78689468b..5835b3566 100644 --- a/src/g_strife/a_programmer.cpp +++ b/src/g_strife/a_programmer.cpp @@ -104,7 +104,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpotLightning) if (self->target == NULL) return; - spot = Spawn("SpectralLightningSpot", self->target->x, self->target->y, self->target->floorz, ALLOW_REPLACE); + spot = Spawn("SpectralLightningSpot", self->target->X(), self->target->Y(), self->target->floorz, ALLOW_REPLACE); if (spot != NULL) { spot->threshold = 25; @@ -122,7 +122,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpotLightning) DEFINE_ACTION_FUNCTION(AActor, A_SpawnProgrammerBase) { - AActor *foo = Spawn("ProgrammerBase", self->x, self->y, self->z + 24*FRACUNIT, ALLOW_REPLACE); + AActor *foo = Spawn("ProgrammerBase", self->PosPlusZ(24*FRACUNIT), ALLOW_REPLACE); if (foo != NULL) { foo->angle = self->angle + ANGLE_180 + (pr_prog.Random2() << 22); diff --git a/src/g_strife/a_rebels.cpp b/src/g_strife/a_rebels.cpp index 81490c361..6c8652f7c 100644 --- a/src/g_strife/a_rebels.cpp +++ b/src/g_strife/a_rebels.cpp @@ -75,8 +75,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_Beacon) AActor *rebel; angle_t an; - rebel = Spawn("Rebel1", self->x, self->y, self->floorz, ALLOW_REPLACE); - if (!P_TryMove (rebel, rebel->x, rebel->y, true)) + rebel = Spawn("Rebel1", self->X(), self->Y(), self->floorz, ALLOW_REPLACE); + if (!P_TryMove (rebel, rebel->X(), rebel->Y(), true)) { rebel->Destroy (); return; @@ -112,7 +112,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Beacon) rebel->SetState (rebel->SeeState); rebel->angle = self->angle; an = self->angle >> ANGLETOFINESHIFT; - Spawn (rebel->x + 20*finecosine[an], rebel->y + 20*finesine[an], rebel->z + TELEFOGHEIGHT, ALLOW_REPLACE); + Spawn (rebel->Vec3Offset(20*finecosine[an], 20*finesine[an], TELEFOGHEIGHT), ALLOW_REPLACE); if (--self->health < 0) { self->SetState(self->FindState(NAME_Death)); diff --git a/src/g_strife/a_sentinel.cpp b/src/g_strife/a_sentinel.cpp index 74f0e917f..550a89ff7 100644 --- a/src/g_strife/a_sentinel.cpp +++ b/src/g_strife/a_sentinel.cpp @@ -27,7 +27,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SentinelBob) { minz = maxz; } - if (minz < self->z) + if (minz < self->Z()) { self->velz -= FRACUNIT; } @@ -35,7 +35,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SentinelBob) { self->velz += FRACUNIT; } - self->reactiontime = (minz >= self->z) ? 4 : 0; + self->reactiontime = (minz >= self->Z()) ? 4 : 0; } DEFINE_ACTION_FUNCTION(AActor, A_SentinelAttack) @@ -48,16 +48,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_SentinelAttack) return; } - missile = P_SpawnMissileZAimed (self, self->z + 32*FRACUNIT, self->target, PClass::FindClass("SentinelFX2")); + missile = P_SpawnMissileZAimed (self, self->Z() + 32*FRACUNIT, self->target, PClass::FindClass("SentinelFX2")); if (missile != NULL && (missile->velx | missile->vely) != 0) { for (int i = 8; i > 1; --i) { trail = Spawn("SentinelFX1", - self->x + FixedMul (missile->radius * i, finecosine[missile->angle >> ANGLETOFINESHIFT]), - self->y + FixedMul (missile->radius * i, finesine[missile->angle >> ANGLETOFINESHIFT]), - missile->z + (missile->velz / 4 * i), ALLOW_REPLACE); + self->Vec3Angle(missile->radius*i, missile->angle, (missile->velz / 4 * i)), ALLOW_REPLACE); if (trail != NULL) { trail->target = self; @@ -67,7 +65,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SentinelAttack) P_CheckMissileSpawn (trail, self->radius); } } - missile->z += missile->velz >> 2; + missile->AddZ(missile->velz >> 2); } } diff --git a/src/g_strife/a_spectral.cpp b/src/g_strife/a_spectral.cpp index 6e2e6488e..51ed7b0d0 100644 --- a/src/g_strife/a_spectral.cpp +++ b/src/g_strife/a_spectral.cpp @@ -28,7 +28,7 @@ void ASpectralMonster::Touch (AActor *toucher) DEFINE_ACTION_FUNCTION(AActor, A_SpectralLightningTail) { - AActor *foo = Spawn("SpectralLightningHTail", self->x - self->velx, self->y - self->vely, self->z, ALLOW_REPLACE); + AActor *foo = Spawn("SpectralLightningHTail", self->Vec3Offset(-self->velx, -self->vely, 0), ALLOW_REPLACE); foo->angle = self->angle; foo->FriendPlayer = self->FriendPlayer; @@ -53,7 +53,6 @@ static FRandom pr_zap5 ("Zap5"); DEFINE_ACTION_FUNCTION(AActor, A_SpectralLightning) { AActor *flash; - fixed_t x, y; if (self->threshold != 0) --self->threshold; @@ -61,17 +60,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpectralLightning) self->velx += pr_zap5.Random2(3) << FRACBITS; self->vely += pr_zap5.Random2(3) << FRACBITS; - x = self->x + pr_zap5.Random2(3) * FRACUNIT * 50; - y = self->y + pr_zap5.Random2(3) * FRACUNIT * 50; + fixedvec2 pos = self->Vec2Offset( + pr_zap5.Random2(3) * FRACUNIT * 50, + pr_zap5.Random2(3) * FRACUNIT * 50); flash = Spawn (self->threshold > 25 ? PClass::FindClass(NAME_SpectralLightningV2) : - PClass::FindClass(NAME_SpectralLightningV1), x, y, ONCEILINGZ, ALLOW_REPLACE); + PClass::FindClass(NAME_SpectralLightningV1), pos.x, pos.y, ONCEILINGZ, ALLOW_REPLACE); flash->target = self->target; flash->velz = -18*FRACUNIT; flash->FriendPlayer = self->FriendPlayer; - flash = Spawn(NAME_SpectralLightningV2, self->x, self->y, ONCEILINGZ, ALLOW_REPLACE); + flash = Spawn(NAME_SpectralLightningV2, self->X(), self->Y(), ONCEILINGZ, ALLOW_REPLACE); flash->target = self->target; flash->velz = -18*FRACUNIT; @@ -95,7 +95,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer2) return; // change angle - exact = R_PointToAngle2 (self->x, self->y, dest->x, dest->y); + exact = self->AngleTo(dest); if (exact != self->angle) { @@ -120,8 +120,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer2) if (!(self->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER))) { // change slope - dist = P_AproxDistance (dest->x - self->x, dest->y - self->y); - dist /= self->Speed; + dist = self->AproxDistance (dest) / self->Speed; if (dist < 1) { @@ -129,11 +128,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer2) } if (dest->height >= 56*FRACUNIT) { - slope = (dest->z+40*FRACUNIT - self->z) / dist; + slope = (dest->Z()+40*FRACUNIT - self->Z()) / dist; } else { - slope = (dest->z + self->height*2/3 - self->z) / dist; + slope = (dest->Z() + self->height*2/3 - self->Z()) / dist; } if (slope < self->velz) { diff --git a/src/g_strife/a_stalker.cpp b/src/g_strife/a_stalker.cpp index 258cbef3f..6a06bf867 100644 --- a/src/g_strife/a_stalker.cpp +++ b/src/g_strife/a_stalker.cpp @@ -17,7 +17,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_StalkerChaseDecide) { self->SetState (self->FindState("SeeFloor")); } - else if (self->ceilingz - self->height > self->z) + else if (self->ceilingz > self->Top()) { self->SetState (self->FindState("Drop")); } diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index 1edea19fa..3145290ef 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -580,7 +580,7 @@ IMPLEMENT_CLASS (AMeat) DEFINE_ACTION_FUNCTION(AActor, A_TossGib) { const char *gibtype = (self->flags & MF_NOBLOOD) ? "Junk" : "Meat"; - AActor *gib = Spawn (gibtype, self->x, self->y, self->z + 24*FRACUNIT, ALLOW_REPLACE); + AActor *gib = Spawn (gibtype, self->PosPlusZ(24*FRACUNIT), ALLOW_REPLACE); angle_t an; int speed; @@ -628,13 +628,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain) { sector_t *sec = self->Sector; - if (self->z == sec->floorplane.ZatPoint (self->x, self->y)) + if (self->Z() == sec->floorplane.ZatPoint(self)) { - if ((sec->special & 0xFF) == Damage_InstantDeath) + if (sec->special == Damage_InstantDeath) { - P_DamageMobj (self, NULL, NULL, 999, NAME_None); + P_DamageMobj (self, NULL, NULL, 999, NAME_InstantDeath); } - else if ((sec->special & 0xFF) == Scroll_StrifeCurrent) + else if (sec->special == Scroll_StrifeCurrent) { int anglespeed = tagManager.GetFirstSectorTag(sec) - 100; fixed_t speed = (anglespeed % 10) << (FRACBITS - 4); @@ -681,7 +681,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ItBurnsItBurns) DEFINE_ACTION_FUNCTION(AActor, A_DropFire) { - AActor *drop = Spawn("FireDroplet", self->x, self->y, self->z + 24*FRACUNIT, ALLOW_REPLACE); + AActor *drop = Spawn("FireDroplet", self->PosPlusZ(24*FRACUNIT), ALLOW_REPLACE); drop->velz = -FRACUNIT; P_RadiusAttack (self, self, 64, 64, NAME_Fire, 0); } diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp index a41058492..a33521087 100644 --- a/src/g_strife/a_strifeweapons.cpp +++ b/src/g_strife/a_strifeweapons.cpp @@ -118,10 +118,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_JabDagger) S_Sound (self, CHAN_WEAPON, linetarget->flags & MF_NOBLOOD ? "misc/metalhit" : "misc/meathit", 1, ATTN_NORM); - self->angle = R_PointToAngle2 (self->x, - self->y, - linetarget->x, - linetarget->y); + self->angle = self->AngleTo(linetarget); self->flags |= MF_JUSTATTACKED; P_DaggerAlert (self, linetarget); } @@ -363,8 +360,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_RocketInFlight) AActor *trail; S_Sound (self, CHAN_VOICE, "misc/missileinflight", 1, ATTN_NORM); - P_SpawnPuff (self, PClass::FindClass("MiniMissilePuff"), self->x, self->y, self->z, self->angle - ANGLE_180, 2, PF_HITTHING); - trail = Spawn("RocketTrail", self->x - self->velx, self->y - self->vely, self->z, ALLOW_REPLACE); + P_SpawnPuff (self, PClass::FindClass("MiniMissilePuff"), self->Pos(), self->angle - ANGLE_180, 2, PF_HITTHING); + trail = Spawn("RocketTrail", self->Vec3Offset(-self->velx, -self->vely, 0), ALLOW_REPLACE); if (trail != NULL) { trail->velz = FRACUNIT; @@ -519,10 +516,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_MaulerTorpedoWave) self->angle += ANGLE_180; // If the torpedo hit the ceiling, it should still spawn the wave - savedz = self->z; - if (wavedef && self->ceilingz - self->z < wavedef->height) + savedz = self->Z(); + if (wavedef && self->ceilingz - self->Z() < wavedef->height) { - self->z = self->ceilingz - wavedef->height; + self->SetZ(self->ceilingz - wavedef->height); } for (int i = 0; i < 80; ++i) @@ -530,12 +527,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_MaulerTorpedoWave) self->angle += ANGLE_45/10; P_SpawnSubMissile (self, PClass::FindClass("MaulerTorpedoWave"), self->target); } - self->z = savedz; + self->SetZ(savedz); } AActor *P_SpawnSubMissile (AActor *source, const PClass *type, AActor *target) { - AActor *other = Spawn (type, source->x, source->y, source->z, ALLOW_REPLACE); + AActor *other = Spawn (type, source->Pos(), ALLOW_REPLACE); if (other == NULL) { @@ -622,20 +619,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_Burnination) yofs = -yofs; } - fixed_t x = self->x + (xofs << FRACBITS); - fixed_t y = self->y + (yofs << FRACBITS); - sector_t * sector = P_PointInSector(x, y); + fixedvec2 pos = self->Vec2Offset(xofs << FRACBITS, yofs << FRACBITS); + sector_t * sector = P_PointInSector(pos.x, pos.y); // The sector's floor is too high so spawn the flame elsewhere. - if (sector->floorplane.ZatPoint(x, y) > self->z + self->MaxStepHeight) + if (sector->floorplane.ZatPoint(pos.x, pos.y) > self->Z() + self->MaxStepHeight) { - x = self->x; - y = self->y; + pos.x = self->X(); + pos.y = self->Y(); } AActor *drop = Spawn ( - x, y, - self->z + 4*FRACUNIT, ALLOW_REPLACE); + pos.x, pos.y, + self->Z() + 4*FRACUNIT, ALLOW_REPLACE); if (drop != NULL) { drop->velx = self->velx + ((pr_phburn.Random2 (7)) << FRACBITS); @@ -680,9 +676,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireGrenade) if (grenadetype != NULL) { - self->z += 32*FRACUNIT; + self->AddZ(32*FRACUNIT); grenade = P_SpawnSubMissile (self, grenadetype, self); - self->z -= 32*FRACUNIT; + self->AddZ(-32*FRACUNIT); if (grenade == NULL) return; @@ -693,15 +689,20 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireGrenade) grenade->velz = FixedMul (finetangent[FINEANGLES/4-(self->pitch>>ANGLETOFINESHIFT)], grenade->Speed) + 8*FRACUNIT; + fixedvec2 offset; + an = self->angle >> ANGLETOFINESHIFT; tworadii = self->radius + grenade->radius; - grenade->x += FixedMul (finecosine[an], tworadii); - grenade->y += FixedMul (finesine[an], tworadii); + offset.x = FixedMul (finecosine[an], tworadii); + offset.y = FixedMul (finesine[an], tworadii); an = self->angle + Angle; an >>= ANGLETOFINESHIFT; - grenade->x += FixedMul (finecosine[an], 15*FRACUNIT); - grenade->y += FixedMul (finesine[an], 15*FRACUNIT); + offset.x += FixedMul (finecosine[an], 15*FRACUNIT); + offset.y += FixedMul (finesine[an], 15*FRACUNIT); + + fixedvec2 newpos = grenade->Vec2Offset(offset.x, offset.y); + grenade->SetOrigin(newpos.x, newpos.y, grenade->Z(), false); } } @@ -926,7 +927,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil1) P_BulletSlope (self, &linetarget); if (linetarget != NULL) { - spot = Spawn("SpectralLightningSpot", linetarget->x, linetarget->y, linetarget->floorz, ALLOW_REPLACE); + spot = Spawn("SpectralLightningSpot", linetarget->X(), linetarget->Y(), linetarget->floorz, ALLOW_REPLACE); if (spot != NULL) { spot->tracer = linetarget; @@ -934,7 +935,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil1) } else { - spot = Spawn("SpectralLightningSpot", self->x, self->y, self->z, ALLOW_REPLACE); + spot = Spawn("SpectralLightningSpot", self->Pos(), ALLOW_REPLACE); if (spot != NULL) { spot->velx += 28 * finecosine[self->angle >> ANGLETOFINESHIFT]; @@ -992,7 +993,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil3) spot = P_SpawnSubMissile (self, PClass::FindClass("SpectralLightningBall1"), self); if (spot != NULL) { - spot->z = self->z + 32*FRACUNIT; + spot->SetZ(self->Z() + 32*FRACUNIT); } } self->angle -= (ANGLE_180/20)*10; diff --git a/src/g_strife/a_thingstoblowup.cpp b/src/g_strife/a_thingstoblowup.cpp index d27260451..3e0efe525 100644 --- a/src/g_strife/a_thingstoblowup.cpp +++ b/src/g_strife/a_thingstoblowup.cpp @@ -18,12 +18,10 @@ extern const PClass *QuestItemClasses[31]; DEFINE_ACTION_FUNCTION(AActor, A_Bang4Cloud) { - fixed_t spawnx, spawny; + fixed_t xo = (pr_bang4cloud.Random2() & 3) * 10240; + fixed_t yo = (pr_bang4cloud.Random2() & 3) * 10240; - spawnx = self->x + (pr_bang4cloud.Random2() & 3) * 10240; - spawny = self->y + (pr_bang4cloud.Random2() & 3) * 10240; - - Spawn("Bang4Cloud", spawnx, spawny, self->z, ALLOW_REPLACE); + Spawn("Bang4Cloud", self->Vec3Offset(xo, yo, 0), ALLOW_REPLACE); } // ------------------------------------------------------------------- @@ -97,7 +95,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightGoesOut) for (int i = 0; i < 8; ++i) { - foo = Spawn("Rubble1", self->x, self->y, self->z, ALLOW_REPLACE); + foo = Spawn("Rubble1", self->Pos(), ALLOW_REPLACE); if (foo != NULL) { int t = pr_lightout() & 15; diff --git a/src/info.h b/src/info.h index bdbb69940..22e3b2f5c 100644 --- a/src/info.h +++ b/src/info.h @@ -283,7 +283,7 @@ struct FDoomEdEntry { const PClass *Type; short Special; - bool ArgsDefined; + signed char ArgsDefined; int Args[5]; }; diff --git a/src/intermission/intermission.cpp b/src/intermission/intermission.cpp index 2a52df58a..a19d0a479 100644 --- a/src/intermission/intermission.cpp +++ b/src/intermission/intermission.cpp @@ -329,6 +329,7 @@ void DIntermissionScreenText::Drawer () int c; const FRemapTable *range; const char *ch = mText; + const int kerning = SmallFont->GetDefaultKerning(); // Count number of rows in this text. Since it does not word-wrap, we just count // line feed characters. @@ -380,6 +381,7 @@ void DIntermissionScreenText::Drawer () } pic = SmallFont->GetChar (c, &w); + w += kerning; w *= CleanXfac; if (cx + w > SCREENWIDTH) continue; diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index ab9c0aee7..3bab8f7e5 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -580,7 +580,7 @@ void GiveSpawner (player_t *player, const PClass *type, int amount) } AInventory *item = static_cast - (Spawn (type, player->mo->x, player->mo->y, player->mo->z, NO_REPLACE)); + (Spawn (type, player->mo->X(), player->mo->Y(), player->mo->Z(), NO_REPLACE)); if (item != NULL) { if (amount > 0) diff --git a/src/m_random.h b/src/m_random.h index b5e21c63c..452ef41fc 100644 --- a/src/m_random.h +++ b/src/m_random.h @@ -57,7 +57,9 @@ public: // Returns a random number in the range [0,mod) int operator() (int mod) { - return GenRand32() % mod; + return (0 == mod) + ? 0 + : (GenRand32() % mod); } // Returns rand# - rand# diff --git a/src/menu/optionmenuitems.h b/src/menu/optionmenuitems.h index c63359f4b..0b0b57759 100644 --- a/src/menu/optionmenuitems.h +++ b/src/menu/optionmenuitems.h @@ -32,6 +32,7 @@ ** */ #include "v_text.h" +#include "gstrings.h" void M_DrawConText (int color, int x, int y, const char *str); @@ -199,6 +200,7 @@ public: { text = (*opt)->mValues[Selection].Text; } + if (*text == '$') text = GStrings(text + 1); screen->DrawText (SmallFont, OptionSettings.mFontColorValue, indent + CURSORSPACE, y, text, DTA_CleanNoMove_1, true, DTA_ColorOverlay, overlay, TAG_DONE); return indent; @@ -503,6 +505,7 @@ public: int Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected) { const char *txt = mCurrent? (const char*)mAltText : mLabel; + if (*txt == '$') txt = GStrings(txt + 1); int w = SmallFont->StringWidth(txt) * CleanXfac_1; int x = (screen->GetWidth() - w) / 2; screen->DrawText (SmallFont, mColor, x, y, txt, DTA_CleanNoMove_1, true, TAG_DONE); diff --git a/src/namedef.h b/src/namedef.h index 22dbe1b51..ae456883c 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -221,6 +221,10 @@ xx(Flash) xx(AltFlash) xx(Reload) xx(Zoom) +xx(User1) +xx(User2) +xx(User3) +xx(User4) // State names used by ASwitchableDecoration xx(Active) @@ -502,6 +506,14 @@ xx(floorplane_a) xx(floorplane_b) xx(floorplane_c) xx(floorplane_d) +xx(damageamount) +xx(damagetype) +xx(damageinterval) +xx(leakiness) +xx(damageterraineffect) +xx(damagehazard) +xx(floorterrain) +xx(ceilingterrain) // USDF keywords xx(Amount) diff --git a/src/nodebuild_utility.cpp b/src/nodebuild_utility.cpp index 14ab7be58..5eba8b7be 100644 --- a/src/nodebuild_utility.cpp +++ b/src/nodebuild_utility.cpp @@ -76,7 +76,8 @@ angle_t FNodeBuilder::PointToAngle (fixed_t x, fixed_t y) #else // !__APPLE__ || __llvm__ double ang = atan2 (double(y), double(x)); #endif // __APPLE__ && !__llvm__ - return angle_t(ang * rad2bam) << 1; + // Convert to signed first since negative double to unsigned is undefined. + return angle_t(int(ang * rad2bam)) << 1; } void FNodeBuilder::FindUsedVertices (vertex_t *oldverts, int max) diff --git a/src/oplsynth/mlopl_io.cpp b/src/oplsynth/mlopl_io.cpp index 691463470..4ec41d6c9 100644 --- a/src/oplsynth/mlopl_io.cpp +++ b/src/oplsynth/mlopl_io.cpp @@ -48,6 +48,7 @@ #define HALF_PI (PI*0.5) EXTERN_CVAR(Int, opl_core) +extern int current_opl_core; OPLio::~OPLio() { @@ -323,7 +324,7 @@ int OPLio::OPLinit(uint numchips, bool stereo, bool initopl3) { assert(numchips >= 1 && numchips <= countof(chips)); uint i; - IsOPL3 = (opl_core == 1 || opl_core == 2 || opl_core == 3); + IsOPL3 = (current_opl_core == 1 || current_opl_core == 2 || current_opl_core == 3); memset(chips, 0, sizeof(chips)); if (IsOPL3) @@ -332,7 +333,7 @@ int OPLio::OPLinit(uint numchips, bool stereo, bool initopl3) } for (i = 0; i < numchips; ++i) { - OPLEmul *chip = IsOPL3 ? (opl_core == 1 ? DBOPLCreate(stereo) : (opl_core == 2 ? JavaOPLCreate(stereo) : NukedOPL3Create(stereo))) : YM3812Create(stereo); + OPLEmul *chip = IsOPL3 ? (current_opl_core == 1 ? DBOPLCreate(stereo) : (current_opl_core == 2 ? JavaOPLCreate(stereo) : NukedOPL3Create(stereo))) : YM3812Create(stereo); if (chip == NULL) { break; diff --git a/src/oplsynth/music_opl_mididevice.cpp b/src/oplsynth/music_opl_mididevice.cpp index 79bb10226..aa6cda7ee 100644 --- a/src/oplsynth/music_opl_mididevice.cpp +++ b/src/oplsynth/music_opl_mididevice.cpp @@ -53,6 +53,7 @@ #endif // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- +void OPL_SetCore(const char *args); // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- @@ -76,8 +77,9 @@ CVAR(Bool, opl_fullpan, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); // //========================================================================== -OPLMIDIDevice::OPLMIDIDevice() +OPLMIDIDevice::OPLMIDIDevice(const char *args) { + OPL_SetCore(args); FullPan = opl_fullpan; FWadLump data = Wads.OpenLumpName("GENMIDI"); OPLloadBank(data); diff --git a/src/oplsynth/music_opldumper_mididevice.cpp b/src/oplsynth/music_opldumper_mididevice.cpp index 46dcdfef2..e6684e1a6 100644 --- a/src/oplsynth/music_opldumper_mididevice.cpp +++ b/src/oplsynth/music_opldumper_mididevice.cpp @@ -262,6 +262,7 @@ protected: //========================================================================== OPLDumperMIDIDevice::OPLDumperMIDIDevice(const char *filename) + : OPLMIDIDevice(NULL) { // Replace the standard OPL device with a disk writer. delete io; diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index 5b29959cb..e294dec69 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -331,23 +331,22 @@ void P_PlayerOnSpecial3DFloor(player_t* player) if(rover->flags & FF_SOLID) { // Player must be on top of the floor to be affected... - if(player->mo->z != rover->top.plane->ZatPoint(player->mo->x, player->mo->y)) continue; + if(player->mo->Z() != rover->top.plane->ZatPoint(player->mo)) continue; } else { //Water and DEATH FOG!!! heh - if (player->mo->z > rover->top.plane->ZatPoint(player->mo->x, player->mo->y) || - (player->mo->z + player->mo->height) < rover->bottom.plane->ZatPoint(player->mo->x, player->mo->y)) + if (player->mo->Z() > rover->top.plane->ZatPoint(player->mo) || + player->mo->Top() < rover->bottom.plane->ZatPoint(player->mo)) continue; } // Apply sector specials - if (rover->model->special || rover->model->damage) - P_PlayerInSpecialSector(player, rover->model); + P_PlayerInSpecialSector(player, rover->model); // Apply flat specials (using the ceiling!) P_PlayerOnSpecialFlat( - player, TerrainTypes[rover->model->GetTexture(rover->flags & FF_INVERTSECTOR? sector_t::floor : sector_t::ceiling)]); + player, rover->model->GetTerrain(rover->top.isceiling)); break; } @@ -373,7 +372,7 @@ bool P_CheckFor3DFloorHit(AActor * mo) if(rover->flags & FF_SOLID && rover->model->SecActTarget) { - if(mo->floorz == rover->top.plane->ZatPoint(mo->x, mo->y)) + if(mo->floorz == rover->top.plane->ZatPoint(mo)) { rover->model->SecActTarget->TriggerAction (mo, SECSPAC_HitFloor); return true; @@ -403,7 +402,7 @@ bool P_CheckFor3DCeilingHit(AActor * mo) if(rover->flags & FF_SOLID && rover->model->SecActTarget) { - if(mo->ceilingz == rover->bottom.plane->ZatPoint(mo->x, mo->y)) + if(mo->ceilingz == rover->bottom.plane->ZatPoint(mo)) { rover->model->SecActTarget->TriggerAction (mo, SECSPAC_HitCeiling); return true; @@ -749,7 +748,7 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li { fixed_t thingbot, thingtop; - thingbot = thing->z; + thingbot = thing->Z(); thingtop = thingbot + (thing->height==0? 1:thing->height); extsector_t::xfloor *xf[2] = {&linedef->frontsector->e->XFloor, &linedef->backsector->e->XFloor}; @@ -763,6 +762,7 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li linedef->frontsector->floorplane.ZatPoint(x, y), linedef->backsector->floorplane.ZatPoint(x, y) }; FTextureID highestfloorpic; + int highestfloorterrain = -1; FTextureID lowestceilingpic; highestfloorpic.SetInvalid(); @@ -789,12 +789,13 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li lowestceilingpic = *rover->bottom.texture; } - if(ff_top > highestfloor && delta1 < delta2 && (!restrict || thing->z >= ff_top)) + if(ff_top > highestfloor && delta1 < delta2 && (!restrict || thing->Z() >= ff_top)) { highestfloor = ff_top; highestfloorpic = *rover->top.texture; + highestfloorterrain = rover->model->GetTerrain(rover->top.isceiling); } - if(ff_top > lowestfloor[j] && ff_top <= thing->z + thing->MaxStepHeight) lowestfloor[j] = ff_top; + if(ff_top > lowestfloor[j] && ff_top <= thing->Z() + thing->MaxStepHeight) lowestfloor[j] = ff_top; } } @@ -802,6 +803,7 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li { open.bottom = highestfloor; open.floorpic = highestfloorpic; + open.floorterrain = highestfloorterrain; } if(lowestceiling < open.top) diff --git a/src/p_3dfloors.h b/src/p_3dfloors.h index 8abd23f03..0dfdf872c 100644 --- a/src/p_3dfloors.h +++ b/src/p_3dfloors.h @@ -144,6 +144,10 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li secplane_t P_FindFloorPlane(sector_t * sector, fixed_t x, fixed_t y, fixed_t z); int P_Find3DFloor(sector_t * sec, fixed_t x, fixed_t y, fixed_t z, bool above, bool floor, fixed_t &cmpz); +inline int P_Find3DFloor(sector_t * sec, const fixedvec3 &pos, bool above, bool floor, fixed_t &cmpz) +{ + return P_Find3DFloor(sec, pos.x, pos.y, pos.z, above, floor, cmpz); +} #endif \ No newline at end of file diff --git a/src/p_3dmidtex.cpp b/src/p_3dmidtex.cpp index 9a9492e08..3338956f3 100644 --- a/src/p_3dmidtex.cpp +++ b/src/p_3dmidtex.cpp @@ -37,6 +37,7 @@ #include "templates.h" #include "p_local.h" +#include "p_terrain.h" //============================================================================ @@ -275,7 +276,7 @@ bool P_LineOpening_3dMidtex(AActor *thing, const line_t *linedef, FLineOpening & open.abovemidtex = false; if (P_GetMidTexturePosition(linedef, 0, &tt, &tb)) { - if (thing->z + (thing->height/2) < (tt + tb)/2) + if (thing->Z() + (thing->height/2) < (tt + tb)/2) { if (tb < open.top) { @@ -285,14 +286,16 @@ bool P_LineOpening_3dMidtex(AActor *thing, const line_t *linedef, FLineOpening & } else { - if (tt > open.bottom && (!restrict || thing->z >= tt)) + if (tt > open.bottom && (!restrict || thing->Z() >= tt)) { open.bottom = tt; open.abovemidtex = true; open.floorpic = linedef->sidedef[0]->GetTexture(side_t::mid); + open.floorterrain = TerrainTypes[open.floorpic]; + } // returns true if it touches the midtexture - return (abs(thing->z - tt) <= thing->MaxStepHeight); + return (abs(thing->Z() - tt) <= thing->MaxStepHeight); } } return false; diff --git a/src/p_acs.cpp b/src/p_acs.cpp index bc0e74469..84ac11f76 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -75,6 +75,7 @@ #include "actorptrselect.h" #include "farchive.h" #include "decallib.h" +#include "p_terrain.h" #include "version.h" #include "p_effect.h" @@ -1265,7 +1266,7 @@ static int UseInventory (AActor *activator, const char *type) // //============================================================================ -static int CheckInventory (AActor *activator, const char *type) +static int CheckInventory (AActor *activator, const char *type, bool max) { if (activator == NULL || type == NULL) return 0; @@ -1276,11 +1277,26 @@ static int CheckInventory (AActor *activator, const char *type) } else if (stricmp (type, "Health") == 0) { + if (max) + { + if (activator->IsKindOf (RUNTIME_CLASS (APlayerPawn))) + return static_cast(activator)->MaxHealth; + else + return activator->SpawnHealth(); + } return activator->health; } const PClass *info = PClass::FindClass (type); AInventory *item = activator->FindInventory (info); + + if (max) + { + if (item) + return item->MaxAmount; + else + return ((AInventory *)GetDefaultByType (info))->MaxAmount; + } return item ? item->Amount : 0; } @@ -1939,11 +1955,14 @@ bool FBehavior::Init(int lumpnum, FileReader * fr, int len) int arraynum = MapVarStore[LittleLong(chunk[2])]; if ((unsigned)arraynum < (unsigned)NumArrays) { - int initsize = MIN (ArrayStore[arraynum].ArraySize, (LittleLong(chunk[1])-4)/4); + // Use unsigned iterator here to avoid issue with GCC 4.9/5.x + // optimizer. Might be some undefined behavior in this code, + // but I don't know what it is. + unsigned int initsize = MIN (ArrayStore[arraynum].ArraySize, (LittleLong(chunk[1])-4)/4); SDWORD *elems = ArrayStore[arraynum].Elements; - for (i = 0; i < initsize; ++i) + for (unsigned int j = 0; j < initsize; ++j) { - elems[i] = LittleLong(chunk[3+i]); + elems[j] = LittleLong(chunk[3+j]); } } chunk = (DWORD *)NextChunk((BYTE *)chunk); @@ -3423,12 +3442,12 @@ int DLevelScript::DoSpawnSpot (int type, int spot, int tid, int angle, bool forc while ( (aspot = iterator.Next ()) ) { - spawned += DoSpawn (type, aspot->x, aspot->y, aspot->z, tid, angle, force); + spawned += DoSpawn (type, aspot->X(), aspot->Y(), aspot->Z(), tid, angle, force); } } else if (activator != NULL) { - spawned += DoSpawn (type, activator->x, activator->y, activator->z, tid, angle, force); + spawned += DoSpawn (type, activator->X(), activator->Y(), activator->Z(), tid, angle, force); } return spawned; } @@ -3444,12 +3463,12 @@ int DLevelScript::DoSpawnSpotFacing (int type, int spot, int tid, bool force) while ( (aspot = iterator.Next ()) ) { - spawned += DoSpawn (type, aspot->x, aspot->y, aspot->z, tid, aspot->angle >> 24, force); + spawned += DoSpawn (type, aspot->X(), aspot->Y(), aspot->Z(), tid, aspot->angle >> 24, force); } } else if (activator != NULL) { - spawned += DoSpawn (type, activator->x, activator->y, activator->z, tid, activator->angle >> 24, force); + spawned += DoSpawn (type, activator->X(), activator->Y(), activator->Z(), tid, activator->angle >> 24, force); } return spawned; } @@ -4127,7 +4146,7 @@ bool DLevelScript::DoCheckActorTexture(int tid, AActor *activator, int string, b F3DFloor *ff = sec->e->XFloor.ffloors[i]; if ((ff->flags & (FF_EXISTS | FF_SOLID)) == (FF_EXISTS | FF_SOLID) && - actor->z >= ff->top.plane->ZatPoint(actor->x, actor->y)) + actor->Z() >= ff->top.plane->ZatPoint(actor)) { // This floor is beneath our feet. secpic = *ff->top.texture; break; @@ -4140,14 +4159,14 @@ bool DLevelScript::DoCheckActorTexture(int tid, AActor *activator, int string, b } else { - fixed_t z = actor->z + actor->height; + fixed_t z = actor->Top(); // Looking through planes from bottom to top for (i = numff-1; i >= 0; --i) { F3DFloor *ff = sec->e->XFloor.ffloors[i]; if ((ff->flags & (FF_EXISTS | FF_SOLID)) == (FF_EXISTS | FF_SOLID) && - z <= ff->bottom.plane->ZatPoint(actor->x, actor->y)) + z <= ff->bottom.plane->ZatPoint(actor)) { // This floor is above our eyes. secpic = *ff->bottom.texture; break; @@ -4442,8 +4461,11 @@ enum EACSFunctions ACSF_ChangeActorRoll, ACSF_GetActorRoll, ACSF_QuakeEx, - ACSF_Warp, - ACSF_SpawnParticle, // 93 + ACSF_Warp, // 92 + ACSF_GetMaxInventory, + ACSF_SetSectorDamage, + ACSF_SetSectorTerrain, + ACSF_SpawnParticle, /* Zandronum's - these must be skipped when we reach 99! -100:ResetMap(0), @@ -4708,8 +4730,8 @@ static bool DoSpawnDecal(AActor *actor, const FDecalTemplate *tpl, int flags, an { angle += actor->angle; } - return NULL != ShootDecal(tpl, actor, actor->Sector, actor->x, actor->y, - actor->z + (actor->height>>1) - actor->floorclip + actor->GetBobOffset() + zofs, + return NULL != ShootDecal(tpl, actor, actor->Sector, actor->X(), actor->Y(), + actor->Z() + (actor->height>>1) - actor->floorclip + actor->GetBobOffset() + zofs, angle, distance, !!(flags & SDF_PERMANENT)); } @@ -5383,6 +5405,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const FName damagetype = argCount > 5 && args[5]? FName(FBehavior::StaticLookupString(args[5])) : NAME_None; fixed_t range = argCount > 6 && args[6]? args[6] : MISSILERANGE; int flags = argCount > 7 && args[7]? args[7] : 0; + int pufftid = argCount > 8 && args[8]? args[8] : 0; int fhflags = 0; if (flags & FHF_NORANDOMPUFFZ) fhflags |= LAF_NORANDOMPUFFZ; @@ -5390,7 +5413,12 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const if (args[0] == 0) { - P_LineAttack(activator, angle, range, pitch, damage, damagetype, pufftype, fhflags); + AActor *puff = P_LineAttack(activator, angle, range, pitch, damage, damagetype, pufftype, fhflags); + if (puff != NULL && pufftid != 0) + { + puff->tid = pufftid; + puff->AddToHash(); + } } else { @@ -5399,7 +5427,12 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const while ((source = it.Next()) != NULL) { - P_LineAttack(source, angle, range, pitch, damage, damagetype, pufftype, fhflags); + AActor *puff = P_LineAttack(source, angle, range, pitch, damage, damagetype, pufftype, fhflags); + if (puff != NULL && pufftid != 0) + { + puff->tid = pufftid; + puff->AddToHash(); + } } } } @@ -5917,7 +5950,47 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) } return false; } + case ACSF_GetMaxInventory: + actor = SingleActorFromTID(args[0], activator); + if (actor != NULL) + { + return CheckInventory(actor, FBehavior::StaticLookupString(args[1]), true); + } + break; + case ACSF_SetSectorDamage: + if (argCount >= 2) + { + FSectorTagIterator it(args[0]); + int s; + while ((s = it.Next()) >= 0) + { + sector_t *sec = §ors[s]; + + sec->damageamount = args[1]; + sec->damagetype = argCount >= 3 ? FName(FBehavior::StaticLookupString(args[2])) : FName(NAME_None); + sec->damageinterval = argCount >= 4 ? clamp(args[3], 1, INT_MAX) : 32; + sec->leakydamage = argCount >= 5 ? args[4] : 0; + } + } + break; + + case ACSF_SetSectorTerrain: + if (argCount >= 3) + { + if (args[1] == sector_t::floor || args[1] == sector_t::ceiling) + { + int terrain = P_FindTerrain(FBehavior::StaticLookupString(args[2])); + FSectorTagIterator it(args[0]); + int s; + while ((s = it.Next()) >= 0) + { + sectors[s].terrainnum[args[1]] = terrain; + } + } + } + break; + case ACSF_SpawnParticle: { fixed_t x = args[0]; @@ -5945,7 +6018,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) P_SpawnParticle(x, y, z, xvel, yvel, zvel, color, fullbright, startalpha, lifetime, size, fadestep, accelx, accely, accelz); } break; - + default: break; } @@ -8369,17 +8442,17 @@ scriptwait: break; case PCD_CHECKINVENTORY: - STACK(1) = CheckInventory (activator, FBehavior::StaticLookupString (STACK(1))); + STACK(1) = CheckInventory (activator, FBehavior::StaticLookupString (STACK(1)), false); break; case PCD_CHECKACTORINVENTORY: STACK(2) = CheckInventory (SingleActorFromTID(STACK(2), NULL), - FBehavior::StaticLookupString (STACK(1))); + FBehavior::StaticLookupString (STACK(1)), false); sp--; break; case PCD_CHECKINVENTORYDIRECT: - PushToStack (CheckInventory (activator, FBehavior::StaticLookupString (TAGSTR(uallong(pc[0]))))); + PushToStack (CheckInventory (activator, FBehavior::StaticLookupString (TAGSTR(uallong(pc[0]))), false)); pc += 1; break; @@ -8555,11 +8628,11 @@ scriptwait: } else if (pcd == PCD_GETACTORZ) { - STACK(1) = actor->z + actor->GetBobOffset(); + STACK(1) = actor->Z() + actor->GetBobOffset(); } else { - STACK(1) = (&actor->x)[pcd - PCD_GETACTORX]; + STACK(1) = pcd == PCD_GETACTORX ? actor->X() : pcd == PCD_GETACTORY ? actor->Y() : actor->Z(); } } break; diff --git a/src/p_buildmap.cpp b/src/p_buildmap.cpp index 670f53751..d9074310d 100644 --- a/src/p_buildmap.cpp +++ b/src/p_buildmap.cpp @@ -443,6 +443,7 @@ static void LoadSectors (sectortype *bsec) sec->movefactor = ORIG_FRICTION_FACTOR; sec->ColorMap = map; sec->ZoneNumber = 0xFFFF; + sec->terrainnum[sector_t::ceiling] = sec->terrainnum[sector_t::floor] = -1; if (bsec->floorstat & 4) { diff --git a/src/p_ceiling.cpp b/src/p_ceiling.cpp index 7efef80a5..3203cf777 100644 --- a/src/p_ceiling.cpp +++ b/src/p_ceiling.cpp @@ -90,6 +90,7 @@ void DCeiling::Serialize (FArchive &arc) void DCeiling::PlayCeilingSound () { + if (m_Sector->Flags & SECF_SILENTMOVE) return; if (m_Sector->seqType >= 0) { SN_StartSequence (m_Sector, CHAN_CEILING, m_Sector->seqType, SEQ_PLATFORM, 0, false); @@ -142,7 +143,7 @@ void DCeiling::Tick () // movers with texture change, change the texture then get removed case genCeilingChgT: case genCeilingChg0: - m_Sector->special = m_NewSpecial; + m_Sector->SetSpecial(&m_NewSpecial); // fall through case genCeilingChg: m_Sector->SetTexture(sector_t::ceiling, m_Texture); @@ -175,7 +176,7 @@ void DCeiling::Tick () // then remove the active ceiling case genCeilingChgT: case genCeilingChg0: - m_Sector->special = m_NewSpecial; + m_Sector->SetSpecial(&m_NewSpecial); // fall through case genCeilingChg: m_Sector->SetTexture(sector_t::ceiling, m_Texture); @@ -435,11 +436,11 @@ DCeiling *DCeiling::Create(sector_t *sec, DCeiling::ECeiling type, line_t *line, switch (change & 3) { case 1: // type is zeroed - ceiling->m_NewSpecial = 0; + ceiling->m_NewSpecial.Clear(); ceiling->m_Type = genCeilingChg0; break; case 2: // type is copied - ceiling->m_NewSpecial = sec->special; + sec->GetSpecial(&ceiling->m_NewSpecial); ceiling->m_Type = genCeilingChgT; break; case 3: // type is left alone @@ -454,11 +455,11 @@ DCeiling *DCeiling::Create(sector_t *sec, DCeiling::ECeiling type, line_t *line, switch (change & 3) { case 1: // type is zeroed - ceiling->m_NewSpecial = 0; + ceiling->m_NewSpecial.Clear(); ceiling->m_Type = genCeilingChg0; break; case 2: // type is copied - ceiling->m_NewSpecial = line->frontsector->special; + line->frontsector->GetSpecial(&ceiling->m_NewSpecial); ceiling->m_Type = genCeilingChgT; break; case 3: // type is left alone diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 069fca6e1..a74b9bd18 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -1117,7 +1117,7 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang if (facetalker) { A_FaceTarget (npc); - pc->angle = R_PointToAngle2 (pc->x, pc->y, npc->x, npc->y); + pc->angle = pc->AngleTo(npc); } if ((npc->flags & MF_FRIENDLY) || (npc->flags4 & MF4_NOHATEPLAYERS)) { @@ -1345,9 +1345,12 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply if (reply->NextNode != 0) { int rootnode = npc->ConversationRoot; - if (reply->NextNode < 0) + unsigned next = (unsigned)(rootnode + (reply->NextNode < 0 ? -1 : 1) * reply->NextNode - 1); + + if (next < StrifeDialogues.Size()) { - npc->Conversation = StrifeDialogues[rootnode - reply->NextNode - 1]; + npc->Conversation = StrifeDialogues[next]; + if (gameaction != ga_slideshow) { P_StartConversation (npc, player->mo, player->ConversationFaceTalker, false); @@ -1358,10 +1361,6 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply S_StopSound (npc, CHAN_VOICE); } } - else - { - npc->Conversation = StrifeDialogues[rootnode + reply->NextNode - 1]; - } } npc->angle = player->ConversationNPCAngle; diff --git a/src/p_doors.cpp b/src/p_doors.cpp index 49ed20f46..bce324902 100644 --- a/src/p_doors.cpp +++ b/src/p_doors.cpp @@ -250,6 +250,8 @@ void DDoor::DoorSound(bool raise, DSeqNode *curseq) const choice = !raise; + if (m_Sector->Flags & SECF_SILENTMOVE) return; + if (m_Speed >= FRACUNIT*8) { choice += 2; @@ -511,8 +513,6 @@ void P_SpawnDoorCloseIn30 (sector_t *sec) fixed_t height; DDoor *door = new DDoor (sec); - sec->special = 0; - door->m_Sector = sec; door->m_Direction = 0; door->m_Type = DDoor::doorRaise; @@ -533,7 +533,6 @@ void P_SpawnDoorCloseIn30 (sector_t *sec) void P_SpawnDoorRaiseIn5Mins (sector_t *sec) { - sec->special = 0; new DDoor (sec, DDoor::doorRaiseIn5Mins, 2*FRACUNIT, TICRATE*30/7, 0); } diff --git a/src/p_effect.cpp b/src/p_effect.cpp index 59142a8cf..3ccfb67d2 100644 --- a/src/p_effect.cpp +++ b/src/p_effect.cpp @@ -381,9 +381,10 @@ static void MakeFountain (AActor *actor, int color1, int color2) angle_t an = M_Random()<<(24-ANGLETOFINESHIFT); fixed_t out = FixedMul (actor->radius, M_Random()<<8); - particle->x = actor->x + FixedMul (out, finecosine[an]); - particle->y = actor->y + FixedMul (out, finesine[an]); - particle->z = actor->z + actor->height + FRACUNIT; + fixedvec3 pos = actor->Vec3Offset(FixedMul(out, finecosine[an]), FixedMul(out, finesine[an]), actor->height + FRACUNIT); + particle->x = pos.x; + particle->y = pos.y; + particle->z = pos.z; if (out < actor->radius/8) particle->velz += FRACUNIT*10/3; else @@ -420,9 +421,10 @@ void P_RunEffect (AActor *actor, int effects) { // Rocket trail - fixed_t backx = actor->x - FixedMul (finecosine[(moveangle)>>ANGLETOFINESHIFT], actor->radius*2); - fixed_t backy = actor->y - FixedMul (finesine[(moveangle)>>ANGLETOFINESHIFT], actor->radius*2); - fixed_t backz = actor->z - (actor->height>>3) * (actor->velz>>16) + (2*actor->height)/3; + + fixed_t backx = - FixedMul (finecosine[(moveangle)>>ANGLETOFINESHIFT], actor->radius*2); + fixed_t backy = - FixedMul (finesine[(moveangle)>>ANGLETOFINESHIFT], actor->radius*2); + fixed_t backz = - (actor->height>>3) * (actor->velz>>16) + (2*actor->height)/3; angle_t an = (moveangle + ANG90) >> ANGLETOFINESHIFT; int speed; @@ -430,9 +432,13 @@ void P_RunEffect (AActor *actor, int effects) particle = JitterParticle (3 + (M_Random() & 31)); if (particle) { fixed_t pathdist = M_Random()<<8; - particle->x = backx - FixedMul(actor->velx, pathdist); - particle->y = backy - FixedMul(actor->vely, pathdist); - particle->z = backz - FixedMul(actor->velz, pathdist); + fixedvec3 pos = actor->Vec3Offset( + backx - FixedMul(actor->velx, pathdist), + backy - FixedMul(actor->vely, pathdist), + backz - FixedMul(actor->velz, pathdist)); + particle->x = pos.x; + particle->y = pos.y; + particle->z = pos.z; speed = (M_Random () - 128) * (FRACUNIT/200); particle->velx += FixedMul (speed, finecosine[an]); particle->vely += FixedMul (speed, finesine[an]); @@ -445,9 +451,13 @@ void P_RunEffect (AActor *actor, int effects) particle_t *particle = JitterParticle (3 + (M_Random() & 31)); if (particle) { fixed_t pathdist = M_Random()<<8; - particle->x = backx - FixedMul(actor->velx, pathdist); - particle->y = backy - FixedMul(actor->vely, pathdist); - particle->z = backz - FixedMul(actor->velz, pathdist) + (M_Random() << 10); + fixedvec3 pos = actor->Vec3Offset( + backx - FixedMul(actor->velx, pathdist), + backy - FixedMul(actor->vely, pathdist), + backz - FixedMul(actor->velz, pathdist) + (M_Random() << 10)); + particle->x = pos.x; + particle->y = pos.y; + particle->z = pos.z; speed = (M_Random () - 128) * (FRACUNIT/200); particle->velx += FixedMul (speed, finecosine[an]); particle->vely += FixedMul (speed, finesine[an]); @@ -466,10 +476,10 @@ void P_RunEffect (AActor *actor, int effects) { // Grenade trail - P_DrawSplash2 (6, - actor->x - FixedMul (finecosine[(moveangle)>>ANGLETOFINESHIFT], actor->radius*2), - actor->y - FixedMul (finesine[(moveangle)>>ANGLETOFINESHIFT], actor->radius*2), - actor->z - (actor->height>>3) * (actor->velz>>16) + (2*actor->height)/3, + fixedvec3 pos = actor->Vec3Angle(-actor->radius * 2, moveangle, + -(actor->height >> 3) * (actor->velz >> 16) + (2 * actor->height) / 3); + + P_DrawSplash2 (6, pos.x, pos.y, pos.z, moveangle + ANG180, 2, 2); } if (effects & FX_FOUNTAINMASK) @@ -501,10 +511,11 @@ void P_RunEffect (AActor *actor, int effects) if (particle != NULL) { angle_t ang = M_Random () << (32-ANGLETOFINESHIFT-8); - particle->x = actor->x + FixedMul (actor->radius, finecosine[ang]); - particle->y = actor->y + FixedMul (actor->radius, finesine[ang]); + fixedvec3 pos = actor->Vec3Offset(FixedMul (actor->radius, finecosine[ang]), FixedMul (actor->radius, finesine[ang]), 0); + particle->x = pos.x; + particle->y = pos.y; + particle->z = pos.z; particle->color = *protectColors[M_Random() & 1]; - particle->z = actor->z; particle->velz = FRACUNIT; particle->accz = M_Random () << 7; particle->size = 1; @@ -644,8 +655,8 @@ void P_DrawRailTrail(AActor *source, const TVector3 &start, const TVecto double r; double dirz; - if (abs(mo->x - FLOAT2FIXED(start.X)) < 20 * FRACUNIT - && (mo->y - FLOAT2FIXED(start.Y)) < 20 * FRACUNIT) + if (abs(mo->X() - FLOAT2FIXED(start.X)) < 20 * FRACUNIT + && (mo->Y() - FLOAT2FIXED(start.Y)) < 20 * FRACUNIT) { // This player (probably) fired the railgun S_Sound (mo, CHAN_WEAPON, sound, 1, ATTN_NORM); } @@ -655,7 +666,7 @@ void P_DrawRailTrail(AActor *source, const TVector3 &start, const TVecto // Only consider sound in 2D (for now, anyway) // [BB] You have to divide by lengthsquared here, not multiply with it. - r = ((start.Y - FIXED2DBL(mo->y)) * (-dir.Y) - (start.X - FIXED2DBL(mo->x)) * (dir.X)) / lengthsquared; + r = ((start.Y - FIXED2DBL(mo->Y())) * (-dir.Y) - (start.X - FIXED2DBL(mo->X())) * (dir.X)) / lengthsquared; r = clamp(r, 0., 1.); dirz = dir.Z; @@ -857,9 +868,14 @@ void P_DisconnectEffect (AActor *actor) if (!p) break; - p->x = actor->x + ((M_Random()-128)<<9) * (actor->radius>>FRACBITS); - p->y = actor->y + ((M_Random()-128)<<9) * (actor->radius>>FRACBITS); - p->z = actor->z + (M_Random()<<8) * (actor->height>>FRACBITS); + + fixed_t xo = ((M_Random() - 128) << 9) * (actor->radius >> FRACBITS); + fixed_t yo = ((M_Random() - 128) << 9) * (actor->radius >> FRACBITS); + fixed_t zo = (M_Random() << 8) * (actor->height >> FRACBITS); + fixedvec3 pos = actor->Vec3Offset(xo, yo, zo); + p->x = pos.x; + p->y = pos.y; + p->z = pos.z; p->accz -= FRACUNIT/4096; p->color = M_Random() < 128 ? maroon1 : maroon2; p->size = 4; diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 5291101a5..90a7a5f5c 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -138,7 +138,7 @@ void P_RecursiveSound (sector_t *sec, AActor *soundtarget, bool splash, int soun for (actor = sec->thinglist; actor != NULL; actor = actor->snext) { if (actor != soundtarget && (!splash || !(actor->flags4 & MF4_NOSPLASHALERT)) && - (!maxdist || (P_AproxDistance(actor->x - emitter->x, actor->y - emitter->y) <= maxdist))) + (!maxdist || (actor->AproxDistance(emitter) <= maxdist))) { actor->LastHeard = soundtarget; } @@ -231,7 +231,7 @@ bool AActor::CheckMeleeRange () if (!pl) return false; - dist = P_AproxDistance (pl->x - x, pl->y - y); + dist = AproxDistance (pl); if (dist >= meleerange + pl->radius) return false; @@ -243,9 +243,9 @@ bool AActor::CheckMeleeRange () // [RH] Don't melee things too far above or below actor. if (!(flags5 & MF5_NOVERTICALMELEERANGE)) { - if (pl->z > z + height) + if (pl->Z() > Top()) return false; - if (pl->z + pl->height < z) + if (pl->Top() < Z()) return false; } @@ -275,16 +275,16 @@ bool P_CheckMeleeRange2 (AActor *actor) return false; } mo = actor->target; - dist = P_AproxDistance (mo->x-actor->x, mo->y-actor->y); + dist = mo->AproxDistance (actor); if (dist >= MELEERANGE*2 || dist < MELEERANGE-20*FRACUNIT + mo->radius) { return false; } - if (mo->z > actor->z+actor->height) + if (mo->Z() > actor->Top()) { // Target is higher than the attacker return false; } - else if (actor->z > mo->z+mo->height) + else if (actor->Z() > mo->Top()) { // Attacker is higher return false; } @@ -348,8 +348,7 @@ bool P_CheckMissileRange (AActor *actor) // OPTIMIZE: get this from a global checksight // [RH] What? - dist = P_AproxDistance (actor->x-actor->target->x, - actor->y-actor->target->y) - 64*FRACUNIT; + dist = actor->AproxDistance (actor->target) - 64*FRACUNIT; if (actor->MeleeState == NULL) dist -= 128*FRACUNIT; // no melee attack, so fire more @@ -393,8 +392,8 @@ bool P_HitFriend(AActor * self) if (self->flags&MF_FRIENDLY && self->target != NULL) { - angle_t angle = R_PointToAngle2 (self->x, self->y, self->target->x, self->target->y); - fixed_t dist = P_AproxDistance (self->x - self->target->x, self->y - self->target->y); + angle_t angle = self->AngleTo(self->target); + fixed_t dist = self->AproxDistance (self->target); P_AimLineAttack (self, angle, dist, &linetarget, 0, true); if (linetarget != NULL && linetarget != self->target) { @@ -435,7 +434,7 @@ bool P_Move (AActor *actor) // it difficult to thrust them vertically in a reasonable manner. // [GZ] Let jumping actors jump. if (!((actor->flags & MF_NOGRAVITY) || (actor->flags6 & MF6_CANJUMP)) - && actor->z > actor->floorz && !(actor->flags2 & MF2_ONMOBJ)) + && actor->Z() > actor->floorz && !(actor->flags2 & MF2_ONMOBJ)) { return false; } @@ -450,7 +449,7 @@ bool P_Move (AActor *actor) if ((actor->flags6 & MF6_JUMPDOWN) && target && !(target->IsFriend(actor)) && - P_AproxDistance(actor->x - target->x, actor->y - target->y) < FRACUNIT*144 && + actor->AproxDistance(target) < FRACUNIT*144 && pr_dropoff() < 235) { dropoff = 2; @@ -474,8 +473,8 @@ bool P_Move (AActor *actor) } } - tryx = (origx = actor->x) + (deltax = FixedMul (speed, xspeed[actor->movedir])); - tryy = (origy = actor->y) + (deltay = FixedMul (speed, yspeed[actor->movedir])); + tryx = (origx = actor->X()) + (deltax = FixedMul (speed, xspeed[actor->movedir])); + tryy = (origy = actor->Y()) + (deltay = FixedMul (speed, yspeed[actor->movedir])); // Like P_XYMovement this should do multiple moves if the step size is too large @@ -520,15 +519,14 @@ bool P_Move (AActor *actor) // so make it switchable if (nomonsterinterpolation) { - actor->PrevX = actor->x; - actor->PrevY = actor->y; - actor->PrevZ = actor->z; + actor->PrevX = actor->X(); + actor->PrevY = actor->Y(); + actor->PrevZ = actor->Z(); } if (try_ok && friction > ORIG_FRICTION) { - actor->x = origx; - actor->y = origy; + actor->SetOrigin(origx, origy, actor->Z(), false); movefactor *= FRACUNIT / ORIG_FRICTION_FACTOR / 4; actor->velx += FixedMul (deltax, movefactor); actor->vely += FixedMul (deltay, movefactor); @@ -539,22 +537,22 @@ bool P_Move (AActor *actor) // actually walking down a step. if (try_ok && !((actor->flags & MF_NOGRAVITY) || (actor->flags6 & MF6_CANJUMP)) - && actor->z > actor->floorz && !(actor->flags2 & MF2_ONMOBJ)) + && actor->Z() > actor->floorz && !(actor->flags2 & MF2_ONMOBJ)) { - if (actor->z <= actor->floorz + actor->MaxStepHeight) + if (actor->Y() <= actor->floorz + actor->MaxStepHeight) { - fixed_t savedz = actor->z; - actor->z = actor->floorz; + fixed_t savedz = actor->Z(); + actor->SetZ(actor->floorz); // Make sure that there isn't some other actor between us and // the floor we could get stuck in. The old code did not do this. if (!P_TestMobjZ(actor)) { - actor->z = savedz; + actor->SetZ(savedz); } else { // The monster just hit the floor, so trigger any actions. if (actor->floorsector->SecActTarget != NULL && - actor->floorz == actor->floorsector->floorplane.ZatPoint(actor->x, actor->y)) + actor->floorz == actor->floorsector->floorplane.ZatPoint(actor)) { actor->floorsector->SecActTarget->TriggerAction(actor, SECSPAC_HitFloor); } @@ -567,12 +565,12 @@ bool P_Move (AActor *actor) { if (((actor->flags6 & MF6_CANJUMP)||(actor->flags & MF_FLOAT)) && tm.floatok) { // must adjust height - fixed_t savedz = actor->z; + fixed_t savedz = actor->Z(); - if (actor->z < tm.floorz) - actor->z += actor->FloatSpeed; + if (actor->Z() < tm.floorz) + actor->AddZ(actor->FloatSpeed); else - actor->z -= actor->FloatSpeed; + actor->AddZ(-actor->FloatSpeed); // [RH] Check to make sure there's nothing in the way of the float @@ -581,7 +579,7 @@ bool P_Move (AActor *actor) actor->flags |= MF_INFLOAT; return true; } - actor->z = savedz; + actor->SetZ(savedz); } if (!spechit.Size ()) @@ -813,28 +811,25 @@ void P_DoNewChaseDir (AActor *actor, fixed_t deltax, fixed_t deltay) void P_NewChaseDir(AActor * actor) { - fixed_t deltax; - fixed_t deltay; + fixedvec2 delta; actor->strafecount = 0; if ((actor->flags5&MF5_CHASEGOAL || actor->goal == actor->target) && actor->goal!=NULL) { - deltax = actor->goal->x - actor->x; - deltay = actor->goal->y - actor->y; + delta = actor->Vec2To(actor->goal); } else if (actor->target != NULL) { - deltax = actor->target->x - actor->x; - deltay = actor->target->y - actor->y; + delta = actor->Vec2To(actor->target); if (!(actor->flags6 & MF6_NOFEAR)) { if ((actor->target->player != NULL && (actor->target->player->cheats & CF_FRIGHTENING)) || (actor->flags4 & MF4_FRIGHTENED)) { - deltax = -deltax; - deltay = -deltay; + delta.x = -delta.x; + delta.y = -delta.y; } } } @@ -848,11 +843,11 @@ void P_NewChaseDir(AActor * actor) // Try to move away from a dropoff if (actor->floorz - actor->dropoffz > actor->MaxDropOffHeight && - actor->z <= actor->floorz && !(actor->flags & MF_DROPOFF) && + actor->Z() <= actor->floorz && !(actor->flags & MF_DROPOFF) && !(actor->flags2 & MF2_ONMOBJ) && !(actor->flags & MF_FLOAT) && !(i_compatflags & COMPATF_DROPOFF)) { - FBoundingBox box(actor->x, actor->y, actor->radius); + FBoundingBox box(actor->X(), actor->Y(), actor->radius); FBlockLinesIterator it(box); line_t *line; @@ -867,18 +862,18 @@ void P_NewChaseDir(AActor * actor) box.Bottom() < line->bbox[BOXTOP] && box.BoxOnLineSide(line) == -1) { - fixed_t front = line->frontsector->floorplane.ZatPoint(actor->x,actor->y); - fixed_t back = line->backsector->floorplane.ZatPoint(actor->x,actor->y); + fixed_t front = line->frontsector->floorplane.ZatPoint(actor); + fixed_t back = line->backsector->floorplane.ZatPoint(actor); angle_t angle; // The monster must contact one of the two floors, // and the other must be a tall dropoff. - if (back == actor->z && front < actor->z - actor->MaxDropOffHeight) + if (back == actor->Z() && front < actor->Z() - actor->MaxDropOffHeight) { angle = R_PointToAngle2(0,0,line->dx,line->dy); // front side dropoff } - else if (front == actor->z && back < actor->z - actor->MaxDropOffHeight) + else if (front == actor->Z() && back < actor->Z() - actor->MaxDropOffHeight) { angle = R_PointToAngle2(line->dx,line->dy,0,0); // back side dropoff } @@ -933,7 +928,7 @@ void P_NewChaseDir(AActor * actor) if (actor->flags3 & MF3_AVOIDMELEE) { bool ismeleeattacker = false; - fixed_t dist = P_AproxDistance(actor->x-target->x, actor->y-target->y); + fixed_t dist = actor->AproxDistance(target); if (target->player == NULL) { ismeleeattacker = (target->MissileState == NULL && dist < (target->meleerange + target->radius)*2); @@ -947,12 +942,12 @@ void P_NewChaseDir(AActor * actor) if (ismeleeattacker) { actor->strafecount = pr_enemystrafe() & 15; - deltax = -deltax, deltay = -deltay; + delta.x = -delta.x, delta.y = -delta.y; } } } - P_DoNewChaseDir(actor, deltax, deltay); + P_DoNewChaseDir(actor, delta.x, delta.y); // If strafing, set movecount to strafecount so that old Doom // logic still works the same, except in the strafing part @@ -984,7 +979,7 @@ void P_RandomChaseDir (AActor *actor) if (actor->flags & MF_FRIENDLY) { AActor *player; - fixed_t deltax, deltay; + fixedvec2 delta; dirtype_t d[3]; if (actor->FriendPlayer != 0) @@ -1006,19 +1001,18 @@ void P_RandomChaseDir (AActor *actor) { if (pr_newchasedir() & 1 || !P_CheckSight (actor, player)) { - deltax = player->x - actor->x; - deltay = player->y - actor->y; + delta = actor->Vec2To(player); - if (deltax>128*FRACUNIT) + if (delta.x>128*FRACUNIT) d[1]= DI_EAST; - else if (deltax<-128*FRACUNIT) + else if (delta.x<-128*FRACUNIT) d[1]= DI_WEST; else d[1]=DI_NODIR; - if (deltay<-128*FRACUNIT) + if (delta.y<-128*FRACUNIT) d[2]= DI_SOUTH; - else if (deltay>128*FRACUNIT) + else if (delta.y>128*FRACUNIT) d[2]= DI_NORTH; else d[2]=DI_NODIR; @@ -1026,13 +1020,13 @@ void P_RandomChaseDir (AActor *actor) // try direct route if (d[1] != DI_NODIR && d[2] != DI_NODIR) { - actor->movedir = diags[((deltay<0)<<1) + (deltax>0)]; + actor->movedir = diags[((delta.y<0)<<1) + (delta.x>0)]; if (actor->movedir != turnaround && P_TryWalk(actor)) return; } // try other directions - if (pr_newchasedir() > 200 || abs(deltay) > abs(deltax)) + if (pr_newchasedir() > 200 || abs(delta.y) > abs(delta.x)) { swapvalues (d[1], d[2]); } @@ -1151,7 +1145,7 @@ bool P_IsVisible(AActor *lookee, AActor *other, INTBOOL allaround, FLookExParams fov = allaround ? 0 : ANGLE_180; } - fixed_t dist = P_AproxDistance (other->x - lookee->x, other->y - lookee->y); + fixed_t dist = lookee->AproxDistance (other); if (maxdist && dist > maxdist) return false; // [KS] too far @@ -1161,7 +1155,7 @@ bool P_IsVisible(AActor *lookee, AActor *other, INTBOOL allaround, FLookExParams if (fov && fov < ANGLE_MAX) { - angle_t an = R_PointToAngle2 (lookee->x, lookee->y, other->x, other->y) - lookee->angle; + angle_t an = lookee->AngleTo(other) - lookee->angle; if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2))) { @@ -1202,8 +1196,7 @@ bool P_LookForMonsters (AActor *actor) { // Not a valid monster continue; } - if (P_AproxDistance (actor->x-mo->x, actor->y-mo->y) - > MONS_LOOK_RANGE) + if (mo->AproxDistance (actor) > MONS_LOOK_RANGE) { // Out of range continue; } @@ -1703,10 +1696,8 @@ bool P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params) if ((player->mo->flags & MF_SHADOW && !(i_compatflags & COMPATF_INVISIBILITY)) || player->mo->flags3 & MF3_GHOST) { - if ((P_AproxDistance (player->mo->x - actor->x, - player->mo->y - actor->y) > 2*MELEERANGE) - && P_AproxDistance (player->mo->velx, player->mo->vely) - < 5*FRACUNIT) + if ((player->mo->AproxDistance (actor) > 2*MELEERANGE) + && P_AproxDistance (player->mo->velx, player->mo->vely) < 5*FRACUNIT) { // Player is sneaking - can't detect continue; } @@ -1903,8 +1894,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx) } else { - dist = P_AproxDistance (targ->x - self->x, - targ->y - self->y); + dist = self->AproxDistance (targ); // [KS] If the target is too far away, don't respond to the sound. if (maxheardist && dist > maxheardist) @@ -1975,8 +1965,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx) { if (self->flags & MF_AMBUSH) { - dist = P_AproxDistance (self->target->x - self->x, - self->target->y - self->y); + dist = self->AproxDistance (self->target); if (P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING) && (!minseedist || dist > minseedist) && (!maxseedist || dist < maxseedist)) @@ -2390,12 +2379,12 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi actor->FastChaseStrafeCount = 0; actor->velx = 0; actor->vely = 0; - fixed_t dist = P_AproxDistance (actor->x - actor->target->x, actor->y - actor->target->y); + fixed_t dist = actor->AproxDistance (actor->target); if (dist < CLASS_BOSS_STRAFE_RANGE) { if (pr_chase() < 100) { - angle_t ang = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); + angle_t ang = actor->AngleTo(actor->target); if (pr_chase() < 128) ang += ANGLE_90; else ang -= ANGLE_90; actor->velx = 13 * finecosine[ang>>ANGLETOFINESHIFT]; @@ -2480,8 +2469,8 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi if ((!fastchase || !actor->FastChaseStrafeCount) && !dontmove) { // CANTLEAVEFLOORPIC handling was completely missing in the non-serpent functions. - fixed_t oldX = actor->x; - fixed_t oldY = actor->y; + fixed_t oldX = actor->X(); + fixed_t oldY = actor->Y(); FTextureID oldFloor = actor->floorpic; // chase towards player @@ -2532,11 +2521,12 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates) if (self->movedir != DI_NODIR) { const fixed_t absSpeed = abs (self->Speed); - fixed_t viletryx = self->x + FixedMul (absSpeed, xspeed[self->movedir]); - fixed_t viletryy = self->y + FixedMul (absSpeed, yspeed[self->movedir]); + fixedvec2 viletry = self->Vec2Offset( + FixedMul (absSpeed, xspeed[self->movedir]), + FixedMul (absSpeed, yspeed[self->movedir]), true); AActor *corpsehit; - FBlockThingsIterator it(FBoundingBox(viletryx, viletryy, 32*FRACUNIT)); + FBlockThingsIterator it(FBoundingBox(viletry.x, viletry.y, 32*FRACUNIT)); while ((corpsehit = it.Next())) { FState *raisestate = corpsehit->GetRaiseState(); @@ -2545,8 +2535,8 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates) // use the current actor's radius instead of the Arch Vile's default. fixed_t maxdist = corpsehit->GetDefault()->radius + self->radius; - if (abs(corpsehit->x - viletryx) > maxdist || - abs(corpsehit->y - viletryy) > maxdist) + if (abs(corpsehit->X() - viletry.x) > maxdist || + abs(corpsehit->Y() - viletry.y) > maxdist) continue; // not actually touching // Let's check if there are floors in between the archvile and its target sector_t *vilesec = self->Sector; @@ -2557,11 +2547,11 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates) if (testsec) { fixed_t zdist1, zdist2; - if (P_Find3DFloor(testsec, corpsehit->x, corpsehit->y, corpsehit->z, false, true, zdist1) - != P_Find3DFloor(testsec, self->x, self->y, self->z, false, true, zdist2)) + if (P_Find3DFloor(testsec, corpsehit->Pos(), false, true, zdist1) + != P_Find3DFloor(testsec, self->Pos(), false, true, zdist2)) { // Not on same floor - if (vilesec == corpsec || abs(zdist1 - self->z) > self->height) + if (vilesec == corpsec || abs(zdist1 - self->Z()) > self->height) continue; } } @@ -2575,7 +2565,7 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates) corpsehit->flags |= MF_SOLID; corpsehit->height = corpsehit->GetDefault()->height; - bool check = P_CheckPosition(corpsehit, corpsehit->x, corpsehit->y); + bool check = P_CheckPosition(corpsehit, corpsehit->Pos()); corpsehit->flags = oldflags; corpsehit->radius = oldradius; corpsehit->height = oldheight; @@ -2749,7 +2739,7 @@ void A_Face (AActor *self, AActor *other, angle_t max_turn, angle_t max_pitch, a self->flags &= ~MF_AMBUSH; - angle_t other_angle = R_PointToAngle2 (self->x, self->y, other->x, other->y); + angle_t other_angle = self->AngleTo(other); // 0 means no limit. Also, if we turn in a single step anyways, no need to go through the algorithms. // It also means that there is no need to check for going past the other. @@ -2787,36 +2777,33 @@ void A_Face (AActor *self, AActor *other, angle_t max_turn, angle_t max_pitch, a // disabled and is so by default. if (max_pitch <= ANGLE_180) { - // [DH] Don't need to do proper fixed->double conversion, since the - // result is only used in a ratio. - double dist_x = other->x - self->x; - double dist_y = other->y - self->y; + TVector2 dist = self->Vec2To(other); // Positioning ala missile spawning, 32 units above foot level - fixed_t source_z = self->z + 32*FRACUNIT + self->GetBobOffset(); - fixed_t target_z = other->z + 32*FRACUNIT + other->GetBobOffset(); + fixed_t source_z = self->Z() + 32*FRACUNIT + self->GetBobOffset(); + fixed_t target_z = other->Z() + 32*FRACUNIT + other->GetBobOffset(); // If the target z is above the target's head, reposition to the middle of // its body. - if (target_z >= other->z + other->height) + if (target_z >= other->Top()) { - target_z = other->z + (other->height / 2); + target_z = other->Z() + (other->height / 2); } //Note there is no +32*FRACUNIT on purpose. This is for customization sake. //If one doesn't want this behavior, just don't use FAF_BOTTOM. if (flags & FAF_BOTTOM) - target_z = other->z + other->GetBobOffset(); + target_z = other->Z() + other->GetBobOffset(); if (flags & FAF_MIDDLE) - target_z = other->z + (other->height / 2) + other->GetBobOffset(); + target_z = other->Z() + (other->height / 2) + other->GetBobOffset(); if (flags & FAF_TOP) - target_z = other->z + (other->height) + other->GetBobOffset(); + target_z = other->Z() + (other->height) + other->GetBobOffset(); if (!(flags & FAF_NODISTFACTOR)) target_z += pitch_offset; - double dist_z = target_z - source_z; - double dist = sqrt(dist_x*dist_x + dist_y*dist_y + dist_z*dist_z); - int other_pitch = (int)rad2bam(asin(dist_z / dist)); + double dist_z = FIXED2DBL(target_z - source_z); + double ddist = sqrt(dist.X*dist.X + dist.Y*dist.Y + dist_z*dist_z); + int other_pitch = (int)rad2bam(asin(dist_z / ddist)); if (max_pitch != 0) { @@ -2922,26 +2909,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_MonsterRail) self->flags &= ~MF_AMBUSH; - self->angle = R_PointToAngle2 (self->x, - self->y, - self->target->x, - self->target->y); + self->angle = self->AngleTo(self->target); self->pitch = P_AimLineAttack (self, self->angle, MISSILERANGE, &linetarget, ANGLE_1*60, 0, self->target); if (linetarget == NULL) { // We probably won't hit the target, but aim at it anyway so we don't look stupid. - TVector2 xydiff(self->target->x - self->x, self->target->y - self->y); - double zdiff = (self->target->z + (self->target->height>>1)) - - (self->z + (self->height>>1) - self->floorclip); + TVector2 xydiff = self->Vec2To(self->target); + double zdiff = FIXED2DBL((self->target->Z() + (self->target->height>>1)) - (self->Z() + (self->height>>1) - self->floorclip)); self->pitch = int(atan2(zdiff, xydiff.Length()) * ANGLE_180 / -M_PI); } // Let the aim trail behind the player - self->angle = R_PointToAngle2 (self->x, - self->y, - self->target->x - self->target->velx * 3, - self->target->y - self->target->vely * 3); + self->angle = self->AngleTo(self->target, -self->target->velx * 3, -self->target->vely * 3); if (self->target->flags & MF_SHADOW && !(self->flags6 & MF6_SEEINVISIBLE)) { @@ -3084,7 +3064,7 @@ AInventory *P_DropItem (AActor *source, const PClass *type, int dropamount, int AActor *mo; fixed_t spawnz; - spawnz = source->z; + spawnz = source->Z(); if (!(i_compatflags & COMPATF_NOTOSSDROPS)) { int style = sv_dropstyle; @@ -3099,7 +3079,7 @@ AInventory *P_DropItem (AActor *source, const PClass *type, int dropamount, int spawnz += source->height / 2; } } - mo = Spawn (type, source->x, source->y, spawnz, ALLOW_REPLACE); + mo = Spawn (type, source->X(), source->Y(), spawnz, ALLOW_REPLACE); if (mo != NULL) { mo->flags |= MF_DROPPED; diff --git a/src/p_floor.cpp b/src/p_floor.cpp index 9e7806039..e3763e677 100644 --- a/src/p_floor.cpp +++ b/src/p_floor.cpp @@ -55,6 +55,8 @@ inline FArchive &operator<< (FArchive &arc, DFloor::EFloor &type) static void StartFloorSound (sector_t *sec) { + if (sec->Flags & SECF_SILENTMOVE) return; + if (sec->seqType >= 0) { SN_StartSequence (sec, CHAN_FLOOR, sec->seqType, SEQ_PLATFORM, 0); @@ -159,7 +161,7 @@ void DFloor::Tick () case donutRaise: case genFloorChgT: case genFloorChg0: - m_Sector->special = (m_Sector->special & SECRET_MASK) | m_NewSpecial; + m_Sector->SetSpecial(&m_NewSpecial); //fall thru case genFloorChg: m_Sector->SetTexture(sector_t::floor, m_Texture); @@ -175,7 +177,7 @@ void DFloor::Tick () case floorLowerAndChange: case genFloorChgT: case genFloorChg0: - m_Sector->special = (m_Sector->special & SECRET_MASK) | m_NewSpecial; + m_Sector->SetSpecial(&m_NewSpecial); //fall thru case genFloorChg: m_Sector->SetTexture(sector_t::floor, m_Texture); @@ -233,14 +235,14 @@ void DFloor::SetFloorChangeType (sector_t *sec, int change) switch (change & 3) { case 1: - m_NewSpecial = 0; + m_NewSpecial.Clear(); m_Type = DFloor::genFloorChg0; break; case 2: m_Type = DFloor::genFloorChg; break; case 3: - m_NewSpecial = sec->special & ~SECRET_MASK; + sec->GetSpecial(&m_NewSpecial); m_Type = DFloor::genFloorChgT; break; } @@ -438,11 +440,11 @@ bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag, { FTextureID oldpic = sec->GetTexture(sector_t::floor); sec->SetTexture(sector_t::floor, line->frontsector->GetTexture(sector_t::floor)); - sec->special = (sec->special & SECRET_MASK) | (line->frontsector->special & ~SECRET_MASK); + sec->TransferSpecial(line->frontsector); } else { - sec->special &= SECRET_MASK; + sec->ClearSpecial(); } break; @@ -453,8 +455,7 @@ bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag, floor->m_Texture = sec->GetTexture(sector_t::floor); // jff 1/24/98 make sure floor->m_NewSpecial gets initialized // in case no surrounding sector is at floordestheight - // --> should not affect compatibility <-- - floor->m_NewSpecial = sec->special & ~SECRET_MASK; + sec->GetSpecial(&floor->m_NewSpecial); //jff 5/23/98 use model subroutine to unify fixes and handling sector_t *modelsec; @@ -462,7 +463,7 @@ bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag, if (modelsec != NULL) { floor->m_Texture = modelsec->GetTexture(sector_t::floor); - floor->m_NewSpecial = modelsec->special & ~SECRET_MASK; + modelsec->GetSpecial(&floor->m_NewSpecial); } break; @@ -635,7 +636,7 @@ bool EV_BuildStairs (int tag, DFloor::EStair type, line_t *line, { // [RH] Find the next sector by scanning for Stairs_Special? tsec = sec->NextSpecialSector ( - (sec->special & 0xff) == Stairs_Special1 ? + sec->special == Stairs_Special1 ? Stairs_Special2 : Stairs_Special1, prev); if ( (ok = (tsec != NULL)) ) @@ -792,7 +793,7 @@ bool EV_DoDonut (int tag, line_t *line, fixed_t pillarspeed, fixed_t slimespeed) floor->m_Sector = s2; floor->m_Speed = slimespeed; floor->m_Texture = s3->GetTexture(sector_t::floor); - floor->m_NewSpecial = 0; + floor->m_NewSpecial.Clear(); height = s3->FindHighestFloorPoint (&spot); floor->m_FloorDestDist = s2->floorplane.PointToDist (spot, height); floor->StartFloorSound (); @@ -1091,7 +1092,7 @@ bool EV_DoChange (line_t *line, EChange changetype, int tag) if (line) { // [RH] if no line, no change sec->SetTexture(sector_t::floor, line->frontsector->GetTexture(sector_t::floor)); - sec->special = (sec->special & SECRET_MASK) | (line->frontsector->special & ~SECRET_MASK); + sec->TransferSpecial(line->frontsector); } break; case numChangeOnly: @@ -1099,7 +1100,7 @@ bool EV_DoChange (line_t *line, EChange changetype, int tag) if (secm) { // if no model, no change sec->SetTexture(sector_t::floor, secm->GetTexture(sector_t::floor)); - sec->special = secm->special; + sec->TransferSpecial(secm); } break; default: diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 203d1688d..0c61b2d7d 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -84,7 +84,7 @@ FName MeansOfDeath; // void P_TouchSpecialThing (AActor *special, AActor *toucher) { - fixed_t delta = special->z - toucher->z; + fixed_t delta = special->Z() - toucher->Z(); // The pickup is at or above the toucher's feet OR // The pickup is below the toucher. @@ -1045,7 +1045,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, return -1; } - if ((rawdamage < TELEFRAG_DAMAGE) || (target->flags7 & MF7_LAXTELEFRAGDMG)) // TELEFRAG_DAMAGE may only be reduced with NOTELEFRAGPIERCE or it may not guarantee its effect. + if ((rawdamage < TELEFRAG_DAMAGE) || (target->flags7 & MF7_LAXTELEFRAGDMG)) // TELEFRAG_DAMAGE may only be reduced with LAXTELEFRAGDMG or it may not guarantee its effect. { if (player && damage > 1) { @@ -1158,13 +1158,13 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, // If the origin and target are in exactly the same spot, choose a random direction. // (Most likely cause is from telefragging somebody during spawning because they // haven't moved from their spawn spot at all.) - if (origin->x == target->x && origin->y == target->y) + if (origin->X() == target->X() && origin->Y() == target->Y()) { ang = pr_kickbackdir.GenRand32(); } else { - ang = R_PointToAngle2 (origin->x, origin->y, target->x, target->y); + ang = origin->AngleTo(target); } // Calculate this as float to avoid overflows so that the @@ -1184,7 +1184,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, // make fall forwards sometimes if ((damage < 40) && (damage > target->health) - && (target->z - origin->z > 64*FRACUNIT) + && (target->Z() - origin->Z() > 64*FRACUNIT) && (pr_damagemobj()&1) // [RH] But only if not too fast and not flying && thrust < 10*FRACUNIT @@ -1221,7 +1221,8 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, ((player && player != source->player) || (!player && target != source)) && target->IsTeammate (source)) { - if (rawdamage < TELEFRAG_DAMAGE) //Use the original damage to check for telefrag amount. Don't let the now-amplified damagetypes do it. + //Use the original damage to check for telefrag amount. Don't let the now-amplified damagetypes do it. + if (rawdamage < TELEFRAG_DAMAGE || (target->flags7 & MF7_LAXTELEFRAGDMG)) { // Still allow telefragging :-( damage = (int)((float)damage * level.teamdamage); if (damage < 0) @@ -1255,8 +1256,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, } // end of game hell hack - if ((target->Sector->special & 255) == dDamage_End - && damage >= target->health) + if ((target->Sector->Flags & SECF_ENDLEVEL) && damage >= target->health) { damage = target->health - 1; } diff --git a/src/p_lights.cpp b/src/p_lights.cpp index 49ef130e8..656b86112 100644 --- a/src/p_lights.cpp +++ b/src/p_lights.cpp @@ -786,12 +786,12 @@ int DPhased::PhaseHelper (sector_t *sector, int index, int light, sector_t *prev l = new DPhased (sector, baselevel); int numsteps = PhaseHelper (sector->NextSpecialSector ( - (sector->special & 0x00ff) == LightSequenceSpecial1 ? + sector->special == LightSequenceSpecial1 ? LightSequenceSpecial2 : LightSequenceSpecial1, prev), index + 1, l->m_BaseLevel, sector); l->m_Phase = ((numsteps - index - 1) * 64) / numsteps; - sector->special &= 0xff00; + sector->special = 0; return numsteps; } @@ -820,7 +820,6 @@ DPhased::DPhased (sector_t *sector, int baselevel, int phase) { m_BaseLevel = baselevel; m_Phase = phase; - sector->special &= 0xff00; } //============================================================================ diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 9c93ca15c..05259ba3e 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -148,7 +148,7 @@ FUNC(LS_Polyobj_MoveToSpot) FActorIterator iterator (arg2); AActor *spot = iterator.Next(); if (spot == NULL) return false; - return EV_MovePolyTo (ln, arg0, SPEED(arg1), spot->x, spot->y, false); + return EV_MovePolyTo (ln, arg0, SPEED(arg1), spot->X(), spot->Y(), false); } FUNC(LS_Polyobj_DoorSwing) @@ -199,7 +199,7 @@ FUNC(LS_Polyobj_OR_MoveToSpot) FActorIterator iterator (arg2); AActor *spot = iterator.Next(); if (spot == NULL) return false; - return EV_MovePolyTo (ln, arg0, SPEED(arg1), spot->x, spot->y, true); + return EV_MovePolyTo (ln, arg0, SPEED(arg1), spot->X(), spot->Y(), true); } FUNC(LS_Polyobj_Stop) @@ -1945,6 +1945,9 @@ FUNC(LS_Sector_ChangeFlags) rtn = false; FSectorTagIterator itr(arg0); + // exclude protected flags + arg1 &= ~SECF_NOMODIFY; + arg2 &= ~SECF_NOMODIFY; while ((secNum = itr.Next()) >= 0) { sectors[secNum].Flags = (sectors[secNum].Flags | arg1) & ~arg2; @@ -2246,7 +2249,7 @@ FUNC(LS_PointPush_SetForce) } FUNC(LS_Sector_SetDamage) -// Sector_SetDamage (tag, amount, mod) +// Sector_SetDamage (tag, amount, mod, interval, leaky) { // The sector still stores the mod in its old format because // adding an FName to the sector_t structure might cause @@ -2257,8 +2260,28 @@ FUNC(LS_Sector_SetDamage) int secnum; while ((secnum = itr.Next()) >= 0) { - sectors[secnum].damage = arg1; - sectors[secnum].mod = arg2; + if (arg3 <= 0) // emulate old and hacky method to handle leakiness. + { + if (arg1 < 20) + { + arg4 = 0; + arg3 = 32; + } + else if (arg1 < 50) + { + arg4 = 5; + arg3 = 32; + } + else + { + arg4 = 256; + arg3 = 1; + } + } + sectors[secnum].damageamount = (short)arg1; + sectors[secnum].damagetype = MODtoDamageType(arg2); + sectors[secnum].damageinterval = (short)arg3; + sectors[secnum].leakydamage = (short)arg4; } return true; } @@ -2587,6 +2610,7 @@ FUNC(LS_Line_SetBlocking) ML_BLOCKUSE, ML_BLOCKSIGHT, ML_BLOCKHITSCAN, + ML_SOUNDBLOCK, -1 }; @@ -3083,7 +3107,7 @@ FUNC(LS_GlassBreak) { glass = Spawn("GlassJunk", x, y, ONFLOORZ, ALLOW_REPLACE); - glass->z += 24 * FRACUNIT; + glass->AddZ(24 * FRACUNIT); glass->SetState (glass->SpawnState + (pr_glass() % glass->health)); an = pr_glass() << (32-8); glass->angle = an; diff --git a/src/p_local.h b/src/p_local.h index 11e6678c1..420fff565 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -134,7 +134,15 @@ enum EPuffFlags }; AActor *P_SpawnPuff (AActor *source, const PClass *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags = 0, AActor *vict = NULL); +inline AActor *P_SpawnPuff(AActor *source, const PClass *pufftype, const fixedvec3 &pos, angle_t dir, int updown, int flags = 0, AActor *vict = NULL) +{ + return P_SpawnPuff(source, pufftype, pos.x, pos.y, pos.z, dir, updown, flags, vict); +} void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AActor *originator); +inline void P_SpawnBlood(const fixedvec3 &pos, angle_t dir, int damage, AActor *originator) +{ + P_SpawnBlood(pos.x, pos.y, pos.z, dir, damage, originator); +} void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator); void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator); void P_RipperBlood (AActor *mo, AActor *bleeder); @@ -144,6 +152,10 @@ void P_ExplodeMissile (AActor *missile, line_t *explodeline, AActor *target); AActor *P_SpawnMissile (AActor* source, AActor* dest, const PClass *type, AActor* owner = NULL); AActor *P_SpawnMissileZ (AActor* source, fixed_t z, AActor* dest, const PClass *type); AActor *P_SpawnMissileXYZ (fixed_t x, fixed_t y, fixed_t z, AActor *source, AActor *dest, const PClass *type, bool checkspawn = true, AActor *owner = NULL); +inline AActor *P_SpawnMissileXYZ(const fixedvec3 &pos, AActor *source, AActor *dest, const PClass *type, bool checkspawn = true, AActor *owner = NULL) +{ + return P_SpawnMissileXYZ(pos.x, pos.y, pos.z, source, dest, type, checkspawn, owner); +} AActor *P_SpawnMissileAngle (AActor *source, const PClass *type, angle_t angle, fixed_t velz); AActor *P_SpawnMissileAngleSpeed (AActor *source, const PClass *type, angle_t angle, fixed_t velz, fixed_t speed); AActor *P_SpawnMissileAngleZ (AActor *source, fixed_t z, const PClass *type, angle_t angle, fixed_t velz); @@ -178,8 +190,8 @@ const PClass *P_GetSpawnableType(int spawnnum); void InitSpawnablesFromMapinfo(); int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, fixed_t zofs, angle_t angle, int flags, fixed_t heightoffset, fixed_t radiusoffset, angle_t pitch); -enum WARPF -{ +enum WARPF +{ WARPF_ABSOLUTEOFFSET = 0x1, WARPF_ABSOLUTEANGLE = 0x2, WARPF_USECALLERANGLE = 0x4, @@ -200,8 +212,8 @@ enum WARPF WARPF_USETID = 0x2000, WARPF_COPYVELOCITY = 0x4000, WARPF_COPYPITCH = 0x8000, -}; - +}; + // @@ -249,6 +261,12 @@ inline int P_PointOnLineSide (fixed_t x, fixed_t y, const line_t *line) : DMulScale32 (y-line->v1->y, line->dx, line->v1->x-x, line->dy) > 0; } +inline int P_PointOnLineSidePrecise (fixed_t x, fixed_t y, const line_t *line) +{ + return DMulScale32 (y-line->v1->y, line->dx, line->v1->x-x, line->dy) > 0; +} + + //========================================================================== // // P_PointOnDivlineSide @@ -267,6 +285,12 @@ inline int P_PointOnDivlineSide (fixed_t x, fixed_t y, const divline_t *line) : (DMulScale32 (y-line->y, line->dx, line->x-x, line->dy) > 0); } +inline int P_PointOnDivlineSidePrecise (fixed_t x, fixed_t y, const divline_t *line) +{ + return DMulScale32 (y-line->y, line->dx, line->x-x, line->dy) > 0; +} + + //========================================================================== // // P_MakeDivline @@ -293,6 +317,7 @@ struct FLineOpening sector_t *topsec; FTextureID ceilingpic; FTextureID floorpic; + int floorterrain; bool touchmidtex; bool abovemidtex; }; @@ -367,7 +392,6 @@ class FPathTraverse divline_t trace; unsigned int intercept_index; unsigned int intercept_count; - fixed_t maxfrac; unsigned int count; void AddLineIntercepts(int bx, int by); @@ -408,6 +432,7 @@ struct FCheckPosition fixed_t ceilingz; fixed_t dropoffz; FTextureID floorpic; + int floorterrain; sector_t *floorsector; FTextureID ceilingpic; sector_t *ceilingsector; @@ -445,13 +470,21 @@ bool P_TestMobjLocation (AActor *mobj); bool P_TestMobjZ (AActor *mobj, bool quick=true, AActor **pOnmobj = NULL); bool P_CheckPosition (AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bool actorsonly=false); bool P_CheckPosition (AActor *thing, fixed_t x, fixed_t y, bool actorsonly=false); +inline bool P_CheckPosition(AActor *thing, const fixedvec3 &pos, bool actorsonly = false) +{ + return P_CheckPosition(thing, pos.x, pos.y, actorsonly); +} AActor *P_CheckOnmobj (AActor *thing); void P_FakeZMovement (AActor *mo); bool P_TryMove (AActor* thing, fixed_t x, fixed_t y, int dropoff, const secplane_t * onfloor, FCheckPosition &tm, bool missileCheck = false); bool P_TryMove (AActor* thing, fixed_t x, fixed_t y, int dropoff, const secplane_t * onfloor = NULL); bool P_CheckMove(AActor *thing, fixed_t x, fixed_t y); void P_ApplyTorque(AActor *mo); -bool P_TeleportMove (AActor* thing, fixed_t x, fixed_t y, fixed_t z, bool telefrag); // [RH] Added z and telefrag parameters +bool P_TeleportMove (AActor* thing, fixed_t x, fixed_t y, fixed_t z, bool telefrag, bool modifyactor = true); // [RH] Added z and telefrag parameters +inline bool P_TeleportMove(AActor* thing, const fixedvec3 &pos, bool telefrag, bool modifyactor = true) +{ + return P_TeleportMove(thing, pos.x, pos.y, pos.z, telefrag, modifyactor); +} void P_PlayerStartStomp (AActor *actor); // [RH] Stomp on things for a newly spawned player void P_SlideMove (AActor* mo, fixed_t tryx, fixed_t tryy, int numsteps); bool P_BounceWall (AActor *mo); @@ -508,7 +541,7 @@ void P_TraceBleed (int damage, AActor *target, angle_t angle, int pitch); void P_TraceBleed (int damage, AActor *target, AActor *missile); // missile version void P_TraceBleed (int damage, AActor *target); // random direction version bool P_HitFloor (AActor *thing); -bool P_HitWater (AActor *thing, sector_t *sec, fixed_t splashx = FIXED_MIN, fixed_t splashy = FIXED_MIN, fixed_t splashz=FIXED_MIN, bool checkabove = false, bool alert = true); +bool P_HitWater (AActor *thing, sector_t *sec, fixed_t splashx = FIXED_MIN, fixed_t splashy = FIXED_MIN, fixed_t splashz=FIXED_MIN, bool checkabove = false, bool alert = true, bool force = false); void P_CheckSplash(AActor *self, fixed_t distance); void P_RailAttack (AActor *source, int damage, int offset_xy, fixed_t offset_z = 0, int color1 = 0, int color2 = 0, double maxdiff = 0, int flags = 0, const PClass *puff = NULL, angle_t angleoffset = 0, angle_t pitchoffset = 0, fixed_t distance = 8192*FRACUNIT, int duration = 0, double sparsity = 1.0, double drift = 1.0, const PClass *spawnclass = NULL, int SpiralOffset = 270); // [RH] Shoot a railgun diff --git a/src/p_map.cpp b/src/p_map.cpp index 5dd0967b9..43c7f6af0 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -52,6 +52,7 @@ #include "p_conversation.h" #include "r_data/r_translate.h" #include "g_level.h" +#include "r_sky.h" CVAR(Bool, cl_bloodsplats, true, CVAR_ARCHIVE) CVAR(Int, sv_smartaim, 0, CVAR_ARCHIVE | CVAR_SERVERINFO) @@ -189,7 +190,7 @@ static bool PIT_FindFloorCeiling(line_t *ld, const FBoundingBox &box, FCheckPosi } else if (r >= (1 << 24)) { - P_LineOpening(open, tmf.thing, ld, sx = ld->v2->x, sy = ld->v2->y, tmf.thing->x, tmf.thing->y, flags); + P_LineOpening(open, tmf.thing, ld, sx = ld->v2->x, sy = ld->v2->y, tmf.thing->X(), tmf.thing->Y(), flags); } else { @@ -242,6 +243,7 @@ void P_GetFloorCeilingZ(FCheckPosition &tmf, int flags) tmf.floorz = tmf.dropoffz = sec->floorplane.ZatPoint(tmf.x, tmf.y); tmf.ceilingz = sec->ceilingplane.ZatPoint(tmf.x, tmf.y); tmf.floorpic = sec->GetTexture(sector_t::floor); + tmf.floorterrain = sec->GetTerrain(sector_t::floor); tmf.ceilingpic = sec->GetTexture(sector_t::ceiling); } else @@ -264,6 +266,7 @@ void P_GetFloorCeilingZ(FCheckPosition &tmf, int flags) { tmf.dropoffz = tmf.floorz = ff_top; tmf.floorpic = *rover->top.texture; + tmf.floorterrain = rover->model->GetTerrain(rover->top.isceiling); } } if (ff_bottom <= tmf.ceilingz && ff_bottom > tmf.z + tmf.thing->height) @@ -285,9 +288,9 @@ void P_FindFloorCeiling(AActor *actor, int flags) FCheckPosition tmf; tmf.thing = actor; - tmf.x = actor->x; - tmf.y = actor->y; - tmf.z = actor->z; + tmf.x = actor->X(); + tmf.y = actor->Y(); + tmf.z = actor->Z(); if (flags & FFCF_ONLYSPAWNPOS) { @@ -304,6 +307,7 @@ void P_FindFloorCeiling(AActor *actor, int flags) tmf.floorz = tmf.dropoffz = actor->floorz; tmf.ceilingz = actor->ceilingz; tmf.floorpic = actor->floorpic; + tmf.floorterrain = actor->floorterrain; tmf.ceilingpic = actor->ceilingpic; P_GetFloorCeilingZ(tmf, flags); } @@ -311,6 +315,7 @@ void P_FindFloorCeiling(AActor *actor, int flags) actor->dropoffz = tmf.dropoffz; actor->ceilingz = tmf.ceilingz; actor->floorpic = tmf.floorpic; + actor->floorterrain = tmf.floorterrain; actor->floorsector = tmf.floorsector; actor->ceilingpic = tmf.ceilingpic; actor->ceilingsector = tmf.ceilingsector; @@ -331,12 +336,13 @@ void P_FindFloorCeiling(AActor *actor, int flags) if (tmf.touchmidtex) tmf.dropoffz = tmf.floorz; - if (!(flags & FFCF_ONLYSPAWNPOS) || (tmf.abovemidtex && (tmf.floorz <= actor->z))) + if (!(flags & FFCF_ONLYSPAWNPOS) || (tmf.abovemidtex && (tmf.floorz <= actor->Z()))) { actor->floorz = tmf.floorz; actor->dropoffz = tmf.dropoffz; actor->ceilingz = tmf.ceilingz; actor->floorpic = tmf.floorpic; + actor->floorterrain = tmf.floorterrain; actor->floorsector = tmf.floorsector; actor->ceilingpic = tmf.ceilingpic; actor->ceilingsector = tmf.ceilingsector; @@ -348,6 +354,7 @@ void P_FindFloorCeiling(AActor *actor, int flags) if (actor->Sector != NULL) { actor->floorpic = actor->Sector->GetTexture(sector_t::floor); + actor->floorterrain = actor->Sector->GetTerrain(sector_t::floor); actor->ceilingpic = actor->Sector->GetTexture(sector_t::ceiling); } } @@ -370,7 +377,7 @@ void P_FindFloorCeiling(AActor *actor, int flags) // //========================================================================== -bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefrag) +bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefrag, bool modifyactor) { FCheckPosition tmf; sector_t *oldsec = thing->Sector; @@ -397,13 +404,13 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra line_t *ld; // P_LineOpening requires the thing's z to be the destination z in order to work. - fixed_t savedz = thing->z; - thing->z = z; + fixed_t savedz = thing->Z(); + thing->SetZ(z); while ((ld = it.Next())) { PIT_FindFloorCeiling(ld, box, tmf, 0); } - thing->z = savedz; + thing->SetZ(savedz); if (tmf.touchmidtex) tmf.dropoffz = tmf.floorz; @@ -420,7 +427,7 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra continue; fixed_t blockdist = th->radius + tmf.thing->radius; - if (abs(th->x - tmf.x) >= blockdist || abs(th->y - tmf.y) >= blockdist) + if (abs(th->X() - tmf.x) >= blockdist || abs(th->Y() - tmf.y) >= blockdist) continue; // [RH] Z-Check @@ -430,8 +437,8 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra { if (!(th->flags3 & thing->flags3 & MF3_DONTOVERLAP)) { - if (z > th->z + th->height || // overhead - z + thing->height < th->z) // underneath + if (z > th->Top() || // overhead + z + thing->height < th->Z()) // underneath continue; } } @@ -449,36 +456,40 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra return false; } - // the move is ok, so link the thing into its new position - thing->SetOrigin(x, y, z); - thing->floorz = tmf.floorz; - thing->ceilingz = tmf.ceilingz; - thing->floorsector = tmf.floorsector; - thing->floorpic = tmf.floorpic; - thing->ceilingsector = tmf.ceilingsector; - thing->ceilingpic = tmf.ceilingpic; - thing->dropoffz = tmf.dropoffz; // killough 11/98 - thing->BlockingLine = NULL; - - if (thing->flags2 & MF2_FLOORCLIP) + if (modifyactor) { - thing->AdjustFloorClip(); - } + // the move is ok, so link the thing into its new position + thing->SetOrigin(x, y, z, false); + thing->floorz = tmf.floorz; + thing->ceilingz = tmf.ceilingz; + thing->floorsector = tmf.floorsector; + thing->floorpic = tmf.floorpic; + thing->floorterrain = tmf.floorterrain; + thing->ceilingsector = tmf.ceilingsector; + thing->ceilingpic = tmf.ceilingpic; + thing->dropoffz = tmf.dropoffz; // killough 11/98 + thing->BlockingLine = NULL; - if (thing == players[consoleplayer].camera) - { - R_ResetViewInterpolation(); - } + if (thing->flags2 & MF2_FLOORCLIP) + { + thing->AdjustFloorClip(); + } - thing->PrevX = x; - thing->PrevY = y; - thing->PrevZ = z; + if (thing == players[consoleplayer].camera) + { + R_ResetViewInterpolation(); + } - // If this teleport was caused by a move, P_TryMove() will handle the - // sector transition messages better than we can here. - if (!(thing->flags6 & MF6_INTRYMOVE)) - { - thing->CheckSectorTransition(oldsec); + thing->PrevX = x; + thing->PrevY = y; + thing->PrevZ = z; + + // If this teleport was caused by a move, P_TryMove() will handle the + // sector transition messages better than we can here. + if (!(thing->flags6 & MF6_INTRYMOVE)) + { + thing->CheckSectorTransition(oldsec); + } } return true; @@ -496,7 +507,7 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra void P_PlayerStartStomp(AActor *actor) { AActor *th; - FBlockThingsIterator it(FBoundingBox(actor->x, actor->y, actor->radius)); + FBlockThingsIterator it(FBoundingBox(actor->X(), actor->Y(), actor->radius)); while ((th = it.Next())) { @@ -514,9 +525,9 @@ void P_PlayerStartStomp(AActor *actor) if (th->player == NULL && !(th->flags3 & MF3_ISMONSTER)) continue; - if (actor->z > th->z + th->height) + if (actor->Z() > th->Top()) continue; // overhead - if (actor->z + actor->height < th->z) + if (actor->Top() < th->Z()) continue; // underneath P_DamageMobj(th, actor, actor, TELEFRAG_DAMAGE, NAME_Telefrag); @@ -529,16 +540,18 @@ void P_PlayerStartStomp(AActor *actor) // //========================================================================== -inline fixed_t secfriction(const sector_t *sec) +inline fixed_t secfriction(const sector_t *sec, int plane = sector_t::floor) { - fixed_t friction = Terrains[TerrainTypes[sec->GetTexture(sector_t::floor)]].Friction; - return friction != 0 ? friction : sec->friction; + if (sec->Flags & SECF_FRICTION) return sec->friction; + fixed_t friction = Terrains[sec->GetTerrain(plane)].Friction; + return friction != 0 ? friction : ORIG_FRICTION; } -inline fixed_t secmovefac(const sector_t *sec) +inline fixed_t secmovefac(const sector_t *sec, int plane = sector_t::floor) { - fixed_t movefactor = Terrains[TerrainTypes[sec->GetTexture(sector_t::floor)]].MoveFactor; - return movefactor != 0 ? movefactor : sec->movefactor; + if (sec->Flags & SECF_FRICTION) return sec->movefactor; + fixed_t movefactor = Terrains[sec->GetTerrain(plane)].MoveFactor; + return movefactor != 0 ? movefactor : ORIG_FRICTION_FACTOR; } //========================================================================== @@ -568,7 +581,7 @@ int P_GetFriction(const AActor *mo, int *frictionfactor) friction = FRICTION_FLY; } else if ((!(mo->flags & MF_NOGRAVITY) && mo->waterlevel > 1) || - (mo->waterlevel == 1 && mo->z > mo->floorz + 6 * FRACUNIT)) + (mo->waterlevel == 1 && mo->Z() > mo->floorz + 6 * FRACUNIT)) { friction = secfriction(mo->Sector); movefactor = secmovefac(mo->Sector) >> 1; @@ -580,15 +593,15 @@ int P_GetFriction(const AActor *mo, int *frictionfactor) if (!(rover->flags & FF_EXISTS)) continue; if (!(rover->flags & FF_SWIMMABLE)) continue; - if (mo->z > rover->top.plane->ZatPoint(mo->x, mo->y) || - mo->z < rover->bottom.plane->ZatPoint(mo->x, mo->y)) + if (mo->Z() > rover->top.plane->ZatPoint(mo) || + mo->Z() < rover->bottom.plane->ZatPoint(mo)) continue; - newfriction = secfriction(rover->model); + newfriction = secfriction(rover->model, rover->top.isceiling); if (newfriction < friction || friction == ORIG_FRICTION) { friction = newfriction; - movefactor = secmovefac(rover->model) >> 1; + movefactor = secmovefac(rover->model, rover->top.isceiling) >> 1; } } } @@ -610,36 +623,36 @@ int P_GetFriction(const AActor *mo, int *frictionfactor) if (rover->flags & FF_SOLID) { // Must be standing on a solid floor - if (mo->z != rover->top.plane->ZatPoint(mo->x, mo->y)) continue; + if (mo->Z() != rover->top.plane->ZatPoint(mo)) continue; } else if (rover->flags & FF_SWIMMABLE) { // Or on or inside a swimmable floor (e.g. in shallow water) - if (mo->z > rover->top.plane->ZatPoint(mo->x, mo->y) || - (mo->z + mo->height) < rover->bottom.plane->ZatPoint(mo->x, mo->y)) + if (mo->Z() > rover->top.plane->ZatPoint(mo) || + (mo->Top()) < rover->bottom.plane->ZatPoint(mo)) continue; } else continue; - newfriction = secfriction(rover->model); + newfriction = secfriction(rover->model, rover->top.isceiling); if (newfriction < friction || friction == ORIG_FRICTION) { friction = newfriction; - movefactor = secmovefac(rover->model); + movefactor = secmovefac(rover->model, rover->top.isceiling); } } - if (!(sec->special & FRICTION_MASK) && - Terrains[TerrainTypes[sec->GetTexture(sector_t::floor)]].Friction == 0) + if (!(sec->Flags & SECF_FRICTION) && + Terrains[sec->GetTerrain(sector_t::floor)].Friction == 0) { continue; } newfriction = secfriction(sec); if ((newfriction < friction || friction == ORIG_FRICTION) && - (mo->z <= sec->floorplane.ZatPoint(mo->x, mo->y) || + (mo->Z() <= sec->floorplane.ZatPoint(mo) || (sec->GetHeightSec() != NULL && - mo->z <= sec->heightsec->floorplane.ZatPoint(mo->x, mo->y)))) + mo->Z() <= sec->heightsec->floorplane.ZatPoint(mo)))) { friction = newfriction; movefactor = secmovefac(sec); @@ -755,6 +768,7 @@ bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm) bool NotBlocked = ((tm.thing->flags3 & MF3_NOBLOCKMONST) || ((i_compatflags & COMPATF_NOBLOCKFRIENDS) && (tm.thing->flags & MF_FRIENDLY))); + fixedvec3 pos = tm.thing->PosRelative(ld); if (!(Projectile) || (ld->flags & (ML_BLOCKEVERYTHING | ML_BLOCKPROJECTILE))) { if (ld->flags & ML_RAILING) @@ -773,7 +787,7 @@ bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm) } tm.thing->BlockingLine = ld; // Calculate line side based on the actor's original position, not the new one. - CheckForPushSpecial(ld, P_PointOnLineSide(tm.thing->x, tm.thing->y, ld), tm.thing, false); + CheckForPushSpecial(ld, P_PointOnLineSide(pos.x, pos.y, ld), tm.thing, false); return false; } } @@ -784,8 +798,8 @@ bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm) { secplane_t frontplane, backplane; // Check 3D floors as well - frontplane = P_FindFloorPlane(ld->frontsector, tm.thing->x, tm.thing->y, tm.thing->floorz); - backplane = P_FindFloorPlane(ld->backsector, tm.thing->x, tm.thing->y, tm.thing->floorz); + frontplane = P_FindFloorPlane(ld->frontsector, pos.x, pos.y, tm.thing->floorz); + backplane = P_FindFloorPlane(ld->backsector, pos.x, pos.y, tm.thing->floorz); if (frontplane.c < STEEPSLOPE || backplane.c < STEEPSLOPE) { const msecnode_t *node = tm.thing->touching_sectorlist; @@ -840,7 +854,7 @@ bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm) } else if (r >= (1 << 24)) { - P_LineOpening(open, tm.thing, ld, sx = ld->v2->x, sy = ld->v2->y, tm.thing->x, tm.thing->y); + P_LineOpening(open, tm.thing, ld, sx = ld->v2->x, sy = ld->v2->y, pos.x, pos.y); } else { @@ -889,6 +903,7 @@ bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm) tm.floorz = open.bottom; tm.floorsector = open.bottomsec; tm.floorpic = open.floorpic; + tm.floorterrain = open.floorterrain; tm.touchmidtex = open.touchmidtex; tm.abovemidtex = open.abovemidtex; tm.thing->BlockingLine = ld; @@ -1017,8 +1032,9 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm) if (!((thing->flags & (MF_SOLID | MF_SPECIAL | MF_SHOOTABLE)) || thing->flags6 & MF6_TOUCHY)) return true; // can't hit thing + fixedvec3 thingpos = thing->PosRelative(tm.thing); fixed_t blockdist = thing->radius + tm.thing->radius; - if (abs(thing->x - tm.x) >= blockdist || abs(thing->y - tm.y) >= blockdist) + if (abs(thingpos.x - tm.x) >= blockdist || abs(thingpos.y - tm.y) >= blockdist) return true; if ((thing->flags2 | tm.thing->flags2) & MF2_THRUACTORS) @@ -1028,13 +1044,13 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm) return true; tm.thing->BlockingMobj = thing; - topz = thing->z + thing->height; + topz = thing->Top(); if (!(i_compatflags & COMPATF_NO_PASSMOBJ) && !(tm.thing->flags & (MF_FLOAT | MF_MISSILE | MF_SKULLFLY | MF_NOGRAVITY)) && (thing->flags & MF_SOLID) && (thing->flags4 & MF4_ACTLIKEBRIDGE)) { // [RH] Let monsters walk on actors as well as floors if ((tm.thing->flags3 & MF3_ISMONSTER) && - topz >= tm.floorz && topz <= tm.thing->z + tm.thing->MaxStepHeight) + topz >= tm.floorz && topz <= tm.thing->Z() + tm.thing->MaxStepHeight) { // The commented-out if is an attempt to prevent monsters from walking off a // thing further than they would walk off a ledge. I can't think of an easy @@ -1057,22 +1073,22 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm) { // Both actors already overlap. To prevent them from remaining stuck allow the move if it // takes them further apart or the move does not change the position (when called from P_ChangeSector.) - if (tm.x == tm.thing->x && tm.y == tm.thing->y) + if (tm.x == tm.thing->X() && tm.y == tm.thing->Y()) { unblocking = true; } - else if (abs(thing->x - tm.thing->x) < (thing->radius+tm.thing->radius) && - abs(thing->y - tm.thing->y) < (thing->radius+tm.thing->radius)) + else if (abs(thingpos.x - tm.thing->X()) < (thing->radius+tm.thing->radius) && + abs(thingpos.y - tm.thing->Y()) < (thing->radius+tm.thing->radius)) { - fixed_t newdist = P_AproxDistance(thing->x - tm.x, thing->y - tm.y); - fixed_t olddist = P_AproxDistance(thing->x - tm.thing->x, thing->y - tm.thing->y); + fixed_t newdist = thing->AproxDistance(tm.x, tm.y, tm.thing); + fixed_t olddist = thing->AproxDistance(tm.thing); if (newdist > olddist) { // ... but not if they did not overlap in z-direction before but would after the move. - unblocking = !((tm.thing->z >= thing->z + thing->height && tm.z < thing->z + thing->height) || - (tm.thing->z + tm.thing->height <= thing->z && tm.z + tm.thing->height > thing->z)); + unblocking = !((tm.thing->Z() >= topz && tm.z < topz) || + (tm.thing->Top() <= thingpos.z && tm.thing->Top() > thingpos.z)); } } } @@ -1090,7 +1106,7 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm) { // Some things prefer not to overlap each other, if possible return unblocking; } - if ((tm.thing->z >= topz) || (tm.thing->z + tm.thing->height <= thing->z)) + if ((tm.thing->Z() >= topz) || (tm.thing->Top() <= thing->Z())) return true; } } @@ -1106,7 +1122,7 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm) // or different species if DONTHARMSPECIES (!(thing->flags6 & MF6_DONTHARMSPECIES) || thing->GetSpecies() != tm.thing->GetSpecies()) && // touches vertically - thing->z + thing->height >= tm.thing->z && tm.thing->z + tm.thing->height >= thing->z && + topz >= tm.thing->Z() && tm.thing->Z() + tm.thing->height >= thingpos.z && // prevents lost souls from exploding when fired by pain elementals (thing->master != tm.thing && tm.thing->master != thing)) // Difference with MBF: MBF hardcodes the LS/PE check and lets actors of the same species @@ -1209,11 +1225,11 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm) } // Check if it went over / under - if (tm.thing->z > thing->z + clipheight) + if (tm.thing->Z() > thingpos.z + clipheight) { // Over thing return true; } - if (tm.thing->z + tm.thing->height < thing->z) + if (tm.thing->Top() < thingpos.z) { // Under thing return true; } @@ -1321,7 +1337,7 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm) !(tm.thing->flags3 & MF3_BLOODLESSIMPACT) && (pr_checkthing() < 192)) { - P_BloodSplatter(tm.thing->x, tm.thing->y, tm.thing->z, thing); + P_BloodSplatter(tm.thing->X(), tm.thing->Y(), tm.thing->Z(), thing); } if (!(tm.thing->flags3 & MF3_BLOODLESSIMPACT)) { @@ -1363,7 +1379,7 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm) // [RH] The next condition is to compensate for the extra height // that gets added by P_CheckPosition() so that you cannot pick // up things that are above your true height. - && thing->z < tm.thing->z + tm.thing->height - tm.thing->MaxStepHeight) + && thingpos.z < tm.thing->Top() - tm.thing->MaxStepHeight) { // Can be picked up by tmthing P_TouchSpecialThing(thing, tm.thing); // can remove thing } @@ -1434,6 +1450,7 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo tm.floorz = tm.dropoffz = newsec->floorplane.ZatPoint(x, y); tm.ceilingz = newsec->ceilingplane.ZatPoint(x, y); tm.floorpic = newsec->GetTexture(sector_t::floor); + tm.floorterrain = newsec->GetTerrain(sector_t::floor); tm.floorsector = newsec; tm.ceilingpic = newsec->GetTexture(sector_t::ceiling); tm.ceilingsector = newsec; @@ -1449,7 +1466,7 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo F3DFloor* rover; fixed_t delta1; fixed_t delta2; - int thingtop = thing->z + (thing->height == 0 ? 1 : thing->height); + int thingtop = thing->Z() + (thing->height == 0 ? 1 : thing->height); for (unsigned i = 0; ie->XFloor.ffloors.Size(); i++) { @@ -1459,13 +1476,14 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo fixed_t ff_bottom = rover->bottom.plane->ZatPoint(x, y); fixed_t ff_top = rover->top.plane->ZatPoint(x, y); - delta1 = thing->z - (ff_bottom + ((ff_top - ff_bottom) / 2)); + delta1 = thing->Z() - (ff_bottom + ((ff_top - ff_bottom) / 2)); delta2 = thingtop - (ff_bottom + ((ff_top - ff_bottom) / 2)); if (ff_top > tm.floorz && abs(delta1) < abs(delta2)) { tm.floorz = tm.dropoffz = ff_top; tm.floorpic = *rover->top.texture; + tm.floorterrain = rover->model->GetTerrain(rover->top.isceiling); } if (ff_bottom < tm.ceilingz && abs(delta1) >= abs(delta2)) { @@ -1510,17 +1528,17 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo return false; } else if (!BlockingMobj->player && !(thing->flags & (MF_FLOAT | MF_MISSILE | MF_SKULLFLY)) && - BlockingMobj->z + BlockingMobj->height - thing->z <= thing->MaxStepHeight) + BlockingMobj->Top() - thing->Z() <= thing->MaxStepHeight) { if (thingblocker == NULL || - BlockingMobj->z > thingblocker->z) + BlockingMobj->Z() > thingblocker->Z()) { thingblocker = BlockingMobj; } thing->BlockingMobj = NULL; } else if (thing->player && - thing->z + thing->height - BlockingMobj->z <= thing->MaxStepHeight) + thing->Top() - BlockingMobj->Z() <= thing->MaxStepHeight) { if (thingblocker) { // There is something to step up on. Return this thing as @@ -1613,10 +1631,10 @@ bool P_TestMobjLocation(AActor *mobj) flags = mobj->flags; mobj->flags &= ~MF_PICKUP; - if (P_CheckPosition(mobj, mobj->x, mobj->y)) + if (P_CheckPosition(mobj, mobj->X(), mobj->Y())) { // XY is ok, now check Z mobj->flags = flags; - if ((mobj->z < mobj->floorz) || (mobj->z + mobj->height > mobj->ceilingz)) + if ((mobj->Z() < mobj->floorz) || (mobj->Top() > mobj->ceilingz)) { // Bad Z return false; } @@ -1640,10 +1658,10 @@ AActor *P_CheckOnmobj(AActor *thing) bool good; AActor *onmobj; - oldz = thing->z; + oldz = thing->Z(); P_FakeZMovement(thing); good = P_TestMobjZ(thing, false, &onmobj); - thing->z = oldz; + thing->SetZ(oldz); return good ? NULL : onmobj; } @@ -1663,7 +1681,7 @@ bool P_TestMobjZ(AActor *actor, bool quick, AActor **pOnmobj) return true; } - FBlockThingsIterator it(FBoundingBox(actor->x, actor->y, actor->radius)); + FBlockThingsIterator it(FBoundingBox(actor->X(), actor->Y(), actor->radius)); AActor *thing; while ((thing = it.Next())) @@ -1705,15 +1723,15 @@ bool P_TestMobjZ(AActor *actor, bool quick, AActor **pOnmobj) { // Don't clip against whoever shot the missile. continue; } - if (actor->z > thing->z + thing->height) + if (actor->Z() > thing->Top()) { // over thing continue; } - else if (actor->z + actor->height <= thing->z) + else if (actor->Top() <= thing->Z()) { // under thing continue; } - else if (!quick && onmobj != NULL && thing->z + thing->height < onmobj->z + onmobj->height) + else if (!quick && onmobj != NULL && thing->Top() < onmobj->Top()) { // something higher is in the way continue; } @@ -1737,35 +1755,35 @@ void P_FakeZMovement(AActor *mo) // // adjust height // - mo->z += mo->velz; + mo->AddZ(mo->velz); if ((mo->flags&MF_FLOAT) && mo->target) { // float down towards target if too close if (!(mo->flags & MF_SKULLFLY) && !(mo->flags & MF_INFLOAT)) { - fixed_t dist = P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y); - fixed_t delta = (mo->target->z + (mo->height >> 1)) - mo->z; + fixed_t dist = mo->AproxDistance(mo->target); + fixed_t delta = (mo->target->Z() + (mo->height >> 1)) - mo->Z(); if (delta < 0 && dist < -(delta * 3)) - mo->z -= mo->FloatSpeed; + mo->AddZ(-mo->FloatSpeed); else if (delta > 0 && dist < (delta * 3)) - mo->z += mo->FloatSpeed; + mo->AddZ(mo->FloatSpeed); } } - if (mo->player && mo->flags&MF_NOGRAVITY && (mo->z > mo->floorz) && !mo->IsNoClip2()) + if (mo->player && mo->flags&MF_NOGRAVITY && (mo->Z() > mo->floorz) && !mo->IsNoClip2()) { - mo->z += finesine[(FINEANGLES / 80 * level.maptime)&FINEMASK] / 8; + mo->AddZ(finesine[(FINEANGLES / 80 * level.maptime)&FINEMASK] / 8); } // // clip movement // - if (mo->z <= mo->floorz) + if (mo->Z() <= mo->floorz) { // hit the floor - mo->z = mo->floorz; + mo->SetZ(mo->floorz); } - if (mo->z + mo->height > mo->ceilingz) + if (mo->Top() > mo->ceilingz) { // hit the ceiling - mo->z = mo->ceilingz - mo->height; + mo->SetZ(mo->ceilingz - mo->height); } } @@ -1782,12 +1800,12 @@ static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, bool windo if (windowcheck && !(ib_compatflags & BCOMPATF_NOWINDOWCHECK) && line->backsector != NULL) { // Make sure this line actually blocks us and is not a window // or similar construct we are standing inside of. - fixed_t fzt = line->frontsector->ceilingplane.ZatPoint(mobj->x, mobj->y); - fixed_t fzb = line->frontsector->floorplane.ZatPoint(mobj->x, mobj->y); - fixed_t bzt = line->backsector->ceilingplane.ZatPoint(mobj->x, mobj->y); - fixed_t bzb = line->backsector->floorplane.ZatPoint(mobj->x, mobj->y); - if (fzt >= mobj->z + mobj->height && bzt >= mobj->z + mobj->height && - fzb <= mobj->z && bzb <= mobj->z) + fixed_t fzt = line->frontsector->ceilingplane.ZatPoint(mobj); + fixed_t fzb = line->frontsector->floorplane.ZatPoint(mobj); + fixed_t bzt = line->backsector->ceilingplane.ZatPoint(mobj); + fixed_t bzb = line->backsector->floorplane.ZatPoint(mobj); + if (fzt >= mobj->Top() && bzt >= mobj->Top() && + fzb <= mobj->Z() && bzb <= mobj->Z()) { // we must also check if some 3D floor in the backsector may be blocking for (unsigned int i = 0; ibacksector->e->XFloor.ffloors.Size(); i++) @@ -1796,10 +1814,10 @@ static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, bool windo if (!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue; - fixed_t ff_bottom = rover->bottom.plane->ZatPoint(mobj->x, mobj->y); - fixed_t ff_top = rover->top.plane->ZatPoint(mobj->x, mobj->y); + fixed_t ff_bottom = rover->bottom.plane->ZatPoint(mobj); + fixed_t ff_top = rover->top.plane->ZatPoint(mobj); - if (ff_bottom < mobj->z + mobj->height && ff_top > mobj->z) + if (ff_bottom < mobj->Top() && ff_top > mobj->Z()) { goto isblocking; } @@ -1842,8 +1860,8 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bool missileCheck) // [GZ] Fired missiles ignore the drop-off test { - fixed_t oldx; - fixed_t oldy; + fixedvec3 oldpos; + sector_t *oldsector; fixed_t oldz; int side; int oldside; @@ -1852,10 +1870,10 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, sector_t* newsec; tm.floatok = false; - oldz = thing->z; + oldz = thing->Z(); if (onfloor) { - thing->z = onfloor->ZatPoint(x, y); + thing->SetZ(onfloor->ZatPoint(x, y)); } thing->flags6 |= MF6_INTRYMOVE; if (!P_CheckPosition(thing, x, y, tm)) @@ -1872,19 +1890,16 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, { goto pushline; } - else if (BlockingMobj->z + BlockingMobj->height - thing->z - > thing->MaxStepHeight - || (BlockingMobj->Sector->ceilingplane.ZatPoint(x, y) - - (BlockingMobj->z + BlockingMobj->height) < thing->height) - || (tm.ceilingz - (BlockingMobj->z + BlockingMobj->height) - < thing->height)) + else if (BlockingMobj->Top() - thing->Z() > thing->MaxStepHeight + || (BlockingMobj->Sector->ceilingplane.ZatPoint(x, y) - (BlockingMobj->Top()) < thing->height) + || (tm.ceilingz - (BlockingMobj->Top()) < thing->height)) { goto pushline; } } if (!(tm.thing->flags2 & MF2_PASSMOBJ) || (i_compatflags & COMPATF_NO_PASSMOBJ)) { - thing->z = oldz; + thing->SetZ(oldz); thing->flags6 &= ~MF6_INTRYMOVE; return false; } @@ -1892,16 +1907,16 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, if (thing->flags3 & MF3_FLOORHUGGER) { - thing->z = tm.floorz; + thing->SetZ(tm.floorz); } else if (thing->flags3 & MF3_CEILINGHUGGER) { - thing->z = tm.ceilingz - thing->height; + thing->SetZ(tm.ceilingz - thing->height); } if (onfloor && tm.floorsector == thing->floorsector) { - thing->z = tm.floorz; + thing->SetZ(tm.floorz); } if (!(thing->flags & MF_NOCLIP)) { @@ -1913,7 +1928,7 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, tm.floatok = true; if (!(thing->flags & MF_TELEPORT) - && tm.ceilingz - thing->z < thing->height + && tm.ceilingz - thing->Z() < thing->height && !(thing->flags3 & MF3_CEILINGHUGGER) && (!(thing->flags2 & MF2_FLY) || !(thing->flags & MF_NOGRAVITY))) { @@ -1922,17 +1937,17 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, if (thing->flags2 & MF2_FLY && thing->flags & MF_NOGRAVITY) { #if 1 - if (thing->z + thing->height > tm.ceilingz) + if (thing->Top() > tm.ceilingz) goto pushline; #else // When flying, slide up or down blocking lines until the actor // is not blocked. - if (thing->z + thing->height > tm.ceilingz) + if (thing->Top() > tm.ceilingz) { thing->velz = -8 * FRACUNIT; goto pushline; } - else if (thing->z < tm.floorz && tm.floorz - tm.dropoffz > thing->MaxDropOffHeight) + else if (thing->Z() < tm.floorz && tm.floorz - tm.dropoffz > thing->MaxDropOffHeight) { thing->velz = 8 * FRACUNIT; goto pushline; @@ -1941,28 +1956,28 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, } if (!(thing->flags & MF_TELEPORT) && !(thing->flags3 & MF3_FLOORHUGGER)) { - if ((thing->flags & MF_MISSILE) && !(thing->flags6 & MF6_STEPMISSILE) && tm.floorz > thing->z) + if ((thing->flags & MF_MISSILE) && !(thing->flags6 & MF6_STEPMISSILE) && tm.floorz > thing->Z()) { // [RH] Don't let normal missiles climb steps goto pushline; } - if (tm.floorz - thing->z > thing->MaxStepHeight) + if (tm.floorz - thing->Z() > thing->MaxStepHeight) { // too big a step up goto pushline; } - else if (thing->z < tm.floorz) + else if (thing->Z() < tm.floorz) { // [RH] Check to make sure there's nothing in the way for the step up - fixed_t savedz = thing->z; + fixed_t savedz = thing->Z(); bool good; - thing->z = tm.floorz; + thing->SetZ(tm.floorz); good = P_TestMobjZ(thing); - thing->z = savedz; + thing->SetZ(savedz); if (!good) { goto pushline; } if (thing->flags6 & MF6_STEPMISSILE) { - thing->z = tm.floorz; + thing->SetZ(tm.floorz); // If moving down, cancel vertical component of the velocity if (thing->velz < 0) { @@ -1988,7 +2003,7 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, } if (dropoff == 2 && // large jump down (e.g. dogs) - (tm.floorz - tm.dropoffz > 128 * FRACUNIT || thing->target == NULL || thing->target->z >tm.dropoffz)) + (tm.floorz - tm.dropoffz > 128 * FRACUNIT || thing->target == NULL || thing->target->Z() >tm.dropoffz)) { dropoff = false; } @@ -2004,14 +2019,14 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, // This is so that it does not walk off of things onto a drop off. if (thing->flags2 & MF2_ONMOBJ) { - floorz = MAX(thing->z, tm.floorz); + floorz = MAX(thing->Z(), tm.floorz); } if (floorz - tm.dropoffz > thing->MaxDropOffHeight && !(thing->flags2 & MF2_BLASTED) && !missileCheck) { // Can't move over a dropoff unless it's been blasted // [GZ] Or missile-spawned - thing->z = oldz; + thing->SetZ(oldz); thing->flags6 &= ~MF6_INTRYMOVE; return false; } @@ -2030,9 +2045,9 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, } if (thing->flags2 & MF2_CANTLEAVEFLOORPIC && (tm.floorpic != thing->floorpic - || tm.floorz - thing->z != 0)) + || tm.floorz - thing->Z() != 0)) { // must stay within a sector of a certain floor type - thing->z = oldz; + thing->SetZ(oldz); thing->flags6 &= ~MF6_INTRYMOVE; return false; } @@ -2047,7 +2062,7 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, thing->player->Bot->dest = NULL; thing->velx = 0; thing->vely = 0; - thing->z = oldz; + thing->SetZ(oldz); thing->flags6 &= ~MF6_INTRYMOVE; return false; } @@ -2067,14 +2082,14 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, { fixed_t eyez = oldz + viewheight; - oldAboveFakeFloor = eyez > oldsec->heightsec->floorplane.ZatPoint(thing->x, thing->y); - oldAboveFakeCeiling = eyez > oldsec->heightsec->ceilingplane.ZatPoint(thing->x, thing->y); + oldAboveFakeFloor = eyez > oldsec->heightsec->floorplane.ZatPoint(thing); + oldAboveFakeCeiling = eyez > oldsec->heightsec->ceilingplane.ZatPoint(thing); } // Borrowed from MBF: if (thing->BounceFlags & BOUNCE_MBF && // killough 8/13/98 !(thing->flags & (MF_MISSILE | MF_NOGRAVITY)) && - !thing->IsSentient() && tm.floorz - thing->z > 16 * FRACUNIT) + !thing->IsSentient() && tm.floorz - thing->Z() > 16 * FRACUNIT) { // too big a step up for MBF bouncers under gravity thing->flags6 &= ~MF6_INTRYMOVE; return false; @@ -2083,17 +2098,17 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, // the move is ok, so link the thing into its new position thing->UnlinkFromWorld(); - oldx = thing->x; - oldy = thing->y; + oldpos = thing->Pos(); + oldsector = thing->Sector; thing->floorz = tm.floorz; thing->ceilingz = tm.ceilingz; thing->dropoffz = tm.dropoffz; // killough 11/98: keep track of dropoffs thing->floorpic = tm.floorpic; + thing->floorterrain = tm.floorterrain; thing->floorsector = tm.floorsector; thing->ceilingpic = tm.ceilingpic; thing->ceilingsector = tm.ceilingsector; - thing->x = x; - thing->y = y; + thing->SetXY(x, y); thing->LinkToWorld(); @@ -2107,9 +2122,11 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, { while (spechit.Pop(ld)) { + fixedvec3 thingpos = thing->PosRelative(ld); + fixedvec3 oldrelpos = PosRelative(oldpos, ld, oldsector); // see if the line was crossed - side = P_PointOnLineSide(thing->x, thing->y, ld); - oldside = P_PointOnLineSide(oldx, oldy, ld); + side = P_PointOnLineSide(thingpos.x, thingpos.y, ld); + oldside = P_PointOnLineSide(oldrelpos.x, oldrelpos.y, ld); if (side != oldside && ld->special && !(thing->flags6 & MF6_NOTRIGGER)) { if (thing->player && (thing->player->cheats & CF_PREDICTING)) @@ -2154,7 +2171,7 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, if (newsec->heightsec && oldsec->heightsec && newsec->SecActTarget) { const sector_t *hs = newsec->heightsec; - fixed_t eyez = thing->z + viewheight; + fixed_t eyez = thing->Z() + viewheight; fixed_t fakez = hs->floorplane.ZatPoint(x, y); if (!oldAboveFakeFloor && eyez > fakez) @@ -2194,7 +2211,7 @@ pushline: return false; } - thing->z = oldz; + thing->SetZ(oldz); if (!(thing->flags&(MF_TELEPORT | MF_NOCLIP))) { int numSpecHitTemp; @@ -2208,7 +2225,8 @@ pushline: { // see which lines were pushed ld = spechit[--numSpecHitTemp]; - side = P_PointOnLineSide(thing->x, thing->y, ld); + fixedvec3 pos = thing->PosRelative(ld); + side = P_PointOnLineSide(pos.x, pos.y, ld); CheckForPushSpecial(ld, side, thing, true); } } @@ -2235,7 +2253,7 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, bool P_CheckMove(AActor *thing, fixed_t x, fixed_t y) { FCheckPosition tm; - fixed_t newz = thing->z; + fixed_t newz = thing->Z(); if (!P_CheckPosition(thing, x, y, tm)) { @@ -2267,7 +2285,7 @@ bool P_CheckMove(AActor *thing, fixed_t x, fixed_t y) } if (thing->flags2 & MF2_FLY && thing->flags & MF_NOGRAVITY) { - if (thing->z + thing->height > tm.ceilingz) + if (thing->Top() > tm.ceilingz) return false; } if (!(thing->flags & MF_TELEPORT) && !(thing->flags3 & MF3_FLOORHUGGER)) @@ -2282,10 +2300,10 @@ bool P_CheckMove(AActor *thing, fixed_t x, fixed_t y) } else if (newz < tm.floorz) { // [RH] Check to make sure there's nothing in the way for the step up - fixed_t savedz = thing->z; - thing->z = newz = tm.floorz; + fixed_t savedz = thing->Z(); + thing->SetZ(newz = tm.floorz); bool good = P_TestMobjZ(thing); - thing->z = savedz; + thing->SetZ(savedz); if (!good) { return false; @@ -2366,7 +2384,7 @@ void FSlide::HitSlideLine(line_t* ld) icyfloor = (P_AproxDistance(tmxmove, tmymove) > 4 * FRACUNIT) && var_friction && // killough 8/28/98: calc friction on demand - slidemo->z <= slidemo->floorz && + slidemo->Z() <= slidemo->floorz && P_GetFriction(slidemo, NULL) > ORIG_FRICTION; if (ld->dx == 0) @@ -2404,7 +2422,8 @@ void FSlide::HitSlideLine(line_t* ld) // The wall is angled. Bounce if the angle of approach is // phares // less than 45 degrees. // phares - side = P_PointOnLineSide(slidemo->x, slidemo->y, ld); + fixedvec3 pos = slidemo->PosRelative(ld); + side = P_PointOnLineSide(pos.x, pos.y, ld); lineangle = R_PointToAngle2(0, 0, ld->dx, ld->dy); @@ -2456,8 +2475,8 @@ void FSlide::HitSlideLine(line_t* ld) P_MakeDivline(ld, &dll); - dlv.x = slidemo->x; - dlv.y = slidemo->y; + dlv.x = pos.x; + dlv.y = pos.y; dlv.dx = dll.dy; dlv.dy = -dll.dx; @@ -2509,7 +2528,8 @@ void FSlide::SlideTraverse(fixed_t startx, fixed_t starty, fixed_t endx, fixed_t if (!(li->flags & ML_TWOSIDED) || !li->backsector) { - if (P_PointOnLineSide(slidemo->x, slidemo->y, li)) + fixedvec3 pos = slidemo->PosRelative(li); + if (P_PointOnLineSide(pos.x, pos.y, li)) { // don't hit the back side continue; @@ -2537,19 +2557,19 @@ void FSlide::SlideTraverse(fixed_t startx, fixed_t starty, fixed_t endx, fixed_t if (open.range < slidemo->height) goto isblocking; // doesn't fit - if (open.top - slidemo->z < slidemo->height) + if (open.top - slidemo->Z() < slidemo->height) goto isblocking; // mobj is too high - if (open.bottom - slidemo->z > slidemo->MaxStepHeight) + if (open.bottom - slidemo->Z() > slidemo->MaxStepHeight) { goto isblocking; // too big a step up } - else if (slidemo->z < open.bottom) + else if (slidemo->Z() < open.bottom) { // [RH] Check to make sure there's nothing in the way for the step up - fixed_t savedz = slidemo->z; - slidemo->z = open.bottom; + fixed_t savedz = slidemo->Z(); + slidemo->SetZ(open.bottom); bool good = P_TestMobjZ(slidemo); - slidemo->z = savedz; + slidemo->SetZ(savedz); if (!good) { goto isblocking; @@ -2610,24 +2630,24 @@ retry: // trace along the three leading corners if (tryx > 0) { - leadx = mo->x + mo->radius; - trailx = mo->x - mo->radius; + leadx = mo->X() + mo->radius; + trailx = mo->X() - mo->radius; } else { - leadx = mo->x - mo->radius; - trailx = mo->x + mo->radius; + leadx = mo->X() - mo->radius; + trailx = mo->X() + mo->radius; } if (tryy > 0) { - leady = mo->y + mo->radius; - traily = mo->y - mo->radius; + leady = mo->Y() + mo->radius; + traily = mo->Y() - mo->radius; } else { - leady = mo->y - mo->radius; - traily = mo->y + mo->radius; + leady = mo->Y() - mo->radius; + traily = mo->Y() + mo->radius; } bestslidefrac = FRACUNIT + 1; @@ -2644,11 +2664,11 @@ retry: // killough 3/15/98: Allow objects to drop off ledges xmove = 0, ymove = tryy; walkplane = P_CheckSlopeWalk(mo, xmove, ymove); - if (!P_TryMove(mo, mo->x + xmove, mo->y + ymove, true, walkplane)) + if (!P_TryMove(mo, mo->X() + xmove, mo->Y() + ymove, true, walkplane)) { xmove = tryx, ymove = 0; walkplane = P_CheckSlopeWalk(mo, xmove, ymove); - P_TryMove(mo, mo->x + xmove, mo->y + ymove, true, walkplane); + P_TryMove(mo, mo->X() + xmove, mo->Y() + ymove, true, walkplane); } return; } @@ -2665,7 +2685,7 @@ retry: const fixed_t startvely = mo->vely; // killough 3/15/98: Allow objects to drop off ledges - if (!P_TryMove(mo, mo->x + newx, mo->y + newy, true)) + if (!P_TryMove(mo, mo->X() + newx, mo->Y() + newy, true)) goto stairstep; if (mo->velx != startvelx || mo->vely != startvely) @@ -2699,7 +2719,7 @@ retry: walkplane = P_CheckSlopeWalk(mo, tmxmove, tmymove); // killough 3/15/98: Allow objects to drop off ledges - if (!P_TryMove(mo, mo->x + tmxmove, mo->y + tmymove, true, walkplane)) + if (!P_TryMove(mo, mo->X() + tmxmove, mo->Y() + tmymove, true, walkplane)) { goto retry; } @@ -2726,16 +2746,16 @@ const secplane_t * P_CheckSlopeWalk(AActor *actor, fixed_t &xmove, fixed_t &ymov } const secplane_t *plane = &actor->floorsector->floorplane; - fixed_t planezhere = plane->ZatPoint(actor->x, actor->y); + fixed_t planezhere = plane->ZatPoint(actor); for (unsigned int i = 0; ifloorsector->e->XFloor.ffloors.Size(); i++) { F3DFloor * rover = actor->floorsector->e->XFloor.ffloors[i]; if (!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue; - fixed_t thisplanez = rover->top.plane->ZatPoint(actor->x, actor->y); + fixed_t thisplanez = rover->top.plane->ZatPoint(actor); - if (thisplanez>planezhere && thisplanez <= actor->z + actor->MaxStepHeight) + if (thisplanez>planezhere && thisplanez <= actor->Z() + actor->MaxStepHeight) { copyplane = *rover->top.plane; if (copyplane.c<0) copyplane.FlipVert(); @@ -2751,9 +2771,9 @@ const secplane_t * P_CheckSlopeWalk(AActor *actor, fixed_t &xmove, fixed_t &ymov F3DFloor * rover = actor->Sector->e->XFloor.ffloors[i]; if (!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue; - fixed_t thisplanez = rover->top.plane->ZatPoint(actor->x, actor->y); + fixed_t thisplanez = rover->top.plane->ZatPoint(actor); - if (thisplanez>planezhere && thisplanez <= actor->z + actor->MaxStepHeight) + if (thisplanez>planezhere && thisplanez <= actor->Z() + actor->MaxStepHeight) { copyplane = *rover->top.plane; if (copyplane.c<0) copyplane.FlipVert(); @@ -2770,7 +2790,7 @@ const secplane_t * P_CheckSlopeWalk(AActor *actor, fixed_t &xmove, fixed_t &ymov return NULL; } - if (actor->z - planezhere > FRACUNIT) + if (actor->Z() - planezhere > FRACUNIT) { // not on floor return NULL; } @@ -2780,9 +2800,9 @@ const secplane_t * P_CheckSlopeWalk(AActor *actor, fixed_t &xmove, fixed_t &ymov fixed_t destx, desty; fixed_t t; - destx = actor->x + xmove; - desty = actor->y + ymove; - t = TMulScale16(plane->a, destx, plane->b, desty, plane->c, actor->z) + plane->d; + destx = actor->X() + xmove; + desty = actor->Y() + ymove; + t = TMulScale16(plane->a, destx, plane->b, desty, plane->c, actor->Z()) + plane->d; if (t < 0) { // Desired location is behind (below) the plane // (i.e. Walking up the plane) @@ -2804,7 +2824,7 @@ const secplane_t * P_CheckSlopeWalk(AActor *actor, fixed_t &xmove, fixed_t &ymov const sector_t *sec = node->m_sector; if (sec->floorplane.c >= STEEPSLOPE) { - if (sec->floorplane.ZatPoint(destx, desty) >= actor->z - actor->MaxStepHeight) + if (sec->floorplane.ZatPoint(destx, desty) >= actor->Z() - actor->MaxStepHeight) { dopush = false; break; @@ -2824,19 +2844,19 @@ const secplane_t * P_CheckSlopeWalk(AActor *actor, fixed_t &xmove, fixed_t &ymov // so that it lies on the plane's surface destx -= FixedMul(plane->a, t); desty -= FixedMul(plane->b, t); - xmove = destx - actor->x; - ymove = desty - actor->y; + xmove = destx - actor->X(); + ymove = desty - actor->Y(); return (actor->floorsector == actor->Sector) ? plane : NULL; } else if (t > 0) { // Desired location is in front of (above) the plane - if (planezhere == actor->z) + if (planezhere == actor->Z()) { // Actor's current spot is on/in the plane, so walk down it // Same principle as walking up, except reversed destx += FixedMul(plane->a, t); desty += FixedMul(plane->b, t); - xmove = destx - actor->x; - ymove = desty - actor->y; + xmove = destx - actor->X(); + ymove = desty - actor->Y(); return (actor->floorsector == actor->Sector) ? plane : NULL; } } @@ -2875,7 +2895,7 @@ bool FSlide::BounceTraverse(fixed_t startx, fixed_t starty, fixed_t endx, fixed_ } if (!(li->flags&ML_TWOSIDED) || !li->backsector) { - if (P_PointOnLineSide(slidemo->x, slidemo->y, li)) + if (P_PointOnLineSide(slidemo->X(), slidemo->Y(), li)) continue; // don't hit the back side goto bounceblocking; } @@ -2886,10 +2906,10 @@ bool FSlide::BounceTraverse(fixed_t startx, fixed_t starty, fixed_t endx, fixed_ if (open.range < slidemo->height) goto bounceblocking; // doesn't fit - if (open.top - slidemo->z < slidemo->height) + if (open.top - slidemo->Z() < slidemo->height) goto bounceblocking; // mobj is too high - if (open.bottom > slidemo->z) + if (open.bottom > slidemo->Z()) goto bounceblocking; // mobj is too low continue; // this line doesn't block movement @@ -2933,26 +2953,26 @@ bool FSlide::BounceWall(AActor *mo) // if (mo->velx > 0) { - leadx = mo->x + mo->radius; + leadx = mo->X() + mo->radius; } else { - leadx = mo->x - mo->radius; + leadx = mo->X() - mo->radius; } if (mo->vely > 0) { - leady = mo->y + mo->radius; + leady = mo->Y() + mo->radius; } else { - leady = mo->y - mo->radius; + leady = mo->Y() - mo->radius; } bestslidefrac = FRACUNIT + 1; bestslideline = mo->BlockingLine; if (BounceTraverse(leadx, leady, leadx + mo->velx, leady + mo->vely) && mo->BlockingLine == NULL) { // Could not find a wall, so bounce off the floor/ceiling instead. - fixed_t floordist = mo->z - mo->floorz; - fixed_t ceildist = mo->ceilingz - mo->z; + fixed_t floordist = mo->Z() - mo->floorz; + fixed_t ceildist = mo->ceilingz - mo->Z(); if (floordist <= ceildist) { mo->FloorBounceMissile(mo->Sector->floorplane); @@ -2983,7 +3003,7 @@ bool FSlide::BounceWall(AActor *mo) return true; } - side = P_PointOnLineSide(mo->x, mo->y, line); + side = P_PointOnLineSide(mo->X(), mo->Y(), line); lineangle = R_PointToAngle2(0, 0, line->dx, line->dy); if (side == 1) { @@ -2998,11 +3018,14 @@ bool FSlide::BounceWall(AActor *mo) movelen = fixed_t(sqrt(double(mo->velx)*mo->velx + double(mo->vely)*mo->vely)); movelen = FixedMul(movelen, mo->wallbouncefactor); - FBoundingBox box(mo->x, mo->y, mo->radius); + FBoundingBox box(mo->X(), mo->Y(), mo->radius); if (box.BoxOnLineSide(line) == -1) { - mo->SetOrigin(mo->x + FixedMul(mo->radius, - finecosine[deltaangle]), mo->y + FixedMul(mo->radius, finesine[deltaangle]), mo->z); + fixedvec3 pos = mo->Vec3Offset( + FixedMul(mo->radius, finecosine[deltaangle]), + FixedMul(mo->radius, finesine[deltaangle]), 0); + mo->SetOrigin(pos, true); + } if (movelen < FRACUNIT) { @@ -3053,7 +3076,7 @@ bool P_BounceActor(AActor *mo, AActor *BlockingMobj, bool ontop) if (!ontop) { fixed_t speed; - angle_t angle = R_PointToAngle2(BlockingMobj->x,BlockingMobj->y, mo->x, mo->y) + ANGLE_1*((pr_bounce() % 16) - 8); + angle_t angle = BlockingMobj->AngleTo(mo) + ANGLE_1*((pr_bounce() % 16) - 8); speed = P_AproxDistance(mo->velx, mo->vely); speed = FixedMul(speed, mo->wallbouncefactor); // [GZ] was 0.75, using wallbouncefactor seems more consistent mo->angle = angle; @@ -3176,7 +3199,7 @@ bool aim_t::AimTraverse3DFloors(const divline_t &trace, intercept_t * in) fixed_t trY = trace.y + FixedMul(trace.dy, in->frac); fixed_t dist = FixedMul(attackrange, in->frac); - frontflag = P_PointOnLineSide(shootthing->x, shootthing->y, li); + frontflag = P_PointOnLineSide(shootthing->X(), shootthing->Y(), li); // 3D floor check. This is not 100% accurate but normally sufficient when // combined with a final sight check @@ -3348,7 +3371,7 @@ void aim_t::AimTraverse(fixed_t startx, fixed_t starty, fixed_t endx, fixed_t en { if (lastceilingplane) { - fixed_t ff_top = lastceilingplane->ZatPoint(th->x, th->y); + fixed_t ff_top = lastceilingplane->ZatPoint(th); fixed_t pitch = -(int)R_PointToAngle2(0, shootz, dist, ff_top); // upper slope intersects with this 3d-floor if (pitch > toppitch) @@ -3358,7 +3381,7 @@ void aim_t::AimTraverse(fixed_t startx, fixed_t starty, fixed_t endx, fixed_t en } if (lastfloorplane) { - fixed_t ff_bottom = lastfloorplane->ZatPoint(th->x, th->y); + fixed_t ff_bottom = lastfloorplane->ZatPoint(th); fixed_t pitch = -(int)R_PointToAngle2(0, shootz, dist, ff_bottom); // lower slope intersects with this 3d-floor if (pitch < bottompitch) @@ -3370,12 +3393,12 @@ void aim_t::AimTraverse(fixed_t startx, fixed_t starty, fixed_t endx, fixed_t en // check angles to see if the thing can be aimed at - thingtoppitch = -(int)R_PointToAngle2(0, shootz, dist, th->z + th->height); + thingtoppitch = -(int)R_PointToAngle2(0, shootz, dist, th->Z() + th->height); if (thingtoppitch > bottompitch) continue; // shot over the thing - thingbottompitch = -(int)R_PointToAngle2(0, shootz, dist, th->z); + thingbottompitch = -(int)R_PointToAngle2(0, shootz, dist, th->Z()); if (thingbottompitch < toppitch) continue; // shot under the thing @@ -3485,9 +3508,9 @@ fixed_t P_AimLineAttack(AActor *t1, angle_t angle, fixed_t distance, AActor **pL aim.shootthing = t1; aim.friender = (friender == NULL) ? t1 : friender; - x2 = t1->x + (distance >> FRACBITS)*finecosine[angle]; - y2 = t1->y + (distance >> FRACBITS)*finesine[angle]; - aim.shootz = t1->z + (t1->height >> 1) - t1->floorclip; + x2 = t1->X() + (distance >> FRACBITS)*finecosine[angle]; + y2 = t1->Y() + (distance >> FRACBITS)*finesine[angle]; + aim.shootz = t1->Z() + (t1->height >> 1) - t1->floorclip; if (t1->player != NULL) { aim.shootz += FixedMul(t1->player->mo->AttackZOffset, t1->player->crouchfactor); @@ -3542,15 +3565,15 @@ fixed_t P_AimLineAttack(AActor *t1, angle_t angle, fixed_t distance, AActor **pL for (unsigned i = 0; iSector->e->XFloor.ffloors.Size(); i++) { F3DFloor * rover = t1->Sector->e->XFloor.ffloors[i]; - fixed_t bottomz = rover->bottom.plane->ZatPoint(t1->x, t1->y); + fixed_t bottomz = rover->bottom.plane->ZatPoint(t1); - if (bottomz >= t1->z + t1->height) aim.lastceilingplane = rover->bottom.plane; + if (bottomz >= t1->Top()) aim.lastceilingplane = rover->bottom.plane; - bottomz = rover->top.plane->ZatPoint(t1->x, t1->y); - if (bottomz <= t1->z) aim.lastfloorplane = rover->top.plane; + bottomz = rover->top.plane->ZatPoint(t1); + if (bottomz <= t1->Z()) aim.lastfloorplane = rover->top.plane; } - aim.AimTraverse(t1->x, t1->y, x2, y2, target); + aim.AimTraverse(t1->X(), t1->Y(), x2, y2, target); if (!aim.linetarget) { @@ -3653,7 +3676,7 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, vy = FixedMul(finecosine[pitch], finesine[angle]); vz = -finesine[pitch]; - shootz = t1->z - t1->floorclip + (t1->height >> 1); + shootz = t1->Z() - t1->floorclip + (t1->height >> 1); if (t1->player != NULL) { shootz += FixedMul(t1->player->mo->AttackZOffset, t1->player->crouchfactor); @@ -3691,7 +3714,7 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, if (puffDefaults != NULL && puffDefaults->flags6 & MF6_NOTRIGGER) tflags = TRACE_NoSky; else tflags = TRACE_NoSky | TRACE_Impact; - if (!Trace(t1->x, t1->y, shootz, t1->Sector, vx, vy, vz, distance, + if (!Trace(t1->X(), t1->Y(), shootz, t1->Sector, vx, vy, vz, distance, MF_SHOOTABLE, ML_BLOCKEVERYTHING | ML_BLOCKHITSCAN, t1, trace, tflags, CheckForActor, &TData)) { // hit nothing @@ -3721,8 +3744,8 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, if (trace.HitType != TRACE_HitWall || trace.Line->special != Line_Horizon) { fixed_t closer = trace.Distance - 4 * FRACUNIT; - puff = P_SpawnPuff(t1, pufftype, t1->x + FixedMul(vx, closer), - t1->y + FixedMul(vy, closer), + fixedvec2 pos = t1->Vec2Offset(FixedMul(vx, closer), FixedMul(vy, closer)); + puff = P_SpawnPuff(t1, pufftype, pos.x, pos.y, shootz + FixedMul(vz, closer), angle - ANG90, 0, puffFlags); } @@ -3758,8 +3781,8 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, { // Using the puff's position is not accurate enough. // Instead make it splash at the actual hit position - hitx = t1->x + FixedMul(vx, trace.Distance); - hity = t1->y + FixedMul(vy, trace.Distance); + hitx = t1->X() + FixedMul(vx, trace.Distance); + hity = t1->Y() + FixedMul(vy, trace.Distance); hitz = shootz + FixedMul(vz, trace.Distance); P_HitWater(puff, P_PointInSector(hitx, hity), hitx, hity, hitz); } @@ -3778,8 +3801,8 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, fixed_t dist = trace.Distance; // position a bit closer for puffs/blood if using compatibility mode. if (i_compatflags & COMPATF_HITSCAN) dist -= 10 * FRACUNIT; - hitx = t1->x + FixedMul(vx, dist); - hity = t1->y + FixedMul(vy, dist); + hitx = t1->X() + FixedMul(vx, dist); + hity = t1->Y() + FixedMul(vy, dist); hitz = shootz + FixedMul(vz, dist); @@ -3920,7 +3943,7 @@ AActor *P_LinePickActor(AActor *t1, angle_t angle, fixed_t distance, int pitch, vy = FixedMul(finecosine[pitch], finesine[angle]); vz = -finesine[pitch]; - shootz = t1->z - t1->floorclip + (t1->height >> 1); + shootz = t1->Z() - t1->floorclip + (t1->height >> 1); if (t1->player != NULL) { shootz += FixedMul(t1->player->mo->AttackZOffset, t1->player->crouchfactor); @@ -3936,7 +3959,7 @@ AActor *P_LinePickActor(AActor *t1, angle_t angle, fixed_t distance, int pitch, TData.Caller = t1; TData.hitGhosts = true; - if (Trace(t1->x, t1->y, shootz, t1->Sector, vx, vy, vz, distance, + if (Trace(t1->X(), t1->Y(), shootz, t1->Sector, vx, vy, vz, distance, actorMask, wallMask, t1, trace, TRACE_NoSky, CheckForActor, &TData)) { if (trace.HitType == TRACE_HitActor) @@ -4040,7 +4063,7 @@ void P_TraceBleed(int damage, fixed_t x, fixed_t y, fixed_t z, AActor *actor, an void P_TraceBleed(int damage, AActor *target, angle_t angle, int pitch) { - P_TraceBleed(damage, target->x, target->y, target->z + target->height / 2, + P_TraceBleed(damage, target->X(), target->Y(), target->Z() + target->height / 2, target, angle, pitch); } @@ -4063,15 +4086,15 @@ void P_TraceBleed(int damage, AActor *target, AActor *missile) { double aim; - aim = atan((double)missile->velz / (double)P_AproxDistance(missile->x - target->x, missile->y - target->y)); + aim = atan((double)missile->velz / (double)target->AproxDistance(missile)); pitch = -(int)(aim * ANGLE_180 / PI); } else { pitch = 0; } - P_TraceBleed(damage, target->x, target->y, target->z + target->height / 2, - target, R_PointToAngle2(missile->x, missile->y, target->x, target->y), + P_TraceBleed(damage, target->X(), target->Y(), target->Z() + target->height / 2, + target, missile->AngleTo(target), pitch); } @@ -4088,7 +4111,7 @@ void P_TraceBleed(int damage, AActor *target) fixed_t one = pr_tracebleed() << 24; fixed_t two = (pr_tracebleed() - 128) << 16; - P_TraceBleed(damage, target->x, target->y, target->z + target->height / 2, + P_TraceBleed(damage, target->X(), target->Y(), target->Z() + target->height / 2, target, one, two); } } @@ -4151,7 +4174,6 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i { fixed_t vx, vy, vz; angle_t angle, pitch; - fixed_t x1, y1; TVector3 start, end; FTraceResults trace; fixed_t shootz; @@ -4165,10 +4187,7 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i vy = FixedMul(finecosine[pitch], finesine[angle]); vz = finesine[pitch]; - x1 = source->x; - y1 = source->y; - - shootz = source->z - source->floorclip + (source->height >> 1) + offset_z; + shootz = source->Z() - source->floorclip + (source->height >> 1) + offset_z; if (!(railflags & RAF_CENTERZ)) { @@ -4183,15 +4202,15 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i } angle = ((source->angle + angleoffset) - ANG90) >> ANGLETOFINESHIFT; - x1 += offset_xy * finecosine[angle]; - y1 += offset_xy * finesine[angle]; + + fixedvec2 xy = source->Vec2Offset(offset_xy * finecosine[angle], offset_xy * finesine[angle]); RailData rail_data; rail_data.Caller = source; rail_data.StopAtOne = !!(railflags & RAF_NOPIERCE); - start.X = FIXED2FLOAT(x1); - start.Y = FIXED2FLOAT(y1); + start.X = FIXED2FLOAT(xy.x); + start.Y = FIXED2FLOAT(xy.y); start.Z = FIXED2FLOAT(shootz); int flags; @@ -4202,7 +4221,7 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i flags = (puffDefaults->flags6 & MF6_NOTRIGGER) ? 0 : TRACE_PCross | TRACE_Impact; rail_data.StopAtInvul = (puffDefaults->flags3 & MF3_FOILINVUL) ? false : true; rail_data.ThruSpecies = (puffDefaults->flags6 & MF6_MTHRUSPECIES) ? true : false; - Trace(x1, y1, shootz, source->Sector, vx, vy, vz, + Trace(xy.x, xy.y, shootz, source->Sector, vx, vy, vz, distance, MF_SHOOTABLE, ML_BLOCKEVERYTHING, source, trace, flags, ProcessRailHit, &rail_data); @@ -4213,7 +4232,7 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i // used as damage inflictor AActor *thepuff = NULL; - if (puffclass != NULL) thepuff = Spawn(puffclass, source->x, source->y, source->z, ALLOW_REPLACE); + if (puffclass != NULL) thepuff = Spawn(puffclass, source->Pos(), ALLOW_REPLACE); for (i = 0; i < rail_data.RailHits.Size(); i++) { @@ -4227,8 +4246,8 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i AActor *hitactor = rail_data.RailHits[i].HitActor; fixed_t hitdist = rail_data.RailHits[i].Distance; - x = x1 + FixedMul(hitdist, vx); - y = y1 + FixedMul(hitdist, vy); + x = xy.x + FixedMul(hitdist, vx); + y = xy.y + FixedMul(hitdist, vy); z = shootz + FixedMul(hitdist, vz); if ((hitactor->flags & MF_NOBLOOD) || @@ -4277,6 +4296,8 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i if (puffclass != NULL && puffDefaults->flags3 & MF3_ALWAYSPUFF) { puff = P_SpawnPuff(source, puffclass, trace.X, trace.Y, trace.Z, (source->angle + angleoffset) - ANG90, 1, 0); + if (puff && (trace.Line != NULL) && (trace.Line->special == Line_Horizon) && !(puff->flags3 & MF3_SKYEXPLODE)) + puff->Destroy(); } if (puff != NULL && puffDefaults->flags7 & MF7_FORCEDECAL && puff->DecalGenerator) SpawnShootDecal(puff, trace); @@ -4284,13 +4305,27 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i SpawnShootDecal(source, trace); } + if (trace.HitType == TRACE_HitFloor || trace.HitType == TRACE_HitCeiling) + { + AActor* puff = NULL; + if (puffclass != NULL && puffDefaults->flags3 & MF3_ALWAYSPUFF) + { + puff = P_SpawnPuff(source, puffclass, trace.X, trace.Y, trace.Z, (source->angle + angleoffset) - ANG90, 1, 0); + if (puff && !(puff->flags3 & MF3_SKYEXPLODE) && + (((trace.HitType == TRACE_HitFloor) && (puff->floorpic == skyflatnum)) || + ((trace.HitType == TRACE_HitCeiling) && (puff->ceilingpic == skyflatnum)))) + { + puff->Destroy(); + } + } + } if (thepuff != NULL) { if (trace.HitType == TRACE_HitFloor && trace.CrossedWater == NULL && trace.Sector->heightsec == NULL) { - thepuff->SetOrigin(trace.X, trace.Y, trace.Z); + thepuff->SetOrigin(trace.X, trace.Y, trace.Z, false); P_HitWater(thepuff, trace.Sector); } if (trace.Crossed3DWater || trace.CrossedWater) @@ -4328,16 +4363,16 @@ void P_AimCamera(AActor *t1, fixed_t &CameraX, fixed_t &CameraY, fixed_t &Camera vy = FixedMul(finecosine[pitch], finesine[angle]); vz = finesine[pitch]; - sz = t1->z - t1->floorclip + t1->height + (fixed_t)(clamp(chase_height, -1000, 1000) * FRACUNIT); + sz = t1->Z() - t1->floorclip + t1->height + (fixed_t)(clamp(chase_height, -1000, 1000) * FRACUNIT); - if (Trace(t1->x, t1->y, sz, t1->Sector, + if (Trace(t1->X(), t1->Y(), sz, t1->Sector, vx, vy, vz, distance, 0, 0, NULL, trace) && trace.Distance > 10 * FRACUNIT) { // Position camera slightly in front of hit thing fixed_t dist = trace.Distance - 5 * FRACUNIT; - CameraX = t1->x + FixedMul(vx, dist); - CameraY = t1->y + FixedMul(vy, dist); + CameraX = t1->X() + FixedMul(vx, dist); + CameraY = t1->Y() + FixedMul(vy, dist); CameraZ = sz + FixedMul(vz, dist); } else @@ -4404,7 +4439,7 @@ bool P_TalkFacing(AActor *player) bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline) { - FPathTraverse it(usething->x, usething->y, endx, endy, PT_ADDLINES | PT_ADDTHINGS); + FPathTraverse it(usething->X(), usething->Y(), endx, endy, PT_ADDLINES | PT_ADDTHINGS); intercept_t *in; while ((in = it.Next())) @@ -4453,7 +4488,7 @@ bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline return true; } - sec = P_PointOnLineSide(usething->x, usething->y, in->d.line) == 0 ? + sec = P_PointOnLineSide(usething->X(), usething->Y(), in->d.line) == 0 ? in->d.line->frontsector : in->d.line->backsector; if (sec != NULL && sec->SecActTarget && @@ -4472,7 +4507,7 @@ bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline continue; // not a special line, but keep checking } - if (P_PointOnLineSide(usething->x, usething->y, in->d.line) == 1) + if (P_PointOnLineSide(usething->X(), usething->Y(), in->d.line) == 1) { if (!(in->d.line->activation & SPAC_UseBack)) { @@ -4532,7 +4567,7 @@ bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline bool P_NoWayTraverse(AActor *usething, fixed_t endx, fixed_t endy) { - FPathTraverse it(usething->x, usething->y, endx, endy, PT_ADDLINES); + FPathTraverse it(usething->X(), usething->Y(), endx, endy, PT_ADDLINES); intercept_t *in; while ((in = it.Next())) @@ -4547,8 +4582,8 @@ bool P_NoWayTraverse(AActor *usething, fixed_t endx, fixed_t endy) P_LineOpening(open, NULL, ld, it.Trace().x + FixedMul(it.Trace().dx, in->frac), it.Trace().y + FixedMul(it.Trace().dy, in->frac)); if (open.range <= 0 || - open.bottom > usething->z + usething->MaxStepHeight || - open.top < usething->z + usething->height) return true; + open.bottom > usething->Z() + usething->MaxStepHeight || + open.top < usething->Top()) return true; } return false; } @@ -4563,18 +4598,10 @@ bool P_NoWayTraverse(AActor *usething, fixed_t endx, fixed_t endy) void P_UseLines(player_t *player) { - angle_t angle; - fixed_t x1, y1, usedist; - bool foundline; - - foundline = false; - - angle = player->mo->angle >> ANGLETOFINESHIFT; - usedist = player->mo->UseRange; + bool foundline = false; // [NS] Now queries the Player's UseRange. - x1 = player->mo->x + FixedMul(usedist, finecosine[angle]); - y1 = player->mo->y + FixedMul(usedist, finesine[angle]); + fixedvec2 end = player->mo->Vec2Angle(player->mo->UseRange, player->mo->angle, true); // old code: // @@ -4582,13 +4609,13 @@ void P_UseLines(player_t *player) // // This added test makes the "oof" sound work on 2s lines -- killough: - if (!P_UseTraverse(player->mo, x1, y1, foundline)) + if (!P_UseTraverse(player->mo, end.x, end.y, foundline)) { // [RH] Give sector a chance to eat the use sector_t *sec = player->mo->Sector; int spac = SECSPAC_Use; if (foundline) spac |= SECSPAC_UseWall; if ((!sec->SecActTarget || !sec->SecActTarget->TriggerAction(player->mo, spac)) && - P_NoWayTraverse(player->mo, x1, y1)) + P_NoWayTraverse(player->mo, end.x, end.y)) { S_Sound(player->mo, CHAN_VOICE, "*usefail", 1, ATTN_IDLE); } @@ -4609,8 +4636,8 @@ bool P_UsePuzzleItem(AActor *PuzzleItemUser, int PuzzleItemType) fixed_t x1, y1, x2, y2, usedist; angle = PuzzleItemUser->angle >> ANGLETOFINESHIFT; - x1 = PuzzleItemUser->x; - y1 = PuzzleItemUser->y; + x1 = PuzzleItemUser->X(); + y1 = PuzzleItemUser->Y(); // [NS] If it's a Player, get their UseRange. if (PuzzleItemUser->player) @@ -4641,7 +4668,7 @@ bool P_UsePuzzleItem(AActor *PuzzleItemUser, int PuzzleItemType) } continue; } - if (P_PointOnLineSide(PuzzleItemUser->x, PuzzleItemUser->y, in->d.line) == 1) + if (P_PointOnLineSide(PuzzleItemUser->X(), PuzzleItemUser->Y(), in->d.line) == 1) { // Don't use back sides return false; } @@ -4708,7 +4735,7 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo double bombdistancefloat = 1.f / (double)(bombdistance - fulldamagedistance); double bombdamagefloat = (double)bombdamage; - FBlockThingsIterator it(FBoundingBox(bombspot->x, bombspot->y, bombdistance << FRACBITS)); + FBlockThingsIterator it(FBoundingBox(bombspot->X(), bombspot->Y(), bombdistance << FRACBITS)); AActor *thing; if (flags & RADF_SOURCEISSPOT) @@ -4757,24 +4784,25 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo fixed_t dx, dy; double boxradius; - dx = abs(thing->x - bombspot->x); - dy = abs(thing->y - bombspot->y); + fixedvec2 vec = bombspot->Vec2To(thing); + dx = abs(vec.x); + dy = abs(vec.y); boxradius = double(thing->radius); // The damage pattern is square, not circular. len = double(dx > dy ? dx : dy); - if (bombspot->z < thing->z || bombspot->z >= thing->z + thing->height) + if (bombspot->Z() < thing->Z() || bombspot->Z() >= thing->Top()) { double dz; - if (bombspot->z > thing->z) + if (bombspot->Z() > thing->Z()) { - dz = double(bombspot->z - thing->z - thing->height); + dz = double(bombspot->Z() - thing->Top()); } else { - dz = double(thing->z - bombspot->z); + dz = double(thing->Z() - bombspot->Z()); } if (len <= boxradius) { @@ -4831,7 +4859,7 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo { thrust *= selfthrustscale; } - velz = (double)(thing->z + (thing->height >> 1) - bombspot->z) * thrust; + velz = (double)(thing->Z() + (thing->height >> 1) - bombspot->Z()) * thrust; if (bombsource != thing) { velz *= 0.5f; @@ -4840,7 +4868,7 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo { velz *= 0.8f; } - angle_t ang = R_PointToAngle2(bombspot->x, bombspot->y, thing->x, thing->y) >> ANGLETOFINESHIFT; + angle_t ang = bombspot->AngleTo(thing) >> ANGLETOFINESHIFT; thing->velx += fixed_t(finecosine[ang] * thrust); thing->vely += fixed_t(finesine[ang] * thrust); if (!(flags & RADF_NODAMAGE)) @@ -4856,8 +4884,9 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo // [RH] Old code just for barrels fixed_t dx, dy, dist; - dx = abs(thing->x - bombspot->x); - dy = abs(thing->y - bombspot->y); + fixedvec2 vec = bombspot->Vec2To(thing); + dx = abs(vec.x); + dy = abs(vec.y); dist = dx>dy ? dx : dy; dist = (dist - thing->radius) >> FRACBITS; @@ -4944,11 +4973,12 @@ bool P_AdjustFloorCeil(AActor *thing, FChangePosition *cpos) thing->flags2 |= MF2_PASSMOBJ; } - bool isgood = P_CheckPosition(thing, thing->x, thing->y, tm); + bool isgood = P_CheckPosition(thing, thing->X(), thing->Y(), tm); thing->floorz = tm.floorz; thing->ceilingz = tm.ceilingz; thing->dropoffz = tm.dropoffz; // killough 11/98: remember dropoffs thing->floorpic = tm.floorpic; + thing->floorterrain = tm.floorterrain; thing->floorsector = tm.floorsector; thing->ceilingpic = tm.ceilingpic; thing->ceilingsector = tm.ceilingsector; @@ -4974,7 +5004,7 @@ void P_FindAboveIntersectors(AActor *actor) return; AActor *thing; - FBlockThingsIterator it(FBoundingBox(actor->x, actor->y, actor->radius)); + FBlockThingsIterator it(FBoundingBox(actor->X(), actor->Y(), actor->radius)); while ((thing = it.Next())) { if (!thing->intersects(actor)) @@ -5005,8 +5035,8 @@ void P_FindAboveIntersectors(AActor *actor) // not what is wanted here. continue; } - if (thing->z >= actor->z && - thing->z <= actor->z + actor->height) + if (thing->Z() >= actor->Z() && + thing->Z() <= actor->Top()) { // Thing intersects above the base intersectors.Push(thing); } @@ -5028,7 +5058,7 @@ void P_FindBelowIntersectors(AActor *actor) return; AActor *thing; - FBlockThingsIterator it(FBoundingBox(actor->x, actor->y, actor->radius)); + FBlockThingsIterator it(FBoundingBox(actor->X(), actor->Y(), actor->radius)); while ((thing = it.Next())) { if (!thing->intersects(actor)) @@ -5059,8 +5089,8 @@ void P_FindBelowIntersectors(AActor *actor) // not what is wanted here. continue; } - if (thing->z + thing->height <= actor->z + actor->height && - thing->z + thing->height > actor->z) + if (thing->Top() <= actor->Top() && + thing->Top() > actor->Z()) { // Thing intersects below the base intersectors.Push(thing); } @@ -5096,8 +5126,7 @@ void P_DoCrunch(AActor *thing, FChangePosition *cpos) { AActor *mo; - mo = Spawn(bloodcls, thing->x, thing->y, - thing->z + thing->height / 2, ALLOW_REPLACE); + mo = Spawn(bloodcls, thing->PosPlusZ(thing->height / 2), ALLOW_REPLACE); mo->velx = pr_crunch.Random2() << 12; mo->vely = pr_crunch.Random2() << 12; @@ -5113,7 +5142,7 @@ void P_DoCrunch(AActor *thing, FChangePosition *cpos) an = (M_Random() - 128) << 24; if (cl_bloodtype >= 1) { - P_DrawSplash2(32, thing->x, thing->y, thing->z + thing->height / 2, an, 2, bloodcolor); + P_DrawSplash2(32, thing->X(), thing->Y(), thing->Z() + thing->height / 2, an, 2, bloodcolor); } } if (thing->CrushPainSound != 0 && !S_GetSoundPlayingInfo(thing, thing->CrushPainSound)) @@ -5141,7 +5170,7 @@ int P_PushUp(AActor *thing, FChangePosition *cpos) unsigned int lastintersect; int mymass = thing->Mass; - if (thing->z + thing->height > thing->ceilingz) + if (thing->Top() > thing->ceilingz) { return 1; } @@ -5170,13 +5199,13 @@ int P_PushUp(AActor *thing, FChangePosition *cpos) return 2; } fixed_t oldz; - oldz = intersect->z; + oldz = intersect->Z(); P_AdjustFloorCeil(intersect, cpos); - intersect->z = thing->z + thing->height + 1; + intersect->SetZ(thing->Top() + 1); if (P_PushUp(intersect, cpos)) { // Move blocked P_DoCrunch(intersect, cpos); - intersect->z = oldz; + intersect->SetZ(oldz); return 2; } } @@ -5197,7 +5226,7 @@ int P_PushDown(AActor *thing, FChangePosition *cpos) unsigned int lastintersect; int mymass = thing->Mass; - if (thing->z <= thing->floorz) + if (thing->Z() <= thing->floorz) { return 1; } @@ -5214,15 +5243,15 @@ int P_PushDown(AActor *thing, FChangePosition *cpos) // Can't push bridges or things more massive than ourself return 2; } - fixed_t oldz = intersect->z; + fixed_t oldz = intersect->Z(); P_AdjustFloorCeil(intersect, cpos); - if (oldz > thing->z - intersect->height) + if (oldz > thing->Z() - intersect->height) { // Only push things down, not up. - intersect->z = thing->z - intersect->height; + intersect->SetZ(thing->Z() - intersect->height); if (P_PushDown(intersect, cpos)) { // Move blocked P_DoCrunch(intersect, cpos); - intersect->z = oldz; + intersect->SetZ(oldz); return 2; } } @@ -5247,24 +5276,24 @@ void PIT_FloorDrop(AActor *thing, FChangePosition *cpos) if (thing->velz == 0 && (!(thing->flags & MF_NOGRAVITY) || - (thing->z == oldfloorz && !(thing->flags & MF_NOLIFTDROP)))) + (thing->Z() == oldfloorz && !(thing->flags & MF_NOLIFTDROP)))) { - fixed_t oldz = thing->z; + fixed_t oldz = thing->Z(); if ((thing->flags & MF_NOGRAVITY) || (thing->flags5 & MF5_MOVEWITHSECTOR) || (((cpos->sector->Flags & SECF_FLOORDROP) || cpos->moveamt < 9 * FRACUNIT) - && thing->z - thing->floorz <= cpos->moveamt)) + && thing->Z() - thing->floorz <= cpos->moveamt)) { - thing->z = thing->floorz; + thing->SetZ(thing->floorz); P_CheckFakeFloorTriggers(thing, oldz); } } - else if ((thing->z != oldfloorz && !(thing->flags & MF_NOLIFTDROP))) + else if ((thing->Z() != oldfloorz && !(thing->flags & MF_NOLIFTDROP))) { - fixed_t oldz = thing->z; + fixed_t oldz = thing->Z(); if ((thing->flags & MF_NOGRAVITY) && (thing->flags6 & MF6_RELATIVETOFLOOR)) { - thing->z = thing->z - oldfloorz + thing->floorz; + thing->AddZ(-oldfloorz + thing->floorz); P_CheckFakeFloorTriggers(thing, oldz); } } @@ -5279,14 +5308,14 @@ void PIT_FloorDrop(AActor *thing, FChangePosition *cpos) void PIT_FloorRaise(AActor *thing, FChangePosition *cpos) { fixed_t oldfloorz = thing->floorz; - fixed_t oldz = thing->z; + fixed_t oldz = thing->Z(); P_AdjustFloorCeil(thing, cpos); if (oldfloorz == thing->floorz) return; // Move things intersecting the floor up - if (thing->z <= thing->floorz) + if (thing->Z() <= thing->floorz) { if (thing->flags4 & MF4_ACTLIKEBRIDGE) { @@ -5294,14 +5323,14 @@ void PIT_FloorRaise(AActor *thing, FChangePosition *cpos) return; // do not move bridge things } intersectors.Clear(); - thing->z = thing->floorz; + thing->SetZ(thing->floorz); } else { if ((thing->flags & MF_NOGRAVITY) && (thing->flags6 & MF6_RELATIVETOFLOOR)) { intersectors.Clear(); - thing->z = thing->z - oldfloorz + thing->floorz; + thing->AddZ(-oldfloorz + thing->floorz); } else return; } @@ -5316,7 +5345,7 @@ void PIT_FloorRaise(AActor *thing, FChangePosition *cpos) break; case 2: P_DoCrunch(thing, cpos); - thing->z = oldz; + thing->SetZ(oldz); break; } } @@ -5331,10 +5360,10 @@ void PIT_CeilingLower(AActor *thing, FChangePosition *cpos) { bool onfloor; - onfloor = thing->z <= thing->floorz; + onfloor = thing->Z() <= thing->floorz; P_AdjustFloorCeil(thing, cpos); - if (thing->z + thing->height > thing->ceilingz) + if (thing->Top() > thing->ceilingz) { if (thing->flags4 & MF4_ACTLIKEBRIDGE) { @@ -5342,14 +5371,14 @@ void PIT_CeilingLower(AActor *thing, FChangePosition *cpos) return; // do not move bridge things } intersectors.Clear(); - fixed_t oldz = thing->z; + fixed_t oldz = thing->Z(); if (thing->ceilingz - thing->height >= thing->floorz) { - thing->z = thing->ceilingz - thing->height; + thing->SetZ(thing->ceilingz - thing->height); } else { - thing->z = thing->floorz; + thing->SetZ(thing->floorz); } switch (P_PushDown(thing, cpos)) { @@ -5357,7 +5386,7 @@ void PIT_CeilingLower(AActor *thing, FChangePosition *cpos) // intentional fall-through case 1: if (onfloor) - thing->z = thing->floorz; + thing->SetZ(thing->floorz); P_DoCrunch(thing, cpos); P_CheckFakeFloorTriggers(thing, oldz); break; @@ -5383,25 +5412,24 @@ void PIT_CeilingRaise(AActor *thing, FChangePosition *cpos) // For DOOM compatibility, only move things that are inside the floor. // (or something else?) Things marked as hanging from the ceiling will // stay where they are. - if (thing->z < thing->floorz && - thing->z + thing->height >= thing->ceilingz - cpos->moveamt && + if (thing->Z() < thing->floorz && + thing->Top() >= thing->ceilingz - cpos->moveamt && !(thing->flags & MF_NOLIFTDROP)) { - fixed_t oldz = thing->z; - thing->z = thing->floorz; - if (thing->z + thing->height > thing->ceilingz) + fixed_t oldz = thing->Z(); + thing->SetZ(thing->floorz); + if (thing->Top() > thing->ceilingz) { - thing->z = thing->ceilingz - thing->height; + thing->SetZ(thing->ceilingz - thing->height); } P_CheckFakeFloorTriggers(thing, oldz); } - else if ((thing->flags2 & MF2_PASSMOBJ) && !isgood && thing->z + thing->height < thing->ceilingz) + else if ((thing->flags2 & MF2_PASSMOBJ) && !isgood && thing->Top() < thing->ceilingz) { AActor *onmobj; - if (!P_TestMobjZ(thing, true, &onmobj) && onmobj->z <= thing->z) + if (!P_TestMobjZ(thing, true, &onmobj) && onmobj->Z() <= thing->Z()) { - thing->z = MIN(thing->ceilingz - thing->height, - onmobj->z + onmobj->height); + thing->SetZ( MIN(thing->ceilingz - thing->height, onmobj->Top())); } } } @@ -5558,8 +5586,8 @@ bool P_ChangeSector(sector_t *sector, int crunch, int amt, int floorOrCeil, bool { n->visited = true; // mark thing as processed - n->m_thing->UpdateWaterLevel(n->m_thing->z, false); - P_CheckFakeFloorTriggers(n->m_thing, n->m_thing->z - amt); + n->m_thing->UpdateWaterLevel(n->m_thing->Z(), false); + P_CheckFakeFloorTriggers(n->m_thing, n->m_thing->Z() - amt); } } } while (n); // repeat from scratch until all things left are marked valid @@ -5779,7 +5807,7 @@ void P_CreateSecNodeList(AActor *thing, fixed_t x, fixed_t y) node = node->m_tnext; } - FBoundingBox box(thing->x, thing->y, thing->radius); + FBoundingBox box(thing->X(), thing->Y(), thing->radius); FBlockLinesIterator it(box); line_t *ld; @@ -5882,13 +5910,13 @@ static void SpawnDeepSplash(AActor *t1, const FTraceResults &trace, AActor *puff den = TMulScale16(plane->a, vx, plane->b, vy, plane->c, vz); if (den != 0) { - num = TMulScale16(plane->a, t1->x, plane->b, t1->y, plane->c, shootz) + plane->d; + num = TMulScale16(plane->a, t1->X(), plane->b, t1->Y(), plane->c, shootz) + plane->d; hitdist = FixedDiv(-num, den); if (hitdist >= 0 && hitdist <= trace.Distance) { - fixed_t hitx = t1->x + FixedMul(vx, hitdist); - fixed_t hity = t1->y + FixedMul(vy, hitdist); + fixed_t hitx = t1->X() + FixedMul(vx, hitdist); + fixed_t hity = t1->Y() + FixedMul(vy, hitdist); fixed_t hitz = shootz + FixedMul(vz, hitdist); P_HitWater(puff != NULL ? puff : t1, P_PointInSector(hitx, hity), hitx, hity, hitz); diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 0a39460e7..07ce97cca 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -194,6 +194,7 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef, open.bottom = ff; open.bottomsec = front; open.floorpic = front->GetTexture(sector_t::floor); + open.floorterrain = front->GetTerrain(sector_t::floor); open.lowfloor = bf; } else @@ -201,6 +202,7 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef, open.bottom = bf; open.bottomsec = back; open.floorpic = back->GetTexture(sector_t::floor); + open.floorterrain = back->GetTerrain(sector_t::floor); open.lowfloor = ff; } } @@ -211,6 +213,7 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef, open.top = FIXED_MAX; open.bottomsec = NULL; open.floorpic.SetInvalid(); + open.floorterrain = -1; open.bottom = FIXED_MIN; open.lowfloor = FIXED_MAX; } @@ -323,7 +326,7 @@ void AActor::LinkToWorld (bool buggy) if (!buggy || numgamenodes == 0) { - sec = P_PointInSector (x, y); + sec = P_PointInSector (X(), Y()); } else { @@ -341,7 +344,7 @@ void AActor::LinkToWorld (sector_t *sec) return; } Sector = sec; - subsector = R_PointInSubsector(x, y); // this is from the rendering nodes, not the gameplay nodes! + subsector = R_PointInSubsector(X(), Y()); // this is from the rendering nodes, not the gameplay nodes! if ( !(flags & MF_NOSECTOR) ) { @@ -368,7 +371,7 @@ void AActor::LinkToWorld (sector_t *sec) // When a node is deleted, its sector links (the links starting // at sector_t->touching_thinglist) are broken. When a node is // added, new sector links are created. - P_CreateSecNodeList (this, x, y); + P_CreateSecNodeList (this, X(), Y()); touching_sectorlist = sector_list; // Attach to thing sector_list = NULL; // clear for next time } @@ -377,10 +380,10 @@ void AActor::LinkToWorld (sector_t *sec) // link into blockmap (inert things don't need to be in the blockmap) if ( !(flags & MF_NOBLOCKMAP) ) { - int x1 = GetSafeBlockX(x - radius - bmaporgx); - int x2 = GetSafeBlockX(x + radius - bmaporgx); - int y1 = GetSafeBlockY(y - radius - bmaporgy); - int y2 = GetSafeBlockY(y + radius - bmaporgy); + int x1 = GetSafeBlockX(X() - radius - bmaporgx); + int x2 = GetSafeBlockX(X() + radius - bmaporgx); + int y1 = GetSafeBlockY(Y() - radius - bmaporgy); + int y2 = GetSafeBlockY(Y() + radius - bmaporgy); if (x1 >= bmapwidth || x2 < 0 || y1 >= bmapheight || y2 < 0) { // thing is off the map @@ -493,7 +496,7 @@ sector_t *AActor::LinkToWorldForMapThing () // that lies directly on a line should always be // considered as "in front" of the line. The orientation // of the line should be irrelevant. - node = (node_t *)node->children[R_PointOnSideSlow (x, y, node)]; + node = (node_t *)node->children[R_PointOnSideSlow (X(), Y(), node)]; } while (!((size_t)node & 1)); @@ -507,8 +510,8 @@ sector_t *AActor::LinkToWorldForMapThing () // one-sided line might go into a subsector behind the line, so // the line would not be included as one of its subsector's segs. - int blockx = GetSafeBlockX(x - bmaporgx); - int blocky = GetSafeBlockY(y - bmaporgy); + int blockx = GetSafeBlockX(X() - bmaporgx); + int blocky = GetSafeBlockY(Y() - bmaporgy); if ((unsigned int)blockx < (unsigned int)bmapwidth && (unsigned int)blocky < (unsigned int)bmapheight) @@ -533,10 +536,10 @@ sector_t *AActor::LinkToWorldForMapThing () } // Not inside the line's bounding box - if (x + radius <= ldef->bbox[BOXLEFT] - || x - radius >= ldef->bbox[BOXRIGHT] - || y + radius <= ldef->bbox[BOXBOTTOM] - || y - radius >= ldef->bbox[BOXTOP] ) + if (X() + radius <= ldef->bbox[BOXLEFT] + || X() - radius >= ldef->bbox[BOXRIGHT] + || Y() + radius <= ldef->bbox[BOXBOTTOM] + || Y() - radius >= ldef->bbox[BOXTOP] ) continue; // Get the exact distance to the line @@ -545,8 +548,8 @@ sector_t *AActor::LinkToWorldForMapThing () P_MakeDivline (ldef, &dll); - dlv.x = x; - dlv.y = y; + dlv.x = X(); + dlv.y = Y(); dlv.dx = FixedDiv(dll.dy, linelen); dlv.dy = -FixedDiv(dll.dx, linelen); @@ -555,7 +558,7 @@ sector_t *AActor::LinkToWorldForMapThing () if (distance < radius) { DPrintf ("%s at (%d,%d) lies on %s line %td, distance = %f\n", - this->GetClass()->TypeName.GetChars(), x>>FRACBITS, y>>FRACBITS, + this->GetClass()->TypeName.GetChars(), X()>>FRACBITS, Y()>>FRACBITS, ldef->dx == 0? "vertical" : ldef->dy == 0? "horizontal" : "diagonal", ldef-lines, FIXED2FLOAT(distance)); angle_t finean = R_PointToAngle2 (0, 0, ldef->dx, ldef->dy); @@ -571,9 +574,8 @@ sector_t *AActor::LinkToWorldForMapThing () // Get the distance we have to move the object away from the wall distance = radius - distance; - x += FixedMul(distance, finecosine[finean]); - y += FixedMul(distance, finesine[finean]); - return P_PointInSector (x, y); + SetXY(X() + FixedMul(distance, finecosine[finean]), Y() + FixedMul(distance, finesine[finean])); + return P_PointInSector (X(), Y()); } } } @@ -582,12 +584,11 @@ sector_t *AActor::LinkToWorldForMapThing () return ssec->sector; } -void AActor::SetOrigin (fixed_t ix, fixed_t iy, fixed_t iz) +void AActor::SetOrigin (fixed_t ix, fixed_t iy, fixed_t iz, bool moving) { UnlinkFromWorld (); - x = ix; - y = iy; - z = iz; + SetXYZ(ix, iy, iz); + if (moving) SetMovement(ix - X(), iy - Y(), iz - Z()); LinkToWorld (); floorz = Sector->floorplane.ZatPoint (ix, iy); ceilingz = Sector->ceilingplane.ZatPoint (ix, iy); @@ -875,8 +876,8 @@ AActor *FBlockThingsIterator::Next(bool centeronly) fixed_t blocktop = blockbottom + MAPBLOCKSIZE; // only return actors with the center in this block - if (me->x >= blockleft && me->x < blockright && - me->y >= blockbottom && me->y < blocktop) + if (me->X() >= blockleft && me->X() < blockright && + me->Y() >= blockbottom && me->Y() < blocktop) { return me; } @@ -982,7 +983,7 @@ void FPathTraverse::AddLineIntercepts(int bx, int by) P_MakeDivline (ld, &dl); frac = P_InterceptVector (&trace, &dl); - if (frac < 0) continue; // behind source + if (frac < 0 || frac > FRACUNIT) continue; // behind source or beyond end point intercept_t newintercept; @@ -1025,41 +1026,41 @@ void FPathTraverse::AddThingIntercepts (int bx, int by, FBlockThingsIterator &it switch (i) { case 0: // Top edge - line.x = thing->x + thing->radius; - line.y = thing->y + thing->radius; + line.x = thing->X() + thing->radius; + line.y = thing->Y() + thing->radius; line.dx = -thing->radius * 2; line.dy = 0; break; case 1: // Right edge - line.x = thing->x + thing->radius; - line.y = thing->y - thing->radius; + line.x = thing->X() + thing->radius; + line.y = thing->Y() - thing->radius; line.dx = 0; line.dy = thing->radius * 2; break; case 2: // Bottom edge - line.x = thing->x - thing->radius; - line.y = thing->y - thing->radius; + line.x = thing->X() - thing->radius; + line.y = thing->Y() - thing->radius; line.dx = thing->radius * 2; line.dy = 0; break; case 3: // Left edge - line.x = thing->x - thing->radius; - line.y = thing->y + thing->radius; + line.x = thing->X() - thing->radius; + line.y = thing->Y() + thing->radius; line.dx = 0; line.dy = thing->radius * -2; break; } // Check if this side is facing the trace origin - if (P_PointOnDivlineSide (trace.x, trace.y, &line) == 0) + if (P_PointOnDivlineSidePrecise (trace.x, trace.y, &line) == 0) { numfronts++; // If it is, see if the trace crosses it - if (P_PointOnDivlineSide (line.x, line.y, &trace) != - P_PointOnDivlineSide (line.x + line.dx, line.y + line.dy, &trace)) + if (P_PointOnDivlineSidePrecise (line.x, line.y, &trace) != + P_PointOnDivlineSidePrecise (line.x + line.dx, line.y + line.dy, &trace)) { // It's a hit fixed_t frac = P_InterceptVector (&trace, &line); @@ -1104,19 +1105,19 @@ void FPathTraverse::AddThingIntercepts (int bx, int by, FBlockThingsIterator &it // check a corner to corner crossection for hit if (tracepositive) { - x1 = thing->x - thing->radius; - y1 = thing->y + thing->radius; + x1 = thing->X() - thing->radius; + y1 = thing->Y() + thing->radius; - x2 = thing->x + thing->radius; - y2 = thing->y - thing->radius; + x2 = thing->X() + thing->radius; + y2 = thing->Y() - thing->radius; } else { - x1 = thing->x - thing->radius; - y1 = thing->y - thing->radius; + x1 = thing->X() - thing->radius; + y1 = thing->Y() - thing->radius; - x2 = thing->x + thing->radius; - y2 = thing->y + thing->radius; + x2 = thing->X() + thing->radius; + y2 = thing->Y() + thing->radius; } s1 = P_PointOnDivlineSide (x1, y1, &trace); @@ -1167,7 +1168,7 @@ intercept_t *FPathTraverse::Next() } } - if (dist > maxfrac || in == NULL) return NULL; // checked everything in range + if (dist > FRACUNIT || in == NULL) return NULL; // checked everything in range in->done = true; return in; } @@ -1385,7 +1386,6 @@ FPathTraverse::FPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, in break; } } - maxfrac = FRACUNIT; } FPathTraverse::~FPathTraverse() @@ -1420,8 +1420,8 @@ AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, in int count; AActor *target; - startX = GetSafeBlockX(mo->x-bmaporgx); - startY = GetSafeBlockY(mo->y-bmaporgy); + startX = GetSafeBlockX(mo->X()-bmaporgx); + startY = GetSafeBlockY(mo->Y()-bmaporgy); validcount++; if (startX >= 0 && startX < bmapwidth && startY >= 0 && startY < bmapheight) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index ab89ae04c..8dda50de6 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -156,9 +156,9 @@ void AActor::Serialize (FArchive &arc) sprite = arc.ReadSprite (); } - arc << x - << y - << z + arc << __pos.x + << __pos.y + << __pos.z << angle << frame << scaleX @@ -191,6 +191,10 @@ void AActor::Serialize (FArchive &arc) << tics << state << Damage; + if (SaveVersion >= 4530) + { + P_SerializeTerrain(arc, floorterrain); + } if (SaveVersion >= 3227) { arc << projectileKickback; @@ -376,11 +380,11 @@ void AActor::Serialize (FArchive &arc) Speed = GetDefault()->Speed; } } - PrevX = x; - PrevY = y; - PrevZ = z; + PrevX = X(); + PrevY = Y(); + PrevZ = Z(); PrevAngle = angle; - UpdateWaterLevel(z, false); + UpdateWaterLevel(Z(), false); } } @@ -392,12 +396,12 @@ AActor::AActor () throw() AActor::AActor (const AActor &other) throw() : DThinker() { - memcpy (&x, &other.x, (BYTE *)&this[1] - (BYTE *)&x); + memcpy (&snext, &other.snext, (BYTE *)&this[1] - (BYTE *)&snext); } AActor &AActor::operator= (const AActor &other) { - memcpy (&x, &other.x, (BYTE *)&this[1] - (BYTE *)&x); + memcpy (&snext, &other.snext, (BYTE *)&this[1] - (BYTE *)&snext); return *this; } @@ -734,7 +738,7 @@ AInventory *AActor::DropInventory (AInventory *item) return NULL; } an = angle >> ANGLETOFINESHIFT; - drop->SetOrigin(x, y, z + 10*FRACUNIT); + drop->SetOrigin(PosPlusZ(10*FRACUNIT), false); drop->angle = angle; drop->velx = velx + 5 * finecosine[an]; drop->vely = vely + 5 * finesine[an]; @@ -1161,7 +1165,7 @@ bool AActor::Grind(bool items) return false; } - AActor *gib = Spawn (i, x, y, z, ALLOW_REPLACE); + AActor *gib = Spawn (i, Pos(), ALLOW_REPLACE); if (gib != NULL) { gib->RenderStyle = RenderStyle; @@ -1280,7 +1284,8 @@ void P_ExplodeMissile (AActor *mo, line_t *line, AActor *target) if (line != NULL && cl_missiledecals) { - int side = P_PointOnLineSide (mo->x, mo->y, line); + fixedvec3 pos = mo->PosRelative(line); + int side = P_PointOnLineSidePrecise (pos.x, pos.y, line); if (line->sidedef[side] == NULL) side ^= 1; if (line->sidedef[side] != NULL) @@ -1297,7 +1302,7 @@ void P_ExplodeMissile (AActor *mo, line_t *line, AActor *target) { SDWORD frac; - num = (SQWORD)(mo->x-line->v1->x)*line->dx+(SQWORD)(mo->y-line->v1->y)*line->dy; + num = (SQWORD)(pos.x-line->v1->x)*line->dx+(SQWORD)(pos.y-line->v1->y)*line->dy; if (num <= 0) { frac = 0; @@ -1313,7 +1318,7 @@ void P_ExplodeMissile (AActor *mo, line_t *line, AActor *target) x = line->v1->x + MulScale30 (line->dx, frac); y = line->v1->y + MulScale30 (line->dy, frac); - z = mo->z; + z = pos.z; F3DFloor * ffloor=NULL; if (line->sidedef[side^1] != NULL) @@ -1423,7 +1428,7 @@ void AActor::PlayBounceSound(bool onfloor) bool AActor::FloorBounceMissile (secplane_t &plane) { - if (z <= floorz && P_HitFloor (this)) + if (Z() <= floorz && P_HitFloor (this)) { // Landed in some sort of liquid if (BounceFlags & BOUNCE_ExplodeOnWater) @@ -1552,7 +1557,7 @@ int P_FaceMobj (AActor *source, AActor *target, angle_t *delta) angle_t angle2; angle1 = source->angle; - angle2 = R_PointToAngle2 (source->x, source->y, target->x, target->y); + angle2 = source->AngleTo(target); if (angle2 > angle1) { diff = angle2 - angle1; @@ -1662,16 +1667,15 @@ bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax, bool preci if (!(actor->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER))) { - if (actor->z + actor->height < target->z || - target->z + target->height < actor->z) + if (actor->Top() < target->Z() || + target->Top() < actor->Z()) { // Need to seek vertically - dist = P_AproxDistance (target->x - actor->x, target->y - actor->y); - dist = dist / speed; + dist = actor->AproxDistance (target) / speed; if (dist < 1) { dist = 1; } - actor->velz = ((target->z+target->height/2) - (actor->z+actor->height/2)) / dist; + actor->velz = ((target->Z() + target->height / 2) - (actor->Z() + actor->height / 2)) / dist; } } } @@ -1680,14 +1684,14 @@ bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax, bool preci angle_t pitch = 0; if (!(actor->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER))) { // Need to seek vertically - double dist = MAX(1.0, FVector2(target->x - actor->x, target->y - actor->y).Length()); + double dist = MAX(1.0, FVector2(actor->Vec2To(target)).Length()); // Aim at a player's eyes and at the middle of the actor for everything else. fixed_t aimheight = target->height/2; if (target->IsKindOf(RUNTIME_CLASS(APlayerPawn))) { aimheight = static_cast(target)->ViewHeight; } - pitch = R_PointToAngle2(0, actor->z + actor->height/2, xs_CRoundToInt(dist), target->z + aimheight); + pitch = R_PointToAngle2(0, actor->Z() + actor->height/2, xs_CRoundToInt(dist), target->Z() + aimheight); pitch >>= ANGLETOFINESHIFT; } @@ -1722,7 +1726,7 @@ fixed_t P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly) int steps, step, totalsteps; fixed_t startx, starty; fixed_t oldfloorz = mo->floorz; - fixed_t oldz = mo->z; + fixed_t oldz = mo->Z(); fixed_t maxmove = (mo->waterlevel < 1) || (mo->flags & MF_MISSILE) || (mo->player && mo->player->crouchoffset<-10*FRACUNIT) ? MAXMOVE : MAXMOVE/4; @@ -1858,8 +1862,8 @@ fixed_t P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly) fixed_t onestepx = startxmove / steps; fixed_t onestepy = startymove / steps; - startx = mo->x; - starty = mo->y; + startx = mo->X(); + starty = mo->Y(); step = 1; totalsteps = steps; @@ -1945,8 +1949,8 @@ fixed_t P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly) onestepy = ymove / steps; P_CheckSlopeWalk (mo, xmove, ymove); } - startx = mo->x - Scale (xmove, step, steps); - starty = mo->y - Scale (ymove, step, steps); + startx = mo->X() - Scale (xmove, step, steps); + starty = mo->Y() - Scale (ymove, step, steps); } } else @@ -1959,7 +1963,7 @@ fixed_t P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly) fixed_t tx, ty; tx = 0, ty = onestepy; walkplane = P_CheckSlopeWalk (mo, tx, ty); - if (P_TryMove (mo, mo->x + tx, mo->y + ty, true, walkplane, tm)) + if (P_TryMove (mo, mo->X() + tx, mo->Y() + ty, true, walkplane, tm)) { mo->velx = 0; } @@ -1967,7 +1971,7 @@ fixed_t P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly) { tx = onestepx, ty = 0; walkplane = P_CheckSlopeWalk (mo, tx, ty); - if (P_TryMove (mo, mo->x + tx, mo->y + ty, true, walkplane, tm)) + if (P_TryMove (mo, mo->X() + tx, mo->Y() + ty, true, walkplane, tm)) { mo->vely = 0; } @@ -2016,7 +2020,7 @@ fixed_t P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly) // Don't change the angle if there's THRUREFLECT on the monster. if (!(BlockingMobj->flags7 & MF7_THRUREFLECT)) { - angle = R_PointToAngle2(BlockingMobj->x, BlockingMobj->y, mo->x, mo->y); + angle = BlockingMobj->AngleTo(mo); bool dontReflect = (mo->AdjustReflectionAngle(BlockingMobj, angle)); // Change angle for deflection/reflection @@ -2030,7 +2034,9 @@ fixed_t P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly) float speed = (float)(mo->Speed); //dest->x - source->x - FVector3 velocity(origin->x - mo->x, origin->y - mo->y, (origin->z + (origin->height/2)) - mo->z); + fixedvec3 vect = mo->Vec3To(origin); + vect.z += origin->height / 2; + FVector3 velocity(vect); velocity.Resize(speed); mo->velx = (fixed_t)(velocity.X); mo->vely = (fixed_t)(velocity.Y); @@ -2074,7 +2080,7 @@ explode: if (tm.ceilingline && tm.ceilingline->backsector && tm.ceilingline->backsector->GetTexture(sector_t::ceiling) == skyflatnum && - mo->z >= tm.ceilingline->backsector->ceilingplane.ZatPoint (mo->x, mo->y)) + mo->Z() >= tm.ceilingline->backsector->ceilingplane.ZatPoint(mo)) { // Hack to prevent missiles exploding against the sky. // Does not handle sky floors. @@ -2099,7 +2105,7 @@ explode: } else { - if (mo->x != ptryx || mo->y != ptryy) + if (mo->X() != ptryx || mo->Y() != ptryy) { // If the new position does not match the desired position, the player // must have gone through a teleporter, so stop moving right now if it @@ -2111,8 +2117,8 @@ explode: } else { - startx = mo->x - Scale (xmove, step, steps); - starty = mo->y - Scale (ymove, step, steps); + startx = mo->X() - Scale (xmove, step, steps); + starty = mo->Y() - Scale (ymove, step, steps); } } } @@ -2132,7 +2138,7 @@ explode: return oldfloorz; } - if (mo->z > mo->floorz && !(mo->flags2 & MF2_ONMOBJ) && + if (mo->Z() > mo->floorz && !(mo->flags2 & MF2_ONMOBJ) && !mo->IsNoClip2() && (!(mo->flags2 & MF2_FLY) || !(mo->flags & MF_NOGRAVITY)) && !mo->waterlevel) @@ -2154,11 +2160,11 @@ explode: // killough 8/11/98: add bouncers // killough 9/15/98: add objects falling off ledges // killough 11/98: only include bouncers hanging off ledges - if ((mo->flags & MF_CORPSE) || (mo->BounceFlags & BOUNCE_MBF && mo->z > mo->dropoffz) || (mo->flags6 & MF6_FALLING)) + if ((mo->flags & MF_CORPSE) || (mo->BounceFlags & BOUNCE_MBF && mo->Z() > mo->dropoffz) || (mo->flags6 & MF6_FALLING)) { // Don't stop sliding if halfway off a step with some velocity if (mo->velx > FRACUNIT/4 || mo->velx < -FRACUNIT/4 || mo->vely > FRACUNIT/4 || mo->vely < -FRACUNIT/4) { - if (mo->floorz > mo->Sector->floorplane.ZatPoint (mo->x, mo->y)) + if (mo->floorz > mo->Sector->floorplane.ZatPoint(mo)) { if (mo->dropoffz != mo->floorz) // 3DMidtex or other special cases that must be excluded { @@ -2169,7 +2175,7 @@ explode: // if the floor comes from one in the current sector stop sliding the corpse! F3DFloor * rover=mo->Sector->e->XFloor.ffloors[i]; if (!(rover->flags&FF_EXISTS)) continue; - if (rover->flags&FF_SOLID && rover->top.plane->ZatPoint(mo->x,mo->y)==mo->floorz) break; + if (rover->flags&FF_SOLID && rover->top.plane->ZatPoint(mo) == mo->floorz) break; } if (i==mo->Sector->e->XFloor.ffloors.Size()) return oldfloorz; @@ -2266,24 +2272,24 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz) { fixed_t dist; fixed_t delta; - fixed_t oldz = mo->z; + fixed_t oldz = mo->Z(); fixed_t grav = mo->GetGravity(); // // check for smooth step up // - if (mo->player && mo->player->mo == mo && mo->z < mo->floorz) + if (mo->player && mo->player->mo == mo && mo->Z() < mo->floorz) { - mo->player->viewheight -= mo->floorz - mo->z; + mo->player->viewheight -= mo->floorz - mo->Z(); mo->player->deltaviewheight = mo->player->GetDeltaViewHeight(); } - mo->z += mo->velz; + mo->AddZ(mo->velz); // // apply gravity // - if (mo->z > mo->floorz && !(mo->flags & MF_NOGRAVITY)) + if (mo->Z() > mo->floorz && !(mo->flags & MF_NOGRAVITY)) { fixed_t startvelz = mo->velz; @@ -2292,7 +2298,7 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz) { // [RH] Double gravity only if running off a ledge. Coming down from // an upward thrust (e.g. a jump) should not double it. - if (mo->velz == 0 && oldfloorz > mo->floorz && mo->z == oldfloorz) + if (mo->velz == 0 && oldfloorz > mo->floorz && mo->Z() == oldfloorz) { mo->velz -= grav + grav; } @@ -2365,7 +2371,7 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz) // Do this only if the item was actually spawned by the map above ground to avoid problems. if (mo->special1 > 0 && (mo->flags2 & MF2_FLOATBOB) && (ib_compatflags & BCOMPATF_FLOATBOB)) { - mo->z = mo->floorz + mo->special1; + mo->SetZ(mo->floorz + mo->special1); } @@ -2376,19 +2382,19 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz) { // float down towards target if too close if (!(mo->flags & (MF_SKULLFLY | MF_INFLOAT))) { - dist = P_AproxDistance (mo->x - mo->target->x, mo->y - mo->target->y); - delta = (mo->target->z + (mo->height>>1)) - mo->z; + dist = mo->AproxDistance (mo->target); + delta = (mo->target->Z() + (mo->height>>1)) - mo->Z(); if (delta < 0 && dist < -(delta*3)) - mo->z -= mo->FloatSpeed; + mo->AddZ(-mo->FloatSpeed); else if (delta > 0 && dist < (delta*3)) - mo->z += mo->FloatSpeed; + mo->AddZ(mo->FloatSpeed); } } - if (mo->player && (mo->flags & MF_NOGRAVITY) && (mo->z > mo->floorz)) + if (mo->player && (mo->flags & MF_NOGRAVITY) && (mo->Z() > mo->floorz)) { if (!mo->IsNoClip2()) { - mo->z += finesine[(FINEANGLES/80*level.maptime)&FINEMASK]/8; + mo->AddZ(finesine[(FINEANGLES/80*level.maptime)&FINEMASK]/8); } mo->velz = FixedMul (mo->velz, FRICTION_FLY); } @@ -2400,22 +2406,22 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz) // // clip movement // - if (mo->z <= mo->floorz) + if (mo->Z() <= mo->floorz) { // Hit the floor if ((!mo->player || !(mo->player->cheats & CF_PREDICTING)) && mo->Sector->SecActTarget != NULL && - mo->Sector->floorplane.ZatPoint (mo->x, mo->y) == mo->floorz) + mo->Sector->floorplane.ZatPoint(mo) == mo->floorz) { // [RH] Let the sector do something to the actor mo->Sector->SecActTarget->TriggerAction (mo, SECSPAC_HitFloor); } P_CheckFor3DFloorHit(mo); // [RH] Need to recheck this because the sector action might have // teleported the actor so it is no longer below the floor. - if (mo->z <= mo->floorz) + if (mo->Z() <= mo->floorz) { if ((mo->flags & MF_MISSILE) && !(mo->flags & MF_NOCLIP)) { - mo->z = mo->floorz; + mo->AddZ(mo->floorz); if (mo->BounceFlags & BOUNCE_Floors) { mo->FloorBounceMissile (mo->floorsector->floorplane); @@ -2456,7 +2462,7 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz) P_MonsterFallingDamage (mo); } } - mo->z = mo->floorz; + mo->SetZ(mo->floorz); if (mo->velz < 0) { const fixed_t minvel = -8*FRACUNIT; // landing speed from a jump with normal gravity @@ -2502,20 +2508,20 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz) mo->AdjustFloorClip (); } - if (mo->z + mo->height > mo->ceilingz) + if (mo->Top() > mo->ceilingz) { // hit the ceiling if ((!mo->player || !(mo->player->cheats & CF_PREDICTING)) && mo->Sector->SecActTarget != NULL && - mo->Sector->ceilingplane.ZatPoint (mo->x, mo->y) == mo->ceilingz) + mo->Sector->ceilingplane.ZatPoint(mo) == mo->ceilingz) { // [RH] Let the sector do something to the actor mo->Sector->SecActTarget->TriggerAction (mo, SECSPAC_HitCeiling); } P_CheckFor3DCeilingHit(mo); // [RH] Need to recheck this because the sector action might have // teleported the actor so it is no longer above the ceiling. - if (mo->z + mo->height > mo->ceilingz) + if (mo->Top() > mo->ceilingz) { - mo->z = mo->ceilingz - mo->height; + mo->SetZ(mo->ceilingz - mo->height); if (mo->BounceFlags & BOUNCE_Ceilings) { // ceiling bounce mo->FloorBounceMissile (mo->ceilingsector->ceilingplane); @@ -2561,7 +2567,7 @@ void P_CheckFakeFloorTriggers (AActor *mo, fixed_t oldz, bool oldz_has_viewheigh if (sec->heightsec != NULL && sec->SecActTarget != NULL) { sector_t *hs = sec->heightsec; - fixed_t waterz = hs->floorplane.ZatPoint (mo->x, mo->y); + fixed_t waterz = hs->floorplane.ZatPoint(mo); fixed_t newz; fixed_t viewheight; @@ -2574,12 +2580,12 @@ void P_CheckFakeFloorTriggers (AActor *mo, fixed_t oldz, bool oldz_has_viewheigh viewheight = mo->height / 2; } - if (oldz > waterz && mo->z <= waterz) + if (oldz > waterz && mo->Z() <= waterz) { // Feet hit fake floor sec->SecActTarget->TriggerAction (mo, SECSPAC_HitFakeFloor); } - newz = mo->z + viewheight; + newz = mo->Z() + viewheight; if (!oldz_has_viewheight) { oldz += viewheight; @@ -2596,7 +2602,7 @@ void P_CheckFakeFloorTriggers (AActor *mo, fixed_t oldz, bool oldz_has_viewheigh if (!(hs->MoreFlags & SECF_FAKEFLOORONLY)) { - waterz = hs->ceilingplane.ZatPoint (mo->x, mo->y); + waterz = hs->ceilingplane.ZatPoint(mo); if (oldz <= waterz && newz > waterz) { // View went above fake ceiling sec->SecActTarget->TriggerAction (mo, SECSPAC_EyesAboveC); @@ -2681,22 +2687,22 @@ void P_NightmareRespawn (AActor *mobj) if (z == ONFLOORZ) { - mo->z += mobj->SpawnPoint[2]; - if (mo->z < mo->floorz) + mo->AddZ(mobj->SpawnPoint[2]); + if (mo->Z() < mo->floorz) { // Do not respawn monsters in the floor, even if that's where they // started. The initial P_ZMovement() call would have put them on // the floor right away, but we need them on the floor now so we // can use P_CheckPosition() properly. - mo->z = mo->floorz; + mo->SetZ(mo->floorz); } - if (mo->z + mo->height > mo->ceilingz) + if (mo->Top() > mo->ceilingz) { - mo->z = mo->ceilingz - mo->height; + mo->SetZ(mo->ceilingz - mo->height); } } else if (z == ONCEILINGZ) { - mo->z -= mobj->SpawnPoint[2]; + mo->AddZ(-mobj->SpawnPoint[2]); } // If there are 3D floors, we need to find floor/ceiling again. @@ -2704,21 +2710,21 @@ void P_NightmareRespawn (AActor *mobj) if (z == ONFLOORZ) { - if (mo->z < mo->floorz) + if (mo->Z() < mo->floorz) { // Do not respawn monsters in the floor, even if that's where they // started. The initial P_ZMovement() call would have put them on // the floor right away, but we need them on the floor now so we // can use P_CheckPosition() properly. - mo->z = mo->floorz; + mo->SetZ(mo->floorz); } - if (mo->z + mo->height > mo->ceilingz) + if (mo->Top() > mo->ceilingz) { // Do the same for the ceiling. - mo->z = mo->ceilingz - mo->height; + mo->SetZ(mo->ceilingz - mo->height); } } // something is occupying its position? - if (!P_CheckPosition(mo, mo->x, mo->y, true)) + if (!P_CheckPosition(mo, mo->X(), mo->Y(), true)) { //[GrafZahl] MF_COUNTKILL still needs to be checked here. mo->ClearCounters(); @@ -2726,7 +2732,7 @@ void P_NightmareRespawn (AActor *mobj) return; // no respawn } - z = mo->z; + z = mo->Z(); // inherit attributes from deceased one mo->SpawnPoint[0] = mobj->SpawnPoint[0]; @@ -2746,7 +2752,7 @@ void P_NightmareRespawn (AActor *mobj) mo->PrevZ = z; // Do not interpolate Z position if we changed it since spawning. // spawn a teleport fog at old spot because of removal of the body? - P_SpawnTeleportFog(mobj, mobj->x, mobj->y, mobj->z + TELEFOGHEIGHT, true, true); + P_SpawnTeleportFog(mobj, mobj->PosPlusZ(TELEFOGHEIGHT), true, true); // spawn a teleport fog at the new spot P_SpawnTeleportFog(mobj, x, y, z + TELEFOGHEIGHT, false, true); @@ -3085,8 +3091,7 @@ bool AActor::IsOkayToAttack (AActor *link) // to only allow the check to succeed if the enemy was in a ~84� FOV of the player if (flags3 & MF3_SCREENSEEKER) { - angle_t angle = R_PointToAngle2(Friend->x, - Friend->y, link->x, link->y) - Friend->angle; + angle_t angle = Friend->AngleTo(link) - Friend->angle; angle >>= 24; if (angle>226 || angle<30) { @@ -3194,16 +3199,16 @@ void AActor::Tick () if (state == NULL) { Printf("Actor of type %s at (%f,%f) left without a state\n", GetClass()->TypeName.GetChars(), - x/65536., y/65536.); + X()/65536., Y()/65536.); Destroy(); return; } // This is necessary to properly interpolate movement outside this function // like from an ActorMover - PrevX = x; - PrevY = y; - PrevZ = z; + PrevX = X(); + PrevY = Y(); + PrevZ = Z(); PrevAngle = angle; if (flags5 & MF5_NOINTERACTION) @@ -3229,9 +3234,8 @@ void AActor::Tick () UnlinkFromWorld (); flags |= MF_NOBLOCKMAP; - x += velx; - y += vely; - z += velz; + SetXYZ(Vec3Offset(velx, vely, vely)); + SetMovement(velx, vely, velz); LinkToWorld (); } else @@ -3278,7 +3282,7 @@ void AActor::Tick () { // add some smoke behind the rocket smokecounter = 0; - AActor *th = Spawn("RocketSmokeTrail", x-velx, y-vely, z-velz, ALLOW_REPLACE); + AActor *th = Spawn("RocketSmokeTrail", Vec3Offset(-velx, -vely, -velz), ALLOW_REPLACE); if (th) { th->tics -= pr_rockettrail()&3; @@ -3293,10 +3297,9 @@ void AActor::Tick () { smokecounter = 0; angle_t moveangle = R_PointToAngle2(0,0,velx,vely); - AActor * th = Spawn("GrenadeSmokeTrail", - x - FixedMul (finecosine[(moveangle)>>ANGLETOFINESHIFT], radius*2) + (pr_rockettrail()<<10), - y - FixedMul (finesine[(moveangle)>>ANGLETOFINESHIFT], radius*2) + (pr_rockettrail()<<10), - z - (height>>3) * (velz>>16) + (2*height)/3, ALLOW_REPLACE); + fixed_t xo = -FixedMul(finecosine[(moveangle) >> ANGLETOFINESHIFT], radius * 2) + (pr_rockettrail() << 10); + fixed_t yo = -FixedMul(finesine[(moveangle) >> ANGLETOFINESHIFT], radius * 2) + (pr_rockettrail() << 10); + AActor * th = Spawn("GrenadeSmokeTrail", Vec3Offset(xo, yo, - (height>>3) * (velz>>16) + (2*height)/3), ALLOW_REPLACE); if (th) { th->tics -= pr_rockettrail()&3; @@ -3306,7 +3309,7 @@ void AActor::Tick () } } - fixed_t oldz = z; + fixed_t oldz = Z(); // [RH] Give the pain elemental vertical friction // This used to be in APainElemental::Tick but in order to use @@ -3388,7 +3391,7 @@ void AActor::Tick () if (health > 0 && !players[i].Bot->enemy && player ? !IsTeammate (players[i].mo) : true - && P_AproxDistance (players[i].mo->x-x, players[i].mo->y-y) < MAX_MONSTER_TARGET_DIST + && AproxDistance (players[i].mo) < MAX_MONSTER_TARGET_DIST && P_CheckSight (players[i].mo, this, SF_SEEPASTBLOCKEVERYTHING)) { //Probably a monster, so go kill it. players[i].Bot->enemy = this; @@ -3452,7 +3455,7 @@ void AActor::Tick () if (player != NULL) { - int scrolltype = sec->special & 0xff; + int scrolltype = sec->special; if (scrolltype >= Scroll_North_Slow && scrolltype <= Scroll_SouthWest_Fast) @@ -3518,16 +3521,16 @@ void AActor::Tick () { continue; } - height = sec->floorplane.ZatPoint (x, y); - if (z > height) + height = sec->floorplane.ZatPoint (this); + if (Z() > height) { if (heightsec == NULL) { continue; } - waterheight = heightsec->floorplane.ZatPoint (x, y); - if (waterheight > height && z >= waterheight) + waterheight = heightsec->floorplane.ZatPoint (this); + if (waterheight > height && Z() >= waterheight) { continue; } @@ -3559,15 +3562,15 @@ void AActor::Tick () if ((flags & MF_SOLID) && !(flags & (MF_NOCLIP|MF_NOGRAVITY)) && !(flags & MF_NOBLOCKMAP) && velz <= 0 && - floorz == z) + floorz == Z()) { secplane_t floorplane; // Check 3D floors as well - floorplane = P_FindFloorPlane(floorsector, x, y, floorz); + floorplane = P_FindFloorPlane(floorsector, X(), Y(), floorz); if (floorplane.c < STEEPSLOPE && - floorplane.ZatPoint (x, y) <= floorz) + floorplane.ZatPoint (this) <= floorz) { const msecnode_t *node; bool dopush = true; @@ -3579,7 +3582,7 @@ void AActor::Tick () const sector_t *sec = node->m_sector; if (sec->floorplane.c >= STEEPSLOPE) { - if (floorplane.ZatPoint (x, y) >= z - MaxStepHeight) + if (floorplane.ZatPoint (this) >= Z() - MaxStepHeight) { dopush = false; break; @@ -3623,7 +3626,7 @@ void AActor::Tick () } } - if (velz || BlockingMobj || z != floorz) + if (velz || BlockingMobj || Z() != floorz) { // Handle Z velocity and gravity if (((flags2 & MF2_PASSMOBJ) || (flags & MF_SPECIAL)) && !(i_compatflags & COMPATF_NO_PASSMOBJ)) { @@ -3642,18 +3645,18 @@ void AActor::Tick () PlayerLandedOnThing (this, onmo); } } - if (onmo->z + onmo->height - z <= MaxStepHeight) + if (onmo->Top() - Z() <= MaxStepHeight) { if (player && player->mo == this) { - player->viewheight -= onmo->z + onmo->height - z; + player->viewheight -= onmo->Top() - Z(); fixed_t deltaview = player->GetDeltaViewHeight(); if (deltaview > player->deltaviewheight) { player->deltaviewheight = deltaview; } } - z = onmo->z + onmo->height; + SetZ(onmo->Top()); } // Check for MF6_BUMPSPECIAL // By default, only players can activate things by bumping into them @@ -3692,7 +3695,7 @@ void AActor::Tick () if (ObjectFlags & OF_EuthanizeMe) return; // actor was destroyed } - else if (z <= floorz) + else if (Z() <= floorz) { Crash(); } @@ -3794,25 +3797,25 @@ void AActor::CheckSectorTransition(sector_t *oldsec) if (Sector->SecActTarget != NULL) { int act = SECSPAC_Enter; - if (z <= Sector->floorplane.ZatPoint(x, y)) + if (Z() <= Sector->floorplane.ZatPoint(this)) { act |= SECSPAC_HitFloor; } - if (z + height >= Sector->ceilingplane.ZatPoint(x, y)) + if (Z() + height >= Sector->ceilingplane.ZatPoint(this)) { act |= SECSPAC_HitCeiling; } - if (Sector->heightsec != NULL && z == Sector->heightsec->floorplane.ZatPoint(x, y)) + if (Sector->heightsec != NULL && Z() == Sector->heightsec->floorplane.ZatPoint(this)) { act |= SECSPAC_HitFakeFloor; } Sector->SecActTarget->TriggerAction(this, act); } - if (z == floorz) + if (Z() == floorz) { P_CheckFor3DFloorHit(this); } - if (z + height == ceilingz) + if (Top() == ceilingz) { P_CheckFor3DCeilingHit(this); } @@ -3849,23 +3852,23 @@ bool AActor::UpdateWaterLevel (fixed_t oldz, bool dosplash) const sector_t *hsec = Sector->GetHeightSec(); if (hsec != NULL) { - fh = hsec->floorplane.ZatPoint (x, y); + fh = hsec->floorplane.ZatPoint (this); //if (hsec->MoreFlags & SECF_UNDERWATERMASK) // also check Boom-style non-swimmable sectors { - if (z < fh) + if (Z() < fh) { waterlevel = 1; - if (z + height/2 < fh) + if (Z() + height/2 < fh) { waterlevel = 2; - if ((player && z + player->viewheight <= fh) || - (z + height <= fh)) + if ((player && Z() + player->viewheight <= fh) || + (Z() + height <= fh)) { waterlevel = 3; } } } - else if (!(hsec->MoreFlags & SECF_FAKEFLOORONLY) && (z + height > hsec->ceilingplane.ZatPoint (x, y))) + else if (!(hsec->MoreFlags & SECF_FAKEFLOORONLY) && (Top() > hsec->ceilingplane.ZatPoint (this))) { waterlevel = 3; } @@ -3891,20 +3894,20 @@ bool AActor::UpdateWaterLevel (fixed_t oldz, bool dosplash) if (!(rover->flags & FF_EXISTS)) continue; if(!(rover->flags & FF_SWIMMABLE) || rover->flags & FF_SOLID) continue; - fixed_t ff_bottom=rover->bottom.plane->ZatPoint(x, y); - fixed_t ff_top=rover->top.plane->ZatPoint(x, y); + fixed_t ff_bottom=rover->bottom.plane->ZatPoint(this); + fixed_t ff_top=rover->top.plane->ZatPoint(this); - if(ff_top <= z || ff_bottom > (z + (height >> 1))) continue; + if(ff_top <= Z() || ff_bottom > (Z() + (height >> 1))) continue; fh=ff_top; - if (z < fh) + if (Z() < fh) { waterlevel = 1; - if (z + height/2 < fh) + if (Z() + height/2 < fh) { waterlevel = 2; - if ((player && z + player->viewheight <= fh) || - (z + height <= fh)) + if ((player && Z() + player->viewheight <= fh) || + (Z() + height <= fh)) { waterlevel = 3; } @@ -3968,9 +3971,10 @@ AActor *AActor::StaticSpawn (const PClass *type, fixed_t ix, fixed_t iy, fixed_t actor->Conversation = NULL; } - actor->x = actor->PrevX = ix; - actor->y = actor->PrevY = iy; - actor->z = actor->PrevZ = iz; + actor->PrevX = ix; + actor->PrevY = iy; + actor->PrevZ = iz; + actor->SetXYZ(ix, iy, iz); actor->picnum.SetInvalid(); actor->health = actor->SpawnHealth(); @@ -4015,11 +4019,11 @@ AActor *AActor::StaticSpawn (const PClass *type, fixed_t ix, fixed_t iy, fixed_t // For FLOATRANDZ just use the floor here. if (iz == ONFLOORZ || iz == FLOATRANDZ) { - actor->z = actor->floorz; + actor->SetZ(actor->floorz, false); } else if (iz == ONCEILINGZ) { - actor->z = actor->ceilingz - actor->height; + actor->SetZ(actor->ceilingz - actor->height); } if (SpawningMapThing || !type->IsDescendantOf (RUNTIME_CLASS(APlayerPawn))) @@ -4035,6 +4039,7 @@ AActor *AActor::StaticSpawn (const PClass *type, fixed_t ix, fixed_t iy, fixed_t { actor->floorsector = actor->Sector; actor->floorpic = actor->floorsector->GetTexture(sector_t::floor); + actor->floorterrain = actor->floorsector->GetTerrain(sector_t::floor); actor->ceilingsector = actor->Sector; actor->ceilingpic = actor->ceilingsector->GetTexture(sector_t::ceiling); } @@ -4046,6 +4051,7 @@ AActor *AActor::StaticSpawn (const PClass *type, fixed_t ix, fixed_t iy, fixed_t else { actor->floorpic = actor->Sector->GetTexture(sector_t::floor); + actor->floorterrain = actor->Sector->GetTerrain(sector_t::floor); actor->floorsector = actor->Sector; actor->ceilingpic = actor->Sector->GetTexture(sector_t::ceiling); actor->ceilingsector = actor->Sector; @@ -4056,11 +4062,11 @@ AActor *AActor::StaticSpawn (const PClass *type, fixed_t ix, fixed_t iy, fixed_t if (iz == ONFLOORZ) { - actor->z = actor->floorz; + actor->SetZ(actor->floorz); } else if (iz == ONCEILINGZ) { - actor->z = actor->ceilingz - actor->height; + actor->SetZ(actor->ceilingz - actor->height); } else if (iz == FLOATRANDZ) { @@ -4068,16 +4074,16 @@ AActor *AActor::StaticSpawn (const PClass *type, fixed_t ix, fixed_t iy, fixed_t if (space > 48*FRACUNIT) { space -= 40*FRACUNIT; - actor->z = MulScale8 (space, rng()) + actor->floorz + 40*FRACUNIT; + actor->SetZ(MulScale8 (space, rng()) + actor->floorz + 40*FRACUNIT); } else { - actor->z = actor->floorz; + actor->SetZ(actor->floorz); } } else { - actor->SpawnPoint[2] = (actor->z - actor->floorz); + actor->SpawnPoint[2] = (actor->Z() - actor->floorz); } if (actor->FloatBobPhase == (BYTE)-1) actor->FloatBobPhase = rng(); // Don't make everything bob in sync (unless deliberately told to do) @@ -4089,7 +4095,7 @@ AActor *AActor::StaticSpawn (const PClass *type, fixed_t ix, fixed_t iy, fixed_t { actor->floorclip = 0; } - actor->UpdateWaterLevel (actor->z, false); + actor->UpdateWaterLevel (actor->Z(), false); if (!SpawningMapThing) { actor->BeginPlay (); @@ -4328,8 +4334,8 @@ void AActor::AdjustFloorClip () fixed_t shallowestclip = FIXED_MAX; const msecnode_t *m; - // possibly standing on a 3D-floor! - if (Sector->e->XFloor.ffloors.Size() && z>Sector->floorplane.ZatPoint(x,y)) floorclip=0; + // possibly standing on a 3D-floor + if (Sector->e->XFloor.ffloors.Size() && Z()>Sector->floorplane.ZatPoint(this)) floorclip=0; // [RH] clip based on shallowest floor player is standing on // If the sector has a deep water effect, then let that effect @@ -4337,9 +4343,9 @@ void AActor::AdjustFloorClip () for (m = touching_sectorlist; m; m = m->m_tnext) { sector_t *hsec = m->m_sector->GetHeightSec(); - if (hsec == NULL && m->m_sector->floorplane.ZatPoint (x, y) == z) + if (hsec == NULL && m->m_sector->floorplane.ZatPoint (this) == Z()) { - fixed_t clip = Terrains[TerrainTypes[m->m_sector->GetTexture(sector_t::floor)]].FootClip; + fixed_t clip = Terrains[m->m_sector->GetTerrain(sector_t::floor)].FootClip; if (clip < shallowestclip) { shallowestclip = clip; @@ -4424,11 +4430,11 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags) ( gameaction != ga_worlddone ) && ( p->mo != NULL ) && ( !(p->mo->Sector->Flags & SECF_NORESPAWN) ) && - ( (p->mo->Sector->special & 255) != Damage_InstantDeath )) + ( p->mo->Sector->damageamount < TELEFRAG_DAMAGE )) // this really should be a bit smarter... { - spawn_x = p->mo->x; - spawn_y = p->mo->y; - spawn_z = p->mo->z; + spawn_x = p->mo->X(); + spawn_y = p->mo->Y(); + spawn_z = p->mo->Z(); spawn_angle = p->mo->angle; } @@ -4465,9 +4471,9 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags) if (level.flags & LEVEL_USEPLAYERSTARTZ) { if (spawn_z == ONFLOORZ) - mobj->z += mthing->z; + mobj->AddZ(mthing->z); else if (spawn_z == ONCEILINGZ) - mobj->z -= mthing->z; + mobj->AddZ(-mthing->z); P_FindFloorCeiling(mobj, FFCF_SAMESECTOR | FFCF_ONLY3DFLOORS | FFCF_3DRESTRICT); } @@ -4588,14 +4594,14 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags) if (multiplayer) { unsigned an = mobj->angle >> ANGLETOFINESHIFT; - Spawn ("TeleportFog", mobj->x+20*finecosine[an], mobj->y+20*finesine[an], mobj->z + TELEFOGHEIGHT, ALLOW_REPLACE); + Spawn ("TeleportFog", mobj->Vec3Offset(20*finecosine[an], 20*finesine[an], TELEFOGHEIGHT), ALLOW_REPLACE); } // "Fix" for one of the starts on exec.wad MAP01: If you start inside the ceiling, // drop down below it, even if that means sinking into the floor. - if (mobj->z + mobj->height > mobj->ceilingz) + if (mobj->Top() > mobj->ceilingz) { - mobj->z = mobj->ceilingz - mobj->height; + mobj->SetZ(mobj->ceilingz - mobj->height, false); } // [BC] Do script stuff @@ -4674,10 +4680,10 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) } // copy args to mapthing so that we have them in one place for the rest of this function - if (mentry->ArgsDefined) + if (mentry->ArgsDefined > 0) { if (mentry->Type!= NULL) mthing->special = mentry->Special; - memcpy(mthing->args, mentry->Args, sizeof(mthing->args)); + memcpy(mthing->args, mentry->Args, sizeof(mthing->args[0]) * mentry->ArgsDefined); } int pnum = -1; @@ -4903,14 +4909,14 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) if (z == ONFLOORZ) { - mobj->z += mthing->z; + mobj->AddZ(mthing->z); if ((mobj->flags2 & MF2_FLOATBOB) && (ib_compatflags & BCOMPATF_FLOATBOB)) { mobj->special1 = mthing->z; } } else if (z == ONCEILINGZ) - mobj->z -= mthing->z; + mobj->AddZ(-mthing->z); mobj->SpawnPoint[0] = mthing->x; mobj->SpawnPoint[1] = mthing->y; @@ -5030,7 +5036,7 @@ AActor *P_SpawnPuff (AActor *source, const PClass *pufftype, fixed_t x, fixed_t puff->target = source; - if (source != NULL) puff->angle = R_PointToAngle2(x, y, source->x, source->y); + if (source != NULL) puff->angle = puff->AngleTo(source); // If a puff has a crash state and an actor was not hit, // it will enter the crash state. This is used by the StrifeSpark @@ -5204,7 +5210,7 @@ void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator) } if (bloodtype >= 1) { - P_DrawSplash2 (40, x, y, z, R_PointToAngle2 (x, y, originator->x, originator->y), 2, bloodcolor); + P_DrawSplash2 (40, x, y, z, R_PointToAngle2 (x, y, originator->X(), originator->Y()), 2, bloodcolor); } } @@ -5244,7 +5250,7 @@ void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator) } if (bloodtype >= 1) { - P_DrawSplash2 (100, x, y, z, R_PointToAngle2 (0, 0, originator->x - x, originator->y - y), 2, bloodcolor); + P_DrawSplash2 (100, x, y, z, R_PointToAngle2 (0, 0, originator->X() - x, originator->Y() - y), 2, bloodcolor); } } @@ -5256,13 +5262,13 @@ void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator) void P_RipperBlood (AActor *mo, AActor *bleeder) { - fixed_t x, y, z; PalEntry bloodcolor = bleeder->GetBloodColor(); const PClass *bloodcls = bleeder->GetBloodType(); - x = mo->x + (pr_ripperblood.Random2 () << 12); - y = mo->y + (pr_ripperblood.Random2 () << 12); - z = mo->z + (pr_ripperblood.Random2 () << 12); + fixed_t xo = (pr_ripperblood.Random2() << 12); + fixed_t yo = (pr_ripperblood.Random2() << 12); + fixed_t zo = (pr_ripperblood.Random2() << 12); + fixedvec3 pos = mo->Vec3Offset(xo, yo, zo); int bloodtype = cl_bloodtype; @@ -5272,7 +5278,7 @@ void P_RipperBlood (AActor *mo, AActor *bleeder) if (bloodcls != NULL) { AActor *th; - th = Spawn (bloodcls, x, y, z, NO_REPLACE); // GetBloodType already performed the replacement + th = Spawn (bloodcls, pos, NO_REPLACE); // GetBloodType already performed the replacement // [NG] Applying PUFFGETSOWNER to the blood will make it target the owner if (th->flags5 & MF5_PUFFGETSOWNER) th->target = bleeder; if (gameinfo.gametype == GAME_Heretic) @@ -5291,7 +5297,7 @@ void P_RipperBlood (AActor *mo, AActor *bleeder) } if (bloodtype >= 1) { - P_DrawSplash2 (28, x, y, z, 0, 0, bloodcolor); + P_DrawSplash2 (28, pos.x, pos.y, pos.z, 0, 0, bloodcolor); } } @@ -5303,13 +5309,13 @@ void P_RipperBlood (AActor *mo, AActor *bleeder) int P_GetThingFloorType (AActor *thing) { - if (thing->floorpic.isValid()) + if (thing->floorterrain >= 0) { - return TerrainTypes[thing->floorpic]; + return thing->floorterrain; } else { - return TerrainTypes[thing->Sector->GetTexture(sector_t::floor)]; + return thing->Sector->GetTerrain(sector_t::floor); } } @@ -5320,7 +5326,7 @@ int P_GetThingFloorType (AActor *thing) // Returns true if hit liquid and splashed, false if not. //--------------------------------------------------------------------------- -bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z, bool checkabove, bool alert) +bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z, bool checkabove, bool alert, bool force) { if (thing->flags3 & MF3_DONTSPLASH) return false; @@ -5333,13 +5339,13 @@ bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z int terrainnum; sector_t *hsec = NULL; - if (x == FIXED_MIN) x = thing->x; - if (y == FIXED_MIN) y = thing->y; - if (z == FIXED_MIN) z = thing->z; + if (x == FIXED_MIN) x = thing->X(); + if (y == FIXED_MIN) y = thing->Y(); + if (z == FIXED_MIN) z = thing->Z(); // don't splash above the object if (checkabove) { - fixed_t compare_z = thing->z + (thing->height >> 1); + fixed_t compare_z = thing->Z() + (thing->height >> 1); // Missiles are typically small and fast, so they might // end up submerged by the move that calls P_HitWater. if (thing->flags & MF_MISSILE) @@ -5362,30 +5368,34 @@ bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z } #endif - for(unsigned int i=0;ie->XFloor.ffloors.Size();i++) - { - F3DFloor * rover = sec->e->XFloor.ffloors[i]; - if (!(rover->flags & FF_EXISTS)) continue; - fixed_t planez = rover->top.plane->ZatPoint(x, y); - if (z > planez - FRACUNIT/2 && z < planez + FRACUNIT/2) // allow minor imprecisions + // 'force' means, we want this sector's terrain, no matter what. + if (!force) + { + for (unsigned int i = 0; ie->XFloor.ffloors.Size(); i++) { - if (rover->flags & (FF_SOLID|FF_SWIMMABLE) ) + F3DFloor * rover = sec->e->XFloor.ffloors[i]; + if (!(rover->flags & FF_EXISTS)) continue; + fixed_t planez = rover->top.plane->ZatPoint(x, y); + if (z > planez - FRACUNIT / 2 && z < planez + FRACUNIT / 2) // allow minor imprecisions { - terrainnum = TerrainTypes[*rover->top.texture]; - goto foundone; + if (rover->flags & (FF_SOLID | FF_SWIMMABLE)) + { + terrainnum = rover->model->GetTerrain(rover->top.isceiling); + goto foundone; + } } + planez = rover->bottom.plane->ZatPoint(x, y); + if (planez < z && !(planez < thing->floorz)) return false; } - planez = rover->bottom.plane->ZatPoint(x, y); - if (planez < z && !(planez < thing->floorz)) return false; } hsec = sec->GetHeightSec(); - if (hsec == NULL || !(hsec->MoreFlags & SECF_CLIPFAKEPLANES)) + if (force || hsec == NULL || !(hsec->MoreFlags & SECF_CLIPFAKEPLANES)) { - terrainnum = TerrainTypes[sec->GetTexture(sector_t::floor)]; + terrainnum = sec->GetTerrain(sector_t::floor); } else { - terrainnum = TerrainTypes[hsec->GetTexture(sector_t::floor)]; + terrainnum = hsec->GetTerrain(sector_t::floor); } foundone: @@ -5403,7 +5413,7 @@ foundone: // Don't splash for living things with small vertical velocities. // There are levels where the constant splashing from the monsters gets extremely annoying - if ((thing->flags3&MF3_ISMONSTER || thing->player) && thing->velz >= -6*FRACUNIT) + if (((thing->flags3&MF3_ISMONSTER || thing->player) && thing->velz >= -6*FRACUNIT) && !force) return Terrains[terrainnum].IsLiquid; splash = &Splashes[splashnum]; @@ -5485,7 +5495,7 @@ bool P_HitFloor (AActor *thing) // don't splash if landing on the edge above water/lava/etc.... for (m = thing->touching_sectorlist; m; m = m->m_tnext) { - if (thing->z == m->m_sector->floorplane.ZatPoint (thing->x, thing->y)) + if (thing->Z() == m->m_sector->floorplane.ZatPoint(thing)) { break; } @@ -5497,7 +5507,7 @@ bool P_HitFloor (AActor *thing) if (!(rover->flags & FF_EXISTS)) continue; if (rover->flags & (FF_SOLID|FF_SWIMMABLE)) { - if (rover->top.plane->ZatPoint(thing->x, thing->y) == thing->z) + if (rover->top.plane->ZatPoint(thing) == thing->Z()) { return P_HitWater (thing, m->m_sector); } @@ -5522,12 +5532,12 @@ bool P_HitFloor (AActor *thing) void P_CheckSplash(AActor *self, fixed_t distance) { - if (self->z <= self->floorz + (distance<floorsector == self->Sector && self->Sector->GetHeightSec() == NULL) + if (self->Z() <= self->floorz + (distance<floorsector == self->Sector && self->Sector->GetHeightSec() == NULL) { // Explosion splashes never alert monsters. This is because A_Explode has // a separate parameter for that so this would get in the way of proper // behavior. - P_HitWater (self, self->Sector, self->x, self->y, self->floorz, false, false); + P_HitWater (self, self->Sector, self->X(), self->Y(), self->floorz, false, false); } } @@ -5564,9 +5574,10 @@ bool P_CheckMissileSpawn (AActor* th, fixed_t maxdist) advance *= 0.5f; } while (TVector2(advance).LengthSquared() >= maxsquared); - th->x += FLOAT2FIXED(advance.X); - th->y += FLOAT2FIXED(advance.Y); - th->z += FLOAT2FIXED(advance.Z); + th->SetXYZ( + th->X() + FLOAT2FIXED(advance.X), + th->Y() + FLOAT2FIXED(advance.Y), + th->Z() + FLOAT2FIXED(advance.Z)); } FCheckPosition tm(!!(th->flags2 & MF2_RIP)); @@ -5590,7 +5601,7 @@ bool P_CheckMissileSpawn (AActor* th, fixed_t maxdist) bool MBFGrenade = (!(th->flags & MF_MISSILE) || (th->BounceFlags & BOUNCE_MBF)); // killough 3/15/98: no dropoff (really = don't care for missiles) - if (!(P_TryMove (th, th->x, th->y, false, NULL, tm, true))) + if (!(P_TryMove (th, th->X(), th->Y(), false, NULL, tm, true))) { // [RH] Don't explode ripping missiles that spawn inside something if (th->BlockingMobj == NULL || !(th->flags2 & MF2_RIP) || (th->BlockingMobj->flags5 & MF5_DONTRIP)) @@ -5643,7 +5654,7 @@ void P_PlaySpawnSound(AActor *missile, AActor *spawner) // If there is no spawner use the spawn position. // But not in a silenced sector. if (!(missile->Sector->Flags & SECF_SILENT)) - S_Sound (missile->x, missile->y, missile->z, CHAN_WEAPON, missile->SeeSound, 1, ATTN_NORM); + S_Sound (missile->X(), missile->Y(), missile->Z(), CHAN_WEAPON, missile->SeeSound, 1, ATTN_NORM); } } } @@ -5672,7 +5683,7 @@ AActor *P_SpawnMissile (AActor *source, AActor *dest, const PClass *type, AActor { return NULL; } - return P_SpawnMissileXYZ (source->x, source->y, source->z + 32*FRACUNIT + source->GetBobOffset(), + return P_SpawnMissileXYZ (source->X(), source->Y(), source->Z() + 32*FRACUNIT + source->GetBobOffset(), source, dest, type, true, owner); } @@ -5682,7 +5693,7 @@ AActor *P_SpawnMissileZ (AActor *source, fixed_t z, AActor *dest, const PClass * { return NULL; } - return P_SpawnMissileXYZ (source->x, source->y, z, source, dest, type); + return P_SpawnMissileXYZ (source->X(), source->Y(), z, source, dest, type); } AActor *P_SpawnMissileXYZ (fixed_t x, fixed_t y, fixed_t z, @@ -5721,16 +5732,16 @@ AActor *P_SpawnMissileXYZ (fixed_t x, fixed_t y, fixed_t z, // missile? // Answer: No, because this way, you can set up sets of parallel missiles. - FVector3 velocity(dest->x - source->x, dest->y - source->y, dest->z - source->z); + FVector3 velocity = source->Vec3To(dest); // Floor and ceiling huggers should never have a vertical component to their velocity if (th->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER)) { velocity.Z = 0; } // [RH] Adjust the trajectory if the missile will go over the target's head. - else if (z - source->z >= dest->height) + else if (z - source->Z() >= dest->height) { - velocity.Z += dest->height - z + source->z; + velocity.Z += dest->height - z + source->Z(); } velocity.Resize (speed); th->velx = (fixed_t)(velocity.X); @@ -5768,23 +5779,23 @@ AActor * P_OldSpawnMissile(AActor * source, AActor * owner, AActor * dest, const } angle_t an; fixed_t dist; - AActor *th = Spawn (type, source->x, source->y, source->z + 4*8*FRACUNIT, ALLOW_REPLACE); + AActor *th = Spawn (type, source->PosPlusZ(4*8*FRACUNIT), ALLOW_REPLACE); P_PlaySpawnSound(th, source); th->target = owner; // record missile's originator - th->angle = an = R_PointToAngle2 (source->x, source->y, dest->x, dest->y); + th->angle = an = source->AngleTo(dest); an >>= ANGLETOFINESHIFT; th->velx = FixedMul (th->Speed, finecosine[an]); th->vely = FixedMul (th->Speed, finesine[an]); - dist = P_AproxDistance (dest->x - source->x, dest->y - source->y); + dist = source->AproxDistance (dest); if (th->Speed) dist = dist / th->Speed; if (dist < 1) dist = 1; - th->velz = (dest->z - source->z) / dist; + th->velz = (dest->Z() - source->Z()) / dist; if (th->flags4 & MF4_SPECTRAL) { @@ -5811,7 +5822,7 @@ AActor *P_SpawnMissileAngle (AActor *source, const PClass *type, { return NULL; } - return P_SpawnMissileAngleZSpeed (source, source->z + 32*FRACUNIT + source->GetBobOffset(), + return P_SpawnMissileAngleZSpeed (source, source->Z() + 32*FRACUNIT + source->GetBobOffset(), type, angle, velz, GetDefaultSpeed (type)); } @@ -5839,10 +5850,10 @@ AActor *P_SpawnMissileZAimed (AActor *source, fixed_t z, AActor *dest, const PCl { an += pr_spawnmissile.Random2() << 20; } - dist = P_AproxDistance (dest->x - source->x, dest->y - source->y); + dist = source->AproxDistance (dest); speed = GetDefaultSpeed (type); dist /= speed; - velz = dist != 0 ? (dest->z - source->z)/dist : speed; + velz = dist != 0 ? (dest->Z() - source->Z())/dist : speed; return P_SpawnMissileAngleZSpeed (source, z, type, an, velz, speed); } @@ -5862,7 +5873,7 @@ AActor *P_SpawnMissileAngleSpeed (AActor *source, const PClass *type, { return NULL; } - return P_SpawnMissileAngleZSpeed (source, source->z + 32*FRACUNIT + source->GetBobOffset(), + return P_SpawnMissileAngleZSpeed (source, source->Z() + 32*FRACUNIT + source->GetBobOffset(), type, angle, velz, speed); } @@ -5880,7 +5891,7 @@ AActor *P_SpawnMissileAngleZSpeed (AActor *source, fixed_t z, z -= source->floorclip; } - mo = Spawn (type, source->x, source->y, z, ALLOW_REPLACE); + mo = Spawn (type, source->X(), source->Y(), z, ALLOW_REPLACE); P_PlaySpawnSound(mo, source); if (owner == NULL) owner = source; @@ -5980,7 +5991,7 @@ AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, if (z != ONFLOORZ && z != ONCEILINGZ) { // Doom spawns missiles 4 units lower than hitscan attacks for players. - z += source->z + (source->height>>1) - source->floorclip; + z += source->Z() + (source->height>>1) - source->floorclip; if (source->player != NULL) // Considering this is for player missiles, it better not be NULL. { z += FixedMul (source->player->mo->AttackZOffset - 4*FRACUNIT, source->player->crouchfactor); @@ -5995,7 +6006,8 @@ AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, z = source->floorz; } } - AActor *MissileActor = Spawn (type, source->x + x, source->y + y, z, ALLOW_REPLACE); + fixedvec2 pos = source->Vec2Offset(x, y); + AActor *MissileActor = Spawn (type, pos.x, pos.y, z, ALLOW_REPLACE); if (pMissileActor) *pMissileActor = MissileActor; P_PlaySpawnSound(MissileActor, source); MissileActor->target = source; @@ -6503,7 +6515,7 @@ void PrintMiscActorInfo(AActor *query) query->args[4], query->special1, query->special2); Printf("\nTID: %d", query->tid); Printf("\nCoord= x: %f, y: %f, z:%f, floor:%f, ceiling:%f.", - FIXED2FLOAT(query->x), FIXED2FLOAT(query->y), FIXED2FLOAT(query->z), + FIXED2FLOAT(query->X()), FIXED2FLOAT(query->Y()), FIXED2FLOAT(query->Z()), FIXED2FLOAT(query->floorz), FIXED2FLOAT(query->ceilingz)); Printf("\nSpeed= %f, velocity= x:%f, y:%f, z:%f, combined:%f.\n", FIXED2FLOAT(query->Speed), FIXED2FLOAT(query->velx), FIXED2FLOAT(query->vely), FIXED2FLOAT(query->velz), diff --git a/src/p_pillar.cpp b/src/p_pillar.cpp index 884218bee..b1cae3af9 100644 --- a/src/p_pillar.cpp +++ b/src/p_pillar.cpp @@ -198,17 +198,20 @@ DPillar::DPillar (sector_t *sector, EPillar type, fixed_t speed, m_FloorSpeed = Scale (speed, floordist, ceilingdist); } - if (sector->seqType >= 0) + if (!(m_Sector->Flags & SECF_SILENTMOVE)) { - SN_StartSequence (sector, CHAN_FLOOR, sector->seqType, SEQ_PLATFORM, 0); - } - else if (sector->SeqName != NAME_None) - { - SN_StartSequence (sector, CHAN_FLOOR, sector->SeqName, 0); - } - else - { - SN_StartSequence (sector, CHAN_FLOOR, "Floor", 0); + if (sector->seqType >= 0) + { + SN_StartSequence(sector, CHAN_FLOOR, sector->seqType, SEQ_PLATFORM, 0); + } + else if (sector->SeqName != NAME_None) + { + SN_StartSequence(sector, CHAN_FLOOR, sector->SeqName, 0); + } + else + { + SN_StartSequence(sector, CHAN_FLOOR, "Floor", 0); + } } } diff --git a/src/p_plats.cpp b/src/p_plats.cpp index 7600637b2..b0697fc34 100644 --- a/src/p_plats.cpp +++ b/src/p_plats.cpp @@ -72,6 +72,8 @@ void DPlat::Serialize (FArchive &arc) void DPlat::PlayPlatSound (const char *sound) { + if (m_Sector->Flags & SECF_SILENTMOVE) return; + if (m_Sector->seqType >= 0) { SN_StartSequence (m_Sector, CHAN_FLOOR, m_Sector->seqType, SEQ_PLATFORM, 0); @@ -280,8 +282,7 @@ bool EV_DoPlat (int tag, line_t *line, DPlat::EPlatType type, int height, { if (line) sec->SetTexture(sector_t::floor, line->sidedef[0]->sector->GetTexture(sector_t::floor)); - if (change == 1) - sec->special &= SECRET_MASK; // Stop damage and other stuff, if any + if (change == 1) sec->ClearSpecial(); } switch (type) @@ -293,7 +294,7 @@ bool EV_DoPlat (int tag, line_t *line, DPlat::EPlatType type, int height, plat->m_Low = sec->floorplane.d; plat->m_Status = DPlat::up; plat->PlayPlatSound ("Floor"); - sec->special &= SECRET_MASK; // NO MORE DAMAGE, IF APPLICABLE + sec->ClearSpecial(); break; case DPlat::platUpByValue: diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 63f3bc648..7cdef059c 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -38,6 +38,30 @@ // TYPES ------------------------------------------------------------------- +struct FGenericButtons +{ + int ReadyFlag; // Flag passed to A_WeaponReady + int StateFlag; // Flag set in WeaponState + int ButtonFlag; // Button to press + ENamedName StateName; // Name of the button/state +}; + +enum EWRF_Options +{ + WRF_NoBob = 1, + WRF_NoSwitch = 1 << 1, + WRF_NoPrimary = 1 << 2, + WRF_NoSecondary = 1 << 3, + WRF_NoFire = WRF_NoPrimary | WRF_NoSecondary, + WRF_AllowReload = 1 << 4, + WRF_AllowZoom = 1 << 5, + WRF_DisableSwitch = 1 << 6, + WRF_AllowUser1 = 1 << 7, + WRF_AllowUser2 = 1 << 8, + WRF_AllowUser3 = 1 << 9, + WRF_AllowUser4 = 1 << 10, +}; + // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- @@ -57,6 +81,16 @@ CVAR(Int, sv_fastweapons, false, CVAR_SERVERINFO); static FRandom pr_wpnreadysnd ("WpnReadySnd"); static FRandom pr_gunshot ("GunShot"); +static const FGenericButtons ButtonChecks[] = +{ + { WRF_AllowZoom, WF_WEAPONZOOMOK, BT_ZOOM, NAME_Zoom }, + { WRF_AllowReload, WF_WEAPONRELOADOK, BT_RELOAD, NAME_Reload }, + { WRF_AllowUser1, WF_USER1OK, BT_USER1, NAME_User1 }, + { WRF_AllowUser2, WF_USER2OK, BT_USER2, NAME_User2 }, + { WRF_AllowUser3, WF_USER3OK, BT_USER3, NAME_User3 }, + { WRF_AllowUser4, WF_USER4OK, BT_USER4, NAME_User4 }, +}; + // CODE -------------------------------------------------------------------- //--------------------------------------------------------------------------- @@ -95,7 +129,8 @@ void P_SetPsprite (player_t *player, int position, FState *state, bool nofunctio if (position == ps_weapon && !nofunction) { // A_WeaponReady will re-set these as needed - player->WeaponState &= ~(WF_WEAPONREADY | WF_WEAPONREADYALT | WF_WEAPONBOBBING | WF_WEAPONSWITCHOK | WF_WEAPONRELOADOK | WF_WEAPONZOOMOK); + player->WeaponState &= ~(WF_WEAPONREADY | WF_WEAPONREADYALT | WF_WEAPONBOBBING | WF_WEAPONSWITCHOK | WF_WEAPONRELOADOK | WF_WEAPONZOOMOK | + WF_USER1OK | WF_USER2OK | WF_USER3OK | WF_USER4OK); } psp = &player->psprites[position]; @@ -289,66 +324,6 @@ void P_FireWeaponAlt (player_t *player, FState *state) } } -//--------------------------------------------------------------------------- -// -// PROC P_ReloadWeapon -// -//--------------------------------------------------------------------------- - -void P_ReloadWeapon (player_t *player, FState *state) -{ - AWeapon *weapon; - if (player->Bot == NULL && bot_observer) - { - return; - } - - weapon = player->ReadyWeapon; - if (weapon == NULL) - { - return; - } - - if (state == NULL) - { - state = weapon->GetRelState(); - } - // [XA] don't change state if still null, so if the modder sets - // WRF_RELOAD to true but forgets to define the Reload state, the weapon - // won't disappear. ;) - if (state != NULL) - P_SetPsprite (player, ps_weapon, state); -} - -//--------------------------------------------------------------------------- -// -// PROC P_ZoomWeapon -// -//--------------------------------------------------------------------------- - -void P_ZoomWeapon (player_t *player, FState *state) -{ - AWeapon *weapon; - if (player->Bot == NULL && bot_observer) - { - return; - } - - weapon = player->ReadyWeapon; - if (weapon == NULL) - { - return; - } - - if (state == NULL) - { - state = weapon->GetZoomState(); - } - // [XA] don't change state if still null. Same reasons as above. - if (state != NULL) - P_SetPsprite (player, ps_weapon, state); -} - //--------------------------------------------------------------------------- // // PROC P_DropWeapon @@ -562,22 +537,21 @@ void DoReadyWeaponToBob (AActor *self) } } -void DoReadyWeaponToReload (AActor *self) +void DoReadyWeaponToGeneric(AActor *self, int paramflags) { - // Prepare for reload action. - player_t *player; - if (self && (player = self->player)) - player->WeaponState |= WF_WEAPONRELOADOK; - return; -} + int flags = 0; -void DoReadyWeaponToZoom (AActor *self) -{ - // Prepare for reload action. - player_t *player; - if (self && (player = self->player)) - player->WeaponState |= WF_WEAPONZOOMOK; - return; + for (size_t i = 0; i < countof(ButtonChecks); ++i) + { + if (paramflags & ButtonChecks[i].ReadyFlag) + { + flags |= ButtonChecks[i].StateFlag; + } + } + if (self != NULL && self->player != NULL) + { + self->player->WeaponState |= flags; + } } // This function replaces calls to A_WeaponReady in other codepointers. @@ -586,22 +560,9 @@ void DoReadyWeapon(AActor *self) DoReadyWeaponToBob(self); DoReadyWeaponToFire(self); DoReadyWeaponToSwitch(self); - DoReadyWeaponToReload(self); - DoReadyWeaponToZoom(self); + DoReadyWeaponToGeneric(self, ~0); } -enum EWRF_Options -{ - WRF_NoBob = 1, - WRF_NoSwitch = 2, - WRF_NoPrimary = 4, - WRF_NoSecondary = 8, - WRF_NoFire = WRF_NoPrimary + WRF_NoSecondary, - WRF_AllowReload = 16, - WRF_AllowZoom = 32, - WRF_DisableSwitch = 64, -}; - DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_WeaponReady) { ACTION_PARAM_START(1); @@ -610,10 +571,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_WeaponReady) DoReadyWeaponToSwitch(self, !(paramflags & WRF_NoSwitch)); if ((paramflags & WRF_NoFire) != WRF_NoFire) DoReadyWeaponToFire(self, !(paramflags & WRF_NoPrimary), !(paramflags & WRF_NoSecondary)); if (!(paramflags & WRF_NoBob)) DoReadyWeaponToBob(self); - if ((paramflags & WRF_AllowReload)) DoReadyWeaponToReload(self); - if ((paramflags & WRF_AllowZoom)) DoReadyWeaponToZoom(self); - - DoReadyWeaponDisableSwitch(self, paramflags & WRF_DisableSwitch); + DoReadyWeaponToGeneric(self, paramflags); + DoReadyWeaponDisableSwitch(self, paramflags & WRF_DisableSwitch); } //--------------------------------------------------------------------------- @@ -690,45 +649,40 @@ void P_CheckWeaponSwitch (player_t *player) //--------------------------------------------------------------------------- // -// PROC P_CheckWeaponReload +// PROC P_CheckWeaponButtons // -// The player can reload the weapon. +// Check extra button presses for weapons. // //--------------------------------------------------------------------------- -void P_CheckWeaponReload (player_t *player) +static void P_CheckWeaponButtons (player_t *player) { - AWeapon *weapon = player->ReadyWeapon; - - if (weapon == NULL) - return; - - // Check for reload. - if ((player->WeaponState & WF_WEAPONRELOADOK) && (player->cmd.ucmd.buttons & BT_RELOAD)) + if (player->Bot == NULL && bot_observer) { - P_ReloadWeapon (player, NULL); + return; } -} - -//--------------------------------------------------------------------------- -// -// PROC P_CheckWeaponZoom -// -// The player can use the weapon's zoom function. -// -//--------------------------------------------------------------------------- - -void P_CheckWeaponZoom (player_t *player) -{ AWeapon *weapon = player->ReadyWeapon; - if (weapon == NULL) - return; - - // Check for zoom. - if ((player->WeaponState & WF_WEAPONZOOMOK) && (player->cmd.ucmd.buttons & BT_ZOOM)) { - P_ZoomWeapon (player, NULL); + return; + } + // The button checks are ordered by precedence. The first one to match a + // button press and affect a state change wins. + for (size_t i = 0; i < countof(ButtonChecks); ++i) + { + if ((player->WeaponState & ButtonChecks[i].StateFlag) && + (player->cmd.ucmd.buttons & ButtonChecks[i].ButtonFlag)) + { + FState *state = weapon->GetStateForButtonName(ButtonChecks[i].StateName); + // [XA] don't change state if still null, so if the modder + // sets WRF_xxx to true but forgets to define the corresponding + // state, the weapon won't disappear. ;) + if (state != NULL) + { + P_SetPsprite(player, ps_weapon, state); + return; + } + } } } @@ -1095,14 +1049,9 @@ void P_MovePsprites (player_t *player) { P_CheckWeaponFire (player); } - if (player->WeaponState & WF_WEAPONRELOADOK) - { - P_CheckWeaponReload (player); - } - if (player->WeaponState & WF_WEAPONZOOMOK) - { - P_CheckWeaponZoom (player); - } + + // Check custom buttons + P_CheckWeaponButtons(player); } } diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 480494320..7623104d7 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -52,6 +52,7 @@ #include "farchive.h" #include "p_lnspec.h" #include "p_acs.h" +#include "p_terrain.h" static void CopyPlayer (player_t *dst, player_t *src, const char *name); static void ReadOnePlayer (FArchive &arc, bool skipload); @@ -354,7 +355,7 @@ void P_SerializeWorld (FArchive &arc) short tag; arc << tag; } - arc << sec->soundtraversed + arc << sec->soundtraversed << sec->seqType << sec->friction << sec->movefactor @@ -368,18 +369,66 @@ void P_SerializeWorld (FArchive &arc) << sec->planes[sector_t::ceiling] << sec->heightsec << sec->bottommap << sec->midmap << sec->topmap - << sec->gravity - << sec->damage - << sec->mod - << sec->SoundTarget + << sec->gravity; + if (SaveVersion >= 4530) + { + P_SerializeTerrain(arc, sec->terrainnum[0]); + P_SerializeTerrain(arc, sec->terrainnum[1]); + } + if (SaveVersion >= 4529) + { + arc << sec->damageamount; + } + else + { + short dmg; + arc << dmg; + sec->damageamount = dmg; + } + if (SaveVersion >= 4528) + { + arc << sec->damageinterval + << sec->leakydamage + << sec->damagetype; + } + else + { + short damagemod; + arc << damagemod; + sec->damagetype = MODtoDamageType(damagemod); + if (sec->damageamount < 20) + { + sec->leakydamage = 0; + sec->damageinterval = 32; + } + else if (sec->damageamount < 50) + { + sec->leakydamage = 5; + sec->damageinterval = 32; + } + else + { + sec->leakydamage = 256; + sec->damageinterval = 1; + } + } + + arc << sec->SoundTarget << sec->SecActTarget << sec->sky << sec->MoreFlags << sec->Flags - << sec->FloorSkyBox << sec->CeilingSkyBox - << sec->ZoneNumber - << sec->secretsector - << sec->interpolations[0] + << sec->SkyBoxes[sector_t::floor] << sec->SkyBoxes[sector_t::ceiling] + << sec->ZoneNumber; + if (SaveVersion < 4529) + { + short secretsector; + arc << secretsector; + if (secretsector) sec->Flags |= SECF_WASSECRET; + sec->special &= ~(SECRET_MASK|FRICTION_MASK|PUSH_MASK); + P_InitSectorSpecial(sec, sec->special, true); + } + arc << sec->interpolations[0] << sec->interpolations[1] << sec->interpolations[2] << sec->interpolations[3] diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 361b220a7..83adc438f 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -26,6 +26,7 @@ #include "doomstat.h" #include "g_level.h" #include "nodebuild.h" +#include "p_terrain.h" #include "po_man.h" #include "farchive.h" #include "r_utility.h" @@ -49,7 +50,7 @@ sector_t *sector_t::NextSpecialSector (int type, sector_t *nogood) const if (NULL != (tsec = getNextSector (ln, this)) && tsec != nogood && - (tsec->special & 0x00ff) == type) + tsec->special == type) { return tsec; } @@ -804,16 +805,8 @@ int sector_t::GetCeilingLight () const ASkyViewpoint *sector_t::GetSkyBox(int which) { - if (which == floor) - { - if (FloorSkyBox != NULL) return FloorSkyBox; - if (MoreFlags & SECF_NOFLOORSKYBOX) return NULL; - } - else - { - if (CeilingSkyBox != NULL) return CeilingSkyBox; - if (MoreFlags & SECF_NOCEILINGSKYBOX) return NULL; - } + if (SkyBoxes[which] != NULL) return SkyBoxes[which]; + if (MoreFlags & (SECF_NOFLOORSKYBOX << which)) return NULL; return level.DefaultSkybox; } @@ -843,6 +836,65 @@ sector_t *sector_t::GetHeightSec() const } +void sector_t::GetSpecial(secspecial_t *spec) +{ + spec->special = special; + spec->damageamount = damageamount; + spec->damagetype = damagetype; + spec->damageinterval = damageinterval; + spec->leakydamage = leakydamage; + spec->Flags = Flags & SECF_SPECIALFLAGS; +} + +void sector_t::SetSpecial(const secspecial_t *spec) +{ + special = spec->special; + damageamount = spec->damageamount; + damagetype = spec->damagetype; + damageinterval = spec->damageinterval; + leakydamage = spec->leakydamage; + Flags = (Flags & ~SECF_SPECIALFLAGS) | (spec->Flags & SECF_SPECIALFLAGS); +} + +void sector_t::TransferSpecial(sector_t *model) +{ + special = model->special; + damageamount = model->damageamount; + damagetype = model->damagetype; + damageinterval = model->damageinterval; + leakydamage = model->leakydamage; + Flags = (Flags&~SECF_SPECIALFLAGS) | (model->Flags & SECF_SPECIALFLAGS); +} + +int sector_t::GetTerrain(int pos) const +{ + return terrainnum[pos] >= 0 ? terrainnum[pos] : TerrainTypes[GetTexture(pos)]; +} + +FArchive &operator<< (FArchive &arc, secspecial_t &p) +{ + if (SaveVersion < 4529) + { + int special; + arc << special; + sector_t sec; + P_InitSectorSpecial(&sec, special, true); + sec.GetSpecial(&p); + } + else + { + arc << p.special + << p.damageamount + << p.damagetype + << p.damageinterval + << p.leakydamage + << p.Flags; + } + return arc; +} + + + bool secplane_t::CopyPlaneIfValid (secplane_t *dest, const secplane_t *opp) const { bool copy = false; diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 50e7f41d6..3749e97aa 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1512,7 +1512,6 @@ void P_LoadSectors (MapData *map, FMissingTextureTracker &missingtex) ss->special = LittleShort(ms->special); else // [RH] Translate to new sector special ss->special = P_TranslateSectorSpecial (LittleShort(ms->special)); - ss->secretsector = !!(ss->special&SECRET_MASK); tagManager.AddSectorTag(i, LittleShort(ms->tag)); ss->thinglist = NULL; ss->touching_thinglist = NULL; // phares 3/14/98 @@ -1533,6 +1532,7 @@ void P_LoadSectors (MapData *map, FMissingTextureTracker &missingtex) ss->gravity = 1.f; // [RH] Default sector gravity of 1.0 ss->ZoneNumber = 0xFFFF; + ss->terrainnum[sector_t::ceiling] = ss->terrainnum[sector_t::floor] = -1; // [RH] Sectors default to white light with the default fade. // If they are outside (have a sky ceiling), they use the outside fog. @@ -4049,7 +4049,7 @@ void P_SetupLevel (const char *lumpname, int position) { if (mo->flags & MF_COUNTKILL) { - if (mo->Sector->special == dDamage_End) + if (mo->Sector->damageamount > 0 && (mo->Sector->Flags & (SECF_ENDGODMODE|SECF_ENDLEVEL)) == (SECF_ENDGODMODE|SECF_ENDLEVEL)) { mo->ClearCounters(); } diff --git a/src/p_sight.cpp b/src/p_sight.cpp index 135698b8b..259b3baa8 100644 --- a/src/p_sight.cpp +++ b/src/p_sight.cpp @@ -68,11 +68,11 @@ public: SightCheck(const AActor * t1, const AActor * t2, int flags) { - lastztop = lastzbottom = sightzstart = t1->z + t1->height - (t1->height>>2); + lastztop = lastzbottom = sightzstart = t1->Z() + t1->height - (t1->height>>2); lastsector = t1->Sector; sightthing=t1; seeingthing=t2; - bottomslope = t2->z - sightzstart; + bottomslope = t2->Z() - sightzstart; topslope = bottomslope + t2->height; Flags = flags; @@ -132,7 +132,7 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in) { int frontflag; - frontflag = P_PointOnLineSide(sightthing->x, sightthing->y, li); + frontflag = P_PointOnLineSidePrecise(sightthing->X(), sightthing->Y(), li); //Check 3D FLOORS! for(int i=1;i<=2;i++) @@ -241,14 +241,14 @@ bool SightCheck::P_SightCheckLine (line_t *ld) return true; } ld->validcount = validcount; - if (P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace) == - P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace)) + if (P_PointOnDivlineSidePrecise (ld->v1->x, ld->v1->y, &trace) == + P_PointOnDivlineSidePrecise (ld->v2->x, ld->v2->y, &trace)) { return true; // line isn't crossed } P_MakeDivline (ld, &dl); - if (P_PointOnDivlineSide (trace.x, trace.y, &dl) == - P_PointOnDivlineSide (trace.x+trace.dx, trace.y+trace.dy, &dl)) + if (P_PointOnDivlineSidePrecise (trace.x, trace.y, &dl) == + P_PointOnDivlineSidePrecise (trace.x+trace.dx, trace.y+trace.dy, &dl)) { return true; // line isn't crossed } @@ -413,8 +413,8 @@ bool SightCheck::P_SightTraverseIntercepts () if((rover->flags & FF_SOLID) == myseethrough || !(rover->flags & FF_EXISTS)) continue; if ((Flags & SF_IGNOREWATERBOUNDARY) && (rover->flags & FF_SOLID) == 0) continue; - fixed_t ff_bottom=rover->bottom.plane->ZatPoint(seeingthing->x, seeingthing->y); - fixed_t ff_top=rover->top.plane->ZatPoint(seeingthing->x, seeingthing->y); + fixed_t ff_bottom=rover->bottom.plane->ZatPoint(seeingthing); + fixed_t ff_top=rover->top.plane->ZatPoint(seeingthing); if (lastztop<=ff_bottom && topz>ff_bottom && lastzbottom<=ff_bottom && bottomz>ff_bottom) return false; if (lastzbottom>=ff_top && bottomz=ff_top && topzflags & FF_EXISTS)) continue; - fixed_t ff_bottom=rover->bottom.plane->ZatPoint(sightthing->x, sightthing->y); - fixed_t ff_top=rover->top.plane->ZatPoint(sightthing->x, sightthing->y); + fixed_t ff_bottom=rover->bottom.plane->ZatPoint(sightthing); + fixed_t ff_top=rover->top.plane->ZatPoint(sightthing); if (sightzstart < ff_top && sightzstart >= ff_bottom) { @@ -691,16 +691,16 @@ sightcounts[0]++; if (!(flags & SF_IGNOREWATERBOUNDARY)) { if ((s1->GetHeightSec() && - ((t1->z + t1->height <= s1->heightsec->floorplane.ZatPoint (t1->x, t1->y) && - t2->z >= s1->heightsec->floorplane.ZatPoint (t2->x, t2->y)) || - (t1->z >= s1->heightsec->ceilingplane.ZatPoint (t1->x, t1->y) && - t2->z + t1->height <= s1->heightsec->ceilingplane.ZatPoint (t2->x, t2->y)))) + ((t1->Z() + t1->height <= s1->heightsec->floorplane.ZatPoint(t1) && + t2->Z() >= s1->heightsec->floorplane.ZatPoint(t2)) || + (t1->Z() >= s1->heightsec->ceilingplane.ZatPoint(t1) && + t2->Z() + t1->height <= s1->heightsec->ceilingplane.ZatPoint(t2)))) || (s2->GetHeightSec() && - ((t2->z + t2->height <= s2->heightsec->floorplane.ZatPoint (t2->x, t2->y) && - t1->z >= s2->heightsec->floorplane.ZatPoint (t1->x, t1->y)) || - (t2->z >= s2->heightsec->ceilingplane.ZatPoint (t2->x, t2->y) && - t1->z + t2->height <= s2->heightsec->ceilingplane.ZatPoint (t1->x, t1->y))))) + ((t2->Z() + t2->height <= s2->heightsec->floorplane.ZatPoint(t2) && + t1->Z() >= s2->heightsec->floorplane.ZatPoint(t1)) || + (t2->Z() >= s2->heightsec->ceilingplane.ZatPoint(t2) && + t1->Z() + t2->height <= s2->heightsec->ceilingplane.ZatPoint(t1))))) { res = false; goto done; @@ -713,7 +713,7 @@ sightcounts[0]++; validcount++; { SightCheck s(t1, t2, flags); - res = s.P_SightPathTraverse (t1->x, t1->y, t2->x, t2->y); + res = s.P_SightPathTraverse (t1->X(), t1->Y(), t2->X(), t2->Y()); } done: diff --git a/src/p_slopes.cpp b/src/p_slopes.cpp index c0b9b5ef0..a3db26526 100644 --- a/src/p_slopes.cpp +++ b/src/p_slopes.cpp @@ -54,7 +54,7 @@ static void P_SlopeLineToPoint (int lineid, fixed_t x, fixed_t y, fixed_t z, boo sector_t *sec; secplane_t *plane; - if (P_PointOnLineSide (x, y, line) == 0) + if (P_PointOnLineSidePrecise (x, y, line) == 0) { sec = line->frontsector; } @@ -363,7 +363,7 @@ static void P_SetSlopesFromVertexHeights(FMapThing *firstmt, FMapThing *lastmt, z3 = h3? *h3 : j==0? sec->GetPlaneTexZ(sector_t::floor) : sec->GetPlaneTexZ(sector_t::ceiling); vt3.Z = FIXED2FLOAT(z3); - if (P_PointOnLineSide(vertexes[vi3].x, vertexes[vi3].y, sec->lines[0]) == 0) + if (P_PointOnLineSidePrecise(vertexes[vi3].x, vertexes[vi3].y, sec->lines[0]) == 0) { vec1 = vt2 - vt3; vec2 = vt1 - vt3; diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 9bc0d4a9b..523295642 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -62,6 +62,7 @@ #include "farchive.h" #include "a_keys.h" #include "c_dispatch.h" +#include "r_sky.h" // State. #include "r_state.h" @@ -71,7 +72,6 @@ #include "r_data/r_interpolate.h" static FRandom pr_playerinspecialsector ("PlayerInSpecialSector"); -void P_SetupPortals(); EXTERN_CVAR(Bool, cl_predict_specials) @@ -288,16 +288,16 @@ bool P_TestActivateLine (line_t *line, AActor *mo, int side, int activationType) } } + if (activationType == SPAC_Use && (lineActivation & SPAC_MUse) && !mo->player && mo->flags4 & MF4_CANUSEWALLS) + { + return true; + } + if (activationType == SPAC_Push && (lineActivation & SPAC_MPush) && !mo->player && mo->flags2 & MF2_PUSHWALL) + { + return true; + } if ((lineActivation & activationType) == 0) { - if (activationType == SPAC_Use && (lineActivation & SPAC_MUse) && !mo->player && mo->flags4 & MF4_CANUSEWALLS) - { - return true; - } - if (activationType == SPAC_Push && (lineActivation & SPAC_MPush) && !mo->player && mo->flags2 & MF2_PUSHWALL) - { - return true; - } if (activationType != SPAC_MCross || lineActivation != SPAC_Cross) { return false; @@ -430,166 +430,62 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector) { // Falling, not all the way down yet? sector = player->mo->Sector; - if (player->mo->z != sector->floorplane.ZatPoint (player->mo->x, player->mo->y) + if (player->mo->Z() != sector->floorplane.ZatPoint(player->mo) && !player->mo->waterlevel) { return; } } - int special = sector->special & ~SECRET_MASK; - // Has hit ground. AInventory *ironfeet; - // Allow subclasses. Better would be to implement it as armor and let that reduce - // the damage as part of the normal damage procedure. Unfortunately, I don't have - // different damage types yet, so that's not happening for now. - for (ironfeet = player->mo->Inventory; ironfeet != NULL; ironfeet = ironfeet->Inventory) - { - if (ironfeet->IsKindOf (RUNTIME_CLASS(APowerIronFeet))) - break; - } - - // [RH] Normal DOOM special or BOOM specialized? - if (special >= dLight_Flicker && special <= 255) - { - switch (special) - { - case Sector_Heal: - // CoD's healing sector - if (!(level.time & 0x1f)) - P_GiveBody (player->mo, 1); - break; - - case Damage_InstantDeath: - // Strife's instant death sector - P_DamageMobj (player->mo, NULL, NULL, 999, NAME_InstantDeath); - break; - - case dDamage_Hellslime: - // HELLSLIME DAMAGE - if (ironfeet == NULL && !(level.time&0x1f)) - P_DamageMobj (player->mo, NULL, NULL, 10, NAME_Slime); - break; - - case dDamage_Nukage: - // NUKAGE DAMAGE - case sLight_Strobe_Hurt: - if (ironfeet == NULL && !(level.time&0x1f)) - P_DamageMobj (player->mo, NULL, NULL, 5, NAME_Slime); - break; - - case hDamage_Sludge: - if (ironfeet == NULL && !(level.time&0x1f)) - P_DamageMobj (player->mo, NULL, NULL, 4, NAME_Slime); - break; - - case dDamage_SuperHellslime: - // SUPER HELLSLIME DAMAGE - case dLight_Strobe_Hurt: - // STROBE HURT - if (ironfeet == NULL || pr_playerinspecialsector() < 5) - { - if (!(level.time&0x1f)) - P_DamageMobj (player->mo, NULL, NULL, 20, NAME_Slime); - } - break; - - case sDamage_Hellslime: - if (ironfeet == NULL) - player->hazardcount += 2; - break; - - case sDamage_SuperHellslime: - if (ironfeet == NULL) - player->hazardcount += 4; - break; - - case dDamage_End: - // EXIT SUPER DAMAGE! (for E1M8 finale) - player->cheats &= ~CF_GODMODE; - - if (!(level.time & 0x1f)) - P_DamageMobj (player->mo, NULL, NULL, 20, NAME_None); - - if (player->health <= 10 && (!deathmatch || !(dmflags & DF_NO_EXIT))) - G_ExitLevel(0, false); - break; - - case dDamage_LavaWimpy: - case dScroll_EastLavaDamage: - if (!(level.time & 15)) - { - P_DamageMobj(player->mo, NULL, NULL, 5, NAME_Fire); - P_HitFloor(player->mo); - } - break; - - case dDamage_LavaHefty: - if(!(level.time & 15)) - { - P_DamageMobj(player->mo, NULL, NULL, 8, NAME_Fire); - P_HitFloor(player->mo); - } - break; - - default: - // [RH] Ignore unknown specials - break; - } - } - else - { - //jff 3/14/98 handle extended sector types for secrets and damage - switch (special & DAMAGE_MASK) - { - case 0x000: // no damage - break; - case 0x100: // 2/5 damage per 31 ticks - if (ironfeet == NULL && !(level.time&0x1f)) - P_DamageMobj (player->mo, NULL, NULL, 5, NAME_Fire); - break; - case 0x200: // 5/10 damage per 31 ticks - if (ironfeet == NULL && !(level.time&0x1f)) - P_DamageMobj (player->mo, NULL, NULL, 10, NAME_Slime); - break; - case 0x300: // 10/20 damage per 31 ticks - if (ironfeet == NULL - || pr_playerinspecialsector() < 5) // take damage even with suit - { - if (!(level.time&0x1f)) - P_DamageMobj (player->mo, NULL, NULL, 20, NAME_Slime); - } - break; - } - } - // [RH] Apply any customizable damage - if (sector->damage) + if (sector->damageamount > 0) { - if (sector->damage < 20) + // Allow subclasses. Better would be to implement it as armor and let that reduce + // the damage as part of the normal damage procedure. Unfortunately, I don't have + // different damage types yet, so that's not happening for now. + for (ironfeet = player->mo->Inventory; ironfeet != NULL; ironfeet = ironfeet->Inventory) { - if (ironfeet == NULL && !(level.time&0x1f)) - P_DamageMobj (player->mo, NULL, NULL, sector->damage, MODtoDamageType (sector->mod)); + if (ironfeet->IsKindOf (RUNTIME_CLASS(APowerIronFeet))) + break; } - else if (sector->damage < 50) + + if (sector->Flags & SECF_ENDGODMODE) player->cheats &= ~CF_GODMODE; + if ((ironfeet == NULL || pr_playerinspecialsector() < sector->leakydamage)) { - if ((ironfeet == NULL || (pr_playerinspecialsector()<5)) - && !(level.time&0x1f)) + if (sector->Flags & SECF_HAZARD) { - P_DamageMobj (player->mo, NULL, NULL, sector->damage, MODtoDamageType (sector->mod)); + player->hazardcount += sector->damageamount; + player->hazardtype = sector->damagetype; + player->hazardinterval = sector->damageinterval; + } + else if (level.time % sector->damageinterval == 0) + { + P_DamageMobj(player->mo, NULL, NULL, sector->damageamount, sector->damagetype); + if ((sector->Flags & SECF_ENDLEVEL) && player->health <= 10 && (!deathmatch || !(dmflags & DF_NO_EXIT))) + { + G_ExitLevel(0, false); + } + if (sector->Flags & SECF_DMGTERRAINFX) + { + P_HitWater(player->mo, sector, INT_MIN, INT_MIN, INT_MIN, false, true, true); + } } } - else + } + else if (sector->damageamount < 0) + { + if (level.time % sector->damageinterval == 0) { - P_DamageMobj (player->mo, NULL, NULL, sector->damage, MODtoDamageType (sector->mod)); + P_GiveBody(player->mo, -sector->damageamount, 100); } } - if (sector->special & SECRET_MASK) + if (sector->isSecret()) { - sector->special &= ~SECRET_MASK; + sector->ClearSecret(); P_GiveSecret(player->mo, true, true, int(sector - sectors)); } } @@ -611,7 +507,7 @@ static void DoSectorDamage(AActor *actor, sector_t *sec, int amount, FName type, if (!(flags & DAMAGE_PLAYERS) && actor->player != NULL) return; - if (!(flags & DAMAGE_IN_AIR) && actor->z != sec->floorplane.ZatPoint(actor->x, actor->y) && !actor->waterlevel) + if (!(flags & DAMAGE_IN_AIR) && actor->Z() != sec->floorplane.ZatPoint(actor) && !actor->waterlevel) return; if (protectClass != NULL) @@ -648,8 +544,8 @@ void P_SectorDamage(int tag, int amount, FName type, const PClass *protectClass, { next = actor->snext; // Only affect actors touching the 3D floor - fixed_t z1 = sec->floorplane.ZatPoint(actor->x, actor->y); - fixed_t z2 = sec->ceilingplane.ZatPoint(actor->x, actor->y); + fixed_t z1 = sec->floorplane.ZatPoint(actor); + fixed_t z2 = sec->ceilingplane.ZatPoint(actor); if (z2 < z1) { // Account for Vavoom-style 3D floors @@ -657,12 +553,12 @@ void P_SectorDamage(int tag, int amount, FName type, const PClass *protectClass, z1 = z2; z2 = zz; } - if (actor->z + actor->height > z1) + if (actor->Z() + actor->height > z1) { // If DAMAGE_IN_AIR is used, anything not beneath the 3D floor will be // damaged (so, anything touching it or above it). Other 3D floors between // the actor and this one will not stop this effect. - if ((flags & DAMAGE_IN_AIR) || actor->z <= z2) + if ((flags & DAMAGE_IN_AIR) || actor->Z() <= z2) { // Here we pass the DAMAGE_IN_AIR flag to disable the floor check, since it // only works with the real sector's floor. We did the appropriate height checks @@ -1013,10 +909,10 @@ static void SetupFloorPortal (AStackPoint *point) { NActorIterator it (NAME_LowerStackLookOnly, point->tid); sector_t *Sector = point->Sector; - Sector->FloorSkyBox = static_cast(it.Next()); - if (Sector->FloorSkyBox != NULL && Sector->FloorSkyBox->bAlways) + Sector->SkyBoxes[sector_t::floor] = static_cast(it.Next()); + if (Sector->SkyBoxes[sector_t::floor] != NULL && Sector->SkyBoxes[sector_t::floor]->bAlways) { - Sector->FloorSkyBox->Mate = point; + Sector->SkyBoxes[sector_t::floor]->Mate = point; if (Sector->GetAlpha(sector_t::floor) == OPAQUE) Sector->SetAlpha(sector_t::floor, Scale (point->args[0], OPAQUE, 255)); } @@ -1026,48 +922,15 @@ static void SetupCeilingPortal (AStackPoint *point) { NActorIterator it (NAME_UpperStackLookOnly, point->tid); sector_t *Sector = point->Sector; - Sector->CeilingSkyBox = static_cast(it.Next()); - if (Sector->CeilingSkyBox != NULL && Sector->CeilingSkyBox->bAlways) + Sector->SkyBoxes[sector_t::ceiling] = static_cast(it.Next()); + if (Sector->SkyBoxes[sector_t::ceiling] != NULL && Sector->SkyBoxes[sector_t::ceiling]->bAlways) { - Sector->CeilingSkyBox->Mate = point; + Sector->SkyBoxes[sector_t::ceiling]->Mate = point; if (Sector->GetAlpha(sector_t::ceiling) == OPAQUE) Sector->SetAlpha(sector_t::ceiling, Scale (point->args[0], OPAQUE, 255)); } } -static bool SpreadCeilingPortal(AStackPoint *pt, fixed_t alpha, sector_t *sector) -{ - bool fail = false; - sector->validcount = validcount; - for(int i=0; ilinecount; i++) - { - line_t *line = sector->lines[i]; - sector_t *backsector = sector == line->frontsector? line->backsector : line->frontsector; - if (line->backsector == line->frontsector) continue; - if (backsector == NULL) { fail = true; continue; } - if (backsector->validcount == validcount) continue; - if (backsector->CeilingSkyBox == pt) continue; - - // Check if the backside would map to the same visplane - if (backsector->CeilingSkyBox != NULL) { fail = true; continue; } - if (backsector->ceilingplane != sector->ceilingplane) { fail = true; continue; } - if (backsector->lightlevel != sector->lightlevel) { fail = true; continue; } - if (backsector->GetTexture(sector_t::ceiling) != sector->GetTexture(sector_t::ceiling)) { fail = true; continue; } - if (backsector->GetXOffset(sector_t::ceiling) != sector->GetXOffset(sector_t::ceiling)) { fail = true; continue; } - if (backsector->GetYOffset(sector_t::ceiling) != sector->GetYOffset(sector_t::ceiling)) { fail = true; continue; } - if (backsector->GetXScale(sector_t::ceiling) != sector->GetXScale(sector_t::ceiling)) { fail = true; continue; } - if (backsector->GetYScale(sector_t::ceiling) != sector->GetYScale(sector_t::ceiling)) { fail = true; continue; } - if (backsector->GetAngle(sector_t::ceiling) != sector->GetAngle(sector_t::ceiling)) { fail = true; continue; } - if (SpreadCeilingPortal(pt, alpha, backsector)) { fail = true; continue; } - } - if (!fail) - { - sector->CeilingSkyBox = pt; - sector->SetAlpha(sector_t::ceiling, alpha); - } - return fail; -} - void P_SetupPortals() { TThinkerIterator it; @@ -1090,26 +953,64 @@ void P_SetupPortals() } } -inline void SetPortal(sector_t *sector, int plane, AStackPoint *portal, fixed_t alpha) +static void SetPortal(sector_t *sector, int plane, ASkyViewpoint *portal, fixed_t alpha) { // plane: 0=floor, 1=ceiling, 2=both if (plane > 0) { - if (sector->CeilingSkyBox == NULL || !sector->CeilingSkyBox->bAlways) + if (sector->SkyBoxes[sector_t::ceiling] == NULL || !sector->SkyBoxes[sector_t::ceiling]->bAlways) { - sector->CeilingSkyBox = portal; + sector->SkyBoxes[sector_t::ceiling] = portal; if (sector->GetAlpha(sector_t::ceiling) == OPAQUE) sector->SetAlpha(sector_t::ceiling, alpha); + + if (!portal->bAlways) sector->SetTexture(sector_t::ceiling, skyflatnum); } } if (plane == 2 || plane == 0) { - if (sector->FloorSkyBox == NULL || !sector->FloorSkyBox->bAlways) + if (sector->SkyBoxes[sector_t::floor] == NULL || !sector->SkyBoxes[sector_t::floor]->bAlways) { - sector->FloorSkyBox = portal; + sector->SkyBoxes[sector_t::floor] = portal; } if (sector->GetAlpha(sector_t::floor) == OPAQUE) sector->SetAlpha(sector_t::floor, alpha); + + if (!portal->bAlways) sector->SetTexture(sector_t::floor, skyflatnum); + } +} + +static void CopyPortal(int sectortag, int plane, ASkyViewpoint *origin, fixed_t alpha, bool tolines) +{ + int s; + FSectorTagIterator itr(sectortag); + while ((s = itr.Next()) >= 0) + { + SetPortal(§ors[s], plane, origin, alpha); + } + + for (int j=0;j= 0) + { + SetPortal(§ors[s], plane, origin, alpha); + } + } + } } } @@ -1125,10 +1026,11 @@ void P_SpawnPortal(line_t *line, int sectortag, int plane, int alpha) lines[i].args[2] == plane && lines[i].args[3] == 1) { - fixed_t x1 = (line->v1->x + line->v2->x) >> 1; - fixed_t y1 = (line->v1->y + line->v2->y) >> 1; - fixed_t x2 = (lines[i].v1->x + lines[i].v2->x) >> 1; - fixed_t y2 = (lines[i].v1->y + lines[i].v2->y) >> 1; + // beware of overflows. + fixed_t x1 = fixed_t((SQWORD(line->v1->x) + SQWORD(line->v2->x)) >> 1); + fixed_t y1 = fixed_t((SQWORD(line->v1->y) + SQWORD(line->v2->y)) >> 1); + fixed_t x2 = fixed_t((SQWORD(lines[i].v1->x) + SQWORD(lines[i].v2->x)) >> 1); + fixed_t y2 = fixed_t((SQWORD(lines[i].v1->y) + SQWORD(lines[i].v2->y)) >> 1); fixed_t alpha = Scale (lines[i].args[4], OPAQUE, 255); AStackPoint *anchor = Spawn(x1, y1, 0, NO_REPLACE); @@ -1142,42 +1044,261 @@ void P_SpawnPortal(line_t *line, int sectortag, int plane, int alpha) reference->flags |= MF_JUSTATTACKED; anchor->flags |= MF_JUSTATTACKED; - int s; - FSectorTagIterator itr(sectortag); - while ((s = itr.Next()) >= 0) - { - SetPortal(§ors[s], plane, reference, alpha); - } - - for (int j=0;j= 0) - { - SetPortal(§ors[s], plane, reference, alpha); - } - } - } - } - + CopyPortal(sectortag, plane, reference, alpha, false); return; } } } +// This searches the viewpoint's sector +// for a skybox line special, gets its tag and transfers the skybox to all tagged sectors. +void P_SpawnSkybox(ASkyViewpoint *origin) +{ + sector_t *Sector = origin->Sector; + if (Sector == NULL) + { + Printf("Sector not initialized for SkyCamCompat\n"); + origin->Sector = Sector = P_PointInSector(origin->X(), origin->Y()); + } + if (Sector) + { + line_t * refline = NULL; + for (short i = 0; i < Sector->linecount; i++) + { + refline = Sector->lines[i]; + if (refline->special == Sector_SetPortal && refline->args[1] == 2) + { + // We found the setup linedef for this skybox, so let's use it for our init. + CopyPortal(refline->args[0], refline->args[2], origin, 0, true); + return; + } + } + } +} + + + +// +// P_SetSectorDamage +// +// Sets damage properties for one sector. Allows combination of original specials with explicit use of the damage properties +// + +static void P_SetupSectorDamage(sector_t *sector, int damage, int interval, int leakchance, FName type, int flags) +{ + // Only set if damage is not yet initialized. This ensures that UDMF takes precedence over sector specials. + if (sector->damageamount == 0) + { + sector->damageamount = damage; + sector->damageinterval = MAX(1, interval); + sector->leakydamage = leakchance; + sector->damagetype = type; + sector->Flags = (sector->Flags & ~SECF_DAMAGEFLAGS) | (flags & SECF_DAMAGEFLAGS); + } +} + +// +// P_InitSectorSpecial +// +// Sets up everything derived from 'sector->special' for one sector +// ('fromload' is necessary to allow conversion upon savegame load.) +// + +void P_InitSectorSpecial(sector_t *sector, int special, bool nothinkers) +{ + // [RH] All secret sectors are marked with a BOOM-ish bitfield + if (sector->special & SECRET_MASK) + { + sector->Flags |= SECF_SECRET | SECF_WASSECRET; + level.total_secrets++; + } + if (sector->special & FRICTION_MASK) + { + sector->Flags |= SECF_FRICTION; + } + if (sector->special & PUSH_MASK) + { + sector->Flags |= SECF_PUSH; + } + if ((sector->special & DAMAGE_MASK) == 0x100) + { + P_SetupSectorDamage(sector, 5, 32, 0, NAME_Fire, 0); + } + else if ((sector->special & DAMAGE_MASK) == 0x200) + { + P_SetupSectorDamage(sector, 10, 32, 0, NAME_Slime, 0); + } + else if ((sector->special & DAMAGE_MASK) == 0x300) + { + P_SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0); + } + sector->special &= 0xff; + + // [RH] Normal DOOM special or BOOM specialized? + bool keepspecial = false; + switch (sector->special) + { + case Light_Phased: + if (!nothinkers) new DPhased (sector, 48, 63 - (sector->lightlevel & 63)); + break; + + // [RH] Hexen-like phased lighting + case LightSequenceStart: + if (!nothinkers) new DPhased (sector); + break; + + case dLight_Flicker: + if (!nothinkers) new DLightFlash (sector); + break; + + case dLight_StrobeFast: + if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, false); + break; + + case dLight_StrobeSlow: + if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, SLOWDARK, false); + break; + + case dLight_Strobe_Hurt: + if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, false); + P_SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0); + break; + + case dDamage_Hellslime: + P_SetupSectorDamage(sector, 10, 32, 0, NAME_Slime, 0); + break; + + case dDamage_Nukage: + P_SetupSectorDamage(sector, 5, 32, 0, NAME_Slime, 0); + break; + + case dLight_Glow: + if (!nothinkers) new DGlow (sector); + break; + + case dSector_DoorCloseIn30: + P_SpawnDoorCloseIn30 (sector); + break; + + case dDamage_End: + P_SetupSectorDamage(sector, 20, 32, 256, NAME_None, SECF_ENDGODMODE|SECF_ENDLEVEL); + break; + + case dLight_StrobeSlowSync: + if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, SLOWDARK, true); + break; + + case dLight_StrobeFastSync: + if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, true); + break; + + case dSector_DoorRaiseIn5Mins: + P_SpawnDoorRaiseIn5Mins (sector); + break; + + case dFriction_Low: + sector->friction = FRICTION_LOW; + sector->movefactor = 0x269; + sector->Flags |= SECF_FRICTION; + break; + + case dDamage_SuperHellslime: + P_SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0); + break; + + case dLight_FireFlicker: + if (!nothinkers) new DFireFlicker (sector); + break; + + case dDamage_LavaWimpy: + P_SetupSectorDamage(sector, 5, 32, 256, NAME_Fire, SECF_DMGTERRAINFX); + break; + + case dDamage_LavaHefty: + P_SetupSectorDamage(sector, 8, 32, 256, NAME_Fire, SECF_DMGTERRAINFX); + break; + + case dScroll_EastLavaDamage: + P_SetupSectorDamage(sector, 5, 32, 256, NAME_Fire, SECF_DMGTERRAINFX); + if (!nothinkers) + { + new DStrobe(sector, STROBEBRIGHT, FASTDARK, false); + new DScroller(DScroller::sc_floor, (-FRACUNIT / 2) << 3, + 0, -1, int(sector - sectors), 0); + } + keepspecial = true; + break; + + case hDamage_Sludge: + P_SetupSectorDamage(sector, 4, 32, 0, NAME_Slime, 0); + break; + + case sLight_Strobe_Hurt: + P_SetupSectorDamage(sector, 5, 32, 0, NAME_Slime, 0); + if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, false); + break; + + case sDamage_Hellslime: + P_SetupSectorDamage(sector, 2, 32, 0, NAME_Slime, SECF_HAZARD); + break; + + case Damage_InstantDeath: + // Strife's instant death sector + P_SetupSectorDamage(sector, TELEFRAG_DAMAGE, 1, 256, NAME_InstantDeath, 0); + break; + + case sDamage_SuperHellslime: + P_SetupSectorDamage(sector, 4, 32, 0, NAME_Slime, SECF_HAZARD); + break; + + case Sector_Hidden: + sector->MoreFlags |= SECF_HIDDEN; + break; + + case Sector_Heal: + // CoD's healing sector + P_SetupSectorDamage(sector, -1, 32, 0, NAME_None, 0); + break; + + case Sky2: + sector->sky = PL_SKYFLAT; + break; + + default: + if (sector->special >= Scroll_North_Slow && + sector->special <= Scroll_SouthWest_Fast) + { // Hexen scroll special + static const char hexenScrollies[24][2] = + { + { 0, 1 }, { 0, 2 }, { 0, 4 }, + { -1, 0 }, { -2, 0 }, { -4, 0 }, + { 0, -1 }, { 0, -2 }, { 0, -4 }, + { 1, 0 }, { 2, 0 }, { 4, 0 }, + { 1, 1 }, { 2, 2 }, { 4, 4 }, + { -1, 1 }, { -2, 2 }, { -4, 4 }, + { -1, -1 }, { -2, -2 }, { -4, -4 }, + { 1, -1 }, { 2, -2 }, { 4, -4 } + }; + + + int i = sector->special - Scroll_North_Slow; + fixed_t dx = hexenScrollies[i][0] * (FRACUNIT/2); + fixed_t dy = hexenScrollies[i][1] * (FRACUNIT/2); + if (!nothinkers) new DScroller (DScroller::sc_floor, dx, dy, -1, int(sector-sectors), 0); + } + else if (sector->special >= Carry_East5 && + sector->special <= Carry_East35) + { // Heretic scroll special + // Only east scrollers also scroll the texture + if (!nothinkers) new DScroller (DScroller::sc_floor, + (-FRACUNIT/2)<<(sector->special - Carry_East5), + 0, -1, int(sector-sectors), 0); + } + keepspecial = true; + break; + } + if (!keepspecial) sector->special = 0; +} // // P_SpawnSpecials @@ -1199,135 +1320,7 @@ void P_SpawnSpecials (void) if (sector->special == 0) continue; - // [RH] All secret sectors are marked with a BOOM-ish bitfield - if (sector->special & SECRET_MASK) - level.total_secrets++; - - switch (sector->special & 0xff) - { - // [RH] Normal DOOM/Hexen specials. We clear off the special for lights - // here instead of inside the spawners. - - case dLight_Flicker: - // FLICKERING LIGHTS - new DLightFlash (sector); - sector->special &= 0xff00; - break; - - case dLight_StrobeFast: - // STROBE FAST - new DStrobe (sector, STROBEBRIGHT, FASTDARK, false); - sector->special &= 0xff00; - break; - - case dLight_StrobeSlow: - // STROBE SLOW - new DStrobe (sector, STROBEBRIGHT, SLOWDARK, false); - sector->special &= 0xff00; - break; - - case dLight_Strobe_Hurt: - case sLight_Strobe_Hurt: - // STROBE FAST/DEATH SLIME - new DStrobe (sector, STROBEBRIGHT, FASTDARK, false); - break; - - case dLight_Glow: - // GLOWING LIGHT - new DGlow (sector); - sector->special &= 0xff00; - break; - - case dSector_DoorCloseIn30: - // DOOR CLOSE IN 30 SECONDS - P_SpawnDoorCloseIn30 (sector); - break; - - case dLight_StrobeSlowSync: - // SYNC STROBE SLOW - new DStrobe (sector, STROBEBRIGHT, SLOWDARK, true); - sector->special &= 0xff00; - break; - - case dLight_StrobeFastSync: - // SYNC STROBE FAST - new DStrobe (sector, STROBEBRIGHT, FASTDARK, true); - sector->special &= 0xff00; - break; - - case dSector_DoorRaiseIn5Mins: - // DOOR RAISE IN 5 MINUTES - P_SpawnDoorRaiseIn5Mins (sector); - break; - - case dLight_FireFlicker: - // fire flickering - new DFireFlicker (sector); - sector->special &= 0xff00; - break; - - case dFriction_Low: - sector->friction = FRICTION_LOW; - sector->movefactor = 0x269; - sector->special &= 0xff00; - sector->special |= FRICTION_MASK; - break; - - // [RH] Hexen-like phased lighting - case LightSequenceStart: - new DPhased (sector); - break; - - case Light_Phased: - new DPhased (sector, 48, 63 - (sector->lightlevel & 63)); - break; - - case Sky2: - sector->sky = PL_SKYFLAT; - break; - - case dScroll_EastLavaDamage: - new DStrobe (sector, STROBEBRIGHT, FASTDARK, false); - new DScroller (DScroller::sc_floor, (-FRACUNIT/2)<<3, - 0, -1, int(sector-sectors), 0); - break; - - case Sector_Hidden: - sector->MoreFlags |= SECF_HIDDEN; - sector->special &= 0xff00; - break; - - default: - if ((sector->special & 0xff) >= Scroll_North_Slow && - (sector->special & 0xff) <= Scroll_SouthWest_Fast) - { // Hexen scroll special - static const char hexenScrollies[24][2] = - { - { 0, 1 }, { 0, 2 }, { 0, 4 }, - { -1, 0 }, { -2, 0 }, { -4, 0 }, - { 0, -1 }, { 0, -2 }, { 0, -4 }, - { 1, 0 }, { 2, 0 }, { 4, 0 }, - { 1, 1 }, { 2, 2 }, { 4, 4 }, - { -1, 1 }, { -2, 2 }, { -4, 4 }, - { -1, -1 }, { -2, -2 }, { -4, -4 }, - { 1, -1 }, { 2, -2 }, { 4, -4 } - }; - - int i = (sector->special & 0xff) - Scroll_North_Slow; - fixed_t dx = hexenScrollies[i][0] * (FRACUNIT/2); - fixed_t dy = hexenScrollies[i][1] * (FRACUNIT/2); - new DScroller (DScroller::sc_floor, dx, dy, -1, int(sector-sectors), 0); - } - else if ((sector->special & 0xff) >= Carry_East5 && - (sector->special & 0xff) <= Carry_East35) - { // Heretic scroll special - // Only east scrollers also scroll the texture - new DScroller (DScroller::sc_floor, - (-FRACUNIT/2)<<((sector->special & 0xff) - Carry_East5), - 0, -1, int(sector-sectors), 0); - } - break; - } + P_InitSectorSpecial(sector, sector->special, false); } // Init other misc stuff @@ -1336,6 +1329,13 @@ void P_SpawnSpecials (void) P_SpawnFriction(); // phares 3/12/98: New friction model using linedefs P_SpawnPushers(); // phares 3/20/98: New pusher model using linedefs + TThinkerIterator it2; + ASkyCamCompat *pt2; + while ((pt2 = it2.Next())) + { + P_SpawnSkybox(pt2); + } + for (i = 0; i < numlines; i++) { switch (lines[i].special) @@ -1449,8 +1449,24 @@ void P_SpawnSpecials (void) FSectorTagIterator itr(lines[i].args[0]); while ((s = itr.Next()) >= 0) { - sectors[s].damage = damage; - sectors[s].mod = 0;//MOD_UNKNOWN; + sector_t *sec = §ors[s]; + sec->damageamount = damage; + sec->damagetype = NAME_None; + if (sec->damageamount < 20) + { + sec->leakydamage = 0; + sec->damageinterval = 32; + } + else if (sec->damageamount < 50) + { + sec->leakydamage = 5; + sec->damageinterval = 32; + } + else + { + sec->leakydamage = 256; + sec->damageinterval = 1; + } } } break; @@ -2052,11 +2068,11 @@ void P_SetSectorFriction (int tag, int amount, bool alterFlag) // can be enabled and disabled at will. if (friction == ORIG_FRICTION) { - sectors[s].special &= ~FRICTION_MASK; + sectors[s].Flags &= ~SECF_FRICTION; } else { - sectors[s].special |= FRICTION_MASK; + sectors[s].Flags |= SECF_FRICTION; } } } @@ -2136,8 +2152,8 @@ DPusher::DPusher (DPusher::EPusher type, line_t *l, int magnitude, int angle, if (source) // point source exist? { m_Radius = (m_Magnitude) << (FRACBITS+1); // where force goes to zero - m_X = m_Source->x; - m_Y = m_Source->y; + m_X = m_Source->X(); + m_Y = m_Source->Y(); } m_Affectee = affectee; } @@ -2172,7 +2188,7 @@ void DPusher::Tick () // Be sure the special sector type is still turned on. If so, proceed. // Else, bail out; the sector type has been changed on us. - if (!(sec->special & PUSH_MASK)) + if (!(sec->Flags & SECF_PUSH)) return; // For constant pushers (wind/current) there are 3 situations: @@ -2218,7 +2234,7 @@ void DPusher::Tick () { int sx = m_X; int sy = m_Y; - int dist = P_AproxDistance (thing->x - sx,thing->y - sy); + int dist = thing->AproxDistance (sx, sy); int speed = (m_Magnitude - ((dist>>FRACBITS)>>1))<<(FRACBITS-PUSH_FACTOR-1); // If speed <= 0, you're outside the effective radius. You also have @@ -2226,7 +2242,7 @@ void DPusher::Tick () if ((speed > 0) && (P_CheckSight (thing, m_Source, SF_IGNOREVISIBILITY))) { - angle_t pushangle = R_PointToAngle2 (thing->x, thing->y, sx, sy); + angle_t pushangle = thing->AngleTo(sx, sy); if (m_Source->GetClass()->TypeName == NAME_PointPusher) pushangle += ANG180; // away pushangle >>= ANGLETOFINESHIFT; @@ -2252,7 +2268,7 @@ void DPusher::Tick () { if (hsec == NULL) { // NOT special water sector - if (thing->z > thing->floorz) // above ground + if (thing->Z() > thing->floorz) // above ground { xspeed = m_Xmag; // full force yspeed = m_Ymag; @@ -2265,8 +2281,8 @@ void DPusher::Tick () } else // special water sector { - ht = hsec->floorplane.ZatPoint (thing->x, thing->y); - if (thing->z > ht) // above ground + ht = hsec->floorplane.ZatPoint(thing); + if (thing->Z() > ht) // above ground { xspeed = m_Xmag; // full force yspeed = m_Ymag; @@ -2294,7 +2310,7 @@ void DPusher::Tick () { // special water sector floor = &hsec->floorplane; } - if (thing->z > floor->ZatPoint (thing->x, thing->y)) + if (thing->Z() > floor->ZatPoint(thing)) { // above ground xspeed = yspeed = 0; // no force } diff --git a/src/p_spec.h b/src/p_spec.h index 0c3ee8745..2f99e4889 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -158,6 +158,7 @@ bool PIT_PushThing (AActor *thing); bool CheckIfExitIsGood (AActor *self, level_info_t *info); // at map load +void P_InitSectorSpecial(sector_t *sector, int special, bool nothinkers); void P_SpawnSpecials (void); // every tic @@ -673,7 +674,7 @@ protected: // [RH] Need these for BOOM-ish transferring ceilings FTextureID m_Texture; - int m_NewSpecial; + secspecial_t m_NewSpecial; // ID int m_Tag; @@ -760,7 +761,7 @@ protected: int m_Crush; bool m_Hexencrush; int m_Direction; - int m_NewSpecial; + secspecial_t m_NewSpecial; FTextureID m_Texture; fixed_t m_FloorDestDist; fixed_t m_Speed; @@ -902,6 +903,10 @@ bool EV_DoChange (line_t *line, EChange changetype, int tag); // P_TELEPT // void P_SpawnTeleportFog(AActor *mobj, fixed_t x, fixed_t y, fixed_t z, bool beforeTele = true, bool setTarget = false); //Spawns teleport fog. Pass the actor to pluck TeleFogFromType and TeleFogToType. 'from' determines if this is the fog to spawn at the old position (true) or new (false). +inline void P_SpawnTeleportFog(AActor *mobj, const fixedvec3 &pos, bool beforeTele = true, bool setTarget = false) +{ + P_SpawnTeleportFog(mobj, pos.x, pos.y, pos.z, beforeTele, setTarget); +} bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, bool useFog, bool sourceFog, bool keepOrientation, bool haltVelocity = true, bool keepHeight = false); bool EV_Teleport (int tid, int tag, line_t *line, int side, AActor *thing, bool fog, bool sourceFog, bool keepOrientation, bool haltVelocity = true, bool keepHeight = false); bool EV_SilentLineTeleport (line_t *line, int side, AActor *thing, int id, INTBOOL reverse); diff --git a/src/p_switch.cpp b/src/p_switch.cpp index 984794c8a..1ae0c43ea 100644 --- a/src/p_switch.cpp +++ b/src/p_switch.cpp @@ -138,8 +138,9 @@ bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno) P_MakeDivline (line, &dll); - dlu.x = user->x; - dlu.y = user->y; + fixedvec3 pos = user->PosRelative(line); + dlu.x = pos.x; + dlu.y = pos.y; dlu.dx = finecosine[user->angle >> ANGLETOFINESHIFT]; dlu.dy = finesine[user->angle >> ANGLETOFINESHIFT]; inter = P_InterceptVector(&dll, &dlu); @@ -167,11 +168,11 @@ bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno) onesided: fixed_t sectorc = front->ceilingplane.ZatPoint(checkx, checky); fixed_t sectorf = front->floorplane.ZatPoint(checkx, checky); - return (user->z + user->height >= sectorf && user->z <= sectorc); + return (user->Top() >= sectorf && user->Z() <= sectorc); } // Now get the information from the line. - P_LineOpening(open, NULL, line, checkx, checky, user->x, user->y); + P_LineOpening(open, NULL, line, checkx, checky, pos.x, pos.y); if (open.range <= 0) goto onesided; @@ -187,8 +188,8 @@ bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno) if (!(rover->flags & FF_EXISTS)) continue; if (!(rover->flags & FF_UPPERTEXTURE)) continue; - if (user->z > rover->top.plane->ZatPoint(checkx, checky) || - user->z + user->height < rover->bottom.plane->ZatPoint(checkx, checky)) + if (user->Z() > rover->top.plane->ZatPoint(checkx, checky) || + user->Top() < rover->bottom.plane->ZatPoint(checkx, checky)) continue; // This 3D floor depicts a switch texture in front of the player's eyes @@ -196,7 +197,7 @@ bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno) } } - return (user->z + user->height > open.top); + return (user->Top() > open.top); } else if ((TexMan.FindSwitch(side->GetTexture(side_t::bottom))) != NULL) { @@ -209,8 +210,8 @@ bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno) if (!(rover->flags & FF_EXISTS)) continue; if (!(rover->flags & FF_LOWERTEXTURE)) continue; - if (user->z > rover->top.plane->ZatPoint(checkx, checky) || - user->z + user->height < rover->bottom.plane->ZatPoint(checkx, checky)) + if (user->Z() > rover->top.plane->ZatPoint(checkx, checky) || + user->Top() < rover->bottom.plane->ZatPoint(checkx, checky)) continue; // This 3D floor depicts a switch texture in front of the player's eyes @@ -218,7 +219,7 @@ bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno) } } - return (user->z < open.bottom); + return (user->Z() < open.bottom); } else if ((flags & ML_3DMIDTEX) || (TexMan.FindSwitch(side->GetTexture(side_t::mid))) != NULL) { @@ -226,12 +227,12 @@ bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno) // to keep compatibility with Eternity's implementation. if (!P_GetMidTexturePosition(line, sideno, &checktop, &checkbot)) return false; - return user->z < checktop && user->z + user->height > checkbot; + return user->Z() < checktop && user->Top() > checkbot; } else { // no switch found. Check whether the player can touch either top or bottom texture - return (user->z + user->height > open.top) || (user->z < open.bottom); + return (user->Top() > open.top) || (user->Z() < open.bottom); } } diff --git a/src/p_teleport.cpp b/src/p_teleport.cpp index 040aca9f4..ab860bfe9 100644 --- a/src/p_teleport.cpp +++ b/src/p_teleport.cpp @@ -101,9 +101,7 @@ bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, { bool predicting = (thing->player && (thing->player->cheats & CF_PREDICTING)); - fixed_t oldx; - fixed_t oldy; - fixed_t oldz; + fixedvec3 old; fixed_t aboveFloor; player_t *player; angle_t an; @@ -112,10 +110,8 @@ bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, fixed_t floorheight, ceilingheight; fixed_t missilespeed; - oldx = thing->x; - oldy = thing->y; - oldz = thing->z; - aboveFloor = thing->z - thing->floorz; + old = thing->Pos(); + aboveFloor = thing->Z() - thing->floorz; destsect = P_PointInSector (x, y); // killough 5/12/98: exclude voodoo dolls: player = thing->player; @@ -171,7 +167,7 @@ bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, } if (player) { - player->viewz = thing->z + player->viewheight; + player->viewz = thing->Z() + player->viewheight; if (resetpitch) { player->mo->pitch = 0; @@ -188,7 +184,7 @@ bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, // Spawn teleport fog at source and destination if (sourceFog && !predicting) { - P_SpawnTeleportFog(thing, oldx, oldy, oldz, true, true); //Passes the actor through which then pulls the TeleFog metadata types based on properties. + P_SpawnTeleportFog(thing, old, true, true); //Passes the actor through which then pulls the TeleFog metadata types based on properties. } if (useFog) { @@ -196,7 +192,7 @@ bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, { fixed_t fogDelta = thing->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT; an = angle >> ANGLETOFINESHIFT; - P_SpawnTeleportFog(thing, x + 20 * finecosine[an], y + 20 * finesine[an], thing->z + fogDelta, false, true); + P_SpawnTeleportFog(thing, x + 20 * finecosine[an], y + 20 * finesine[an], thing->Z() + fogDelta, false, true); } if (thing->player) @@ -372,11 +368,11 @@ bool EV_Teleport (int tid, int tag, line_t *line, int side, AActor *thing, bool velx = thing->velx; vely = thing->vely; - z = searcher->z; + z = searcher->Z(); } else if (searcher->IsKindOf (PClass::FindClass(NAME_TeleportDest2))) { - z = searcher->z; + z = searcher->Z(); } else { @@ -386,7 +382,7 @@ bool EV_Teleport (int tid, int tag, line_t *line, int side, AActor *thing, bool { badangle = 1 << ANGLETOFINESHIFT; } - if (P_Teleport (thing, searcher->x, searcher->y, z, searcher->angle + badangle, fog, sourceFog, keepOrientation, haltVelocity, keepHeight)) + if (P_Teleport (thing, searcher->X(), searcher->Y(), z, searcher->angle + badangle, fog, sourceFog, keepOrientation, haltVelocity, keepHeight)) { // [RH] Lee Killough's changes for silent teleporters from BOOM if (!fog && line && keepOrientation) @@ -447,8 +443,8 @@ bool EV_SilentLineTeleport (line_t *line, int side, AActor *thing, int id, INTBO } else { - SQWORD num = (SQWORD)(thing->x-line->v1->x)*line->dx + - (SQWORD)(thing->y-line->v1->y)*line->dy; + SQWORD num = (SQWORD)(thing->X()-line->v1->x)*line->dx + + (SQWORD)(thing->Y()-line->v1->y)*line->dy; if (num <= 0) { pos = 0; @@ -461,8 +457,8 @@ bool EV_SilentLineTeleport (line_t *line, int side, AActor *thing, int id, INTBO { pos = (SDWORD)(num / (den>>30)); } - nposx = thing->x - line->v1->x - MulScale30 (line->dx, pos); - nposy = thing->y - line->v1->y - MulScale30 (line->dy, pos); + nposx = thing->X() - line->v1->x - MulScale30 (line->dx, pos); + nposy = thing->Y() - line->v1->y - MulScale30 (line->dy, pos); } } @@ -502,7 +498,7 @@ bool EV_SilentLineTeleport (line_t *line, int side, AActor *thing, int id, INTBO bool stepdown = l->frontsector->floorplane.ZatPoint(x, y) < l->backsector->floorplane.ZatPoint(x, y); // Height of thing above ground - fixed_t z = thing->z - thing->floorz; + fixed_t z = thing->Z() - thing->floorz; // Side to exit the linedef on positionally. // @@ -530,7 +526,7 @@ bool EV_SilentLineTeleport (line_t *line, int side, AActor *thing, int id, INTBO int fudge = FUDGEFACTOR; // Make sure we are on correct side of exit linedef. - while (P_PointOnLineSide(x, y, l) != side && --fudge >= 0) + while (P_PointOnLineSidePrecise(x, y, l) != side && --fudge >= 0) { if (abs(l->dx) > abs(l->dy)) y -= (l->dx < 0) != side ? -1 : 1; @@ -615,16 +611,16 @@ bool EV_TeleportOther (int other_tid, int dest_tid, bool fog) static bool DoGroupForOne (AActor *victim, AActor *source, AActor *dest, bool floorz, bool fog) { int an = (dest->angle - source->angle) >> ANGLETOFINESHIFT; - fixed_t offX = victim->x - source->x; - fixed_t offY = victim->y - source->y; + fixed_t offX = victim->X() - source->X(); + fixed_t offY = victim->Y() - source->Y(); angle_t offAngle = victim->angle - source->angle; fixed_t newX = DMulScale16 (offX, finecosine[an], -offY, finesine[an]); fixed_t newY = DMulScale16 (offX, finesine[an], offY, finecosine[an]); bool res = - P_Teleport (victim, dest->x + newX, - dest->y + newY, - floorz ? ONFLOORZ : dest->z + victim->z - source->z, + P_Teleport (victim, dest->X() + newX, + dest->Y() + newY, + floorz ? ONFLOORZ : dest->Z() + victim->Z() - source->Z(), 0, fog, fog, !fog); // P_Teleport only changes angle if fog is true victim->angle = dest->angle + offAngle; @@ -692,8 +688,8 @@ bool EV_TeleportGroup (int group_tid, AActor *victim, int source_tid, int dest_t if (moveSource && didSomething) { didSomething |= - P_Teleport (sourceOrigin, destOrigin->x, destOrigin->y, - floorz ? ONFLOORZ : destOrigin->z, 0, false, false, true); + P_Teleport (sourceOrigin, destOrigin->X(), destOrigin->Y(), + floorz ? ONFLOORZ : destOrigin->Z(), 0, false, false, true); sourceOrigin->angle = destOrigin->angle; } diff --git a/src/p_terrain.cpp b/src/p_terrain.cpp index a1a9ea25b..af8de5cab 100644 --- a/src/p_terrain.cpp +++ b/src/p_terrain.cpp @@ -46,6 +46,7 @@ #include "s_sound.h" #include "p_local.h" #include "templates.h" +#include "farchive.h" // MACROS ------------------------------------------------------------------ @@ -121,7 +122,6 @@ static void ParseSplash (FScanner &sc); static void ParseTerrain (FScanner &sc); static void ParseFloor (FScanner &sc); static int FindSplash (FName name); -static int FindTerrain (FName name); static void GenericParse (FScanner &sc, FGenericParse *parser, const char **keywords, void *fields, const char *type, FName name); static void ParseDamage (FScanner &sc, int keyword, void *fields); @@ -427,7 +427,7 @@ void ParseTerrain (FScanner &sc) sc.MustGetString (); name = sc.String; - terrainnum = (int)FindTerrain (name); + terrainnum = (int)P_FindTerrain (name); if (terrainnum < 0) { FTerrainDef def; @@ -637,7 +637,7 @@ static void ParseFloor (FScanner &sc) return; } sc.MustGetString (); - terrain = FindTerrain (sc.String); + terrain = P_FindTerrain (sc.String); if (terrain == -1) { Printf ("Unknown terrain %s\n", sc.String); @@ -657,7 +657,7 @@ static void ParseDefault (FScanner &sc) int terrain; sc.MustGetString (); - terrain = FindTerrain (sc.String); + terrain = P_FindTerrain (sc.String); if (terrain == -1) { Printf ("Unknown terrain %s\n", sc.String); @@ -692,7 +692,7 @@ int FindSplash (FName name) // //========================================================================== -int FindTerrain (FName name) +int P_FindTerrain (FName name) { unsigned int i; @@ -705,3 +705,26 @@ int FindTerrain (FName name) } return -1; } + +void P_SerializeTerrain(FArchive &arc, int &terrainnum) +{ + FName val; + if (arc.IsStoring()) + { + if (terrainnum < 0 || terrainnum >= (int)Terrains.Size()) + { + val = NAME_Null; + } + else + { + val = Terrains[terrainnum].Name; + } + arc << val; + } + else + { + arc << val; + terrainnum = P_FindTerrain(val); + + } +} diff --git a/src/p_terrain.h b/src/p_terrain.h index 482c66b00..dab4904b6 100644 --- a/src/p_terrain.h +++ b/src/p_terrain.h @@ -122,4 +122,8 @@ struct FTerrainDef extern TArray Splashes; extern TArray Terrains; +class FArchive; +int P_FindTerrain(FName name); +void P_SerializeTerrain(FArchive &arc, int &terrainnum); + #endif //__P_TERRAIN_H__ diff --git a/src/p_things.cpp b/src/p_things.cpp index 7e38a3c68..85d7961af 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -82,7 +82,7 @@ bool P_Thing_Spawn (int tid, AActor *source, int type, angle_t angle, bool fog, } while (spot != NULL) { - mobj = Spawn (kind, spot->x, spot->y, spot->z, ALLOW_REPLACE); + mobj = Spawn (kind, spot->Pos(), ALLOW_REPLACE); if (mobj != NULL) { @@ -94,7 +94,7 @@ bool P_Thing_Spawn (int tid, AActor *source, int type, angle_t angle, bool fog, mobj->angle = (angle != ANGLE_MAX ? angle : spot->angle); if (fog) { - P_SpawnTeleportFog(mobj, spot->x, spot->y, spot->z + TELEFOGHEIGHT, false, true); + P_SpawnTeleportFog(mobj, spot->X(), spot->Y(), spot->Z() + TELEFOGHEIGHT, false, true); } if (mobj->flags & MF_SPECIAL) mobj->flags |= MF_DROPPED; // Don't respawn @@ -123,11 +123,11 @@ bool P_MoveThing(AActor *source, fixed_t x, fixed_t y, fixed_t z, bool fog) { fixed_t oldx, oldy, oldz; - oldx = source->x; - oldy = source->y; - oldz = source->z; + oldx = source->X(); + oldy = source->Y(); + oldz = source->Z(); - source->SetOrigin (x, y, z); + source->SetOrigin (x, y, z, false); if (P_TestMobjLocation (source)) { if (fog) @@ -146,7 +146,7 @@ bool P_MoveThing(AActor *source, fixed_t x, fixed_t y, fixed_t z, bool fog) } else { - source->SetOrigin (oldx, oldy, oldz); + source->SetOrigin (oldx, oldy, oldz, false); return false; } } @@ -165,7 +165,7 @@ bool P_Thing_Move (int tid, AActor *source, int mapspot, bool fog) if (source != NULL && target != NULL) { - return P_MoveThing(source, target->x, target->y, target->z, fog); + return P_MoveThing(source, target->X(), target->Y(), target->Z(), fog); } return false; } @@ -218,7 +218,7 @@ bool P_Thing_Projectile (int tid, AActor *source, int type, const char *type_nam { do { - fixed_t z = spot->z; + fixed_t z = spot->Z(); if (defflags3 & MF3_FLOORHUGGER) { z = ONFLOORZ; @@ -231,7 +231,7 @@ bool P_Thing_Projectile (int tid, AActor *source, int type, const char *type_nam { z -= spot->floorclip; } - mobj = Spawn (kind, spot->x, spot->y, z, ALLOW_REPLACE); + mobj = Spawn (kind, spot->X(), spot->Y(), z, ALLOW_REPLACE); if (mobj) { @@ -254,8 +254,9 @@ bool P_Thing_Projectile (int tid, AActor *source, int type, const char *type_nam if (targ != NULL) { - fixed_t spot[3] = { targ->x, targ->y, targ->z+targ->height/2 }; - FVector3 aim(float(spot[0] - mobj->x), float(spot[1] - mobj->y), float(spot[2] - mobj->z)); + fixedvec3 vect = mobj->Vec3To(targ); + vect.z += targ->height / 2; + FVector3 aim = vect; if (leadTarget && speed > 0 && (targ->velx | targ->vely | targ->velz)) { @@ -304,7 +305,8 @@ bool P_Thing_Projectile (int tid, AActor *source, int type, const char *type_nam } else { -nolead: mobj->angle = R_PointToAngle2 (mobj->x, mobj->y, targ->x, targ->y); +nolead: + mobj->angle = mobj->AngleTo(targ); aim.Resize (fspeed); mobj->velx = fixed_t(aim[0]); mobj->vely = fixed_t(aim[1]); @@ -434,7 +436,7 @@ bool P_Thing_Raise(AActor *thing, AActor *raiser) thing->flags |= MF_SOLID; thing->height = info->height; // [RH] Use real height thing->radius = info->radius; // [RH] Use real radius - if (!P_CheckPosition (thing, thing->x, thing->y)) + if (!P_CheckPosition (thing, thing->Pos())) { thing->flags = oldflags; thing->radius = oldradius; @@ -476,7 +478,7 @@ bool P_Thing_CanRaise(AActor *thing) thing->height = info->height; thing->radius = info->radius; - bool check = P_CheckPosition (thing, thing->x, thing->y); + bool check = P_CheckPosition (thing, thing->Pos()); // Restore checked properties thing->flags = oldflags; @@ -689,9 +691,7 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, caller = temp; } - fixed_t oldx = caller->x; - fixed_t oldy = caller->y; - fixed_t oldz = caller->z; + fixedvec3 old = caller->Pos(); zofs += FixedMul(reference->height, heightoffset); @@ -723,18 +723,18 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, // now the caller's floorz should be appropriate for the assigned xy-position // assigning position again with. // extra unlink, link and environment calculation - caller->SetOrigin( - reference->x + xofs + FixedMul(rad, finecosine[fineangle]), - reference->y + yofs + FixedMul(rad, finesine[fineangle]), - reference->z); - caller->z = caller->floorz + zofs; + caller->SetOrigin(reference->Vec3Offset( + xofs + FixedMul(rad, finecosine[fineangle]), + yofs + FixedMul(rad, finesine[fineangle]), + 0), true); + caller->SetZ(caller->floorz + zofs); } else { - caller->SetOrigin( - reference->x + xofs + FixedMul(rad, finecosine[fineangle]), - reference->y + yofs + FixedMul(rad, finesine[fineangle]), - reference->z + zofs); + caller->SetOrigin(reference->Vec3Offset( + xofs + FixedMul(rad, finecosine[fineangle]), + yofs + FixedMul(rad, finesine[fineangle]), + zofs), true); } } else // [MC] The idea behind "absolute" is meant to be "absolute". Override everything, just like A_SpawnItemEx's. @@ -742,7 +742,7 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, if (flags & WARPF_TOFLOOR) { caller->SetOrigin(xofs + FixedMul(rad, finecosine[fineangle]), yofs + FixedMul(rad, finesine[fineangle]), zofs); - caller->z = caller->floorz + zofs; + caller->SetZ(caller->floorz + zofs); } else { @@ -754,7 +754,7 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, { if (flags & WARPF_TESTONLY) { - caller->SetOrigin(oldx, oldy, oldz); + caller->SetOrigin(old, true); } else { @@ -781,29 +781,29 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, if (flags & WARPF_WARPINTERPOLATION) { - caller->PrevX += caller->x - oldx; - caller->PrevY += caller->y - oldy; - caller->PrevZ += caller->z - oldz; + caller->PrevX += caller->X() - old.x; + caller->PrevY += caller->Y() - old.y; + caller->PrevZ += caller->Z() - old.z; } else if (flags & WARPF_COPYINTERPOLATION) { - caller->PrevX = caller->x + reference->PrevX - reference->x; - caller->PrevY = caller->y + reference->PrevY - reference->y; - caller->PrevZ = caller->z + reference->PrevZ - reference->z; + caller->PrevX = caller->X() + reference->PrevX - reference->X(); + caller->PrevY = caller->Y() + reference->PrevY - reference->Y(); + caller->PrevZ = caller->Z() + reference->PrevZ - reference->Z(); } else if (!(flags & WARPF_INTERPOLATE)) { - caller->PrevX = caller->x; - caller->PrevY = caller->y; - caller->PrevZ = caller->z; + caller->PrevX = caller->X(); + caller->PrevY = caller->Y(); + caller->PrevZ = caller->Z(); } if ((flags & WARPF_BOB) && (reference->flags2 & MF2_FLOATBOB)) { - caller->z += reference->GetBobOffset(); + caller->AddZ(reference->GetBobOffset()); } } return true; } - caller->SetOrigin(oldx, oldy, oldz); + caller->SetOrigin(old, true); return false; } \ No newline at end of file diff --git a/src/p_trace.cpp b/src/p_trace.cpp index 4b4683be5..619a61361 100644 --- a/src/p_trace.cpp +++ b/src/p_trace.cpp @@ -524,12 +524,12 @@ cont: hity = StartY + FixedMul (Vy, dist); hitz = StartZ + FixedMul (Vz, dist); - if (hitz > in->d.thing->z + in->d.thing->height) + if (hitz > in->d.thing->Top()) { // trace enters above actor if (Vz >= 0) continue; // Going up: can't hit // Does it hit the top of the actor? - dist = FixedDiv(in->d.thing->z + in->d.thing->height - StartZ, Vz); + dist = FixedDiv(in->d.thing->Top() - StartZ, Vz); if (dist > MaxDist) continue; in->frac = FixedDiv(dist, MaxDist); @@ -539,15 +539,15 @@ cont: hitz = StartZ + FixedMul (Vz, dist); // calculated coordinate is outside the actor's bounding box - if (abs(hitx - in->d.thing->x) > in->d.thing->radius || - abs(hity - in->d.thing->y) > in->d.thing->radius) continue; + if (abs(hitx - in->d.thing->X()) > in->d.thing->radius || + abs(hity - in->d.thing->Y()) > in->d.thing->radius) continue; } - else if (hitz < in->d.thing->z) + else if (hitz < in->d.thing->Z()) { // trace enters below actor if (Vz <= 0) continue; // Going down: can't hit // Does it hit the bottom of the actor? - dist = FixedDiv(in->d.thing->z - StartZ, Vz); + dist = FixedDiv(in->d.thing->Z() - StartZ, Vz); if (dist > MaxDist) continue; in->frac = FixedDiv(dist, MaxDist); @@ -556,8 +556,8 @@ cont: hitz = StartZ + FixedMul (Vz, dist); // calculated coordinate is outside the actor's bounding box - if (abs(hitx - in->d.thing->x) > in->d.thing->radius || - abs(hity - in->d.thing->y) > in->d.thing->radius) continue; + if (abs(hitx - in->d.thing->X()) > in->d.thing->radius || + abs(hity - in->d.thing->Y()) > in->d.thing->radius) continue; } // check for extrafloors first diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 269ce7e3d..9cfcbc0c2 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -47,6 +47,7 @@ #include "r_data/colormaps.h" #include "w_wad.h" #include "p_tags.h" +#include "p_terrain.h" //=========================================================================== // @@ -785,7 +786,7 @@ public: bool strifetrans = false; bool strifetrans2 = false; FString arg0str, arg1str; - int lineid; // forZDoomTranslated namespace + int lineid = -1; // forZDoomTranslated namespace FString tagstring; memset(ld, 0, sizeof(*ld)); @@ -1082,7 +1083,7 @@ public: maplinedef_t mld; memset(&mld, 0, sizeof(mld)); mld.special = ld->special; - mld.tag = lineid; + mld.tag = ld->args[0]; P_TranslateLineDef(ld, &mld); ld->flags = saved | (ld->flags&(ML_MONSTERSCANACTIVATE|ML_REPEAT_SPECIAL|ML_FIRSTSIDEONLY)); } @@ -1299,6 +1300,8 @@ public: sec->prevsec = -1; // stair retriggering until build completes sec->heightsec = NULL; // sector used to get floor and ceiling height sec->sectornum = index; + sec->damageinterval = 32; + sec->terrainnum[sector_t::ceiling] = sec->terrainnum[sector_t::floor] = -1; if (floordrop) sec->Flags = SECF_FLOORDROP; // killough 3/7/98: end changes @@ -1524,6 +1527,39 @@ public: cp[3] = CheckFloat(key); break; + case NAME_damageamount: + sec->damageamount = CheckInt(key); + break; + + case NAME_damagetype: + sec->damagetype = CheckString(key); + break; + + case NAME_damageinterval: + sec->damageinterval = CheckInt(key); + if (sec->damageinterval < 1) sec->damageinterval = 1; + break; + + case NAME_leakiness: + sec->leakydamage = CheckInt(key); + break; + + case NAME_damageterraineffect: + Flag(sec->Flags, SECF_DMGTERRAINFX, key); + break; + + case NAME_damagehazard: + Flag(sec->Flags, SECF_HAZARD, key); + break; + + case NAME_floorterrain: + sec->terrainnum[sector_t::floor] = P_FindTerrain(CheckString(key)); + break; + + case NAME_ceilingterrain: + sec->terrainnum[sector_t::ceiling] = P_FindTerrain(CheckString(key)); + break; + case NAME_MoreIds: // delay parsing of the tag string until parsing of the sector is complete // This ensures that the ID is always the first tag in the list. @@ -1550,7 +1586,15 @@ public: } } - sec->secretsector = !!(sec->special&SECRET_MASK); + if (sec->damageamount == 0) + { + // If no damage is set, clear all other related properties so that they do not interfere + // with other means of setting them. + sec->damagetype = NAME_None; + sec->damageinterval = 0; + sec->leakydamage = 0; + sec->Flags &= ~SECF_DAMAGEFLAGS; + } // Reset the planes to their defaults if not all of the plane equation's parameters were found. if (fplaneflags != 15) @@ -1594,10 +1638,10 @@ public: { // [RH] Sectors default to white light with the default fade. // If they are outside (have a sky ceiling), they use the outside fog. - if (level.outsidefog != 0xff000000 && (sec->GetTexture(sector_t::ceiling) == skyflatnum || (sec->special&0xff) == Sector_Outside)) + if (level.outsidefog != 0xff000000 && (sec->GetTexture(sector_t::ceiling) == skyflatnum || (sec->special & 0xff) == Sector_Outside)) { if (fogMap == NULL) - fogMap = GetSpecialLights (PalEntry (255,255,255), level.outsidefog, 0); + fogMap = GetSpecialLights(PalEntry(255, 255, 255), level.outsidefog, 0); sec->ColorMap = fogMap; } else @@ -1610,9 +1654,9 @@ public: else { if (lightcolor == -1) lightcolor = PalEntry(255,255,255); - if (fadecolor == -1) + if (fadecolor == -1) { - if (level.outsidefog != 0xff000000 && (sec->GetTexture(sector_t::ceiling) == skyflatnum || (sec->special&0xff) == Sector_Outside)) + if (level.outsidefog != 0xff000000 && (sec->GetTexture(sector_t::ceiling) == skyflatnum || (sec->special & 0xff) == Sector_Outside)) fadecolor = level.outsidefog; else fadecolor = level.fadeto; diff --git a/src/p_user.cpp b/src/p_user.cpp index 0d5cdce20..c4c594858 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -362,6 +362,8 @@ player_t &player_t::operator=(const player_t &p) damagecount = p.damagecount; bonuscount = p.bonuscount; hazardcount = p.hazardcount; + hazardtype = p.hazardtype; + hazardinterval = p.hazardinterval; poisoncount = p.poisoncount; poisontype = p.poisontype; poisonpaintype = p.poisonpaintype; @@ -566,6 +568,10 @@ void APlayerPawn::Serialize (FArchive &arc) { arc << AirCapacity; } + if (SaveVersion >= 4526) + { + arc << ViewHeight; + } } //=========================================================================== @@ -665,10 +671,10 @@ void APlayerPawn::PostBeginPlay() // Voodoo dolls: restore original floorz/ceilingz logic if (player == NULL || player->mo != this) { - dropoffz = floorz = Sector->floorplane.ZatPoint(x, y); - ceilingz = Sector->ceilingplane.ZatPoint(x, y); + dropoffz = floorz = Sector->floorplane.ZatPoint(this); + ceilingz = Sector->ceilingplane.ZatPoint(this); P_FindFloorCeiling(this, FFCF_ONLYSPAWNPOS); - z = floorz; + SetZ(floorz); } else { @@ -1547,7 +1553,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SkullPop) } self->flags &= ~MF_SOLID; - mo = (APlayerPawn *)Spawn (spawntype, self->x, self->y, self->z + 48*FRACUNIT, NO_REPLACE); + mo = (APlayerPawn *)Spawn (spawntype, self->PosPlusZ(48*FRACUNIT), NO_REPLACE); //mo->target = self; mo->velx = pr_skullpop.Random2() << 9; mo->vely = pr_skullpop.Random2() << 9; @@ -1756,7 +1762,7 @@ void P_CalcHeight (player_t *player) if (player->cheats & CF_NOVELOCITY) { - player->viewz = player->mo->z + defaultviewheight; + player->viewz = player->mo->Z() + defaultviewheight; if (player->viewz > player->mo->ceilingz-4*FRACUNIT) player->viewz = player->mo->ceilingz-4*FRACUNIT; @@ -1812,9 +1818,9 @@ void P_CalcHeight (player_t *player) { bob = 0; } - player->viewz = player->mo->z + player->viewheight + bob; + player->viewz = player->mo->Z() + player->viewheight + bob; if (player->mo->floorclip && player->playerstate != PST_DEAD - && player->mo->z <= player->mo->floorz) + && player->mo->Z() <= player->mo->floorz) { player->viewz -= player->mo->floorclip; } @@ -1857,7 +1863,7 @@ void P_MovePlayer (player_t *player) mo->angle += cmd->ucmd.yaw << 16; } - player->onground = (mo->z <= mo->floorz) || (mo->flags2 & MF2_ONMOBJ) || (mo->BounceFlags & BOUNCE_MBF) || (player->cheats & CF_NOCLIP2); + player->onground = (mo->Z() <= mo->floorz) || (mo->flags2 & MF2_ONMOBJ) || (mo->BounceFlags & BOUNCE_MBF) || (player->cheats & CF_NOCLIP2); // killough 10/98: // @@ -1914,7 +1920,7 @@ void P_MovePlayer (player_t *player) { fprintf (debugfile, "move player for pl %d%c: (%d,%d,%d) (%d,%d) %d %d w%d [", int(player-players), player->cheats&CF_PREDICTING?'p':' ', - player->mo->x, player->mo->y, player->mo->z,forwardmove, sidemove, movefactor, friction, player->mo->waterlevel); + player->mo->X(), player->mo->Y(), player->mo->Z(),forwardmove, sidemove, movefactor, friction, player->mo->waterlevel); msecnode_t *n = player->mo->touching_sectorlist; while (n != NULL) { @@ -2046,7 +2052,7 @@ void P_DeathThink (player_t *player) P_MovePsprites (player); - player->onground = (player->mo->z <= player->mo->floorz); + player->onground = (player->mo->Z() <= player->mo->floorz); if (player->mo->IsKindOf (RUNTIME_CLASS(APlayerChunk))) { // Flying bloody skull or flying ice chunk player->viewheight = 6 * FRACUNIT; @@ -2159,7 +2165,7 @@ void P_CrouchMove(player_t * player, int direction) // check whether the move is ok player->mo->height = FixedMul(defaultheight, player->crouchfactor); - if (!P_TryMove(player->mo, player->mo->x, player->mo->y, false, NULL)) + if (!P_TryMove(player->mo, player->mo->X(), player->mo->Y(), false, NULL)) { player->mo->height = savedheight; if (direction > 0) @@ -2176,7 +2182,7 @@ void P_CrouchMove(player_t * player, int direction) player->crouchviewdelta = player->viewheight - player->mo->ViewHeight; // Check for eyes going above/below fake floor due to crouching motion. - P_CheckFakeFloorTriggers(player->mo, player->mo->z + oldheight, true); + P_CheckFakeFloorTriggers(player->mo, player->mo->Z() + oldheight, true); } //---------------------------------------------------------------------------- @@ -2197,7 +2203,7 @@ void P_PlayerThink (player_t *player) if (debugfile && !(player->cheats & CF_PREDICTING)) { fprintf (debugfile, "tic %d for pl %td: (%d, %d, %d, %u) b:%02x p:%d y:%d f:%d s:%d u:%d\n", - gametic, player-players, player->mo->x, player->mo->y, player->mo->z, + gametic, player-players, player->mo->X(), player->mo->Y(), player->mo->Z(), player->mo->angle>>ANGLETOFINESHIFT, player->cmd.ucmd.buttons, player->cmd.ucmd.pitch, player->cmd.ucmd.yaw, player->cmd.ucmd.forwardmove, player->cmd.ucmd.sidemove, player->cmd.ucmd.upmove); @@ -2323,7 +2329,7 @@ void P_PlayerThink (player_t *player) player->crouching = 0; } if (crouchdir == 1 && player->crouchfactor < FRACUNIT && - player->mo->z + player->mo->height < player->mo->ceilingz) + player->mo->Top() < player->mo->ceilingz) { P_CrouchMove(player, 1); } @@ -2534,12 +2540,9 @@ void P_PlayerThink (player_t *player) if (!(player->cheats & CF_PREDICTING)) { P_PlayerOnSpecial3DFloor (player); - if (player->mo->Sector->special || player->mo->Sector->damage) - { - P_PlayerInSpecialSector (player); - } - if (player->mo->z <= player->mo->Sector->floorplane.ZatPoint( - player->mo->x, player->mo->y) || + P_PlayerInSpecialSector (player); + + if (player->mo->Z() <= player->mo->Sector->floorplane.ZatPoint(player->mo) || player->mo->waterlevel) { // Player must be touching the floor @@ -2596,8 +2599,8 @@ void P_PlayerThink (player_t *player) if (player->hazardcount) { player->hazardcount--; - if (!(level.time & 31) && player->hazardcount > 16*TICRATE) - P_DamageMobj (player->mo, NULL, NULL, 5, NAME_Slime); + if (!(level.time % player->hazardinterval) && player->hazardcount > 16*TICRATE) + P_DamageMobj (player->mo, NULL, NULL, 5, player->hazardtype); } if (player->poisoncount && !(level.time & 15)) @@ -2693,7 +2696,7 @@ void P_PredictPlayer (player_t *player) PredictionPlayerBackup = *player; APlayerPawn *act = player->mo; - memcpy(PredictionActorBackup, &act->x, sizeof(APlayerPawn) - ((BYTE *)&act->x - (BYTE *)act)); + memcpy(PredictionActorBackup, &act->snext, sizeof(APlayerPawn) - ((BYTE *)&act->snext - (BYTE *)act)); act->flags &= ~MF_PICKUP; act->flags2 &= ~MF2_PUSHWALL; @@ -2765,16 +2768,16 @@ void P_PredictPlayer (player_t *player) { // Z is not compared as lifts will alter this with no apparent change // Make lerping less picky by only testing whole units - DoLerp = ((PredictionLast.x >> 16) != (player->mo->x >> 16) || - (PredictionLast.y >> 16) != (player->mo->y >> 16)); + DoLerp = ((PredictionLast.x >> 16) != (player->mo->X() >> 16) || + (PredictionLast.y >> 16) != (player->mo->Y() >> 16)); // Aditional Debug information if (developer && DoLerp) { DPrintf("Lerp! Ltic (%d) && Ptic (%d) | Lx (%d) && Px (%d) | Ly (%d) && Py (%d)\n", PredictionLast.gametic, i, - (PredictionLast.x >> 16), (player->mo->x >> 16), - (PredictionLast.y >> 16), (player->mo->y >> 16)); + (PredictionLast.x >> 16), (player->mo->X() >> 16), + (PredictionLast.y >> 16), (player->mo->Y() >> 16)); } } } @@ -2792,9 +2795,9 @@ void P_PredictPlayer (player_t *player) } PredictionLast.gametic = maxtic - 1; - PredictionLast.x = player->mo->x; - PredictionLast.y = player->mo->y; - PredictionLast.z = player->mo->z; + PredictionLast.x = player->mo->X(); + PredictionLast.y = player->mo->Y(); + PredictionLast.z = player->mo->Z(); if (PredictionLerptics > 0) { @@ -2802,9 +2805,7 @@ void P_PredictPlayer (player_t *player) P_LerpCalculate(PredictionLerpFrom, PredictionLast, PredictionLerpResult, (float)PredictionLerptics * cl_predict_lerpscale)) { PredictionLerptics++; - player->mo->x = PredictionLerpResult.x; - player->mo->y = PredictionLerpResult.y; - player->mo->z = PredictionLerpResult.z; + player->mo->SetXYZ(PredictionLerpResult.x, PredictionLerpResult.y, PredictionLerpResult.z); } else { @@ -2836,7 +2837,7 @@ void P_UnPredictPlayer () player->camera = savedcamera; act->UnlinkFromWorld(); - memcpy(&act->x, PredictionActorBackup, sizeof(APlayerPawn) - ((BYTE *)&act->x - (BYTE *)act)); + memcpy(&act->snext, PredictionActorBackup, sizeof(APlayerPawn) - ((BYTE *)&act->snext - (BYTE *)act)); // The blockmap ordering needs to remain unchanged, too. // Restore sector links and refrences. @@ -3010,7 +3011,12 @@ void player_t::Serialize (FArchive &arc) << air_finished << turnticks << oldbuttons; - bool IsBot; + if (SaveVersion >= 4929) + { + arc << hazardtype + << hazardinterval; + } + bool IsBot = false; if (SaveVersion >= 4514) { arc << Bot; @@ -3039,6 +3045,12 @@ void player_t::Serialize (FArchive &arc) WeaponState = ((cheats >> 14) & 1) | ((cheats & (0x37 << 24)) >> (24 - 1)); cheats &= ~((1 << 14) | (0x37 << 24)); } + if (SaveVersion < 4527) + { + BYTE oldWeaponState; + arc << oldWeaponState; + WeaponState = oldWeaponState; + } else { arc << WeaponState; @@ -3099,7 +3111,7 @@ void player_t::Serialize (FArchive &arc) } else { - onground = (mo->z <= mo->floorz) || (mo->flags2 & MF2_ONMOBJ) || (mo->BounceFlags & BOUNCE_MBF) || (cheats & CF_NOCLIP2); + onground = (mo->Z() <= mo->floorz) || (mo->flags2 & MF2_ONMOBJ) || (mo->BounceFlags & BOUNCE_MBF) || (cheats & CF_NOCLIP2); } if (SaveVersion < 4514 && IsBot) diff --git a/src/p_writemap.cpp b/src/p_writemap.cpp index e31d2c4c3..8f1a4edfa 100644 --- a/src/p_writemap.cpp +++ b/src/p_writemap.cpp @@ -98,8 +98,8 @@ static int WriteTHINGS (FILE *file) mapthinghexen_t mt = { 0, 0, 0, 0, 0, 0, 0, 0, {0} }; AActor *mo = players[consoleplayer].mo; - mt.x = LittleShort(short(mo->x >> FRACBITS)); - mt.y = LittleShort(short(mo->y >> FRACBITS)); + mt.x = LittleShort(short(mo->X() >> FRACBITS)); + mt.y = LittleShort(short(mo->Y() >> FRACBITS)); mt.angle = LittleShort(short(MulScale32 (mo->angle >> ANGLETOFINESHIFT, 360))); mt.type = LittleShort((short)1); mt.flags = LittleShort((short)(7|224|MTF_SINGLE)); diff --git a/src/pathexpander.cpp b/src/pathexpander.cpp new file mode 100644 index 000000000..2ed0f3ec3 --- /dev/null +++ b/src/pathexpander.cpp @@ -0,0 +1,134 @@ +/* +** pathexpander.cpp +** Utility class for expanding a given path with a range of directories +** +**--------------------------------------------------------------------------- +** Copyright 2015 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include "pathexpander.h" +#include "cmdlib.h" +#include "w_wad.h" + +//============================================================================ +// +// +// +//============================================================================ + +static FString BuildPath(const FString &base, const char *name) +{ + FString current; + if (base.IsNotEmpty()) + { + current = base; + if (current[current.Len() - 1] != '/') current += '/'; + } + current += name; + return current; +} + +//============================================================================ +// +// This is meant to find and open files for reading. +// +//============================================================================ + +FileReader *PathExpander::openFileReader(const char *name, int *plumpnum) +{ + FileReader *fp; + FString current_filename; + + if (!name || !(*name)) + { + return 0; + } + + /* First try the given name */ + current_filename = name; + FixPathSeperator(current_filename); + + + if (openmode != OM_FILE) + { + int lumpnum = Wads.CheckNumForFullName(current_filename); + if (lumpnum >= 0) + { + fp = Wads.ReopenLumpNum(lumpnum); + if (plumpnum) *plumpnum = lumpnum; + return fp; + } + if (openmode == OM_LUMP) // search the path list when not loading the main config + { + for (unsigned int plp = PathList.Size(); plp-- != 0; ) + { /* Try along the path then */ + current_filename = BuildPath(PathList[plp], name); + lumpnum = Wads.CheckNumForFullName(current_filename); + if (lumpnum >= 0) + { + fp = Wads.ReopenLumpNum(lumpnum); + if (plumpnum) *plumpnum = lumpnum; + return fp; + } + } + return NULL; + } + } + if (plumpnum) *plumpnum = -1; + + + fp = new FileReader; + if (fp->Open(current_filename)) return fp; + + if (name[0] != '/') + { + for (unsigned int plp = PathList.Size(); plp-- != 0; ) + { /* Try along the path then */ + current_filename = BuildPath(PathList[plp], name); + if (fp->Open(current_filename)) return fp; + } + } + delete fp; + + /* Nothing could be opened. */ + return NULL; +} + +/* This adds a directory to the path list */ +void PathExpander::addToPathlist(const char *s) +{ + FString copy = s; + FixPathSeperator(copy); + PathList.Push(copy); +} + +void PathExpander::clearPathlist() +{ + PathList.Clear(); +} diff --git a/src/pathexpander.h b/src/pathexpander.h new file mode 100644 index 000000000..3183349d5 --- /dev/null +++ b/src/pathexpander.h @@ -0,0 +1,31 @@ +#ifndef __PATHEXPANDER_H +#define __PATHEXPANDER_H + +#include "tarray.h" +#include "zstring.h" +#include "files.h" + +class PathExpander +{ + TArray PathList; + +public: + int openmode; + + enum + { + OM_FILEORLUMP = 0, + OM_LUMP, + OM_FILE + }; + + PathExpander(int om = OM_FILEORLUMP) + { + openmode = om; + } + void addToPathlist(const char *s); + void clearPathlist(); + FileReader *openFileReader(const char *name, int *plumpnum); +}; + +#endif diff --git a/src/po_man.cpp b/src/po_man.cpp index 60627e4f3..a0cc4487b 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -901,7 +901,8 @@ void FPolyObj::ThrustMobj (AActor *actor, side_t *side) actor->vely += thrustY; if (crush) { - if (bHurtOnTouch || !P_CheckMove (actor, actor->x + thrustX, actor->y + thrustY)) + fixedvec2 pos = actor->Vec2Offset(thrustX, thrustY); + if (bHurtOnTouch || !P_CheckMove (actor, pos.x, pos.y)) { int newdam = P_DamageMobj (actor, NULL, NULL, crush, NAME_Crush); P_TraceBleed (newdam > 0 ? newdam : crush, actor); @@ -1199,8 +1200,8 @@ bool FPolyObj::CheckMobjBlocking (side_t *sd) && !((mobj->flags & MF_FLOAT) && (ld->flags & ML_BLOCK_FLOATERS)) && (!(ld->flags & ML_3DMIDTEX) || (!P_LineOpening_3dMidtex(mobj, ld, open) && - (mobj->z + mobj->height < open.top) - ) || (open.abovemidtex && mobj->z > mobj->floorz)) + (mobj->Top() < open.top) + ) || (open.abovemidtex && mobj->Z() > mobj->floorz)) ) { // [BL] We can't just continue here since we must @@ -1213,7 +1214,7 @@ bool FPolyObj::CheckMobjBlocking (side_t *sd) performBlockingThrust = true; } - FBoundingBox box(mobj->x, mobj->y, mobj->radius); + FBoundingBox box(mobj->X(), mobj->Y(), mobj->radius); if (box.Right() <= ld->bbox[BOXLEFT] || box.Left() >= ld->bbox[BOXRIGHT] @@ -1231,15 +1232,15 @@ bool FPolyObj::CheckMobjBlocking (side_t *sd) // Best use the one facing the player and ignore the back side. if (ld->sidedef[1] != NULL) { - int side = P_PointOnLineSide(mobj->x, mobj->y, ld); + int side = P_PointOnLineSidePrecise(mobj->X(), mobj->Y(), ld); if (ld->sidedef[side] != sd) { continue; } // [BL] See if we hit below the floor/ceiling of the poly. else if(!performBlockingThrust && ( - mobj->z < ld->sidedef[!side]->sector->GetSecPlane(sector_t::floor).ZatPoint(mobj->x, mobj->y) || - mobj->z + mobj->height > ld->sidedef[!side]->sector->GetSecPlane(sector_t::ceiling).ZatPoint(mobj->x, mobj->y) + mobj->Z() < ld->sidedef[!side]->sector->GetSecPlane(sector_t::floor).ZatPoint(mobj) || + mobj->Top() > ld->sidedef[!side]->sector->GetSecPlane(sector_t::ceiling).ZatPoint(mobj) )) { performBlockingThrust = true; @@ -1533,11 +1534,15 @@ static void IterFindPolySides (FPolyObj *po, side_t *side) // //========================================================================== +static int STACK_ARGS posicmp(const void *a, const void *b) +{ + return (*(const side_t **)a)->linedef->args[1] - (*(const side_t **)b)->linedef->args[1]; +} + static void SpawnPolyobj (int index, int tag, int type) { unsigned int ii; int i; - int j; FPolyObj *po = &polyobjs[index]; for (ii = 0; ii < KnownPolySides.Size(); ++ii) @@ -1577,59 +1582,24 @@ static void SpawnPolyobj (int index, int tag, int type) // didn't find a polyobj through PO_LINE_START TArray polySideList; unsigned int psIndexOld; - for (j = 1; j < PO_MAXPOLYSEGS; j++) - { - psIndexOld = po->Sidedefs.Size(); - for (ii = 0; ii < KnownPolySides.Size(); ++ii) - { - i = KnownPolySides[ii]; + psIndexOld = po->Sidedefs.Size(); - if (i >= 0 && - sides[i].linedef->special == Polyobj_ExplicitLine && - sides[i].linedef->args[0] == tag) - { - if (!sides[i].linedef->args[1]) - { - I_Error ("SpawnPolyobj: Explicit line missing order number (probably %d) in poly %d.\n", - j+1, tag); - } - if (sides[i].linedef->args[1] == j) - { - po->Sidedefs.Push (&sides[i]); - } - } - } - // Clear out any specials for these segs...we cannot clear them out - // in the above loop, since we aren't guaranteed one seg per linedef. - for (ii = 0; ii < KnownPolySides.Size(); ++ii) + for (ii = 0; ii < KnownPolySides.Size(); ++ii) + { + i = KnownPolySides[ii]; + + if (i >= 0 && + sides[i].linedef->special == Polyobj_ExplicitLine && + sides[i].linedef->args[0] == tag) { - i = KnownPolySides[ii]; - if (i >= 0 && - sides[i].linedef->special == Polyobj_ExplicitLine && - sides[i].linedef->args[0] == tag && sides[i].linedef->args[1] == j) + if (!sides[i].linedef->args[1]) { - sides[i].linedef->special = 0; - sides[i].linedef->args[0] = 0; - KnownPolySides[ii] = -1; - } - } - if (po->Sidedefs.Size() == psIndexOld) - { // Check if an explicit line order has been skipped. - // A line has been skipped if there are any more explicit - // lines with the current tag value. [RH] Can this actually happen? - for (ii = 0; ii < KnownPolySides.Size(); ++ii) - { - i = KnownPolySides[ii]; - if (i >= 0 && - sides[i].linedef->special == Polyobj_ExplicitLine && - sides[i].linedef->args[0] == tag) - { - I_Error ("SpawnPolyobj: Missing explicit line %d for poly %d\n", - j, tag); - } + I_Error("SpawnPolyobj: Explicit line missing order number in poly %d, linedef %d.\n", tag, int(sides[i].linedef - lines)); } + po->Sidedefs.Push (&sides[i]); } } + qsort(&po->Sidedefs[0], po->Sidedefs.Size(), sizeof(po->Sidedefs[0]), posicmp); if (po->Sidedefs.Size() > 0) { po->crush = (type != SMT_PolySpawn) ? 3 : 0; diff --git a/src/posix/cocoa/i_common.h b/src/posix/cocoa/i_common.h index 545540b2f..c0986b90a 100644 --- a/src/posix/cocoa/i_common.h +++ b/src/posix/cocoa/i_common.h @@ -31,6 +31,9 @@ ** */ +#ifndef COCOA_I_COMMON_INCLUDED +#define COCOA_I_COMMON_INCLUDED + #import @@ -50,12 +53,23 @@ struct RenderBufferOptions extern RenderBufferOptions rbOpts; +// Version of AppKit framework we are interested in +// The following values are needed to build with earlier SDKs + +#define AppKit10_4 824 +#define AppKit10_5 949 +#define AppKit10_6 1038 +#define AppKit10_7 1138 + + +@interface NSWindow(ExitAppOnClose) +- (void)exitAppOnClose; +@end + + inline bool I_IsHiDPISupported() { - // The following value shoud be equal to NSAppKitVersionNumber10_7 - // and it's hard-coded in order to build on earlier SDKs - - return NSAppKitVersionNumber >= 1138; + return NSAppKitVersionNumber >= AppKit10_7; } void I_ProcessEvent(NSEvent* event); @@ -79,6 +93,7 @@ typedef float CGFloat; // From HIToolbox/Events.h enum { + kVK_ANSI_F = 0x03, kVK_Return = 0x24, kVK_Tab = 0x30, kVK_Space = 0x31, @@ -168,3 +183,5 @@ typedef NSInteger NSApplicationActivationPolicy; @end #endif // prior to 10.7 + +#endif // COCOA_I_COMMON_INCLUDED diff --git a/src/posix/cocoa/i_input.mm b/src/posix/cocoa/i_input.mm index 5e0c5f1c8..3bbf42a9a 100644 --- a/src/posix/cocoa/i_input.mm +++ b/src/posix/cocoa/i_input.mm @@ -57,6 +57,8 @@ CVAR(Bool, use_mouse, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Bool, m_noprescale, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Bool, m_filter, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Bool, k_allowfullscreentoggle, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) + CUSTOM_CVAR(Int, mouse_capturemode, 1, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) { if (self < 0) @@ -542,6 +544,16 @@ void ProcessKeyboardEvent(NSEvent* theEvent) return; } + if (k_allowfullscreentoggle + && (kVK_ANSI_F == keyCode) + && (NSCommandKeyMask & [theEvent modifierFlags]) + && (NSKeyDown == [theEvent type]) + && ![theEvent isARepeat]) + { + ToggleFullscreen = !ToggleFullscreen; + return; + } + if (GUICapture) { ProcessKeyboardEventInMenu(theEvent); diff --git a/src/posix/cocoa/i_main.mm b/src/posix/cocoa/i_main.mm index 05a8081f6..2f65254a9 100644 --- a/src/posix/cocoa/i_main.mm +++ b/src/posix/cocoa/i_main.mm @@ -47,6 +47,7 @@ #include "i_system.h" #include "m_argv.h" #include "s_sound.h" +#include "st_console.h" #include "version.h" #undef Class @@ -125,18 +126,7 @@ void Mac_I_FatalError(const char* const message) { I_SetMainWindowVisible(false); - const CFStringRef errorString = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, - message, kCFStringEncodingASCII, kCFAllocatorNull); - - if (NULL != errorString) - { - CFOptionFlags dummy; - - CFUserNotificationDisplayAlert( 0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL, - CFSTR("Fatal Error"), errorString, CFSTR("Exit"), NULL, NULL, &dummy); - - CFRelease(errorString); - } + FConsoleWindow::GetInstance().ShowFatalError(message); } @@ -315,6 +305,9 @@ ApplicationController* appCtrl; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; + FConsoleWindow::CreateInstance(); + atterm(FConsoleWindow::DeleteInstance); + exit(OriginalMain(s_argc, s_argv)); } diff --git a/src/posix/cocoa/i_system.mm b/src/posix/cocoa/i_system.mm new file mode 100644 index 000000000..498498d94 --- /dev/null +++ b/src/posix/cocoa/i_system.mm @@ -0,0 +1,378 @@ +/* + ** i_system.mm + ** + **--------------------------------------------------------------------------- + ** Copyright 2012-2015 Alexey Lysiuk + ** All rights reserved. + ** + ** Redistribution and use in source and binary forms, with or without + ** modification, are permitted provided that the following conditions + ** are met: + ** + ** 1. Redistributions of source code must retain the above copyright + ** notice, this list of conditions and the following disclaimer. + ** 2. Redistributions in binary form must reproduce the above copyright + ** notice, this list of conditions and the following disclaimer in the + ** documentation and/or other materials provided with the distribution. + ** 3. The name of the author may not be used to endorse or promote products + ** derived from this software without specific prior written permission. + ** + ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **--------------------------------------------------------------------------- + ** + */ + +#include "i_common.h" + +#include +#include +#include + +#include "d_ticcmd.h" +#include "doomdef.h" +#include "doomerrors.h" +#include "doomstat.h" +#include "g_game.h" +#include "gameconfigfile.h" +#include "i_sound.h" +#include "i_system.h" +#include "st_console.h" +#include "v_text.h" +#include "x86.h" + + +EXTERN_CVAR(String, language) + +DWORD LanguageIDs[4]; + + +int (*I_GetTime)(bool saveMS); +int (*I_WaitForTic)(int); +void (*I_FreezeTime)(bool frozen); + + +void I_Tactile(int /*on*/, int /*off*/, int /*total*/) +{ +} + + +ticcmd_t* I_BaseTiccmd() +{ + static ticcmd_t emptycmd; + return &emptycmd; +} + + +void I_WaitVBL(const int count) +{ + // I_WaitVBL is never used to actually synchronize to the + // vertical blank. Instead, it's used for delay purposes. + usleep(1000000 * count / 70); +} + + +// +// SetLanguageIDs +// +void SetLanguageIDs() +{ + size_t langlen = strlen(language); + + DWORD lang = (langlen < 2 || langlen > 3) + ? MAKE_ID('e', 'n', 'u', '\0') + : MAKE_ID(language[0], language[1], language[2], '\0'); + + LanguageIDs[3] = LanguageIDs[2] = LanguageIDs[1] = LanguageIDs[0] = lang; +} + + +void I_InitTimer(); +void I_ShutdownTimer(); + +void I_Init(void) +{ + CheckCPUID(&CPU); + DumpCPUInfo(&CPU); + + atterm(I_ShutdownSound); + I_InitSound(); + I_InitTimer(); +} + +static int has_exited; + +void I_Quit() +{ + has_exited = 1; // Prevent infinitely recursive exits -- killough + + if (demorecording) + { + G_CheckDemoStatus(); + } + + C_DeinitConsole(); + + I_ShutdownTimer(); +} + + +extern FILE* Logfile; +bool gameisdead; + +void STACK_ARGS I_FatalError(const char* const error, ...) +{ + static bool alreadyThrown = false; + gameisdead = true; + + if (!alreadyThrown) // ignore all but the first message -- killough + { + alreadyThrown = true; + + char errortext[MAX_ERRORTEXT]; + int index; + va_list argptr; + va_start(argptr, error); + index = vsnprintf(errortext, MAX_ERRORTEXT, error, argptr); + va_end(argptr); + + extern void Mac_I_FatalError(const char*); + Mac_I_FatalError(errortext); + + // Record error to log (if logging) + if (Logfile) + { + fprintf(Logfile, "\n**** DIED WITH FATAL ERROR:\n%s\n", errortext); + fflush(Logfile); + } + + fprintf(stderr, "%s\n", errortext); + exit(-1); + } + + if (!has_exited) // If it hasn't exited yet, exit now -- killough + { + has_exited = 1; // Prevent infinitely recursive exits -- killough + exit(-1); + } +} + +void STACK_ARGS I_Error(const char* const error, ...) +{ + va_list argptr; + char errortext[MAX_ERRORTEXT]; + + va_start(argptr, error); + vsnprintf(errortext, MAX_ERRORTEXT, error, argptr); + va_end(argptr); + + throw CRecoverableError(errortext); +} + + +void I_SetIWADInfo() +{ +} + + +void I_PrintStr(const char* const message) +{ + FConsoleWindow::GetInstance().AddText(message); + + // Strip out any color escape sequences before writing to output + char* const copy = new char[strlen(message) + 1]; + const char* srcp = message; + char* dstp = copy; + + while ('\0' != *srcp) + { + if (TEXTCOLOR_ESCAPE == *srcp) + { + if ('\0' != srcp[1]) + { + srcp += 2; + } + else + { + break; + } + } + else if (0x1d == *srcp || 0x1f == *srcp) // Opening and closing bar character + { + *dstp++ = '-'; + *srcp++; + } + else if (0x1e == *srcp) // Middle bar character + { + *dstp++ = '='; + *srcp++; + } + else + { + *dstp++ = *srcp++; + } + } + + *dstp = '\0'; + + fputs(copy, stdout); + delete[] copy; + fflush(stdout); +} + + +int I_PickIWad(WadStuff* const wads, const int numwads, const bool showwin, const int defaultiwad) +{ + if (!showwin) + { + return defaultiwad; + } + + I_SetMainWindowVisible(false); + + extern int I_PickIWad_Cocoa(WadStuff*, int, bool, int); + const int result = I_PickIWad_Cocoa(wads, numwads, showwin, defaultiwad); + + I_SetMainWindowVisible(true); + + return result; +} + + +bool I_WriteIniFailed() +{ + printf("The config file %s could not be saved:\n%s\n", GameConfig->GetPathName(), strerror(errno)); + return false; // return true to retry +} + + +static const char *pattern; + +#if MAC_OS_X_VERSION_MAX_ALLOWED < 1080 +static int matchfile(struct dirent *ent) +#else +static int matchfile(const struct dirent *ent) +#endif +{ + return fnmatch(pattern, ent->d_name, FNM_NOESCAPE) == 0; +} + +void* I_FindFirst(const char* const filespec, findstate_t* const fileinfo) +{ + FString dir; + + const char* const slash = strrchr(filespec, '/'); + + if (slash) + { + pattern = slash+1; + dir = FString(filespec, slash - filespec + 1); + } + else + { + pattern = filespec; + dir = "."; + } + + fileinfo->current = 0; + fileinfo->count = scandir(dir.GetChars(), &fileinfo->namelist, matchfile, alphasort); + + if (fileinfo->count > 0) + { + return fileinfo; + } + + return (void*)-1; +} + +int I_FindNext(void* const handle, findstate_t* const fileinfo) +{ + findstate_t* const state = static_cast(handle); + + if (state->current < fileinfo->count) + { + return ++state->current < fileinfo->count ? 0 : -1; + } + + return -1; +} + +int I_FindClose(void* const handle) +{ + findstate_t* const state = static_cast(handle); + + if (handle != (void*)-1 && state->count > 0) + { + for (int i = 0; i < state->count; ++i) + { + free(state->namelist[i]); + } + + free(state->namelist); + state->namelist = NULL; + state->count = 0; + } + + return 0; +} + +int I_FindAttr(findstate_t* const fileinfo) +{ + dirent* const ent = fileinfo->namelist[fileinfo->current]; + struct stat buf; + + if (stat(ent->d_name, &buf) == 0) + { + return S_ISDIR(buf.st_mode) ? FA_DIREC : 0; + } + + return 0; +} + + +void I_PutInClipboard(const char* const string) +{ + NSPasteboard* const pasteBoard = [NSPasteboard generalPasteboard]; + NSString* const stringType = NSStringPboardType; + NSArray* const types = [NSArray arrayWithObjects:stringType, nil]; + NSString* const content = [NSString stringWithUTF8String:string]; + + [pasteBoard declareTypes:types + owner:nil]; + [pasteBoard setString:content + forType:stringType]; +} + +FString I_GetFromClipboard(bool returnNothing) +{ + if (returnNothing) + { + return FString(); + } + + NSPasteboard* const pasteBoard = [NSPasteboard generalPasteboard]; + NSString* const value = [pasteBoard stringForType:NSStringPboardType]; + + return FString([value UTF8String]); +} + + +unsigned int I_MakeRNGSeed() +{ + return static_cast(arc4random()); +} + + +TArray I_GetGogPaths() +{ + // GOG's Doom games are Windows only at the moment + return TArray(); +} diff --git a/src/posix/cocoa/i_video.mm b/src/posix/cocoa/i_video.mm index 3fc2b2aed..1a535c088 100644 --- a/src/posix/cocoa/i_video.mm +++ b/src/posix/cocoa/i_video.mm @@ -47,6 +47,7 @@ #include "m_argv.h" #include "r_renderer.h" #include "r_swrenderer.h" +#include "st_console.h" #include "stats.h" #include "textures.h" #include "v_palette.h" @@ -58,6 +59,18 @@ #undef Class +@implementation NSWindow(ExitAppOnClose) + +- (void)exitAppOnClose +{ + NSButton* closeButton = [self standardWindowButton:NSWindowCloseButton]; + [closeButton setAction:@selector(terminate:)]; + [closeButton setTarget:NSApp]; +} + +@end + + EXTERN_CVAR(Bool, ticker ) EXTERN_CVAR(Bool, vid_vsync) EXTERN_CVAR(Bool, vid_hidpi) @@ -407,7 +420,7 @@ CocoaVideo::CocoaVideo(const int multisample) attributes[i++] = NSOpenGLPFAStencilSize; attributes[i++] = NSOpenGLPixelFormatAttribute(8); - if (!vid_autoswitch) + if (NSAppKitVersionNumber >= AppKit10_5 && !vid_autoswitch) { attributes[i++] = NSOpenGLPFAAllowOfflineRenderers; } @@ -433,6 +446,8 @@ CocoaVideo::CocoaVideo(const int multisample) [[glView openGLContext] makeCurrentContext]; [m_window setContentView:glView]; + + FConsoleWindow::GetInstance().Show(false); } void CocoaVideo::StartModeIterator(const int bits, const bool fullscreen) @@ -555,16 +570,15 @@ void CocoaVideo::SetWindowVisible(bool visible) { [video->m_window orderOut:nil]; } + + I_SetNativeMouse(!visible); } } static bool HasModernFullscreenAPI() { - // The following value shoud be equal to NSAppKitVersionNumber10_6 - // and it's hard-coded in order to build on earlier SDKs - - return NSAppKitVersionNumber >= 1038; + return NSAppKitVersionNumber >= AppKit10_6; } void CocoaVideo::SetStyleMask(const NSUInteger styleMask) @@ -625,7 +639,7 @@ void CocoaVideo::SetFullscreenMode(const int width, const int height) [m_window setHidesOnDeactivate:YES]; } - [m_window setFrame:displayRect display:YES]; + [m_window setFrame:screenFrame display:YES]; [m_window setFrameOrigin:NSMakePoint(0.0f, 0.0f)]; } @@ -662,10 +676,7 @@ void CocoaVideo::SetWindowedMode(const int width, const int height) [m_window setContentSize:windowSize]; [m_window center]; - - NSButton* closeButton = [m_window standardWindowButton:NSWindowCloseButton]; - [closeButton setAction:@selector(terminate:)]; - [closeButton setTarget:NSApp]; + [m_window exitAppOnClose]; } void CocoaVideo::SetMode(const int width, const int height, const bool fullscreen, const bool hiDPI) @@ -1211,7 +1222,7 @@ bool I_SetCursor(FTexture* cursorpic) // Create image from representation and set it as cursor NSData* imageData = [bitmapImageRep representationUsingType:NSPNGFileType - properties:nil]; + properties:[NSDictionary dictionary]]; NSImage* cursorImage = [[NSImage alloc] initWithData:imageData]; cursor = [[NSCursor alloc] initWithImage:cursorImage @@ -1231,10 +1242,7 @@ NSSize I_GetContentViewSize(const NSWindow* const window) const NSView* const view = [window contentView]; const NSSize frameSize = [view frame].size; - // TODO: figure out why [NSView frame] returns different values in "fullscreen" and in window - // In "fullscreen" the result is multiplied by [NSScreen backingScaleFactor], but not in window - - return (vid_hidpi && !fullscreen) + return (vid_hidpi) ? [view convertSizeToBacking:frameSize] : frameSize; } @@ -1242,5 +1250,4 @@ NSSize I_GetContentViewSize(const NSWindow* const window) void I_SetMainWindowVisible(bool visible) { CocoaVideo::SetWindowVisible(visible); - I_SetNativeMouse(!visible); } diff --git a/src/posix/cocoa/st_console.h b/src/posix/cocoa/st_console.h new file mode 100644 index 000000000..6b6f01820 --- /dev/null +++ b/src/posix/cocoa/st_console.h @@ -0,0 +1,94 @@ +/* + ** st_console.h + ** + **--------------------------------------------------------------------------- + ** Copyright 2015 Alexey Lysiuk + ** All rights reserved. + ** + ** Redistribution and use in source and binary forms, with or without + ** modification, are permitted provided that the following conditions + ** are met: + ** + ** 1. Redistributions of source code must retain the above copyright + ** notice, this list of conditions and the following disclaimer. + ** 2. Redistributions in binary form must reproduce the above copyright + ** notice, this list of conditions and the following disclaimer in the + ** documentation and/or other materials provided with the distribution. + ** 3. The name of the author may not be used to endorse or promote products + ** derived from this software without specific prior written permission. + ** + ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **--------------------------------------------------------------------------- + ** + */ + +#ifndef COCOA_ST_CONSOLE_INCLUDED +#define COCOA_ST_CONSOLE_INCLUDED + +@class NSButton; +@class NSProgressIndicator; +@class NSScrollView; +@class NSTextField; +@class NSTextView; +@class NSView; +@class NSWindow; + +struct PalEntry; + + +class FConsoleWindow +{ +public: + static FConsoleWindow& GetInstance(); + + static void CreateInstance(); + static void DeleteInstance(); + + void Show(bool visible); + void ShowFatalError(const char* message); + + void AddText(const char* message); + + void SetTitleText(); + void SetProgressBar(bool visible); + + // FStartupScreen functionality + void Progress(int current, int maximum); + void NetInit(const char* message, int playerCount); + void NetProgress(int count); + void NetDone(); + +private: + NSWindow* m_window; + NSTextView* m_textView; + NSScrollView* m_scrollView; + NSProgressIndicator* m_progressBar; + + NSView* m_netView; + NSTextField* m_netMessageText; + NSTextField* m_netCountText; + NSProgressIndicator* m_netProgressBar; + NSButton* m_netAbortButton; + + unsigned int m_characterCount; + + int m_netCurPos; + int m_netMaxPos; + + FConsoleWindow(); + + void ExpandTextView(float height); + + void AddText(const PalEntry& color, const char* message); +}; + +#endif // COCOA_ST_CONSOLE_INCLUDED diff --git a/src/posix/cocoa/st_console.mm b/src/posix/cocoa/st_console.mm new file mode 100644 index 000000000..e952d22d6 --- /dev/null +++ b/src/posix/cocoa/st_console.mm @@ -0,0 +1,499 @@ +/* + ** st_console.mm + ** + **--------------------------------------------------------------------------- + ** Copyright 2015 Alexey Lysiuk + ** All rights reserved. + ** + ** Redistribution and use in source and binary forms, with or without + ** modification, are permitted provided that the following conditions + ** are met: + ** + ** 1. Redistributions of source code must retain the above copyright + ** notice, this list of conditions and the following disclaimer. + ** 2. Redistributions in binary form must reproduce the above copyright + ** notice, this list of conditions and the following disclaimer in the + ** documentation and/or other materials provided with the distribution. + ** 3. The name of the author may not be used to endorse or promote products + ** derived from this software without specific prior written permission. + ** + ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **--------------------------------------------------------------------------- + ** + */ + +#include "i_common.h" + +#include "d_main.h" +#include "i_system.h" +#include "st_console.h" +#include "v_text.h" +#include "version.h" + + +static NSColor* RGB(const BYTE red, const BYTE green, const BYTE blue) +{ + return [NSColor colorWithCalibratedRed:red / 255.0f + green:green / 255.0f + blue:blue / 255.0f + alpha:1.0f]; +} + +static NSColor* RGB(const PalEntry& color) +{ + return RGB(color.r, color.g, color.b); +} + +static NSColor* RGB(const DWORD color) +{ + return RGB(PalEntry(color)); +} + + +static const CGFloat PROGRESS_BAR_HEIGHT = 18.0f; +static const CGFloat NET_VIEW_HEIGHT = 88.0f; + + +FConsoleWindow::FConsoleWindow() +: m_window([NSWindow alloc]) +, m_textView([NSTextView alloc]) +, m_scrollView([NSScrollView alloc]) +, m_progressBar(nil) +, m_netView(nil) +, m_netMessageText(nil) +, m_netCountText(nil) +, m_netProgressBar(nil) +, m_netAbortButton(nil) +, m_characterCount(0) +, m_netCurPos(0) +, m_netMaxPos(0) +{ + const CGFloat initialWidth = 512.0f; + const CGFloat initialHeight = 384.0f; + const NSRect initialRect = NSMakeRect(0.0f, 0.0f, initialWidth, initialHeight); + + [m_textView initWithFrame:initialRect]; + [m_textView setEditable:NO]; + [m_textView setBackgroundColor:RGB(70, 70, 70)]; + [m_textView setMinSize:NSMakeSize(0.0f, initialHeight)]; + [m_textView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)]; + [m_textView setVerticallyResizable:YES]; + [m_textView setHorizontallyResizable:NO]; + [m_textView setAutoresizingMask:NSViewWidthSizable]; + + NSTextContainer* const textContainer = [m_textView textContainer]; + [textContainer setContainerSize:NSMakeSize(initialWidth, FLT_MAX)]; + [textContainer setWidthTracksTextView:YES]; + + [m_scrollView initWithFrame:NSMakeRect(0.0f, 0.0f, initialWidth, initialHeight)]; + [m_scrollView setBorderType:NSNoBorder]; + [m_scrollView setHasVerticalScroller:YES]; + [m_scrollView setHasHorizontalScroller:NO]; + [m_scrollView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + [m_scrollView setDocumentView:m_textView]; + + NSString* const title = [NSString stringWithFormat:@"%s %s - Console", GAMESIG, GetVersionString()]; + + [m_window initWithContentRect:initialRect + styleMask:NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask + backing:NSBackingStoreBuffered + defer:NO]; + [m_window setMinSize:[m_window frame].size]; + [m_window setShowsResizeIndicator:NO]; + [m_window setTitle:title]; + [m_window center]; + [m_window exitAppOnClose]; + + [[m_window contentView] addSubview:m_scrollView]; + + [m_window makeKeyAndOrderFront:nil]; +} + + +static FConsoleWindow* s_instance; + + +void FConsoleWindow::CreateInstance() +{ + assert(NULL == s_instance); + s_instance = new FConsoleWindow; +} + +void FConsoleWindow::DeleteInstance() +{ + assert(NULL != s_instance); + delete s_instance; + s_instance = NULL; +} + +FConsoleWindow& FConsoleWindow::GetInstance() +{ + assert(NULL != s_instance); + return *s_instance; +} + + +void FConsoleWindow::Show(const bool visible) +{ + if (visible) + { + [m_window orderFront:nil]; + } + else + { + [m_window orderOut:nil]; + } +} + +void FConsoleWindow::ShowFatalError(const char* const message) +{ + SetProgressBar(false); + NetDone(); + + const CGFloat textViewWidth = [m_scrollView frame].size.width; + + ExpandTextView(-32.0f); + + NSButton* quitButton = [[NSButton alloc] initWithFrame:NSMakeRect(textViewWidth - 76.0f, 0.0f, 72.0f, 30.0f)]; + [quitButton setAutoresizingMask:NSViewMinXMargin]; + [quitButton setBezelStyle:NSRoundedBezelStyle]; + [quitButton setTitle:@"Quit"]; + [quitButton setKeyEquivalent:@"\r"]; + [quitButton setTarget:NSApp]; + [quitButton setAction:@selector(terminate:)]; + + NSView* quitPanel = [[NSView alloc] initWithFrame:NSMakeRect(0.0f, 0.0f, textViewWidth, 32.0f)]; + [quitPanel setAutoresizingMask:NSViewWidthSizable]; + [quitPanel addSubview:quitButton]; + + [[m_window contentView] addSubview:quitPanel]; + [m_window orderFront:nil]; + + AddText(PalEntry(255, 0, 0), "\nExecution could not continue.\n"); + AddText(PalEntry(255, 255, 170), message); + AddText("\n"); + + [NSApp runModalForWindow:m_window]; +} + + +void FConsoleWindow::AddText(const char* message) +{ + PalEntry color(223, 223, 223); + + char buffer[1024] = {}; + size_t pos = 0; + bool reset = false; + + while (*message != '\0') + { + if ((TEXTCOLOR_ESCAPE == *message && 0 != pos) + || (pos == sizeof buffer - 1) + || reset) + { + buffer[pos] = '\0'; + pos = 0; + reset = false; + + AddText(color, buffer); + } + +#define CHECK_BUFFER_SPACE \ + if (pos >= sizeof buffer - 3) { reset = true; continue; } + + if (TEXTCOLOR_ESCAPE == *message) + { + const BYTE* colorID = reinterpret_cast(message) + 1; + if ('\0' == colorID) + { + break; + } + + const EColorRange range = V_ParseFontColor(colorID, CR_UNTRANSLATED, CR_YELLOW); + + if (range != CR_UNDEFINED) + { + color = V_LogColorFromColorRange(range); + } + + message += 2; + } + else if (0x1d == *message) // Opening bar character + { + CHECK_BUFFER_SPACE; + + // Insert BOX DRAWINGS LIGHT LEFT AND HEAVY RIGHT + buffer[pos++] = '\xe2'; + buffer[pos++] = '\x95'; + buffer[pos++] = '\xbc'; + ++message; + } + else if (0x1e == *message) // Middle bar character + { + CHECK_BUFFER_SPACE; + + // Insert BOX DRAWINGS HEAVY HORIZONTAL + buffer[pos++] = '\xe2'; + buffer[pos++] = '\x94'; + buffer[pos++] = '\x81'; + ++message; + } + else if (0x1f == *message) // Closing bar character + { + CHECK_BUFFER_SPACE; + + // Insert BOX DRAWINGS HEAVY LEFT AND LIGHT RIGHT + buffer[pos++] = '\xe2'; + buffer[pos++] = '\x95'; + buffer[pos++] = '\xbe'; + ++message; + } + else + { + buffer[pos++] = *message++; + } + +#undef CHECK_BUFFER_SPACE + } + + if (0 != pos) + { + buffer[pos] = '\0'; + + AddText(color, buffer); + } + + if ([m_window isVisible]) + { + [m_textView scrollRangeToVisible:NSMakeRange(m_characterCount, 0)]; + + [[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode]; + } +} + +void FConsoleWindow::AddText(const PalEntry& color, const char* const message) +{ + NSString* const text = [NSString stringWithUTF8String:message]; + + NSDictionary* const attributes = [NSDictionary dictionaryWithObjectsAndKeys: + [NSFont systemFontOfSize:14.0f], NSFontAttributeName, + RGB(color), NSForegroundColorAttributeName, + nil]; + + NSAttributedString* const formattedText = + [[NSAttributedString alloc] initWithString:text + attributes:attributes]; + [[m_textView textStorage] appendAttributedString:formattedText]; + + m_characterCount += [text length]; +} + + +void FConsoleWindow::SetTitleText() +{ + static const CGFloat TITLE_TEXT_HEIGHT = 32.0f; + + NSRect textViewFrame = [m_scrollView frame]; + textViewFrame.size.height -= TITLE_TEXT_HEIGHT; + [m_scrollView setFrame:textViewFrame]; + + const NSRect titleTextRect = NSMakeRect( + 0.0f, + textViewFrame.origin.y + textViewFrame.size.height, + textViewFrame.size.width, + TITLE_TEXT_HEIGHT); + + NSTextField* titleText = [[NSTextField alloc] initWithFrame:titleTextRect]; + [titleText setStringValue:[NSString stringWithUTF8String:DoomStartupInfo.Name]]; + [titleText setAlignment:NSCenterTextAlignment]; + [titleText setTextColor:RGB(DoomStartupInfo.FgColor)]; + [titleText setBackgroundColor:RGB(DoomStartupInfo.BkColor)]; + [titleText setFont:[NSFont fontWithName:@"Trebuchet MS Bold" size:18.0f]]; + [titleText setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin]; + [titleText setSelectable:NO]; + [titleText setBordered:NO]; + + [[m_window contentView] addSubview:titleText]; +} + +void FConsoleWindow::SetProgressBar(const bool visible) +{ + if ( (!visible && nil == m_progressBar) + || (visible && nil != m_progressBar)) + { + return; + } + + if (visible) + { + ExpandTextView(-PROGRESS_BAR_HEIGHT); + + m_progressBar = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(2.0f, 0.0f, 508.0f, 16.0f)]; + [m_progressBar setIndeterminate:NO]; + [m_progressBar setAutoresizingMask:NSViewWidthSizable]; + + [[m_window contentView] addSubview:m_progressBar]; + } + else + { + ExpandTextView(PROGRESS_BAR_HEIGHT); + + [m_progressBar removeFromSuperview]; + [m_progressBar release]; + m_progressBar = nil; + } +} + + +void FConsoleWindow::ExpandTextView(const float height) +{ + NSRect textFrame = [m_scrollView frame]; + textFrame.origin.y -= height; + textFrame.size.height += height; + [m_scrollView setFrame:textFrame]; +} + + +void FConsoleWindow::Progress(const int current, const int maximum) +{ + if (nil == m_progressBar) + { + return; + } + + static unsigned int previousTime = I_MSTime(); + unsigned int currentTime = I_MSTime(); + + if (currentTime - previousTime > 33) // approx. 30 FPS + { + previousTime = currentTime; + + [m_progressBar setMaxValue:maximum]; + [m_progressBar setDoubleValue:current]; + + [[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode]; + } +} + + +void FConsoleWindow::NetInit(const char* const message, const int playerCount) +{ + if (nil == m_netView) + { + SetProgressBar(false); + ExpandTextView(-NET_VIEW_HEIGHT); + + // Message like 'Waiting for players' or 'Contacting host' + m_netMessageText = [[NSTextField alloc] initWithFrame:NSMakeRect(12.0f, 64.0f, 400.0f, 16.0f)]; + [m_netMessageText setAutoresizingMask:NSViewWidthSizable]; + [m_netMessageText setDrawsBackground:NO]; + [m_netMessageText setSelectable:NO]; + [m_netMessageText setBordered:NO]; + + // Text with connected/total players count + m_netCountText = [[NSTextField alloc] initWithFrame:NSMakeRect(428.0f, 64.0f, 72.0f, 16.0f)]; + [m_netCountText setAutoresizingMask:NSViewMinXMargin]; + [m_netCountText setAlignment:NSRightTextAlignment]; + [m_netCountText setDrawsBackground:NO]; + [m_netCountText setSelectable:NO]; + [m_netCountText setBordered:NO]; + + // Connection progress + m_netProgressBar = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(12.0f, 40.0f, 488.0f, 16.0f)]; + [m_netProgressBar setAutoresizingMask:NSViewWidthSizable]; + [m_netProgressBar setMaxValue:playerCount]; + + if (0 == playerCount) + { + // Joining game + [m_netProgressBar setIndeterminate:YES]; + [m_netProgressBar startAnimation:nil]; + } + else + { + // Hosting game + [m_netProgressBar setIndeterminate:NO]; + } + + // Cancel network game button + m_netAbortButton = [[NSButton alloc] initWithFrame:NSMakeRect(432.0f, 8.0f, 72.0f, 28.0f)]; + [m_netAbortButton setAutoresizingMask:NSViewMinXMargin]; + [m_netAbortButton setBezelStyle:NSRoundedBezelStyle]; + [m_netAbortButton setTitle:@"Cancel"]; + [m_netAbortButton setKeyEquivalent:@"\r"]; + [m_netAbortButton setTarget:NSApp]; + [m_netAbortButton setAction:@selector(terminate:)]; + + // Panel for controls above + m_netView = [[NSView alloc] initWithFrame:NSMakeRect(0.0f, 0.0f, 512.0f, NET_VIEW_HEIGHT)]; + [m_netView setAutoresizingMask:NSViewWidthSizable]; + [m_netView addSubview:m_netMessageText]; + [m_netView addSubview:m_netCountText]; + [m_netView addSubview:m_netProgressBar]; + [m_netView addSubview:m_netAbortButton]; + + NSRect windowRect = [m_window frame]; + windowRect.origin.y -= NET_VIEW_HEIGHT; + windowRect.size.height += NET_VIEW_HEIGHT; + + [m_window setFrame:windowRect display:YES]; + [[m_window contentView] addSubview:m_netView]; + } + + [m_netMessageText setStringValue:[NSString stringWithUTF8String:message]]; + + m_netCurPos = 0; + m_netMaxPos = playerCount; + + NetProgress(1); // You always know about yourself +} + +void FConsoleWindow::NetProgress(const int count) +{ + if (0 == count) + { + ++m_netCurPos; + } + else + { + m_netCurPos = count; + } + + if (nil == m_netView) + { + return; + } + + if (m_netMaxPos > 1) + { + [m_netCountText setStringValue:[NSString stringWithFormat:@"%d / %d", m_netCurPos, m_netMaxPos]]; + [m_netProgressBar setDoubleValue:MIN(m_netCurPos, m_netMaxPos)]; + } +} + +void FConsoleWindow::NetDone() +{ + if (nil != m_netView) + { + ExpandTextView(NET_VIEW_HEIGHT); + + [m_netView removeFromSuperview]; + [m_netView release]; + m_netView = nil; + + // Released by m_netView + m_netMessageText = nil; + m_netCountText = nil; + m_netProgressBar = nil; + m_netAbortButton = nil; + } +} diff --git a/src/posix/cocoa/st_start.mm b/src/posix/cocoa/st_start.mm new file mode 100644 index 000000000..36582c64b --- /dev/null +++ b/src/posix/cocoa/st_start.mm @@ -0,0 +1,192 @@ +/* + ** st_start.mm + ** + **--------------------------------------------------------------------------- + ** Copyright 2015 Alexey Lysiuk + ** All rights reserved. + ** + ** Redistribution and use in source and binary forms, with or without + ** modification, are permitted provided that the following conditions + ** are met: + ** + ** 1. Redistributions of source code must retain the above copyright + ** notice, this list of conditions and the following disclaimer. + ** 2. Redistributions in binary form must reproduce the above copyright + ** notice, this list of conditions and the following disclaimer in the + ** documentation and/or other materials provided with the distribution. + ** 3. The name of the author may not be used to endorse or promote products + ** derived from this software without specific prior written permission. + ** + ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **--------------------------------------------------------------------------- + ** + */ + +#include + +#import + +#include "c_cvars.h" +#include "st_console.h" +#include "st_start.h" +#include "v_text.h" + + +FStartupScreen *StartScreen; + + +CUSTOM_CVAR(Int, showendoom, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (self < 0) + { + self = 0; + } + else if (self > 2) + { + self = 2; + } +} + + +// --------------------------------------------------------------------------- + + +class FBasicStartupScreen : public FStartupScreen +{ +public: + FBasicStartupScreen(int maxProgress, bool showBar); + ~FBasicStartupScreen(); + + virtual void Progress(); + + virtual void NetInit(const char* message, int playerCount); + virtual void NetProgress(int count); + virtual void NetMessage(const char *format, ...); + virtual void NetDone(); + virtual bool NetLoop(bool (*timerCallback)(void*), void* userData); +}; + + +FBasicStartupScreen::FBasicStartupScreen(int maxProgress, bool showBar) +: FStartupScreen(maxProgress) +{ + FConsoleWindow& consoleWindow = FConsoleWindow::GetInstance(); + consoleWindow.SetProgressBar(true); + consoleWindow.SetTitleText(); + +#if 0 + // Testing code, please do not remove + consoleWindow.AddText("----------------------------------------------------------------\n"); + consoleWindow.AddText("1234567890 !@#$%^&*() ,<.>/?;:'\" [{]}\\| `~-_=+ " + "This is very very very long message needed to trigger word wrapping...\n\n"); + consoleWindow.AddText("Multiline...\n\tmessage...\n\t\twith...\n\t\t\ttabs.\n\n"); + + consoleWindow.AddText(TEXTCOLOR_BRICK "TEXTCOLOR_BRICK\n" TEXTCOLOR_TAN "TEXTCOLOR_TAN\n"); + consoleWindow.AddText(TEXTCOLOR_GRAY "TEXTCOLOR_GRAY & TEXTCOLOR_GREY\n"); + consoleWindow.AddText(TEXTCOLOR_GREEN "TEXTCOLOR_GREEN\n" TEXTCOLOR_BROWN "TEXTCOLOR_BROWN\n"); + consoleWindow.AddText(TEXTCOLOR_GOLD "TEXTCOLOR_GOLD\n" TEXTCOLOR_RED "TEXTCOLOR_RED\n"); + consoleWindow.AddText(TEXTCOLOR_BLUE "TEXTCOLOR_BLUE\n" TEXTCOLOR_ORANGE "TEXTCOLOR_ORANGE\n"); + consoleWindow.AddText(TEXTCOLOR_WHITE "TEXTCOLOR_WHITE\n" TEXTCOLOR_YELLOW "TEXTCOLOR_YELLOW\n"); + consoleWindow.AddText(TEXTCOLOR_UNTRANSLATED "TEXTCOLOR_UNTRANSLATED\n"); + consoleWindow.AddText(TEXTCOLOR_BLACK "TEXTCOLOR_BLACK\n" TEXTCOLOR_LIGHTBLUE "TEXTCOLOR_LIGHTBLUE\n"); + consoleWindow.AddText(TEXTCOLOR_CREAM "TEXTCOLOR_CREAM\n" TEXTCOLOR_OLIVE "TEXTCOLOR_OLIVE\n"); + consoleWindow.AddText(TEXTCOLOR_DARKGREEN "TEXTCOLOR_DARKGREEN\n" TEXTCOLOR_DARKRED "TEXTCOLOR_DARKRED\n"); + consoleWindow.AddText(TEXTCOLOR_DARKBROWN "TEXTCOLOR_DARKBROWN\n" TEXTCOLOR_PURPLE "TEXTCOLOR_PURPLE\n"); + consoleWindow.AddText(TEXTCOLOR_DARKGRAY "TEXTCOLOR_DARKGRAY\n" TEXTCOLOR_CYAN "TEXTCOLOR_CYAN\n"); + consoleWindow.AddText(TEXTCOLOR_NORMAL "TEXTCOLOR_NORMAL\n" TEXTCOLOR_BOLD "TEXTCOLOR_BOLD\n"); + consoleWindow.AddText(TEXTCOLOR_CHAT "TEXTCOLOR_CHAT\n" TEXTCOLOR_TEAMCHAT "TEXTCOLOR_TEAMCHAT\n"); + consoleWindow.AddText("----------------------------------------------------------------\n"); +#endif // _DEBUG +} + +FBasicStartupScreen::~FBasicStartupScreen() +{ + FConsoleWindow::GetInstance().SetProgressBar(false); +} + + +void FBasicStartupScreen::Progress() +{ + if (CurPos < MaxPos) + { + ++CurPos; + } + + FConsoleWindow::GetInstance().Progress(CurPos, MaxPos); +} + + +void FBasicStartupScreen::NetInit(const char* const message, const int playerCount) +{ + FConsoleWindow::GetInstance().NetInit(message, playerCount); +} + +void FBasicStartupScreen::NetProgress(const int count) +{ + FConsoleWindow::GetInstance().NetProgress(count); +} + +void FBasicStartupScreen::NetMessage(const char* const format, ...) +{ + va_list args; + va_start(args, format); + + FString message; + message.VFormat(format, args); + va_end(args); + + Printf("%s\n", message.GetChars()); +} + +void FBasicStartupScreen::NetDone() +{ + FConsoleWindow::GetInstance().NetDone(); +} + +bool FBasicStartupScreen::NetLoop(bool (*timerCallback)(void*), void* const userData) +{ + while (true) + { + if (timerCallback(userData)) + { + break; + } + + [[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode]; + + // Do not poll to often + usleep(50000); + } + + return true; +} + + +// --------------------------------------------------------------------------- + + +FStartupScreen *FStartupScreen::CreateInstance(const int maxProgress) +{ + return new FBasicStartupScreen(maxProgress, true); +} + + +// --------------------------------------------------------------------------- + + +void ST_Endoom() +{ + extern void I_ShutdownJoysticks(); + I_ShutdownJoysticks(); + + exit(0); +} diff --git a/src/posix/osx/iwadpicker_cocoa.mm b/src/posix/osx/iwadpicker_cocoa.mm index d2bc1ff0c..5f2ff2ae2 100644 --- a/src/posix/osx/iwadpicker_cocoa.mm +++ b/src/posix/osx/iwadpicker_cocoa.mm @@ -462,20 +462,14 @@ static void RestartWithParameters(const char* iwadPath, NSString* parameters) [pool release]; } -void I_SetMainWindowVisible(bool visible); - // Simple wrapper so we can call this from outside. int I_PickIWad_Cocoa (WadStuff *wads, int numwads, bool showwin, int defaultiwad) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - I_SetMainWindowVisible(false); - IWADPicker *picker = [IWADPicker alloc]; int ret = [picker pickIWad:wads num:numwads showWindow:showwin defaultWad:defaultiwad]; - I_SetMainWindowVisible(true); - NSString* parametersToAppend = [picker commandLineParameters]; osx_additional_parameters = [parametersToAppend UTF8String]; diff --git a/src/posix/sdl/crashcatcher.c b/src/posix/sdl/crashcatcher.c index f85713e31..70c9e7b0c 100644 --- a/src/posix/sdl/crashcatcher.c +++ b/src/posix/sdl/crashcatcher.c @@ -15,7 +15,7 @@ #ifndef PR_SET_PTRACER #define PR_SET_PTRACER 0x59616d61 #endif -#elif defined (__APPLE__) +#elif defined (__APPLE__) || defined (__FreeBSD__) #include #endif diff --git a/src/posix/sdl/i_gui.cpp b/src/posix/sdl/i_gui.cpp index f9e6714b4..37a3b1062 100644 --- a/src/posix/sdl/i_gui.cpp +++ b/src/posix/sdl/i_gui.cpp @@ -54,8 +54,3 @@ bool I_SetCursor(FTexture *cursorpic) } return true; } - -void I_SetMainWindowVisible(bool visible) -{ - -} diff --git a/src/posix/i_system.cpp b/src/posix/sdl/i_system.cpp similarity index 100% rename from src/posix/i_system.cpp rename to src/posix/sdl/i_system.cpp diff --git a/src/posix/st_start.cpp b/src/posix/sdl/st_start.cpp similarity index 100% rename from src/posix/st_start.cpp rename to src/posix/sdl/st_start.cpp diff --git a/src/r_defs.h b/src/r_defs.h index a93622b41..4f0b5ed01 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -194,14 +194,19 @@ class ASectorAction : public AActor { DECLARE_CLASS (ASectorAction, AActor) public: + ASectorAction (bool activatedByUse = false); void Destroy (); void BeginPlay (); void Activate (AActor *source); void Deactivate (AActor *source); bool TriggerAction(AActor *triggerer, int activationType); + bool CanTrigger (AActor *triggerer) const; + bool IsActivatedByUse() const; protected: virtual bool DoTriggerAction(AActor *triggerer, int activationType); bool CheckTrigger(AActor *triggerer) const; +private: + bool ActivatedByUse; }; class ASkyViewpoint; @@ -243,6 +248,11 @@ struct secplane_t return FixedMul (ic, -d - DMulScale16 (a, v->x, b, v->y)); } + fixed_t ZatPoint (const AActor *ac) const + { + return FixedMul (ic, -d - DMulScale16 (a, ac->X(), b, ac->Y())); + } + // Returns the value of z at (x,y) if d is equal to dist fixed_t ZatPointDist (fixed_t x, fixed_t y, fixed_t dist) const { @@ -341,7 +351,7 @@ enum SECF_DRAWN = 128, // sector has been drawn at least once SECF_HIDDEN = 256, // Do not draw on textured automap SECF_NOFLOORSKYBOX = 512, // force use of regular sky - SECF_NOCEILINGSKYBOX = 1024, // force use of regular sky + SECF_NOCEILINGSKYBOX = 1024, // force use of regular sky (do not separate from NOFLOORSKYBOX!!!) }; enum @@ -350,6 +360,20 @@ enum SECF_NOFALLINGDAMAGE= 2, // No falling damage in this sector SECF_FLOORDROP = 4, // all actors standing on this floor will remain on it when it lowers very fast. SECF_NORESPAWN = 8, // players can not respawn in this sector + SECF_FRICTION = 16, // sector has friction enabled + SECF_PUSH = 32, // pushers enabled + SECF_SILENTMOVE = 64, // Sector movement makes mo sound (Eternity got this so this may be useful for an extended cross-port standard.) + SECF_DMGTERRAINFX = 128, // spawns terrain splash when inflicting damage + SECF_ENDGODMODE = 256, // getting damaged by this sector ends god mode + SECF_ENDLEVEL = 512, // ends level when health goes below 10 + SECF_HAZARD = 1024, // Change to Strife's delayed damage handling. + + SECF_WASSECRET = 1 << 30, // a secret that was discovered + SECF_SECRET = 1 << 31, // a secret sector + + SECF_DAMAGEFLAGS = SECF_ENDGODMODE|SECF_ENDLEVEL|SECF_DMGTERRAINFX|SECF_HAZARD, + SECF_NOMODIFY = SECF_SECRET|SECF_WASSECRET, // not modifiable by Sector_ChangeFlags + SECF_SPECIALFLAGS = SECF_DAMAGEFLAGS|SECF_FRICTION|SECF_PUSH, // these flags originate from 'special and must be transferrable by floor thinkers }; enum @@ -422,6 +446,28 @@ struct FTransform fixed_t base_angle, base_yoffs; }; +struct secspecial_t +{ + FNameNoInit damagetype; // [RH] Means-of-death for applied damage + int damageamount; // [RH] Damage to do while standing on floor + short special; + short damageinterval; // Interval for damage application + short leakydamage; // chance of leaking through radiation suit + int Flags; + + secspecial_t() + { + Clear(); + } + + void Clear() + { + memset(this, 0, sizeof(*this)); + } +}; + +FArchive &operator<< (FArchive &arc, secspecial_t &p); + struct sector_t { // Member functions @@ -637,7 +683,48 @@ struct sector_t return pos == floor? floorplane:ceilingplane; } + fixed_t HighestCeiling(AActor *a) const + { + return ceilingplane.ZatPoint(a); + } + fixed_t LowestFloor(AActor *a) const + { + return floorplane.ZatPoint(a); + } + + + bool isSecret() const + { + return !!(Flags & SECF_SECRET); + } + + bool wasSecret() const + { + return !!(Flags & SECF_WASSECRET); + } + + void ClearSecret() + { + Flags &= ~SECF_SECRET; + } + + void ClearSpecial() + { + // clears all variables that originate from 'special'. Used for sector type transferring thinkers + special = 0; + damageamount = 0; + damageinterval = 0; + damagetype = NAME_None; + leakydamage = 0; + Flags &= ~SECF_SPECIALFLAGS; + } + + int GetTerrain(int pos) const; + + void TransferSpecial(sector_t *model); + void GetSpecial(secspecial_t *spec); + void SetSpecial(const secspecial_t *spec); bool PlaneMoving(int pos); @@ -670,6 +757,8 @@ struct sector_t // when processed as mobj properties. Fix is to make them sector properties. fixed_t friction, movefactor; + int terrainnum[2]; + // thinker_t for reversable actions TObjPtr floordata; // jff 2/22/98 make thinkers on TObjPtr ceilingdata; // floors, ceilings, lighting, @@ -704,9 +793,11 @@ struct sector_t // thinglist is a subset of touching_thinglist struct msecnode_t *touching_thinglist; // phares 3/14/98 - float gravity; // [RH] Sector gravity (1.0 is normal) - short damage; // [RH] Damage to do while standing on floor - short mod; // [RH] Means-of-death for applied damage + float gravity; // [RH] Sector gravity (1.0 is normal) + FNameNoInit damagetype; // [RH] Means-of-death for applied damage + int damageamount; // [RH] Damage to do while standing on floor + short damageinterval; // Interval for damage application + short leakydamage; // chance of leaking through radiation suit WORD ZoneNumber; // [RH] Zone this sector belongs to WORD MoreFlags; // [RH] Internal sector flags @@ -720,9 +811,8 @@ struct sector_t // [RH] The sky box to render for this sector. NULL means use a // regular sky. - TObjPtr FloorSkyBox, CeilingSkyBox; + TObjPtr SkyBoxes[2]; - short secretsector; //jff 2/16/98 remembers if sector WAS secret (automap) int sectornum; // for comparing sector copies extsector_t * e; // This stores data that requires construction/destruction. Such data must not be copied by R_FakeFlat. @@ -898,6 +988,11 @@ struct line_t sector_t *frontsector, *backsector; int validcount; // if == validcount, already checked int locknumber; // [Dusk] lock number for special + + bool isLinePortal() const + { + return false; + } }; // phares 3/14/98 diff --git a/src/r_plane.cpp b/src/r_plane.cpp index 8cab34230..84967c164 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -1224,9 +1224,10 @@ void R_DrawSkyBoxes () extralight = 0; R_SetVisibility (sky->args[0] * 0.25f); - viewx = sky->PrevX + FixedMul(r_TicFrac, sky->x - sky->PrevX); - viewy = sky->PrevY + FixedMul(r_TicFrac, sky->y - sky->PrevY); - viewz = sky->PrevZ + FixedMul(r_TicFrac, sky->z - sky->PrevZ); + fixedvec3 viewpos = sky->InterpolatedPosition(r_TicFrac); + viewx = viewpos.x; + viewy = viewpos.y; + viewz = viewpos.z; viewangle = savedangle + sky->PrevAngle + FixedMul(r_TicFrac, sky->angle - sky->PrevAngle); R_CopyStackedViewParameters(); @@ -1235,8 +1236,8 @@ void R_DrawSkyBoxes () { extralight = pl->extralight; R_SetVisibility (pl->visibility); - viewx = pl->viewx - sky->Mate->x + sky->x; - viewy = pl->viewy - sky->Mate->y + sky->y; + viewx = pl->viewx - sky->Mate->X() + sky->X(); + viewy = pl->viewy - sky->Mate->Y() + sky->Y(); viewz = pl->viewz; viewangle = pl->viewangle; } @@ -1280,6 +1281,7 @@ void R_DrawSkyBoxes () ds_p->sprtopclip = R_NewOpening (pl->maxx - pl->minx + 1); ds_p->maskedtexturecol = ds_p->swall = -1; ds_p->bFogBoundary = false; + ds_p->fake = 0; memcpy (openings + ds_p->sprbottomclip, floorclip + pl->minx, (pl->maxx - pl->minx + 1)*sizeof(short)); memcpy (openings + ds_p->sprtopclip, ceilingclip + pl->minx, (pl->maxx - pl->minx + 1)*sizeof(short)); diff --git a/src/r_things.cpp b/src/r_things.cpp index 8e53fb6d1..8ad5f76a9 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -670,9 +670,10 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor } // [RH] Interpolate the sprite's position to make it look smooth - fx = thing->PrevX + FixedMul (r_TicFrac, thing->x - thing->PrevX); - fy = thing->PrevY + FixedMul (r_TicFrac, thing->y - thing->PrevY); - fz = thing->PrevZ + FixedMul (r_TicFrac, thing->z - thing->PrevZ) + thing->GetBobOffset(r_TicFrac); + fixedvec3 pos = thing->InterpolatedPosition(r_TicFrac); + fx = pos.x; + fy = pos.y; + fz = pos.z +thing->GetBobOffset(r_TicFrac); tex = NULL; voxel = NULL; @@ -1145,12 +1146,12 @@ void R_AddSprites (sector_t *sec, int lightlevel, int fakeside) { if(!(rover->top.plane->a) && !(rover->top.plane->b)) { - if(rover->top.plane->Zat0() <= thing->z) fakefloor = rover; + if(rover->top.plane->Zat0() <= thing->Z()) fakefloor = rover; } } if(!(rover->bottom.plane->a) && !(rover->bottom.plane->b)) { - if(rover->bottom.plane->Zat0() >= thing->z + thing->height) fakeceiling = rover; + if(rover->bottom.plane->Zat0() >= thing->Top()) fakeceiling = rover; } } R_ProjectSprite (thing, fakeside, fakefloor, fakeceiling); diff --git a/src/r_utility.cpp b/src/r_utility.cpp index cfe1767c7..d4d3ec97b 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -587,8 +587,8 @@ void R_InterpolateView (player_t *player, fixed_t frac, InterpolationViewer *ivi player - players == consoleplayer && camera == player->mo && !demoplayback && - iview->nviewx == camera->x && - iview->nviewy == camera->y && + iview->nviewx == camera->X() && + iview->nviewy == camera->Y() && !(player->cheats & (CF_TOTALLYFROZEN|CF_FROZEN)) && player->playerstate == PST_LIVE && player->mo->reactiontime == 0 && @@ -839,9 +839,9 @@ void R_SetupFrame (AActor *actor) } else { - iview->nviewx = camera->x; - iview->nviewy = camera->y; - iview->nviewz = camera->player ? camera->player->viewz : camera->z + camera->GetClass()->Meta.GetMetaFixed(AMETA_CameraHeight); + iview->nviewx = camera->X(); + iview->nviewy = camera->Y(); + iview->nviewz = camera->player ? camera->player->viewz : camera->Z() + camera->GetClass()->Meta.GetMetaFixed(AMETA_CameraHeight); viewsector = camera->Sector; r_showviewer = false; } diff --git a/src/resourcefiles/file_7z.cpp b/src/resourcefiles/file_7z.cpp index 1fb553932..65676fcf4 100644 --- a/src/resourcefiles/file_7z.cpp +++ b/src/resourcefiles/file_7z.cpp @@ -252,25 +252,26 @@ bool F7ZFile::Open(bool quiet) } return false; } - NumLumps = Archive->DB.db.NumFiles; + CSzArEx* const archPtr = &Archive->DB; + + NumLumps = archPtr->NumFiles; Lumps = new F7ZLump[NumLumps]; F7ZLump *lump_p = Lumps; TArray nameUTF16; TArray nameASCII; + for (DWORD i = 0; i < NumLumps; ++i) { - CSzFileItem *file = &Archive->DB.db.Files[i]; - // skip Directories - if (file->IsDir) + if (SzArEx_IsDir(archPtr, i)) { skipped++; continue; } - const size_t nameLength = SzArEx_GetFileNameUtf16(&Archive->DB, i, NULL); + const size_t nameLength = SzArEx_GetFileNameUtf16(archPtr, i, NULL); if (0 == nameLength) { @@ -280,7 +281,7 @@ bool F7ZFile::Open(bool quiet) nameUTF16.Resize((unsigned)nameLength); nameASCII.Resize((unsigned)nameLength); - SzArEx_GetFileNameUtf16(&Archive->DB, i, &nameUTF16[0]); + SzArEx_GetFileNameUtf16(archPtr, i, &nameUTF16[0]); for (size_t c = 0; c < nameLength; ++c) { nameASCII[c] = static_cast(nameUTF16[c]); @@ -291,7 +292,7 @@ bool F7ZFile::Open(bool quiet) name.ToLower(); lump_p->LumpNameSetup(name); - lump_p->LumpSize = int(file->Size); + lump_p->LumpSize = static_cast(SzArEx_GetFileSize(archPtr, i)); lump_p->Owner = this; lump_p->Flags = LUMPF_ZIPFILE; lump_p->Position = i; diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp index c72005813..8170c1a30 100644 --- a/src/s_advsound.cpp +++ b/src/s_advsound.cpp @@ -1364,15 +1364,36 @@ static void S_AddSNDINFO (int lump) case SI_MidiDevice: { sc.MustGetString(); FName nm = sc.String; + FScanner::SavedPos save = sc.SavePos(); + + sc.SetCMode(true); sc.MustGetString(); - if (sc.Compare("timidity")) MidiDevices[nm] = MDEV_TIMIDITY; - else if (sc.Compare("fmod") || sc.Compare("sndsys")) MidiDevices[nm] = MDEV_SNDSYS; - else if (sc.Compare("standard")) MidiDevices[nm] = MDEV_MMAPI; - else if (sc.Compare("opl")) MidiDevices[nm] = MDEV_OPL; - else if (sc.Compare("default")) MidiDevices[nm] = MDEV_DEFAULT; - else if (sc.Compare("fluidsynth")) MidiDevices[nm] = MDEV_FLUIDSYNTH; - else if (sc.Compare("gus")) MidiDevices[nm] = MDEV_GUS; + MidiDeviceSetting devset; + if (sc.Compare("timidity")) devset.device = MDEV_TIMIDITY; + else if (sc.Compare("fmod") || sc.Compare("sndsys")) devset.device = MDEV_SNDSYS; + else if (sc.Compare("standard")) devset.device = MDEV_MMAPI; + else if (sc.Compare("opl")) devset.device = MDEV_OPL; + else if (sc.Compare("default")) devset.device = MDEV_DEFAULT; + else if (sc.Compare("fluidsynth")) devset.device = MDEV_FLUIDSYNTH; + else if (sc.Compare("gus")) devset.device = MDEV_GUS; + else if (sc.Compare("wildmidi")) devset.device = MDEV_WILDMIDI; else sc.ScriptError("Unknown MIDI device %s\n", sc.String); + + if (sc.CheckString(",")) + { + sc.SetCMode(false); + sc.MustGetString(); + devset.args = sc.String; + } + else + { + // This does not really do what one might expect, because the next token has already been parsed and can be a '$'. + // So in order to continue parsing without C-Mode, we need to reset and parse the last token again. + sc.SetCMode(false); + sc.RestorePos(save); + sc.MustGetString(); + } + MidiDevices[nm] = devset; } break; diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 7b38e816c..2a9703ae4 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -175,9 +175,10 @@ void S_NoiseDebug (void) return; } - listener.X = FIXED2FLOAT(players[consoleplayer].camera->x); - listener.Y = FIXED2FLOAT(players[consoleplayer].camera->z); - listener.Z = FIXED2FLOAT(players[consoleplayer].camera->y); + + listener.X = FIXED2FLOAT(players[consoleplayer].camera->SoundX()); + listener.Y = FIXED2FLOAT(players[consoleplayer].camera->SoundZ()); + listener.Z = FIXED2FLOAT(players[consoleplayer].camera->SoundY()); // Display the oldest channel first. for (chan = Channels; chan->NextChan != NULL; chan = chan->NextChan) @@ -666,9 +667,9 @@ static void CalcPosVel(int type, const AActor *actor, const sector_t *sector, if (players[consoleplayer].camera != NULL) { - x = players[consoleplayer].camera->x; - y = players[consoleplayer].camera->z; - z = players[consoleplayer].camera->y; + x = players[consoleplayer].camera->SoundX(); + y = players[consoleplayer].camera->SoundZ(); + z = players[consoleplayer].camera->SoundY(); } else { @@ -685,9 +686,9 @@ static void CalcPosVel(int type, const AActor *actor, const sector_t *sector, // assert(actor != NULL); if (actor != NULL) { - x = actor->x; - y = actor->z; - z = actor->y; + x = actor->SoundX(); + y = actor->SoundZ(); + z = actor->SoundY(); } break; @@ -723,7 +724,7 @@ static void CalcPosVel(int type, const AActor *actor, const sector_t *sector, { if ((chanflags & CHAN_LISTENERZ) && players[consoleplayer].camera != NULL) { - y = players[consoleplayer].camera != NULL ? players[consoleplayer].camera->z : 0; + y = players[consoleplayer].camera != NULL ? players[consoleplayer].camera->SoundZ() : 0; } pos->X = FIXED2FLOAT(x); pos->Y = FIXED2FLOAT(y); @@ -763,8 +764,8 @@ static void CalcSectorSoundOrg(const sector_t *sec, int channum, fixed_t *x, fix // Are we inside the sector? If yes, the closest point is the one we're on. if (P_PointInSector(*x, *y) == sec) { - *x = players[consoleplayer].camera->x; - *y = players[consoleplayer].camera->y; + *x = players[consoleplayer].camera->SoundX(); + *y = players[consoleplayer].camera->SoundY(); } else { @@ -1567,9 +1568,9 @@ void S_RelinkSound (AActor *from, AActor *to) { chan->Actor = NULL; chan->SourceType = SOURCE_Unattached; - chan->Point[0] = FIXED2FLOAT(from->x); - chan->Point[1] = FIXED2FLOAT(from->z); - chan->Point[2] = FIXED2FLOAT(from->y); + chan->Point[0] = FIXED2FLOAT(from->SoundX()); + chan->Point[1] = FIXED2FLOAT(from->SoundZ()); + chan->Point[2] = FIXED2FLOAT(from->SoundY()); } else { @@ -1959,9 +1960,9 @@ static void S_SetListener(SoundListener &listener, AActor *listenactor) listener.velocity.Z = listenactor->vely * (TICRATE/65536.f); */ listener.velocity.Zero(); - listener.position.X = FIXED2FLOAT(listenactor->x); - listener.position.Y = FIXED2FLOAT(listenactor->z); - listener.position.Z = FIXED2FLOAT(listenactor->y); + listener.position.X = FIXED2FLOAT(listenactor->SoundX()); + listener.position.Y = FIXED2FLOAT(listenactor->SoundZ()); + listener.position.Z = FIXED2FLOAT(listenactor->SoundY()); listener.underwater = listenactor->waterlevel == 3; assert(zones != NULL); listener.Environment = zones[listenactor->Sector->ZoneNumber].Environment; @@ -2421,11 +2422,8 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) { int lumpnum = -1; int length = 0; - int device = MDEV_DEFAULT; MusInfo *handle = NULL; - - int *devp = MidiDevices.CheckKey(musicname); - if (devp != NULL) device = *devp; + MidiDeviceSetting *devp = MidiDevices.CheckKey(musicname); // Strip off any leading file:// component. if (strncmp(musicname, "file://", 7) == 0) @@ -2495,7 +2493,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) } else { - mus_playing.handle = I_RegisterSong (reader, device); + mus_playing.handle = I_RegisterSong (reader, devp); } } @@ -2643,10 +2641,7 @@ CCMD (loopsound) } else { - AActor *icon = Spawn("SpeakerIcon", players[consoleplayer].mo->x, - players[consoleplayer].mo->y, - players[consoleplayer].mo->z + 32*FRACUNIT, - ALLOW_REPLACE); + AActor *icon = Spawn("SpeakerIcon", players[consoleplayer].mo->PosPlusZ(32*FRACUNIT), ALLOW_REPLACE); if (icon != NULL) { S_Sound(icon, CHAN_BODY | CHAN_LOOP, id, 1.f, ATTN_IDLE); diff --git a/src/s_sound.h b/src/s_sound.h index 49fb81fb3..a72f3be0c 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -394,10 +394,22 @@ enum EMidiDevice MDEV_TIMIDITY = 3, MDEV_FLUIDSYNTH = 4, MDEV_GUS = 5, + MDEV_WILDMIDI = 6, +}; + +struct MidiDeviceSetting +{ + int device; + FString args; + + MidiDeviceSetting() + { + device = MDEV_DEFAULT; + } }; typedef TMap MusicAliasMap; -typedef TMap MidiDeviceMap; +typedef TMap MidiDeviceMap; extern MusicAliasMap MusicAliases; extern MidiDeviceMap MidiDevices; diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 33ca0495d..e7a617f5a 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -44,7 +44,7 @@ extern HWND Window; #define FALSE 0 #define TRUE 1 #endif -#ifdef __APPLE__ +#if defined(__FreeBSD__) || defined(__APPLE__) #include #elif __sun #include @@ -462,14 +462,12 @@ public: Stream->release(); Channel = NULL; Stream = NULL; - Owner->Sys->setStreamBufferSize(64*1024, FMOD_TIMEUNIT_RAWBYTES); // Open the stream asynchronously, so we don't hang the game while trying to reconnect. // (It would be nice to do the initial open asynchronously as well, but I'd need to rethink // the music system design to pull that off.) result = Owner->Sys->createSound(URL, (Loop ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF) | FMOD_SOFTWARE | FMOD_2D | FMOD_CREATESTREAM | FMOD_NONBLOCKING, NULL, &Stream); JustStarted = true; - Owner->Sys->setStreamBufferSize(16*1024, FMOD_TIMEUNIT_RAWBYTES); return result != FMOD_OK; } if (JustStarted && openstate == FMOD_OPENSTATE_PLAYING) @@ -1170,6 +1168,9 @@ bool FMODSoundRenderer::Init() } Sys->set3DSettings(0.5f, 96.f, 1.f); Sys->set3DRolloffCallback(RolloffCallback); + // The default is 16k, which periodically starves later FMOD versions + // when streaming FLAC files. + Sys->setStreamBufferSize(64*1024, FMOD_TIMEUNIT_RAWBYTES); snd_sfxvolume.Callback (); return true; } @@ -1733,10 +1734,6 @@ SoundStream *FMODSoundRenderer::OpenStream(const char *url, int flags) exinfo.dlsname = patches; } - // Use a larger buffer for URLs so that it's less likely to be effected - // by hiccups in the data rate from the remote server. - Sys->setStreamBufferSize(64*1024, FMOD_TIMEUNIT_RAWBYTES); - result = Sys->createSound(url, mode, &exinfo, &stream); if(result == FMOD_ERR_FORMAT && exinfo.dlsname != NULL) { @@ -1748,9 +1745,6 @@ SoundStream *FMODSoundRenderer::OpenStream(const char *url, int flags) } } - // Restore standard buffer size. - Sys->setStreamBufferSize(16*1024, FMOD_TIMEUNIT_RAWBYTES); - if(result != FMOD_OK) return NULL; diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index 3f8fac0da..5723a18dc 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -162,7 +162,7 @@ void I_InitMusic (void) if (!setatterm) { setatterm = true; - atterm (I_ShutdownMusic); + atterm (I_ShutdownMusicExit); #ifndef _WIN32 signal (SIGCHLD, ChildSigHandler); @@ -178,7 +178,7 @@ void I_InitMusic (void) // //========================================================================== -void I_ShutdownMusic(void) +void I_ShutdownMusic(bool onexit) { if (MusicDown) return; @@ -189,11 +189,17 @@ void I_ShutdownMusic(void) assert (currSong == NULL); } Timidity::FreeAll(); + if (onexit) WildMidi_Shutdown(); #ifdef _WIN32 I_ShutdownMusicWin32(); #endif // _WIN32 } +void I_ShutdownMusicExit() +{ + I_ShutdownMusic(true); +} + //========================================================================== // @@ -280,6 +286,10 @@ void MusInfo::FluidSettingStr(const char *, const char *) { } +void MusInfo::WildMidiSetOption(int opt, int set) +{ +} + FString MusInfo::GetStats() { return "No stats available for this song"; @@ -301,21 +311,21 @@ MusInfo *MusInfo::GetWaveDumper(const char *filename, int rate) // //========================================================================== -static MIDIStreamer *CreateMIDIStreamer(FileReader &reader, EMidiDevice devtype, EMIDIType miditype) +static MIDIStreamer *CreateMIDIStreamer(FileReader &reader, EMidiDevice devtype, EMIDIType miditype, const char *args) { switch (miditype) { case MIDI_MUS: - return new MUSSong2(reader, devtype); + return new MUSSong2(reader, devtype, args); case MIDI_MIDI: - return new MIDISong2(reader, devtype); + return new MIDISong2(reader, devtype, args); case MIDI_HMI: - return new HMISong(reader, devtype); + return new HMISong(reader, devtype, args); case MIDI_XMI: - return new XMISong(reader, devtype); + return new XMISong(reader, devtype, args); default: return NULL; @@ -377,7 +387,7 @@ static EMIDIType IdentifyMIDIType(DWORD *id, int size) // //========================================================================== -MusInfo *I_RegisterSong (FileReader *reader, int device) +MusInfo *I_RegisterSong (FileReader *reader, MidiDeviceSetting *device) { MusInfo *info = NULL; const char *fmt; @@ -395,12 +405,6 @@ MusInfo *I_RegisterSong (FileReader *reader, int device) return 0; } -#ifndef _WIN32 - // non-Windows platforms don't support MDEV_MMAPI so map to MDEV_SNDSYS - if (device == MDEV_MMAPI) - device = MDEV_SNDSYS; -#endif - // Check for gzip compression. Some formats are expected to have players // that can handle it, so it simplifies things if we make all songs // gzippable. @@ -437,10 +441,15 @@ MusInfo *I_RegisterSong (FileReader *reader, int device) EMIDIType miditype = IdentifyMIDIType(id, sizeof(id)); if (miditype != MIDI_NOTMIDI) { - EMidiDevice devtype = (EMidiDevice)device; + EMidiDevice devtype = device == NULL? MDEV_DEFAULT : (EMidiDevice)device->device; +#ifndef _WIN32 + // non-Windows platforms don't support MDEV_MMAPI so map to MDEV_SNDSYS + if (devtype == MDEV_MMAPI) + devtype = MDEV_SNDSYS; +#endif retry_as_sndsys: - info = CreateMIDIStreamer(*reader, devtype, miditype); + info = CreateMIDIStreamer(*reader, devtype, miditype, device != NULL? device->args.GetChars() : ""); if (info != NULL && !info->IsValid()) { delete info; @@ -454,7 +463,7 @@ retry_as_sndsys: #ifdef _WIN32 if (info == NULL && devtype != MDEV_MMAPI && snd_mididevice >= 0) { - info = CreateMIDIStreamer(*reader, MDEV_MMAPI, miditype); + info = CreateMIDIStreamer(*reader, MDEV_MMAPI, miditype, ""); } #endif } @@ -465,7 +474,7 @@ retry_as_sndsys: (id[0] == MAKE_ID('D','B','R','A') && id[1] == MAKE_ID('W','O','P','L')) || // DosBox Raw OPL (id[0] == MAKE_ID('A','D','L','I') && *((BYTE *)id + 4) == 'B')) // Martin Fernandez's modified IMF { - info = new OPLMUSSong (*reader); + info = new OPLMUSSong (*reader, device != NULL? device->args.GetChars() : ""); } // Check for game music else if ((fmt = GME_CheckFormat(id[0])) != NULL && fmt[0] != '\0') diff --git a/src/sound/i_music.h b/src/sound/i_music.h index f6a6dbadd..514400e5d 100644 --- a/src/sound/i_music.h +++ b/src/sound/i_music.h @@ -43,7 +43,8 @@ struct FOptionValues; // MUSIC I/O // void I_InitMusic (); -void I_ShutdownMusic (); +void I_ShutdownMusic (bool onexit = false); +void I_ShutdownMusicExit (); void I_BuildMIDIMenuList (FOptionValues *); void I_UpdateMusic (); @@ -52,7 +53,8 @@ void I_SetMusicVolume (float volume); // Registers a song handle to song data. class MusInfo; -MusInfo *I_RegisterSong (FileReader *reader, int device); +struct MidiDeviceSetting; +MusInfo *I_RegisterSong (FileReader *reader, MidiDeviceSetting *device); MusInfo *I_RegisterCDSong (int track, int cdid = 0); MusInfo *I_RegisterURLSong (const char *url); @@ -81,6 +83,7 @@ public: virtual void FluidSettingInt(const char *setting, int value); // FluidSynth settings virtual void FluidSettingNum(const char *setting, double value); // " virtual void FluidSettingStr(const char *setting, const char *value); // " + virtual void WildMidiSetOption(int opt, int set); void Start(bool loop, float rel_vol = -1.f, int subsong = 0); diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index 77aa31312..52364ab58 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -24,6 +24,7 @@ #include "i_music.h" #include "s_sound.h" #include "files.h" +#include "wildmidi/wildmidi_lib.h" void I_InitMusicWin32 (); void I_ShutdownMusicWin32 (); @@ -101,6 +102,7 @@ public: virtual void FluidSettingInt(const char *setting, int value); virtual void FluidSettingNum(const char *setting, double value); virtual void FluidSettingStr(const char *setting, const char *value); + virtual void WildMidiSetOption(int opt, int set); virtual bool Preprocess(MIDIStreamer *song, bool looping); virtual FString GetStats(); }; @@ -183,7 +185,7 @@ public: class TimidityPPMIDIDevice : public PseudoMIDIDevice { public: - TimidityPPMIDIDevice(); + TimidityPPMIDIDevice(const char *args); ~TimidityPPMIDIDevice(); int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); @@ -218,7 +220,6 @@ protected: #endif }; - // Base class for software synthesizer MIDI output devices ------------------ class SoftSynthMIDIDevice : public MIDIDevice @@ -269,7 +270,7 @@ protected: class OPLMIDIDevice : public SoftSynthMIDIDevice, protected OPLmusicBlock { public: - OPLMIDIDevice(); + OPLMIDIDevice(const char *args); int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); void Close(); int GetTechnology() const; @@ -302,7 +303,7 @@ namespace Timidity { struct Renderer; } class TimidityMIDIDevice : public SoftSynthMIDIDevice { public: - TimidityMIDIDevice(); + TimidityMIDIDevice(const char *args); ~TimidityMIDIDevice(); int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); @@ -331,6 +332,27 @@ protected: FILE *File; }; +// WildMidi implementation of a MIDI device --------------------------------- + +class WildMIDIDevice : public SoftSynthMIDIDevice +{ +public: + WildMIDIDevice(const char *args); + ~WildMIDIDevice(); + + int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); + void PrecacheInstruments(const WORD *instruments, int count); + FString GetStats(); + +protected: + WildMidi_Renderer *Renderer; + + void HandleEvent(int status, int parm1, int parm2); + void HandleLongEvent(const BYTE *data, int len); + void ComputeOutput(float *buffer, int len); + void WildMidiSetOption(int opt, int set); +}; + // FluidSynth implementation of a MIDI device ------------------------------- #ifdef HAVE_FLUIDSYNTH @@ -344,7 +366,7 @@ struct fluid_synth_t; class FluidSynthMIDIDevice : public SoftSynthMIDIDevice { public: - FluidSynthMIDIDevice(); + FluidSynthMIDIDevice(const char *args); ~FluidSynthMIDIDevice(); int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); @@ -409,7 +431,7 @@ protected: class MIDIStreamer : public MusInfo { public: - MIDIStreamer(EMidiDevice type); + MIDIStreamer(EMidiDevice type, const char *args); ~MIDIStreamer(); void MusicVolumeChanged(); @@ -427,6 +449,7 @@ public: void FluidSettingInt(const char *setting, int value); void FluidSettingNum(const char *setting, double value); void FluidSettingStr(const char *setting, const char *value); + void WildMidiSetOption(int opt, int set); void CreateSMF(TArray &file, int looplimit=0); protected: @@ -494,6 +517,7 @@ protected: bool CallbackIsThreaded; int LoopLimit; FString DumpFilename; + FString Args; }; // MUS file played with a MIDI stream --------------------------------------- @@ -501,7 +525,7 @@ protected: class MUSSong2 : public MIDIStreamer { public: - MUSSong2(FileReader &reader, EMidiDevice type); + MUSSong2(FileReader &reader, EMidiDevice type, const char *args); ~MUSSong2(); MusInfo *GetOPLDumper(const char *filename); @@ -527,7 +551,7 @@ protected: class MIDISong2 : public MIDIStreamer { public: - MIDISong2(FileReader &reader, EMidiDevice type); + MIDISong2(FileReader &reader, EMidiDevice type, const char *args); ~MIDISong2(); MusInfo *GetOPLDumper(const char *filename); @@ -546,7 +570,7 @@ protected: struct TrackInfo; void ProcessInitialMetaEvents (); - DWORD *SendCommand (DWORD *event, TrackInfo *track, DWORD delay); + DWORD *SendCommand (DWORD *event, TrackInfo *track, DWORD delay, ptrdiff_t room, bool &sysex_noroom); TrackInfo *FindNextDue (); BYTE *MusHeader; @@ -584,7 +608,7 @@ protected: class HMISong : public MIDIStreamer { public: - HMISong(FileReader &reader, EMidiDevice type); + HMISong(FileReader &reader, EMidiDevice type, const char *args); ~HMISong(); MusInfo *GetOPLDumper(const char *filename); @@ -627,7 +651,7 @@ protected: class XMISong : public MIDIStreamer { public: - XMISong(FileReader &reader, EMidiDevice type); + XMISong(FileReader &reader, EMidiDevice type, const char *args); ~XMISong(); MusInfo *GetOPLDumper(const char *filename); @@ -690,7 +714,7 @@ protected: class OPLMUSSong : public StreamSong { public: - OPLMUSSong (FileReader &reader); + OPLMUSSong (FileReader &reader, const char *args); ~OPLMUSSong (); void Play (bool looping, int subsong); bool IsPlaying (); diff --git a/src/sound/music_fluidsynth_mididevice.cpp b/src/sound/music_fluidsynth_mididevice.cpp index af8fe6667..3be4de56b 100644 --- a/src/sound/music_fluidsynth_mididevice.cpp +++ b/src/sound/music_fluidsynth_mididevice.cpp @@ -255,7 +255,7 @@ CUSTOM_CVAR(Int, fluid_chorus_type, FLUID_CHORUS_DEFAULT_TYPE, CVAR_ARCHIVE|CVAR // //========================================================================== -FluidSynthMIDIDevice::FluidSynthMIDIDevice() +FluidSynthMIDIDevice::FluidSynthMIDIDevice(const char *args) { FluidSynth = NULL; FluidSettings = NULL; @@ -293,7 +293,15 @@ FluidSynthMIDIDevice::FluidSynthMIDIDevice() fluid_reverb_width, fluid_reverb_level); fluid_synth_set_chorus(FluidSynth, fluid_chorus_voices, fluid_chorus_level, fluid_chorus_speed, fluid_chorus_depth, fluid_chorus_type); - if (0 == LoadPatchSets(fluid_patchset)) + + // try loading a patch set that got specified with $mididevice. + int res = 0; + if (args != NULL && *args != 0) + { + res = LoadPatchSets(args); + } + + if (res == 0 && 0 == LoadPatchSets(fluid_patchset)) { #ifdef __unix__ // This is the standard location on Ubuntu. diff --git a/src/sound/music_hmi_midiout.cpp b/src/sound/music_hmi_midiout.cpp index 5fef706dd..ca3ae0905 100644 --- a/src/sound/music_hmi_midiout.cpp +++ b/src/sound/music_hmi_midiout.cpp @@ -128,8 +128,8 @@ extern char MIDI_CommonLengths[15]; // //========================================================================== -HMISong::HMISong (FileReader &reader, EMidiDevice type) -: MIDIStreamer(type), MusHeader(0), Tracks(0) +HMISong::HMISong (FileReader &reader, EMidiDevice type, const char *args) +: MIDIStreamer(type, args), MusHeader(0), Tracks(0) { #ifdef _WIN32 if (ExitEvent == NULL) diff --git a/src/sound/music_midi_base.cpp b/src/sound/music_midi_base.cpp index 649f9002e..260f635b2 100644 --- a/src/sound/music_midi_base.cpp +++ b/src/sound/music_midi_base.cpp @@ -11,9 +11,9 @@ static DWORD nummididevices; static bool nummididevicesset; #ifdef HAVE_FLUIDSYNTH -#define NUM_DEF_DEVICES 5 +#define NUM_DEF_DEVICES 6 #else -#define NUM_DEF_DEVICES 4 +#define NUM_DEF_DEVICES 5 #endif static void AddDefaultMidiDevices(FOptionValues *opt) @@ -33,8 +33,10 @@ static void AddDefaultMidiDevices(FOptionValues *opt) pair[p+1].Value = -3.0; pair[p+2].Text = "TiMidity++"; pair[p+2].Value = -2.0; - pair[p+3].Text = "Sound System"; - pair[p+3].Value = -1.0; + pair[p+3].Text = "WildMidi"; + pair[p+3].Value = -6.0; + pair[p+4].Text = "Sound System"; + pair[p+4].Value = -1.0; } @@ -70,7 +72,7 @@ CUSTOM_CVAR (Int, snd_mididevice, -1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) if (!nummididevicesset) return; - if ((self >= (signed)nummididevices) || (self < -5)) + if ((self >= (signed)nummididevices) || (self < -6)) { Printf ("ID out of range. Using default device.\n"); self = 0; @@ -166,6 +168,7 @@ CCMD (snd_listmididevices) MIDIOUTCAPS caps; MMRESULT res; + PrintMidiDevice (-6, "WildMidi", MOD_SWSYNTH, 0); #ifdef HAVE_FLUIDSYNTH PrintMidiDevice (-5, "FluidSynth", MOD_SWSYNTH, 0); #endif @@ -196,8 +199,8 @@ CCMD (snd_listmididevices) CUSTOM_CVAR(Int, snd_mididevice, -1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { - if (self < -5) - self = -5; + if (self < -6) + self = -6; else if (self > -1) self = -1; else @@ -211,6 +214,7 @@ void I_BuildMIDIMenuList (FOptionValues *opt) CCMD (snd_listmididevices) { + Printf("%s-6. WildMidi\n", -6 == snd_mididevice ? TEXTCOLOR_BOLD : ""); #ifdef HAVE_FLUIDSYNTH Printf("%s-5. FluidSynth\n", -5 == snd_mididevice ? TEXTCOLOR_BOLD : ""); #endif diff --git a/src/sound/music_midi_timidity.cpp b/src/sound/music_midi_timidity.cpp index dbc56cc56..667de8842 100644 --- a/src/sound/music_midi_timidity.cpp +++ b/src/sound/music_midi_timidity.cpp @@ -58,7 +58,7 @@ CUSTOM_CVAR (Int, timidity_pipe, 90, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) } } -CUSTOM_CVAR (Int, timidity_frequency, 22050, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CUSTOM_CVAR (Int, timidity_frequency, 44100, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { // Clamp frequency to Timidity's limits if (self < 4000) self = 4000; @@ -72,7 +72,7 @@ CUSTOM_CVAR (Int, timidity_frequency, 22050, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // //========================================================================== -TimidityPPMIDIDevice::TimidityPPMIDIDevice() +TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args) : DiskName("zmid"), #ifdef _WIN32 ReadWavePipe(INVALID_HANDLE_VALUE), WriteWavePipe(INVALID_HANDLE_VALUE), @@ -85,7 +85,13 @@ TimidityPPMIDIDevice::TimidityPPMIDIDevice() #ifndef _WIN32 WavePipe[0] = WavePipe[1] = -1; #endif - + + if (args == NULL || *args == 0) args = timidity_exe; + + CommandLine.Format("%s %s -EFchorus=%s -EFreverb=%s -s%d ", + args, *timidity_extargs, + *timidity_chorus, *timidity_reverb, *timidity_frequency); + if (DiskName == NULL) { Printf(PRINT_BOLD, "Could not create temp music file\n"); @@ -187,10 +193,6 @@ int TimidityPPMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWO Validated = true; #endif // WIN32 - CommandLine.Format("%s %s -EFchorus=%s -EFreverb=%s -s%d ", - *timidity_exe, *timidity_extargs, - *timidity_chorus, *timidity_reverb, *timidity_frequency); - pipeSize = (timidity_pipe * timidity_frequency / 1000) << (timidity_stereo + !timidity_8bit); diff --git a/src/sound/music_midistream.cpp b/src/sound/music_midistream.cpp index 6c85c06af..579fd7851 100644 --- a/src/sound/music_midistream.cpp +++ b/src/sound/music_midistream.cpp @@ -89,12 +89,12 @@ static const BYTE StaticMIDIhead[] = // //========================================================================== -MIDIStreamer::MIDIStreamer(EMidiDevice type) +MIDIStreamer::MIDIStreamer(EMidiDevice type, const char *args) : #ifdef _WIN32 PlayerThread(0), ExitEvent(0), BufferDoneEvent(0), #endif - MIDI(0), Division(0), InitialTempo(500000), DeviceType(type) + MIDI(0), Division(0), InitialTempo(500000), DeviceType(type), Args(args) { #ifdef _WIN32 BufferDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL); @@ -240,6 +240,7 @@ EMidiDevice MIDIStreamer::SelectMIDIDevice(EMidiDevice device) #ifdef HAVE_FLUIDSYNTH case -5: return MDEV_FLUIDSYNTH; #endif + case -6: return MDEV_WILDMIDI; default: #ifdef _WIN32 return MDEV_MMAPI; @@ -268,19 +269,19 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype) const #ifdef HAVE_FLUIDSYNTH case MDEV_FLUIDSYNTH: - return new FluidSynthMIDIDevice; + return new FluidSynthMIDIDevice(Args); #endif case MDEV_SNDSYS: return new SndSysMIDIDevice; case MDEV_GUS: - return new TimidityMIDIDevice; + return new TimidityMIDIDevice(Args); case MDEV_OPL: try { - return new OPLMIDIDevice; + return new OPLMIDIDevice(Args); } catch (CRecoverableError &err) { @@ -290,7 +291,10 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype) const } case MDEV_TIMIDITY: - return new TimidityPPMIDIDevice; + return new TimidityPPMIDIDevice(Args); + + case MDEV_WILDMIDI: + return new WildMIDIDevice(Args); default: return NULL; @@ -622,6 +626,21 @@ void MIDIStreamer::FluidSettingStr(const char *setting, const char *value) } +//========================================================================== +// +// MIDIDeviceStreamer :: WildMidiSetOption +// +//========================================================================== + +void MIDIStreamer::WildMidiSetOption(int opt, int set) +{ + if (MIDI != NULL) + { + MIDI->WildMidiSetOption(opt, set); + } +} + + //========================================================================== // // MIDIStreamer :: OutputVolume @@ -1192,9 +1211,15 @@ void MIDIStreamer::CreateSMF(TArray &file, int looplimit) len--; file.Push(MIDI_SYSEX); WriteVarLen(file, len); - memcpy(&file[file.Reserve(len - 1)], bytes, len); - running_status = 255; + memcpy(&file[file.Reserve(len)], bytes + 1, len); } + else + { + file.Push(MIDI_SYSEXEND); + WriteVarLen(file, len); + memcpy(&file[file.Reserve(len)], bytes, len); + } + running_status = 255; } else if (MEVT_EVENTTYPE(event[2]) == 0) { @@ -1512,6 +1537,16 @@ void MIDIDevice::FluidSettingStr(const char *setting, const char *value) { } +//========================================================================== +// +// MIDIDevice :: WildMidiSetOption +// +//========================================================================== + +void MIDIDevice::WildMidiSetOption(int opt, int set) +{ +} + //========================================================================== // // MIDIDevice :: GetStats diff --git a/src/sound/music_mus_midiout.cpp b/src/sound/music_mus_midiout.cpp index 5f7d2d503..bc810b4a8 100644 --- a/src/sound/music_mus_midiout.cpp +++ b/src/sound/music_mus_midiout.cpp @@ -43,6 +43,7 @@ #include "doomdef.h" #include "m_swap.h" #include "files.h" +#include "s_sound.h" // MACROS ------------------------------------------------------------------ @@ -92,8 +93,8 @@ static const BYTE CtrlTranslate[15] = // //========================================================================== -MUSSong2::MUSSong2 (FileReader &reader, EMidiDevice type) -: MIDIStreamer(type), MusHeader(0), MusBuffer(0) +MUSSong2::MUSSong2 (FileReader &reader, EMidiDevice type, const char *args) +: MIDIStreamer(type, args), MusHeader(0), MusBuffer(0) { #ifdef _WIN32 if (ExitEvent == NULL) @@ -210,23 +211,44 @@ bool MUSSong2::CheckDone() void MUSSong2::Precache() { - WORD *work = (WORD *)alloca(MusHeader->NumInstruments * sizeof(WORD)); - const WORD *used = (WORD *)MusHeader + sizeof(MUSHeader) / sizeof(WORD); - int i, j; + TArray work(MusHeader->NumInstruments); + const BYTE *used = (BYTE *)MusHeader + sizeof(MUSHeader) / sizeof(BYTE); + int i, k; - for (i = j = 0; i < MusHeader->NumInstruments; ++i) + for (i = k = 0; i < MusHeader->NumInstruments; ++i) { - WORD instr = LittleShort(used[i]); + BYTE instr = used[k++]; + WORD val; if (instr < 128) { - work[j++] = instr; + val = instr; } - else if (used[i] >= 135 && used[i] <= 181) + else if (instr >= 135 && instr <= 188) { // Percussions are 100-based, not 128-based, eh? - work[j++] = instr - 100 + (1 << 14); + val = instr - 100 + (1 << 14); + } + else + { + // skip it. + val = used[k++]; + k += val; + continue; + } + + int numbanks = used[k++]; + if (numbanks > 0) + { + for (int b = 0; b < numbanks; b++) + { + work.Push(val | (used[k++] << 7)); + } + } + else + { + work.Push(val); } } - MIDI->PrecacheInstruments(&work[0], j); + MIDI->PrecacheInstruments(&work[0], work.Size()); } //========================================================================== diff --git a/src/sound/music_mus_opl.cpp b/src/sound/music_mus_opl.cpp index 3b5012ad9..562330ef9 100644 --- a/src/sound/music_mus_opl.cpp +++ b/src/sound/music_mus_opl.cpp @@ -20,16 +20,25 @@ CUSTOM_CVAR (Int, opl_numchips, 2, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) } } -CVAR(Int, opl_core, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR(Int, opl_core, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +int current_opl_core; -OPLMUSSong::OPLMUSSong (FileReader &reader) +// Get OPL core override from $mididevice +void OPL_SetCore(const char *args) +{ + current_opl_core = opl_core; + if (args != NULL && *args >= '0' && *args < '4') current_opl_core = *args - '0'; +} + +OPLMUSSong::OPLMUSSong (FileReader &reader, const char *args) { int samples = int(OPL_SAMPLE_RATE / 14); + OPL_SetCore(args); Music = new OPLmusicFile (&reader); m_Stream = GSnd->CreateStream (FillStream, samples*4, - (opl_core == 0 ? SoundStream::Mono : 0) | SoundStream::Float, int(OPL_SAMPLE_RATE), this); + (current_opl_core == 0 ? SoundStream::Mono : 0) | SoundStream::Float, int(OPL_SAMPLE_RATE), this); if (m_Stream == NULL) { Printf (PRINT_BOLD, "Could not create music stream.\n"); diff --git a/src/sound/music_smf_midiout.cpp b/src/sound/music_smf_midiout.cpp index d5d307ec7..43755eb08 100644 --- a/src/sound/music_smf_midiout.cpp +++ b/src/sound/music_smf_midiout.cpp @@ -102,8 +102,8 @@ char MIDI_CommonLengths[15] = { 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // //========================================================================== -MIDISong2::MIDISong2 (FileReader &reader, EMidiDevice type) -: MIDIStreamer(type), MusHeader(0), Tracks(0) +MIDISong2::MIDISong2 (FileReader &reader, EMidiDevice type, const char *args) +: MIDIStreamer(type, args), MusHeader(0), Tracks(0) { int p; int i; @@ -322,7 +322,12 @@ DWORD *MIDISong2::MakeEvents(DWORD *events, DWORD *max_event_p, DWORD max_time) // Play all events for this tick. do { - DWORD *new_events = SendCommand(events, TrackDue, time); + bool sysex_noroom = false; + DWORD *new_events = SendCommand(events, TrackDue, time, max_event_p - events, sysex_noroom); + if (sysex_noroom) + { + return events; + } TrackDue = FindNextDue(); if (new_events != events) { @@ -366,12 +371,15 @@ void MIDISong2::AdvanceTracks(DWORD time) // //========================================================================== -DWORD *MIDISong2::SendCommand (DWORD *events, TrackInfo *track, DWORD delay) +DWORD *MIDISong2::SendCommand (DWORD *events, TrackInfo *track, DWORD delay, ptrdiff_t room, bool &sysex_noroom) { DWORD len; BYTE event, data1 = 0, data2 = 0; int i; + sysex_noroom = false; + size_t start_p = track->TrackP; + CHECK_FINISHED event = track->TrackBegin[track->TrackP++]; CHECK_FINISHED @@ -588,13 +596,44 @@ DWORD *MIDISong2::SendCommand (DWORD *events, TrackInfo *track, DWORD delay) } else { - // Skip SysEx events just because I don't want to bother with them. - // The old MIDI player ignored them too, so this won't break - // anything that played before. + // SysEx events could potentially not have enough room in the buffer... if (event == MIDI_SYSEX || event == MIDI_SYSEXEND) { - len = track->ReadVarLen (); - track->TrackP += len; + len = track->ReadVarLen(); + if (len >= (MAX_EVENTS-1)*3*4) + { // This message will never fit. Throw it away. + track->TrackP += len; + } + else if (len + 12 >= (size_t)room * 4) + { // Not enough room left in this buffer. Backup and wait for the next one. + track->TrackP = start_p; + sysex_noroom = true; + return events; + } + else + { + events[0] = delay; + events[1] = 0; + BYTE *msg = (BYTE *)&events[3]; + if (event == MIDI_SYSEX) + { // Need to add the SysEx marker to the message. + events[2] = (MEVT_LONGMSG << 24) | (len + 1); + *msg++ = MIDI_SYSEX; + } + else + { + events[2] = (MEVT_LONGMSG << 24) | len; + } + memcpy(msg, &track->TrackBegin[track->TrackP], len); + msg += len; + // Must pad with 0 + while ((size_t)msg & 3) + { + *msg++ = 0; + } + events = (DWORD *)msg; + track->TrackP += len; + } } else if (event == MIDI_META) { diff --git a/src/sound/music_timidity_mididevice.cpp b/src/sound/music_timidity_mididevice.cpp index 9e5be625b..a63e1d723 100644 --- a/src/sound/music_timidity_mididevice.cpp +++ b/src/sound/music_timidity_mididevice.cpp @@ -86,10 +86,10 @@ struct FmtChunk // //========================================================================== -TimidityMIDIDevice::TimidityMIDIDevice() +TimidityMIDIDevice::TimidityMIDIDevice(const char *args) { Renderer = NULL; - Renderer = new Timidity::Renderer((float)SampleRate); + Renderer = new Timidity::Renderer((float)SampleRate, args); } //========================================================================== @@ -245,6 +245,7 @@ FString TimidityMIDIDevice::GetStats() //========================================================================== TimidityWaveWriterMIDIDevice::TimidityWaveWriterMIDIDevice(const char *filename, int rate) + :TimidityMIDIDevice(NULL) { File = fopen(filename, "wb"); if (File != NULL) diff --git a/src/sound/music_wildmidi_mididevice.cpp b/src/sound/music_wildmidi_mididevice.cpp new file mode 100644 index 000000000..03ededb46 --- /dev/null +++ b/src/sound/music_wildmidi_mididevice.cpp @@ -0,0 +1,234 @@ +/* +** music_wildmidi_mididevice.cpp +** Provides access to WildMidi as a generic MIDI device. +** +**--------------------------------------------------------------------------- +** Copyright 2015 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +// HEADER FILES ------------------------------------------------------------ + +#include "i_musicinterns.h" +#include "templates.h" +#include "doomdef.h" +#include "m_swap.h" +#include "w_wad.h" +#include "v_text.h" + +// MACROS ------------------------------------------------------------------ + +// TYPES ------------------------------------------------------------------- + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +static FString CurrentConfig; + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +CVAR(String, wildmidi_config, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Int, wildmidi_frequency, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Bool, wildmidi_reverb, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + if (currSong != NULL) + currSong->WildMidiSetOption(WM_MO_REVERB, *self? WM_MO_REVERB:0); +} + +CUSTOM_CVAR(Bool, wildmidi_enhanced_resampling, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + if (currSong != NULL) + currSong->WildMidiSetOption(WM_MO_ENHANCED_RESAMPLING, *self? WM_MO_ENHANCED_RESAMPLING:0); +} + +// CODE -------------------------------------------------------------------- + +//========================================================================== +// +// WildMIDIDevice Constructor +// +//========================================================================== + +WildMIDIDevice::WildMIDIDevice(const char *args) +{ + Renderer = NULL; + + if (wildmidi_frequency >= 11025 && wildmidi_frequency < 65536) + { // Use our own sample rate instead of the global one + SampleRate = wildmidi_frequency; + } + else + { // Else make sure we're not outside of WildMidi's range + SampleRate = clamp(SampleRate, 11025, 65535); + } + + if (args == NULL || *args == 0) args = wildmidi_config; + + if (CurrentConfig.CompareNoCase(args) != 0 || SampleRate != WildMidi_GetSampleRate()) + { + if (CurrentConfig.IsNotEmpty()) + { + WildMidi_Shutdown(); + CurrentConfig = ""; + } + if (!WildMidi_Init(args, SampleRate, 0)) + { + CurrentConfig = args; + } + } + if (CurrentConfig.IsNotEmpty()) + { + Renderer = new WildMidi_Renderer(); + int flags = 0; + if (wildmidi_enhanced_resampling) flags |= WM_MO_ENHANCED_RESAMPLING; + if (wildmidi_reverb) flags |= WM_MO_REVERB; + Renderer->SetOption(WM_MO_ENHANCED_RESAMPLING | WM_MO_REVERB, flags); + } +} + +//========================================================================== +// +// WildMIDIDevice Destructor +// +//========================================================================== + +WildMIDIDevice::~WildMIDIDevice() +{ + Close(); + if (Renderer != NULL) + { + delete Renderer; + } + // Do not shut down the device so that it can be reused for the next song being played. +} + +//========================================================================== +// +// WildMIDIDevice :: Open +// +// Returns 0 on success. +// +//========================================================================== + +int WildMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata) +{ + if (Renderer == NULL) + { + return 1; + } + int ret = OpenStream(2, 0, callback, userdata); + if (ret == 0) + { +// Renderer->Reset(); + } + return ret; +} + +//========================================================================== +// +// WildMIDIDevice :: PrecacheInstruments +// +// Each entry is packed as follows: +// Bits 0- 6: Instrument number +// Bits 7-13: Bank number +// Bit 14: Select drum set if 1, tone bank if 0 +// +//========================================================================== + +void WildMIDIDevice::PrecacheInstruments(const WORD *instruments, int count) +{ + for (int i = 0; i < count; ++i) + { + Renderer->LoadInstrument((instruments[i] >> 7) & 127, instruments[i] >> 14, instruments[i] & 127); + } +} + + +//========================================================================== +// +// WildMIDIDevice :: HandleEvent +// +//========================================================================== + +void WildMIDIDevice::HandleEvent(int status, int parm1, int parm2) +{ + Renderer->ShortEvent(status, parm1, parm2); +} + +//========================================================================== +// +// WildMIDIDevice :: HandleLongEvent +// +//========================================================================== + +void WildMIDIDevice::HandleLongEvent(const BYTE *data, int len) +{ + Renderer->LongEvent(data, len); +} + +//========================================================================== +// +// WildMIDIDevice :: ComputeOutput +// +//========================================================================== + +void WildMIDIDevice::ComputeOutput(float *buffer, int len) +{ + Renderer->ComputeOutput(buffer, len); +} + +//========================================================================== +// +// WildMIDIDevice :: GetStats +// +//========================================================================== + +FString WildMIDIDevice::GetStats() +{ + FString out; + out.Format("%3d voices", Renderer->GetVoiceCount()); + return out; +} + +//========================================================================== +// +// WildMIDIDevice :: GetStats +// +//========================================================================== + +void WildMIDIDevice::WildMidiSetOption(int opt, int set) +{ + Renderer->SetOption(opt, set); +} diff --git a/src/sound/music_xmi_midiout.cpp b/src/sound/music_xmi_midiout.cpp index 6c179a16a..71246f518 100644 --- a/src/sound/music_xmi_midiout.cpp +++ b/src/sound/music_xmi_midiout.cpp @@ -108,8 +108,8 @@ extern char MIDI_CommonLengths[15]; // //========================================================================== -XMISong::XMISong (FileReader &reader, EMidiDevice type) -: MIDIStreamer(type), MusHeader(0), Songs(0) +XMISong::XMISong (FileReader &reader, EMidiDevice type, const char *args) +: MIDIStreamer(type, args), MusHeader(0), Songs(0) { #ifdef _WIN32 if (ExitEvent == NULL) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index b8a2c802d..2b403b9de 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -236,27 +236,27 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TransferPointer) { ACTION_PARAM_START(5); ACTION_PARAM_INT(ptr_source, 0); - ACTION_PARAM_INT(ptr_recepient, 1); + ACTION_PARAM_INT(ptr_recipient, 1); ACTION_PARAM_INT(ptr_sourcefield, 2); - ACTION_PARAM_INT(ptr_recepientfield, 3); + ACTION_PARAM_INT(ptr_recipientfield, 3); ACTION_PARAM_INT(flags, 4); - AActor *source, *recepient; + AActor *source, *recipient; // Exchange pointers with actors to whom you have pointers (or with yourself, if you must) source = COPY_AAPTR(self, ptr_source); - COPY_AAPTR_NOT_NULL(self, recepient, ptr_recepient); // pick an actor to store the provided pointer value + COPY_AAPTR_NOT_NULL(self, recipient, ptr_recipient); // pick an actor to store the provided pointer value // convert source from dataprovider to data source = COPY_AAPTR(source, ptr_sourcefield); - if (source == recepient) source = NULL; // The recepient should not acquire a pointer to itself; will write NULL + if (source == recipient) source = NULL; // The recipient should not acquire a pointer to itself; will write NULL - if (ptr_recepientfield == AAPTR_DEFAULT) ptr_recepientfield = ptr_sourcefield; // If default: Write to same field as data was read from + if (ptr_recipientfield == AAPTR_DEFAULT) ptr_recipientfield = ptr_sourcefield; // If default: Write to same field as data was read from - ASSIGN_AAPTR(recepient, ptr_recepientfield, source, flags); + ASSIGN_AAPTR(recipient, ptr_recipientfield, source, flags); } //========================================================================== @@ -327,9 +327,9 @@ static void DoAttack (AActor *self, bool domelee, bool domissile, else if (domissile && MissileType != NULL) { // This seemingly senseless code is needed for proper aiming. - self->z += MissileHeight + self->GetBobOffset() - 32*FRACUNIT; - AActor *missile = P_SpawnMissileXYZ (self->x, self->y, self->z + 32*FRACUNIT, self, self->target, MissileType, false); - self->z -= MissileHeight + self->GetBobOffset() - 32*FRACUNIT; + self->AddZ(MissileHeight + self->GetBobOffset() - 32*FRACUNIT); + AActor *missile = P_SpawnMissileXYZ (self->PosPlusZ(32*FRACUNIT), self, self->target, MissileType, false); + self->AddZ(-(MissileHeight + self->GetBobOffset() - 32*FRACUNIT)); if (missile) { @@ -671,10 +671,10 @@ void DoJumpIfCloser(AActor *target, DECLARE_PARAMINFO) // No target - no jump if (!target) return; - if (P_AproxDistance(self->x-target->x, self->y-target->y) < dist && + if (self->AproxDistance(target) < dist && (noz || - ((self->z > target->z && self->z - (target->z + target->height) < dist) || - (self->z <= target->z && target->z - (self->z + self->height) < dist)))) + ((self->Z() > target->Z() && self->Z() - target->Top() < dist) || + (self->Z() <= target->Z() && target->Z() - self->Top() < dist)))) { ACTION_JUMP(jump); } @@ -914,9 +914,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile) { ACTION_PARAM_START(7); ACTION_PARAM_CLASS(ti, 0); - ACTION_PARAM_FIXED(SpawnHeight, 1); - ACTION_PARAM_INT(Spawnofs_XY, 2); - ACTION_PARAM_ANGLE(Angle, 3); + ACTION_PARAM_FIXED(spawnheight, 1); + ACTION_PARAM_INT(spawnofs_xy, 2); + ACTION_PARAM_ANGLE(angle, 3); ACTION_PARAM_INT(flags, 4); ACTION_PARAM_ANGLE(pitch, 5); ACTION_PARAM_INT(ptr, 6); @@ -928,46 +928,41 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile) AActor * targ; AActor * missile; - if (ref != NULL || aimmode==2) + if (ref != NULL || aimmode == 2) { if (ti) { angle_t ang = (self->angle - ANGLE_90) >> ANGLETOFINESHIFT; - fixed_t x = Spawnofs_XY * finecosine[ang]; - fixed_t y = Spawnofs_XY * finesine[ang]; - fixed_t z = SpawnHeight + self->GetBobOffset() - 32*FRACUNIT + (self->player? self->player->crouchoffset : 0); + fixed_t x = spawnofs_xy * finecosine[ang]; + fixed_t y = spawnofs_xy * finesine[ang]; + fixed_t z = spawnheight + self->GetBobOffset() - 32*FRACUNIT + (self->player? self->player->crouchoffset : 0); + fixedvec3 pos = self->Pos(); switch (aimmode) { case 0: default: // same adjustment as above (in all 3 directions this time) - for better aiming! - self->x += x; - self->y += y; - self->z += z; - missile = P_SpawnMissileXYZ(self->x, self->y, self->z + 32*FRACUNIT, self, ref, ti, false); - self->x -= x; - self->y -= y; - self->z -= z; + self->SetXYZ(self->Vec3Offset(x, y, z)); + missile = P_SpawnMissileXYZ(self->PosPlusZ(32*FRACUNIT), self, ref, ti, false); + self->SetXYZ(pos); break; case 1: - missile = P_SpawnMissileXYZ(self->x+x, self->y+y, self->z + self->GetBobOffset() + SpawnHeight, self, ref, ti, false); + missile = P_SpawnMissileXYZ(self->Vec3Offset(x, y, self->GetBobOffset() + spawnheight), self, ref, ti, false); break; case 2: - self->x += x; - self->y += y; - missile = P_SpawnMissileAngleZSpeed(self, self->z + self->GetBobOffset() + SpawnHeight, ti, self->angle, 0, GetDefaultByType(ti)->Speed, self, false); - self->x -= x; - self->y -= y; + self->SetXYZ(self->Vec3Offset(x, y, self->Z())); + missile = P_SpawnMissileAngleZSpeed(self, self->Z() + self->GetBobOffset() + spawnheight, ti, self->angle, 0, GetDefaultByType(ti)->Speed, self, false); + self->SetXYZ(pos); flags |= CMF_ABSOLUTEPITCH; break; } - if (missile) + if (missile != NULL) { // Use the actual velocity instead of the missile's Speed property // so that this can handle missiles with a high vertical velocity @@ -1000,30 +995,31 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile) // otherwise affecting the spawned actor. } - missile->angle = (CMF_ABSOLUTEANGLE & flags) ? Angle : missile->angle + Angle ; + missile->angle = (CMF_ABSOLUTEANGLE & flags) ? angle : missile->angle + angle ; ang = missile->angle >> ANGLETOFINESHIFT; - missile->velx = FixedMul (missilespeed, finecosine[ang]); - missile->vely = FixedMul (missilespeed, finesine[ang]); + missile->velx = FixedMul(missilespeed, finecosine[ang]); + missile->vely = FixedMul(missilespeed, finesine[ang]); // handle projectile shooting projectiles - track the // links back to a real owner if (self->isMissile(!!(flags & CMF_TRACKOWNER))) { - AActor * owner=self ;//->target; - while (owner->isMissile(!!(flags & CMF_TRACKOWNER)) && owner->target) owner=owner->target; - targ=owner; - missile->target=owner; + AActor *owner = self ;//->target; + while (owner->isMissile(!!(flags & CMF_TRACKOWNER)) && owner->target) + owner = owner->target; + targ = owner; + missile->target = owner; // automatic handling of seeker missiles if (self->flags2 & missile->flags2 & MF2_SEEKERMISSILE) { - missile->tracer=self->tracer; + missile->tracer = self->tracer; } } - else if (missile->flags2&MF2_SEEKERMISSILE) + else if (missile->flags2 & MF2_SEEKERMISSILE) { // automatic handling of seeker missiles - missile->tracer=self->target; + missile->tracer = self->target; } // we must redo the spectral check here because the owner is set after spawning so the FriendPlayer value may be wrong if (missile->flags4 & MF4_SPECTRAL) @@ -1044,7 +1040,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile) else if (flags & CMF_CHECKTARGETDEAD) { // Target is dead and the attack shall be aborted. - if (self->SeeState != NULL && (self->health > 0 || !(self->flags3 & MF3_ISMONSTER))) self->SetState(self->SeeState); + if (self->SeeState != NULL && (self->health > 0 || !(self->flags3 & MF3_ISMONSTER))) + self->SetState(self->SeeState); } } @@ -1065,27 +1062,28 @@ enum CBA_Flags DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack) { ACTION_PARAM_START(8); - ACTION_PARAM_ANGLE(Spread_XY, 0); - ACTION_PARAM_ANGLE(Spread_Z, 1); - ACTION_PARAM_INT(NumBullets, 2); - ACTION_PARAM_INT(DamagePerBullet, 3); + ACTION_PARAM_ANGLE(spread_xy, 0); + ACTION_PARAM_ANGLE(spread_z, 1); + ACTION_PARAM_INT(numbullets, 2); + ACTION_PARAM_INT(damageperbullet, 3); ACTION_PARAM_CLASS(pufftype, 4); - ACTION_PARAM_FIXED(Range, 5); - ACTION_PARAM_INT(Flags, 6); + ACTION_PARAM_FIXED(range, 5); + ACTION_PARAM_INT(flags, 6); ACTION_PARAM_INT(ptr, 7); AActor *ref = COPY_AAPTR(self, ptr); - if(Range==0) Range=MISSILERANGE; + if (range == 0) + range = MISSILERANGE; int i; int bangle; int bslope = 0; - int laflags = (Flags & CBAF_NORANDOMPUFFZ)? LAF_NORANDOMPUFFZ : 0; + int laflags = (flags & CBAF_NORANDOMPUFFZ)? LAF_NORANDOMPUFFZ : 0; - if (ref || (Flags & CBAF_AIMFACING)) + if (ref != NULL || (flags & CBAF_AIMFACING)) { - if (!(Flags & CBAF_AIMFACING)) + if (!(flags & CBAF_AIMFACING)) { A_Face(self, ref); } @@ -1093,31 +1091,31 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack) if (!pufftype) pufftype = PClass::FindClass(NAME_BulletPuff); - if (!(Flags & CBAF_NOPITCH)) bslope = P_AimLineAttack (self, bangle, MISSILERANGE); + if (!(flags & CBAF_NOPITCH)) bslope = P_AimLineAttack (self, bangle, MISSILERANGE); S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM); - for (i=0 ; itarget) return; @@ -1144,13 +1143,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMeleeAttack) A_FaceTarget (self); if (self->CheckMeleeRange ()) { - if (MeleeSound) S_Sound (self, CHAN_WEAPON, MeleeSound, 1, ATTN_NORM); - int newdam = P_DamageMobj (self->target, self, self, damage, DamageType); - if (bleed) P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); + if (meleesound) + S_Sound (self, CHAN_WEAPON, meleesound, 1, ATTN_NORM); + int newdam = P_DamageMobj (self->target, self, self, damage, damagetype); + if (bleed) + P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); } else { - if (MissSound) S_Sound (self, CHAN_WEAPON, MissSound, 1, ATTN_NORM); + if (misssound) + S_Sound (self, CHAN_WEAPON, misssound, 1, ATTN_NORM); } } @@ -1163,36 +1165,39 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomComboAttack) { ACTION_PARAM_START(6); ACTION_PARAM_CLASS(ti, 0); - ACTION_PARAM_FIXED(SpawnHeight, 1); + ACTION_PARAM_FIXED(spawnheight, 1); ACTION_PARAM_INT(damage, 2); - ACTION_PARAM_SOUND(MeleeSound, 3); - ACTION_PARAM_NAME(DamageType, 4); + ACTION_PARAM_SOUND(meleesound, 3); + ACTION_PARAM_NAME(damagetype, 4); ACTION_PARAM_BOOL(bleed, 5); if (!self->target) return; A_FaceTarget (self); - if (self->CheckMeleeRange ()) + if (self->CheckMeleeRange()) { - if (DamageType==NAME_None) DamageType = NAME_Melee; // Melee is the default type - if (MeleeSound) S_Sound (self, CHAN_WEAPON, MeleeSound, 1, ATTN_NORM); - int newdam = P_DamageMobj (self->target, self, self, damage, DamageType); - if (bleed) P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); + if (damagetype == NAME_None) + damagetype = NAME_Melee; // Melee is the default type + if (meleesound) + S_Sound (self, CHAN_WEAPON, meleesound, 1, ATTN_NORM); + int newdam = P_DamageMobj (self->target, self, self, damage, damagetype); + if (bleed) + P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); } else if (ti) { // This seemingly senseless code is needed for proper aiming. - self->z += SpawnHeight + self->GetBobOffset() - 32*FRACUNIT; - AActor *missile = P_SpawnMissileXYZ (self->x, self->y, self->z + 32*FRACUNIT, self, self->target, ti, false); - self->z -= SpawnHeight + self->GetBobOffset() - 32*FRACUNIT; + self->AddZ(spawnheight + self->GetBobOffset() - 32*FRACUNIT); + AActor *missile = P_SpawnMissileXYZ (self->PosPlusZ(32*FRACUNIT), self, self->target, ti, false); + self->AddZ(-(spawnheight + self->GetBobOffset() - 32*FRACUNIT)); if (missile) { // automatic handling of seeker missiles - if (missile->flags2&MF2_SEEKERMISSILE) + if (missile->flags2 & MF2_SEEKERMISSILE) { - missile->tracer=self->target; + missile->tracer = self->target; } P_CheckMissileSpawn(missile, self->radius); } @@ -1238,77 +1243,81 @@ enum FB_Flags DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets) { ACTION_PARAM_START(7); - ACTION_PARAM_ANGLE(Spread_XY, 0); - ACTION_PARAM_ANGLE(Spread_Z, 1); - ACTION_PARAM_INT(NumberOfBullets, 2); - ACTION_PARAM_INT(DamagePerBullet, 3); - ACTION_PARAM_CLASS(PuffType, 4); - ACTION_PARAM_INT(Flags, 5); - ACTION_PARAM_FIXED(Range, 6); + ACTION_PARAM_ANGLE(spread_xy, 0); + ACTION_PARAM_ANGLE(spread_z, 1); + ACTION_PARAM_INT(numbullets, 2); + ACTION_PARAM_INT(damageperbullet, 3); + ACTION_PARAM_CLASS(pufftype, 4); + ACTION_PARAM_INT(flags, 5); + ACTION_PARAM_FIXED(range, 6); if (!self->player) return; - player_t * player=self->player; - AWeapon * weapon=player->ReadyWeapon; + player_t *player = self->player; + AWeapon *weapon = player->ReadyWeapon; int i; int bangle; int bslope = 0; - int laflags = (Flags & FBF_NORANDOMPUFFZ)? LAF_NORANDOMPUFFZ : 0; + int laflags = (flags & FBF_NORANDOMPUFFZ)? LAF_NORANDOMPUFFZ : 0; - if ((Flags & FBF_USEAMMO) && weapon) + if ((flags & FBF_USEAMMO) && weapon) { - if (!weapon->DepleteAmmo(weapon->bAltFire, true)) return; // out of ammo + if (!weapon->DepleteAmmo(weapon->bAltFire, true)) + return; // out of ammo } - if (Range == 0) Range = PLAYERMISSILERANGE; + if (range == 0) + range = PLAYERMISSILERANGE; - if (!(Flags & FBF_NOFLASH)) static_cast(self)->PlayAttacking2 (); + if (!(flags & FBF_NOFLASH)) static_cast(self)->PlayAttacking2 (); - if (!(Flags & FBF_NOPITCH)) bslope = P_BulletSlope(self); + if (!(flags & FBF_NOPITCH)) bslope = P_BulletSlope(self); bangle = self->angle; - if (!PuffType) PuffType = PClass::FindClass(NAME_BulletPuff); + if (pufftype == NULL) + pufftype = PClass::FindClass(NAME_BulletPuff); if (weapon != NULL) { - S_Sound (self, CHAN_WEAPON, weapon->AttackSound, 1, ATTN_NORM); + S_Sound(self, CHAN_WEAPON, weapon->AttackSound, 1, ATTN_NORM); } - if ((NumberOfBullets==1 && !player->refire) || NumberOfBullets==0) + if ((numbullets == 1 && !player->refire) || numbullets == 0) { - int damage = DamagePerBullet; + int damage = damageperbullet; - if (!(Flags & FBF_NORANDOM)) + if (!(flags & FBF_NORANDOM)) damage *= ((pr_cwbullet()%3)+1); - P_LineAttack(self, bangle, Range, bslope, damage, NAME_Hitscan, PuffType, laflags); + P_LineAttack(self, bangle, range, bslope, damage, NAME_Hitscan, pufftype, laflags); } else { - if (NumberOfBullets == -1) NumberOfBullets = 1; - for (i=0 ; iplayer) return; - player_t *player=self->player; - AWeapon * weapon=player->ReadyWeapon; + player_t *player = self->player; + AWeapon *weapon = player->ReadyWeapon; AActor *linetarget; // Only use ammo if called from a weapon - if (UseAmmo && ACTION_CALL_FROM_WEAPON() && weapon) + if (useammo && ACTION_CALL_FROM_WEAPON() && weapon) { - if (!weapon->DepleteAmmo(weapon->bAltFire, true)) return; // out of ammo + if (!weapon->DepleteAmmo(weapon->bAltFire, true)) + return; // out of ammo } if (ti) { angle_t ang = (self->angle - ANGLE_90) >> ANGLETOFINESHIFT; - fixed_t x = SpawnOfs_XY * finecosine[ang]; - fixed_t y = SpawnOfs_XY * finesine[ang]; - fixed_t z = SpawnHeight; + fixed_t x = spawnofs_xy * finecosine[ang]; + fixed_t y = spawnofs_xy * finesine[ang]; + fixed_t z = spawnheight; fixed_t shootangle = self->angle; - if (Flags & FPF_AIMATANGLE) shootangle += Angle; + if (flags & FPF_AIMATANGLE) shootangle += angle; // Temporarily adjusts the pitch - fixed_t SavedPlayerPitch = self->pitch; + fixed_t saved_player_pitch = self->pitch; self->pitch -= pitch; - AActor * misl=P_SpawnPlayerMissile (self, x, y, z, ti, shootangle, &linetarget, NULL, false, (Flags & FPF_NOAUTOAIM) != 0); - self->pitch = SavedPlayerPitch; + AActor * misl=P_SpawnPlayerMissile (self, x, y, z, ti, shootangle, &linetarget, NULL, false, (flags & FPF_NOAUTOAIM) != 0); + self->pitch = saved_player_pitch; // automatic handling of seeker missiles if (misl) { - if (Flags & FPF_TRANSFERTRANSLATION) misl->Translation = self->Translation; - if (linetarget && misl->flags2&MF2_SEEKERMISSILE) misl->tracer=linetarget; - if (!(Flags & FPF_AIMATANGLE)) + if (flags & FPF_TRANSFERTRANSLATION) + misl->Translation = self->Translation; + if (linetarget && (misl->flags2 & MF2_SEEKERMISSILE)) + misl->tracer = linetarget; + if (!(flags & FPF_AIMATANGLE)) { // This original implementation is to aim straight ahead and then offset // the angle from the resulting direction. FVector3 velocity(misl->velx, misl->vely, 0); fixed_t missilespeed = (fixed_t)velocity.Length(); - misl->angle += Angle; + misl->angle += angle; angle_t an = misl->angle >> ANGLETOFINESHIFT; misl->velx = FixedMul (missilespeed, finecosine[an]); misl->vely = FixedMul (missilespeed, finesine[an]); @@ -1407,12 +1419,12 @@ enum DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) { ACTION_PARAM_START(8); - ACTION_PARAM_INT(Damage, 0); + ACTION_PARAM_INT(damage, 0); ACTION_PARAM_BOOL(norandom, 1); ACTION_PARAM_INT(flags, 2); - ACTION_PARAM_CLASS(PuffType, 3); - ACTION_PARAM_FIXED(Range, 4); - ACTION_PARAM_FIXED(LifeSteal, 5); + ACTION_PARAM_CLASS(pufftype, 3); + ACTION_PARAM_FIXED(range, 4); + ACTION_PARAM_FIXED(lifesteal, 5); ACTION_PARAM_INT(lifestealmax, 6); ACTION_PARAM_CLASS(armorbonustype, 7); ACTION_PARAM_SOUND(MeleeSound, 8); @@ -1429,22 +1441,26 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) AActor * linetarget; int actualdamage; - if (!norandom) Damage *= (pr_cwpunch()%8+1); + if (!norandom) + damage *= pr_cwpunch() % 8 + 1; angle = self->angle + (pr_cwpunch.Random2() << 18); - if (Range == 0) Range = MELEERANGE; - pitch = P_AimLineAttack (self, angle, Range, &linetarget); + if (range == 0) + range = MELEERANGE; + pitch = P_AimLineAttack (self, angle, range, &linetarget); // only use ammo when actually hitting something! if ((flags & CPF_USEAMMO) && linetarget && weapon) { - if (!weapon->DepleteAmmo(weapon->bAltFire, true)) return; // out of ammo + if (!weapon->DepleteAmmo(weapon->bAltFire, true)) + return; // out of ammo } - if (!PuffType) PuffType = PClass::FindClass(NAME_BulletPuff); + if (pufftype == NULL) + pufftype = PClass::FindClass(NAME_BulletPuff); int puffFlags = LAF_ISMELEEATTACK | ((flags & CPF_NORANDOMPUFFZ) ? LAF_NORANDOMPUFFZ : 0); - P_LineAttack (self, angle, Range, pitch, Damage, NAME_Melee, PuffType, puffFlags, &linetarget, &actualdamage); + P_LineAttack (self, angle, range, pitch, damage, NAME_Melee, pufftype, puffFlags, &linetarget, &actualdamage); if (!linetarget) { @@ -1452,33 +1468,34 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) } else { - if (LifeSteal && !(linetarget->flags5 & MF5_DONTDRAIN)) + if (lifesteal && !(linetarget->flags5 & MF5_DONTDRAIN)) { if (flags & CPF_STEALARMOR) { - if (!armorbonustype) armorbonustype = PClass::FindClass("ArmorBonus"); - - if (armorbonustype->IsDescendantOf (RUNTIME_CLASS(ABasicArmorBonus))) + if (armorbonustype == NULL) { - ABasicArmorBonus *armorbonus = static_cast(Spawn (armorbonustype, 0,0,0, NO_REPLACE)); - armorbonus->SaveAmount *= (actualdamage * LifeSteal) >> FRACBITS; + armorbonustype = PClass::FindClass("ArmorBonus"); + } + if (armorbonustype != NULL) + { + assert(armorbonustype->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus))); + ABasicArmorBonus *armorbonus = static_cast(Spawn(armorbonustype, 0,0,0, NO_REPLACE)); + armorbonus->SaveAmount *= (actualdamage * lifesteal) >> FRACBITS; armorbonus->MaxSaveAmount = lifestealmax <= 0 ? armorbonus->MaxSaveAmount : lifestealmax; armorbonus->flags |= MF_DROPPED; armorbonus->ClearCounters(); - if (!armorbonus->CallTryPickup (self)) + if (!armorbonus->CallTryPickup(self)) { armorbonus->Destroy (); } } } - else { - P_GiveBody (self, (actualdamage * LifeSteal) >> FRACBITS, lifestealmax); + P_GiveBody (self, (actualdamage * lifesteal) >> FRACBITS, lifestealmax); } } - if (weapon != NULL) { if (MeleeSound) S_Sound(self, CHAN_WEAPON, MeleeSound, 1, ATTN_NORM); @@ -1488,10 +1505,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) if (!(flags & CPF_NOTURN)) { // turn to face target - self->angle = R_PointToAngle2 (self->x, - self->y, - linetarget->x, - linetarget->y); + self->angle = self->AngleTo(linetarget); } if (flags & CPF_PULLIN) self->flags |= MF_JUSTATTACKED; @@ -1508,52 +1522,53 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack) { ACTION_PARAM_START(17); - ACTION_PARAM_INT(Damage, 0); - ACTION_PARAM_INT(Spawnofs_XY, 1); - ACTION_PARAM_BOOL(UseAmmo, 2); - ACTION_PARAM_COLOR(Color1, 3); - ACTION_PARAM_COLOR(Color2, 4); - ACTION_PARAM_INT(Flags, 5); - ACTION_PARAM_DOUBLE(MaxDiff, 6); - ACTION_PARAM_CLASS(PuffType, 7); - ACTION_PARAM_ANGLE(Spread_XY, 8); - ACTION_PARAM_ANGLE(Spread_Z, 9); - ACTION_PARAM_FIXED(Range, 10); - ACTION_PARAM_INT(Duration, 11); - ACTION_PARAM_DOUBLE(Sparsity, 12); - ACTION_PARAM_DOUBLE(DriftSpeed, 13); - ACTION_PARAM_CLASS(SpawnClass, 14); - ACTION_PARAM_FIXED(Spawnofs_Z, 15); + ACTION_PARAM_INT(damage, 0); + ACTION_PARAM_INT(spawnofs_xy, 1); + ACTION_PARAM_BOOL(useammo, 2); + ACTION_PARAM_COLOR(color1, 3); + ACTION_PARAM_COLOR(color2, 4); + ACTION_PARAM_INT(flags, 5); + ACTION_PARAM_DOUBLE(maxdiff, 6); + ACTION_PARAM_CLASS(pufftype, 7); + ACTION_PARAM_ANGLE(spread_xy, 8); + ACTION_PARAM_ANGLE(spread_z, 9); + ACTION_PARAM_FIXED(range, 10); + ACTION_PARAM_INT(duration, 11); + ACTION_PARAM_DOUBLE(sparsity, 12); + ACTION_PARAM_DOUBLE(driftspeed, 13); + ACTION_PARAM_CLASS(spawnclass, 14); + ACTION_PARAM_FIXED(spawnofs_z, 15); ACTION_PARAM_INT(SpiralOffset, 16); - if(Range==0) Range=8192*FRACUNIT; - if(Sparsity==0) Sparsity=1.0; + if (range == 0) range = 8192*FRACUNIT; + if (sparsity == 0) sparsity=1.0; if (!self->player) return; - AWeapon * weapon=self->player->ReadyWeapon; + AWeapon *weapon = self->player->ReadyWeapon; // only use ammo when actually hitting something! - if (UseAmmo) + if (useammo) { - if (!weapon->DepleteAmmo(weapon->bAltFire, true)) return; // out of ammo + if (!weapon->DepleteAmmo(weapon->bAltFire, true)) + return; // out of ammo } angle_t angle; angle_t slope; - if (Flags & RAF_EXPLICITANGLE) + if (flags & RAF_EXPLICITANGLE) { - angle = Spread_XY; - slope = Spread_Z; + angle = spread_xy; + slope = spread_z; } else { - angle = pr_crailgun.Random2() * (Spread_XY / 255); - slope = pr_crailgun.Random2() * (Spread_Z / 255); + angle = pr_crailgun.Random2() * (spread_xy / 255); + slope = pr_crailgun.Random2() * (spread_z / 255); } - P_RailAttack (self, Damage, Spawnofs_XY, Spawnofs_Z, Color1, Color2, MaxDiff, Flags, PuffType, angle, slope, Range, Duration, Sparsity, DriftSpeed, SpawnClass, SpiralOffset); + P_RailAttack (self, damage, spawnofs_xy, spawnofs_z, color1, color2, maxdiff, flags, pufftype, angle, slope, range, duration, sparsity, driftspeed, spawnclass, SpiralOffset); } //========================================================================== @@ -1572,31 +1587,30 @@ enum DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) { ACTION_PARAM_START(17); - ACTION_PARAM_INT(Damage, 0); - ACTION_PARAM_INT(Spawnofs_XY, 1); - ACTION_PARAM_COLOR(Color1, 2); - ACTION_PARAM_COLOR(Color2, 3); - ACTION_PARAM_INT(Flags, 4); + ACTION_PARAM_INT(damage, 0); + ACTION_PARAM_INT(spawnofs_xy, 1); + ACTION_PARAM_COLOR(color1, 2); + ACTION_PARAM_COLOR(color2, 3); + ACTION_PARAM_INT(flags, 4); ACTION_PARAM_INT(aim, 5); - ACTION_PARAM_DOUBLE(MaxDiff, 6); - ACTION_PARAM_CLASS(PuffType, 7); - ACTION_PARAM_ANGLE(Spread_XY, 8); - ACTION_PARAM_ANGLE(Spread_Z, 9); - ACTION_PARAM_FIXED(Range, 10); - ACTION_PARAM_INT(Duration, 11); - ACTION_PARAM_DOUBLE(Sparsity, 12); - ACTION_PARAM_DOUBLE(DriftSpeed, 13); - ACTION_PARAM_CLASS(SpawnClass, 14); - ACTION_PARAM_FIXED(Spawnofs_Z, 15); + ACTION_PARAM_DOUBLE(maxdiff, 6); + ACTION_PARAM_CLASS(pufftype, 7); + ACTION_PARAM_ANGLE(spread_xy, 8); + ACTION_PARAM_ANGLE(spread_z, 9); + ACTION_PARAM_FIXED(range, 10); + ACTION_PARAM_INT(duration, 11); + ACTION_PARAM_DOUBLE(sparsity, 12); + ACTION_PARAM_DOUBLE(driftspeed, 13); + ACTION_PARAM_CLASS(spawnclass, 14); + ACTION_PARAM_FIXED(spawnofs_z, 15); ACTION_PARAM_INT(SpiralOffset, 16); - if(Range==0) Range=8192*FRACUNIT; - if(Sparsity==0) Sparsity=1.0; + if (range == 0) range = 8192*FRACUNIT; + if (sparsity == 0) sparsity = 1; AActor *linetarget; - fixed_t saved_x = self->x; - fixed_t saved_y = self->y; + fixedvec3 savedpos = self->Pos(); angle_t saved_angle = self->angle; fixed_t saved_pitch = self->pitch; @@ -1615,37 +1629,32 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) if (aim) { - self->angle = R_PointToAngle2 (self->x, - self->y, - self->target->x, - self->target->y); + self->angle = self->AngleTo(self->target); } self->pitch = P_AimLineAttack (self, self->angle, MISSILERANGE, &linetarget, ANGLE_1*60, 0, aim ? self->target : NULL); if (linetarget == NULL && aim) { // We probably won't hit the target, but aim at it anyway so we don't look stupid. - TVector2 xydiff(self->target->x - self->x, self->target->y - self->y); - double zdiff = (self->target->z + (self->target->height>>1)) - - (self->z + (self->height>>1) - self->floorclip); + fixedvec2 pos = self->Vec2To(self->target); + TVector2 xydiff(pos.x, pos.y); + double zdiff = (self->target->Z() + (self->target->height>>1)) - + (self->Z() + (self->height>>1) - self->floorclip); self->pitch = int(atan2(zdiff, xydiff.Length()) * ANGLE_180 / -M_PI); } // Let the aim trail behind the player if (aim) { - saved_angle = self->angle = R_PointToAngle2 (self->x, self->y, - self->target->x - self->target->velx * 3, - self->target->y - self->target->vely * 3); + saved_angle = self->angle = self->AngleTo(self->target, -self->target->velx * 3, -self->target->vely * 3); if (aim == CRF_AIMDIRECT) { // Tricky: We must offset to the angle of the current position // but then change the angle again to ensure proper aim. - self->x += Spawnofs_XY * finecosine[self->angle]; - self->y += Spawnofs_XY * finesine[self->angle]; - Spawnofs_XY = 0; - self->angle = R_PointToAngle2 (self->x, self->y, - self->target->x - self->target->velx * 3, - self->target->y - self->target->vely * 3); + self->SetXY(self->Vec2Offset( + spawnofs_xy * finecosine[self->angle], + spawnofs_xy * finesine[self->angle])); + spawnofs_xy = 0; + self->angle = self->AngleTo(self->target,- self->target->velx * 3, -self->target->vely * 3); } if (self->target->flags & MF_SHADOW) @@ -1661,21 +1670,20 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) angle_t angleoffset; angle_t slopeoffset; - if (Flags & CRF_EXPLICITANGLE) + if (flags & CRF_EXPLICITANGLE) { - angleoffset = Spread_XY; - slopeoffset = Spread_Z; + angleoffset = spread_xy; + slopeoffset = spread_z; } else { - angleoffset = pr_crailgun.Random2() * (Spread_XY / 255); - slopeoffset = pr_crailgun.Random2() * (Spread_Z / 255); + angleoffset = pr_crailgun.Random2() * (spread_xy / 255); + slopeoffset = pr_crailgun.Random2() * (spread_z / 255); } - P_RailAttack (self, Damage, Spawnofs_XY, Spawnofs_Z, Color1, Color2, MaxDiff, Flags, PuffType, angleoffset, slopeoffset, Range, Duration, Sparsity, DriftSpeed, SpawnClass, SpiralOffset); + P_RailAttack (self, damage, spawnofs_xy, spawnofs_z, color1, color2, maxdiff, flags, pufftype, angleoffset, slopeoffset, range, duration, sparsity, driftspeed, spawnclass,SpiralOffset); - self->x = saved_x; - self->y = saved_y; + self->SetXYZ(savedpos); self->angle = saved_angle; self->pitch = saved_pitch; } @@ -1912,10 +1920,10 @@ static bool InitSpawnedItem(AActor *self, AActor *mo, int flags) { originator = originator->target; } - } + } if (flags & SIXF_TELEFRAG) { - P_TeleportMove(mo, mo->x, mo->y, mo->z, true); + P_TeleportMove(mo, mo->Pos(), true); // This is needed to ensure consistent behavior. // Otherwise it will only spawn if nothing gets telefragged flags |= SIXF_NOCHECKPOSITION; @@ -1969,7 +1977,7 @@ static bool InitSpawnedItem(AActor *self, AActor *mo, int flags) mo->tracer = NULL; } if (flags & SIXF_SETMASTER) - { + { // don't let it attack you (optional)! mo->master = originator; } if (flags & SIXF_SETTARGET) @@ -2084,10 +2092,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItem) if (useammo && !weapon->DepleteAmmo(weapon->bAltFire)) return; } - AActor * mo = Spawn( missile, - self->x + FixedMul(distance, finecosine[self->angle>>ANGLETOFINESHIFT]), - self->y + FixedMul(distance, finesine[self->angle>>ANGLETOFINESHIFT]), - self->z - self->floorclip + self->GetBobOffset() + zheight, ALLOW_REPLACE); + AActor * mo = Spawn( missile, self->Vec3Angle(distance, self->angle, -self->floorclip + self->GetBobOffset() + zheight), ALLOW_REPLACE); int flags = (transfer_translation ? SIXF_TRANSFERTRANSLATION : 0) + (useammo ? SIXF_SETMASTER : 0); bool res = InitSpawnedItem(self, mo, flags); @@ -2111,7 +2116,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx) ACTION_PARAM_FIXED(xvel, 4); ACTION_PARAM_FIXED(yvel, 5); ACTION_PARAM_FIXED(zvel, 6); - ACTION_PARAM_ANGLE(Angle, 7); + ACTION_PARAM_ANGLE(angle, 7); ACTION_PARAM_INT(flags, 8); ACTION_PARAM_INT(chance, 9); ACTION_PARAM_INT(tid, 10); @@ -2127,26 +2132,26 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx) // Don't spawn monsters if this actor has been massacred if (self->DamageType == NAME_Massacre && GetDefaultByType(missile)->flags3&MF3_ISMONSTER) return; - fixed_t x,y; + fixedvec2 pos; if (!(flags & SIXF_ABSOLUTEANGLE)) { - Angle += self->angle; + angle += self->angle; } - angle_t ang = Angle >> ANGLETOFINESHIFT; + angle_t ang = angle >> ANGLETOFINESHIFT; if (flags & SIXF_ABSOLUTEPOSITION) { - x = self->x + xofs; - y = self->y + yofs; + pos = self->Vec2Offset(xofs, yofs); } else { // in relative mode negative y values mean 'left' and positive ones mean 'right' // This is the inverse orientation of the absolute mode! - x = self->x + FixedMul(xofs, finecosine[ang]) + FixedMul(yofs, finesine[ang]); - y = self->y + FixedMul(xofs, finesine[ang]) - FixedMul(yofs, finecosine[ang]); + pos = self->Vec2Offset( + FixedMul(xofs, finecosine[ang]) + FixedMul(yofs, finesine[ang]), + FixedMul(xofs, finesine[ang]) - FixedMul(yofs, finecosine[ang])); } if (!(flags & SIXF_ABSOLUTEVELOCITY)) @@ -2157,7 +2162,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx) xvel = newxvel; } - AActor *mo = Spawn(missile, x, y, self->z - self->floorclip + self->GetBobOffset() + zofs, ALLOW_REPLACE); + AActor *mo = Spawn(missile, pos.x, pos.y, self->Z() - self->floorclip + self->GetBobOffset() + zofs, ALLOW_REPLACE); bool res = InitSpawnedItem(self, mo, flags); ACTION_SET_RESULT(res); // for an inventory item's use state if (res) @@ -2180,7 +2185,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx) mo->vely = yvel; mo->velz = zvel; } - mo->angle = Angle; + mo->angle = angle; } } @@ -2214,8 +2219,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ThrowGrenade) AActor * bo; - bo = Spawn(missile, self->x, self->y, - self->z - self->floorclip + self->GetBobOffset() + zheight + 35*FRACUNIT + (self->player? self->player->crouchoffset : 0), + bo = Spawn(missile, + self->PosPlusZ(-self->floorclip + self->GetBobOffset() + zheight + 35*FRACUNIT + (self->player? self->player->crouchoffset : 0)), ALLOW_REPLACE); if (bo) { @@ -2265,8 +2270,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Recoil) angle_t angle = self->angle + ANG180; angle >>= ANGLETOFINESHIFT; - self->velx += FixedMul (xyvel, finecosine[angle]); - self->vely += FixedMul (xyvel, finesine[angle]); + self->velx += FixedMul(xyvel, finecosine[angle]); + self->vely += FixedMul(xyvel, finesine[angle]); } @@ -2445,12 +2450,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeIn) self->RenderStyle.Flags &= ~STYLEF_Alpha1; self->alpha += reduce; - if (self->alpha >= (FRACUNIT * 1)) + if (self->alpha >= FRACUNIT) { if (flags & FTF_CLAMP) - self->alpha = (FRACUNIT * 1); + { + self->alpha = FRACUNIT; + } if (flags & FTF_REMOVE) - self->Destroy(); + { + P_RemoveThing(self); + } } } @@ -2476,9 +2485,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeOut) if (self->alpha <= 0) { if (flags & FTF_CLAMP) + { self->alpha = 0; + } if (flags & FTF_REMOVE) - self->Destroy(); + { + P_RemoveThing(self); + } } } @@ -2519,14 +2532,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeTo) } if (flags & FTF_CLAMP) { - if (self->alpha > (FRACUNIT * 1)) - self->alpha = (FRACUNIT * 1); - else if (self->alpha < 0) - self->alpha = 0; + self->alpha = clamp(self->alpha, 0, FRACUNIT); } if (self->alpha == target && (flags & FTF_REMOVE)) { - self->Destroy(); + P_RemoveThing(self); } } @@ -2590,14 +2600,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnDebris) if (debris == NULL) return; // only positive values make sense here - if (mult_v<=0) mult_v=FRACUNIT; - if (mult_h<=0) mult_h=FRACUNIT; + if (mult_v <= 0) + mult_v = FRACUNIT; + if (mult_h <= 0) + mult_h = FRACUNIT; for (i = 0; i < GetDefaultByType(debris)->health; i++) { - mo = Spawn(debris, self->x+((pr_spawndebris()-128)<<12), - self->y + ((pr_spawndebris()-128)<<12), - self->z + (pr_spawndebris()*self->height/256+self->GetBobOffset()), ALLOW_REPLACE); + fixed_t xo = ((pr_spawndebris() - 128) << 12); + fixed_t yo = ((pr_spawndebris() - 128) << 12); + fixed_t zo = (pr_spawndebris()*self->height / 256 + self->GetBobOffset()); + mo = Spawn(debris, self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); if (mo) { if (transfer_translation) @@ -2645,7 +2658,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnParticle) size = clamp(size, 0, 0xFF); // Clamp to byte if (lifetime != 0) - P_SpawnParticle(xoff + self->x, yoff + self->y, zoff + self->z, xvel, yvel, zvel, color, fullbright, startalpha, lifetime, size, fadestep, accelx, accely, accelz); + P_SpawnParticle(xoff + self->X(), yoff + self->Y(), zoff + self->Z(), xvel, yvel, zvel, color, fullbright, startalpha, lifetime, size, fadestep, accelx, accely, accelz); } @@ -2697,23 +2710,22 @@ static bool DoCheckSightOrRange(AActor *self, AActor *camera, double range, bool return false; } // Check distance first, since it's cheaper than checking sight. - double dx = self->x - camera->x; - double dy = self->y - camera->y; - double dz; - fixed_t eyez = (camera->z + camera->height - (camera->height>>2)); // same eye height as P_CheckSight - if (eyez > self->z + self->height) + fixedvec2 pos = camera->Vec2To(self); + fixed_t dz; + fixed_t eyez = (camera->Top() - (camera->height>>2)); // same eye height as P_CheckSight + if (eyez > self->Top()) { - dz = self->z + self->height - eyez; + dz = self->Top() - eyez; } - else if (eyez < self->z) + else if (eyez < self->Z()) { - dz = self->z - eyez; + dz = self->Z() - eyez; } else { dz = 0; } - double distance = (dx * dx) + (dy * dy) + (twodi == 0? (dz * dz) : 0); + double distance = ((double)pos.x * pos.x) + ((double)pos.y * pos.y) + (twodi == 0? ((double)dz * dz) : 0); if (distance <= range){ // Within range return true; @@ -2770,20 +2782,23 @@ static bool DoCheckRange(AActor *self, AActor *camera, double range, bool twodi) return false; } // Check distance first, since it's cheaper than checking sight. - double dx = self->x - camera->x; - double dy = self->y - camera->y; - double dz; - fixed_t eyez = (camera->z + camera->height - (camera->height>>2)); // same eye height as P_CheckSight - if (eyez > self->z + self->height){ - dz = self->z + self->height - eyez; + fixedvec2 pos = camera->Vec2To(self); + fixed_t dz; + fixed_t eyez = (camera->Top() - (camera->height>>2)); // same eye height as P_CheckSight + if (eyez > self->Top()) + { + dz = self->Top() - eyez; } - else if (eyez < self->z){ - dz = self->z - eyez; + else if (eyez < self->Z()) + { + dz = self->Z() - eyez; } - else{ + else + { dz = 0; } - double distance = (dx * dx) + (dy * dy) + (twodi == 0? (dz * dz) : 0); + double distance = ((double)pos.x * pos.x) + ((double)pos.y * pos.y) + (twodi == 0? ((double)dz * dz) : 0); + if (distance <= range){ // Within range return true; @@ -2943,14 +2958,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Burst) i = (pr_burst.Random2()) % (numChunks/4); for (i = MAX (24, numChunks + i); i >= 0; i--) { - mo = Spawn(chunk, - self->x + (((pr_burst()-128)*self->radius)>>7), - self->y + (((pr_burst()-128)*self->radius)>>7), - self->z + (pr_burst()*self->height/255 + self->GetBobOffset()), ALLOW_REPLACE); + fixed_t xo = (((pr_burst() - 128)*self->radius) >> 7); + fixed_t yo = (((pr_burst() - 128)*self->radius) >> 7); + fixed_t zo = (pr_burst()*self->height / 255 + self->GetBobOffset()); + mo = Spawn(chunk, self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); if (mo) { - mo->velz = FixedDiv(mo->z - self->z, self->height)<<2; + mo->velz = FixedDiv(mo->Z() - self->Z(), self->height)<<2; mo->velx = pr_burst.Random2 () << (FRACBITS-7); mo->vely = pr_burst.Random2 () << (FRACBITS-7); mo->RenderStyle = self->RenderStyle; @@ -2981,7 +2996,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckFloor) ACTION_PARAM_STATE(jump, 0); ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - if (self->z <= self->floorz) + if (self->Z() <= self->floorz) { ACTION_JUMP(jump); } @@ -3001,7 +3016,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckCeiling) ACTION_PARAM_STATE(jump, 0); ACTION_SET_RESULT(false); - if (self->z+self->height >= self->ceilingz) // Height needs to be counted + if (self->Top() >= self->ceilingz) // Height needs to be counted { ACTION_JUMP(jump); } @@ -3056,9 +3071,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Respawn) ACTION_PARAM_START(1); ACTION_PARAM_INT(flags, 0); bool oktorespawn = false; - fixed_t oldx = self->x; - fixed_t oldy = self->y; - fixed_t oldz = self->z; + fixedvec3 pos = self->Pos(); self->flags |= MF_SOLID; self->height = self->GetDefault()->height; self->radius = self->GetDefault()->radius; @@ -3067,22 +3080,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Respawn) if (flags & RSF_TELEFRAG) { // [KS] DIE DIE DIE DIE erm *ahem* =) - oktorespawn = P_TeleportMove(self, self->x, self->y, self->z, true); - if (oktorespawn) - { // Need to do this over again, since P_TeleportMove() will redo - // it with the proper point-on-side calculation. - self->UnlinkFromWorld(); - self->LinkToWorld(true); - sector_t *sec = self->Sector; - self->dropoffz = - self->floorz = sec->floorplane.ZatPoint(self->x, self->y); - self->ceilingz = sec->ceilingplane.ZatPoint(self->x, self->y); - P_FindFloorCeiling(self, FFCF_ONLYSPAWNPOS); - } + oktorespawn = P_TeleportMove(self, self->Pos(), true, false); } else { - oktorespawn = P_CheckPosition(self, self->x, self->y, true); + oktorespawn = P_CheckPosition(self, self->X(), self->Y(), true); } if (oktorespawn) @@ -3101,8 +3103,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Respawn) else { // Don't attack yourself (Re: "Marine targets itself after suicide") - if (self->target == self) self->target = NULL; - if (self->lastenemy == self) self->lastenemy = NULL; + if (self->target == self) + self->target = NULL; + if (self->lastenemy == self) + self->lastenemy = NULL; } self->flags = (defs->flags & ~MF_FRIENDLY) | (self->flags & MF_FRIENDLY); @@ -3117,8 +3121,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Respawn) if (flags & RSF_FOG) { - P_SpawnTeleportFog(self, oldx, oldy, oldz, true, true); - P_SpawnTeleportFog(self, self->x, self->y, self->z, false, true); + P_SpawnTeleportFog(self, pos, true, true); + P_SpawnTeleportFog(self, self->Pos(), false, true); } if (self->CountsAsKill()) { @@ -3317,9 +3321,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) */ AActor *target; - fixed_t - x1, y1, z1, - vx, vy, vz; + fixedvec3 pos; + fixed_t vx, vy, vz; ACTION_PARAM_START(9); @@ -3355,29 +3358,27 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) offsetwidth = FixedMul(self->radius, offsetwidth); } - x1 = self->x; - y1 = self->y; - z1 = self->z + offsetheight - self->floorclip; + pos = self->PosPlusZ(offsetheight - self->floorclip); if (!(flags & CLOFF_FROMBASE)) { // default to hitscan origin // Synced with hitscan: self->height is strangely NON-conscientious about getting the right actor for player - z1 += (self->height >> 1); + pos.z += (self->height >> 1); if (self->player != NULL) { - z1 += FixedMul (self->player->mo->AttackZOffset, self->player->crouchfactor); + pos.z += FixedMul (self->player->mo->AttackZOffset, self->player->crouchfactor); } else { - z1 += 8*FRACUNIT; + pos.z += 8*FRACUNIT; } } if (target) { - FVector2 xyvec(target->x - x1, target->y - y1); - fixed_t distance = P_AproxDistance((fixed_t)xyvec.Length(), target->z - z1); + fixed_t xydist = self->Distance2D(target); + fixed_t distance = P_AproxDistance(xydist, target->Z() - pos.z); if (range && !(flags & CLOFF_CHECKPARTIAL)) { @@ -3391,13 +3392,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) { ang = self->angle; } - else ang = R_PointToAngle2 (x1, y1, target->x, target->y); + else ang = self->AngleTo (target); angle += ang; ang >>= ANGLETOFINESHIFT; - x1 += FixedMul(offsetwidth, finesine[ang]); - y1 -= FixedMul(offsetwidth, finecosine[ang]); + + fixedvec2 xy = self->Vec2Offset( + FixedMul(offsetwidth, finesine[ang]), + -FixedMul(offsetwidth, finecosine[ang])); + + pos.x = xy.x; + pos.y = xy.y; } if (flags & CLOFF_NOAIM_VERT) @@ -3406,11 +3412,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) } else if (flags & CLOFF_AIM_VERT_NOOFFSET) { - pitch += R_PointToAngle2 (0,0, (fixed_t)xyvec.Length(), target->z - z1 + offsetheight + target->height / 2); + pitch += R_PointToAngle2 (0,0, xydist, target->Z() - pos.z + offsetheight + target->height / 2); } else { - pitch += R_PointToAngle2 (0,0, (fixed_t)xyvec.Length(), target->z - z1 + target->height / 2); + pitch += R_PointToAngle2 (0,0, xydist, target->Z() - pos.z + target->height / 2); } } else if (flags & CLOFF_ALLOWNULL) @@ -3419,8 +3425,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) pitch += self->pitch; angle_t ang = self->angle >> ANGLETOFINESHIFT; - x1 += FixedMul(offsetwidth, finesine[ang]); - y1 -= FixedMul(offsetwidth, finecosine[ang]); + + fixedvec2 xy = self->Vec2Offset( + FixedMul(offsetwidth, finesine[ang]), + -FixedMul(offsetwidth, finecosine[ang])); + + pos.x = xy.x; + pos.y = xy.y; } else return; @@ -3440,7 +3451,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) range */ - sector_t *sec = P_PointInSector(x1, y1); + sector_t *sec = P_PointInSector(pos.x, pos.y); if (range == 0) { @@ -3455,7 +3466,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) lof_data.Flags = flags; lof_data.BadActor = false; - Trace(x1, y1, z1, sec, vx, vy, vz, range, ActorFlags::FromInt(0xFFFFFFFF), ML_BLOCKEVERYTHING, self, trace, 0, + Trace(pos.x, pos.y, pos.z, sec, vx, vy, vz, range, ActorFlags::FromInt(0xFFFFFFFF), ML_BLOCKEVERYTHING, self, trace, 0, CheckLOFTraceFunc, &lof_data); if (trace.HitType == TRACE_HitActor || @@ -3542,9 +3553,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) target = self->target; } - if (!target) return; // [KS] Let's not call P_CheckSight unnecessarily in this case. + if (target == NULL) + return; // [KS] Let's not call P_CheckSight unnecessarily in this case. - if ((flags & JLOSF_DEADNOJUMP) && (target->health <= 0)) return; + if ((flags & JLOSF_DEADNOJUMP) && (target->health <= 0)) + { + return; + } doCheckSight = !(flags & JLOSF_NOSIGHT); } @@ -3580,8 +3595,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) // [FDARI] If actors share team, don't jump if ((flags & JLOSF_ALLYNOJUMP) && self->IsFriend(target)) return; - fixed_t distance = P_AproxDistance(target->x - self->x, target->y - self->y); - distance = P_AproxDistance(distance, target->z - self->z); + fixed_t distance = self->AproxDistance3D(target); if (dist_max && (distance > dist_max)) return; @@ -3611,11 +3625,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) if (fov && (fov < ANGLE_MAX)) { - an = R_PointToAngle2 (viewport->x, - viewport->y, - target->x, - target->y) - - viewport->angle; + an = viewport->AngleTo(target) - viewport->angle; if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2))) { @@ -3669,8 +3679,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) if ((flags & JLOSF_DEADNOJUMP) && (target->health <= 0)) return; - fixed_t distance = P_AproxDistance(target->x - self->x, target->y - self->y); - distance = P_AproxDistance(distance, target->z - self->z); + fixed_t distance = self->AproxDistance3D(target); if (dist_max && (distance > dist_max)) return; @@ -3690,11 +3699,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) if (fov && (fov < ANGLE_MAX)) { - an = R_PointToAngle2 (target->x, - target->y, - self->x, - self->y) - - target->angle; + an = target->AngleTo(self) - target->angle; if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2))) { @@ -3743,10 +3748,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckForReload) else { // We need to reload. However, don't reload if we're out of ammo. - weapon->CheckAmmo( false, false ); + weapon->CheckAmmo(false, false); } - if(!dontincrement) + if (!dontincrement) weapon->ReloadCounter = ReloadCounter; } @@ -3987,7 +3992,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MonsterRefire) if (pr_monsterrefire() < prob) return; - if (!self->target + if (self->target == NULL || P_HitFriend (self) || self->target->health <= 0 || !P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES) ) @@ -4018,8 +4023,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetAngle) ACTION_PARAM_INT(ptr, 2); AActor *ref = COPY_AAPTR(self, ptr); - - if (!ref) + if (ref != NULL) { ACTION_SET_RESULT(false); return; @@ -4300,12 +4304,12 @@ enum T_Flags DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) { ACTION_PARAM_START(7); - ACTION_PARAM_STATE(TeleportState, 0); - ACTION_PARAM_CLASS(TargetType, 1); - ACTION_PARAM_CLASS(FogType, 2); - ACTION_PARAM_INT(Flags, 3); - ACTION_PARAM_FIXED(MinDist, 4); - ACTION_PARAM_FIXED(MaxDist, 5); + ACTION_PARAM_STATE(teleport_state, 0); + ACTION_PARAM_CLASS(target_type, 1); + ACTION_PARAM_CLASS(fog_type, 2); + ACTION_PARAM_INT(flags, 3); + ACTION_PARAM_FIXED(mindist, 4); + ACTION_PARAM_FIXED(maxdist, 5); ACTION_PARAM_INT(ptr, 6); AActor *ref = COPY_AAPTR(self, ptr); @@ -4316,14 +4320,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) return; } - if ((ref->flags2 & MF2_NOTELEPORT) && !(Flags & TF_OVERRIDE)) + if ((ref->flags2 & MF2_NOTELEPORT) && !(flags & TF_OVERRIDE)) { ACTION_SET_RESULT(false); return; } // Randomly choose not to teleport like A_Srcr2Decide. - if (Flags & TF_RANDOMDECIDE) + if (flags & TF_RANDOMDECIDE) { static const int chance[] = { @@ -4347,97 +4351,93 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) return; } - if (!TargetType) - TargetType = PClass::FindClass("BossSpot"); + if (target_type == NULL) + { + target_type = PClass::FindClass("BossSpot"); + } - AActor * spot = state->GetSpotWithMinMaxDistance(TargetType, ref->x, ref->y, MinDist, MaxDist); + AActor * spot = state->GetSpotWithMinMaxDistance(target_type, ref->X(), ref->Y(), mindist, maxdist); if (spot == NULL) { ACTION_SET_RESULT(false); return; } - fixed_t prevX = ref->x; - fixed_t prevY = ref->y; - fixed_t prevZ = ref->z; - fixed_t aboveFloor = spot->z - spot->floorz; + fixedvec3 prev = ref->Pos(); + fixed_t aboveFloor = spot->Z() - spot->floorz; fixed_t finalz = spot->floorz + aboveFloor; - if (spot->z + ref->height > spot->ceilingz) + if (spot->Z() + ref->height > spot->ceilingz) finalz = spot->ceilingz - ref->height; - else if (spot->z < spot->floorz) + else if (spot->Z() < spot->floorz) finalz = spot->floorz; - //Take precedence and cooperate with telefragging first. - bool teleResult = P_TeleportMove(ref, spot->x, spot->y, finalz, Flags & TF_TELEFRAG); + bool tele_result = P_TeleportMove(ref, spot->X(), spot->Y(), finalz, flags & TF_TELEFRAG); - if (!teleResult && (Flags & TF_FORCED)) + if (!tele_result && (flags & TF_FORCED)) { //If for some reason the original move didn't work, regardless of telefrag, force it to move. - ref->SetOrigin(spot->x, spot->y, finalz); - teleResult = true; + ref->SetOrigin(spot->X(), spot->Y(), finalz, false); + tele_result = true; } AActor *fog1 = NULL, *fog2 = NULL; - if (teleResult) + if (tele_result) { - //If a fog type is defined in the parameter, or the user wants to use the actor's predefined fogs, //and if there's no desire to be fogless, spawn a fog based upon settings. - if (FogType || (Flags & TF_USEACTORFOG)) + if (fog_type || (flags & TF_USEACTORFOG)) { - if (!(Flags & TF_NOSRCFOG)) + if (!(flags & TF_NOSRCFOG)) { - if (Flags & TF_USEACTORFOG) - P_SpawnTeleportFog(ref, prevX, prevY, prevZ, true, true); + if (flags & TF_USEACTORFOG) + P_SpawnTeleportFog(ref, prev, true, true); else { - fog1 = Spawn(FogType, prevX, prevY, prevZ, ALLOW_REPLACE); + fog1 = Spawn(fog_type, prev, ALLOW_REPLACE); if (fog1 != NULL) fog1->target = ref; } } - if (!(Flags & TF_NODESTFOG)) + if (!(flags & TF_NODESTFOG)) { - if (Flags & TF_USEACTORFOG) - P_SpawnTeleportFog(ref, ref->x, ref->y, ref->z, false, true); + if (flags & TF_USEACTORFOG) + P_SpawnTeleportFog(ref, ref->Pos(), false, true); else { - fog2 = Spawn(FogType, ref->x, ref->y, ref->z, ALLOW_REPLACE); + fog2 = Spawn(fog_type, ref->Pos(), ALLOW_REPLACE); if (fog2 != NULL) fog2->target = ref; } } - } - if (Flags & TF_USESPOTZ) - ref->z = spot->z; - else - ref->z = ref->floorz; + ref->SetZ((flags & TF_USESPOTZ) ? spot->Z() : ref->floorz, false); + self->SetZ((flags & TF_USESPOTZ) ? spot->Z() : self->floorz, false); - if (!(Flags & TF_KEEPANGLE)) + if (!(flags & TF_KEEPANGLE)) ref->angle = spot->angle; - if (!(Flags & TF_KEEPVELOCITY)) + if (!(flags & TF_KEEPVELOCITY)) ref->velx = ref->vely = ref->velz = 0; - if (!(Flags & TF_NOJUMP)) //The state jump should only happen with the calling actor. + if (!(flags & TF_NOJUMP)) //The state jump should only happen with the calling actor. { ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - if (TeleportState == NULL) + if (teleport_state == NULL) { // Default to Teleport. - TeleportState = self->FindState("Teleport"); + teleport_state = self->FindState("Teleport"); // If still nothing, then return. - if (!TeleportState) return; + if (teleport_state == NULL) + return; } - ACTION_JUMP(TeleportState); + ACTION_JUMP(teleport_state); return; } } - ACTION_SET_RESULT(teleResult); + ACTION_SET_RESULT(tele_result); } //=========================================================================== @@ -4515,8 +4515,8 @@ void A_Weave(AActor *self, int xyspeed, int zspeed, fixed_t xydist, fixed_t zdis if (xydist != 0 && xyspeed != 0) { dist = MulScale13(finesine[weaveXY << BOBTOFINESHIFT], xydist); - newX = self->x - FixedMul (finecosine[angle], dist); - newY = self->y - FixedMul (finesine[angle], dist); + newX = self->X() - FixedMul (finecosine[angle], dist); + newY = self->Y() - FixedMul (finesine[angle], dist); weaveXY = (weaveXY + xyspeed) & 63; dist = MulScale13(finesine[weaveXY << BOBTOFINESHIFT], xydist); newX += FixedMul (finecosine[angle], dist); @@ -4529,17 +4529,22 @@ void A_Weave(AActor *self, int xyspeed, int zspeed, fixed_t xydist, fixed_t zdis { self->UnlinkFromWorld (); self->flags |= MF_NOBLOCKMAP; - self->x = newX; - self->y = newY; + // the following 4 lines are for future-proofing this for both interpolation overhaul and line portals. + // For portals we need to calculate the destination including the portal offset + // and for interpolation we need to set the performed movement explicitly, because SetXY cannot do that. + newX -= self->X(); + newY -= self->Y(); + self->SetXY(self->Vec2Offset(newX, newY)); + self->SetMovement(newX, newY, 0); self->LinkToWorld (); } self->WeaveIndexXY = weaveXY; } if (zdist != 0 && zspeed != 0) { - self->z -= MulScale13(finesine[weaveZ << BOBTOFINESHIFT], zdist); + self->AddZ(-MulScale13(finesine[weaveZ << BOBTOFINESHIFT], zdist)); weaveZ = (weaveZ + zspeed) & 63; - self->z += MulScale13(finesine[weaveZ << BOBTOFINESHIFT], zdist); + self->AddZ(MulScale13(finesine[weaveZ << BOBTOFINESHIFT], zdist)); self->WeaveIndexZ = weaveZ; } } @@ -4624,14 +4629,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack) // Target can dodge if it can see enemy - angle_t angle = R_PointToAngle2(self->target->x, self->target->y, self->x, self->y) - self->target->angle; + angle_t angle = self->target->AngleTo(self) - self->target->angle; angle >>= 24; bool dodge = (P_CheckSight(self->target, self) && (angle>226 || angle<30)); // Distance check is simplistic - fixed_t dx = abs (self->x - self->target->x); - fixed_t dy = abs (self->y - self->target->y); - fixed_t dz; + fixedvec2 vec = self->Vec2To(self->target); + fixed_t dx = abs (vec.x); + fixed_t dy = abs (vec.y); fixed_t dist = dx > dy ? dx : dy; // Some enemies are more precise @@ -4660,13 +4665,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack) if (pr_cabullet() < hitchance) { // Compute position for spawning blood/puff - dx = self->target->x; - dy = self->target->y; - dz = self->target->z + (self->target->height>>1); - angle = R_PointToAngle2(dx, dy, self->x, self->y); + angle = self->target->AngleTo(self); - dx += FixedMul(self->target->radius, finecosine[angle>>ANGLETOFINESHIFT]); - dy += FixedMul(self->target->radius, finesine[angle>>ANGLETOFINESHIFT]); + fixedvec3 bloodpos = self->target->Vec3Angle(self->target->radius, angle, self->target->height >> 1); + int damage = flags & WAF_NORANDOM ? maxdamage : (1 + (pr_cabullet() % maxdamage)); if (dist >= pointblank) @@ -4687,7 +4689,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack) if ((0 && dpuff->flags3 & MF3_PUFFONACTORS) || !spawnblood) { spawnblood = false; - P_SpawnPuff(self, pufftype, dx, dy, dz, angle, 0); + P_SpawnPuff(self, pufftype, bloodpos, angle, 0); } } else if (self->target->flags3 & MF3_GHOST) @@ -4697,8 +4699,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack) int newdam = P_DamageMobj(self->target, self, self, damage, mod, DMG_THRUSTLESS); if (spawnblood) { - P_SpawnBlood(dx, dy, dz, angle, newdam > 0 ? newdam : damage, self->target); - P_TraceBleed(newdam > 0 ? newdam : damage, self->target, R_PointToAngle2(self->x, self->y, dx, dy), 0); + P_SpawnBlood(bloodpos, angle, newdam > 0 ? newdam : damage, self->target); + P_TraceBleed(newdam > 0 ? newdam : damage, self->target, self->AngleTo(dx, dy, self->target), 0); } } } @@ -4945,7 +4947,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) { amount = 1; } - FBlockThingsIterator it(FBoundingBox(self->x, self->y, distance)); + FBlockThingsIterator it(FBoundingBox(self->X(), self->Y(), distance)); AActor *thing; bool given = false; @@ -5018,11 +5020,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) if (selfPass || monsterPass || corpsePass || killedPass || itemPass || objectPass || missilePass || playerPass || voodooPass) { + fixedvec3 diff = self->Vec3To(thing); + diff.z += (thing->height - self->height) / 2; if (flags & RGF_CUBE) { // check if inside a cube - double dx = fabs((double)(thing->x - self->x)); - double dy = fabs((double)(thing->y - self->y)); - double dz = fabs((double)(thing->z + thing->height / 2) - (self->z + self->height / 2)); + double dx = fabs((double)(diff.x)); + double dy = fabs((double)(diff.y)); + double dz = fabs((double)(diff.z)); double dist = (double)distance; double min = (double)mindist; if ((dx > dist || dy > dist || dz > dist) || (min && (dx < min && dy < min && dz < min))) @@ -5034,9 +5038,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) { // check if inside a sphere double distsquared = double(distance) * double(distance); double minsquared = double(mindist) * double(mindist); - TVector3 tpos(thing->x, thing->y, thing->z + thing->height / 2); - TVector3 spos(self->x, self->y, self->z + self->height / 2); - if ((tpos - spos).LengthSquared() > distsquared || (minsquared && ((tpos - spos).LengthSquared() < minsquared))) + double lengthsquared = TVector3(diff.x, diff.y, diff.z).LengthSquared(); + if (lengthsquared > distsquared || (minsquared && (lengthsquared < minsquared))) { continue; } @@ -5862,9 +5865,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfHigherOrLower) } ACTION_SET_RESULT(false); //No inventory jump chains please. - if ((high) && (mobj->z > ((includeHeight ? self->height : 0) + self->z + offsethigh))) + if ((high) && (mobj->Z() > ((includeHeight ? self->height : 0) + self->Z() + offsethigh))) ACTION_JUMP(high); - else if ((low) && (mobj->z + (includeHeight ? mobj->height : 0)) < (self->z + offsetlow)) + else if ((low) && (mobj->Z() + (includeHeight ? mobj->height : 0)) < (self->Z() + offsetlow)) ACTION_JUMP(low); } @@ -5984,10 +5987,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckProximity) continue; //Make sure it's in range and respect the desire for Z or not. - if (P_AproxDistance(ref->x - mo->x, ref->y - mo->y) < distance && + if (ref->AproxDistance(mo) < distance && ((flags & CPXF_NOZ) || - ((ref->z > mo->z && ref->z - (mo->z + mo->height) < distance) || - (ref->z <= mo->z && mo->z - (ref->z + ref->height) < distance)))) + ((ref->Z() > mo->Z() && ref->Top() < distance) || + (ref->Z() <= mo->Z() && mo->Z() - ref->Top() < distance)))) { if (mo->flags6 & MF6_KILLED) { diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 3746a6ca7..6267ae6d9 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -69,9 +69,9 @@ DEFINE_MEMBER_VARIABLE(special2, AActor) DEFINE_MEMBER_VARIABLE(tid, AActor) DEFINE_MEMBER_VARIABLE(TIDtoHate, AActor) DEFINE_MEMBER_VARIABLE(waterlevel, AActor) -DEFINE_MEMBER_VARIABLE(x, AActor) -DEFINE_MEMBER_VARIABLE(y, AActor) -DEFINE_MEMBER_VARIABLE(z, AActor) +DEFINE_MEMBER_VARIABLE_ALIAS(x, __pos.x, AActor) +DEFINE_MEMBER_VARIABLE_ALIAS(y, __pos.y, AActor) +DEFINE_MEMBER_VARIABLE_ALIAS(z, __pos.z, AActor) DEFINE_MEMBER_VARIABLE(velx, AActor) DEFINE_MEMBER_VARIABLE(vely, AActor) DEFINE_MEMBER_VARIABLE(velz, AActor) diff --git a/src/timidity/common.cpp b/src/timidity/common.cpp index 92d9b009a..57fd26e0c 100644 --- a/src/timidity/common.cpp +++ b/src/timidity/common.cpp @@ -35,82 +35,6 @@ namespace Timidity { -static TArray PathList; - -FString BuildPath(FString base, const char *name) -{ - FString current; - if (base.IsNotEmpty()) - { - current = base; - if (current[current.Len() - 1] != '/') current += '/'; - } - current += name; - return current; -} - -/* This is meant to find and open files for reading. */ -FileReader *open_filereader(const char *name, int open, int *plumpnum) -{ - FileReader *fp; - FString current_filename; - - if (!name || !(*name)) - { - return 0; - } - - /* First try the given name */ - current_filename = name; - FixPathSeperator(current_filename); - - int lumpnum = Wads.CheckNumForFullName(current_filename); - - if (open != OM_FILE) - { - if (lumpnum >= 0) - { - fp = Wads.ReopenLumpNum(lumpnum); - if (plumpnum) *plumpnum = lumpnum; - return fp; - } - if (open == OM_LUMP) // search the path list when not loading the main config - { - for (unsigned int plp = PathList.Size(); plp-- != 0; ) - { /* Try along the path then */ - current_filename = BuildPath(PathList[plp], name); - lumpnum = Wads.CheckNumForFullName(current_filename); - if (lumpnum >= 0) - { - fp = Wads.ReopenLumpNum(lumpnum); - if (plumpnum) *plumpnum = lumpnum; - return fp; - } - } - return NULL; - } - } - if (plumpnum) *plumpnum = -1; - - - fp = new FileReader; - if (fp->Open(current_filename)) return fp; - - if (name[0] != '/') - { - for (unsigned int plp = PathList.Size(); plp-- != 0; ) - { /* Try along the path then */ - current_filename = BuildPath(PathList[plp], name); - if (fp->Open(current_filename)) return fp; - } - } - delete fp; - - /* Nothing could be opened. */ - current_filename = ""; - return NULL; -} - /* This'll allocate memory or die. */ @@ -132,17 +56,5 @@ void *safe_malloc(size_t count) return 0; // Unreachable. } -/* This adds a directory to the path list */ -void add_to_pathlist(const char *s) -{ - FString copy = s; - FixPathSeperator(copy); - PathList.Push(copy); -} - -void clear_pathlist() -{ - PathList.Clear(); -} } diff --git a/src/timidity/instrum.cpp b/src/timidity/instrum.cpp index 7454ca7a4..fa9360267 100644 --- a/src/timidity/instrum.cpp +++ b/src/timidity/instrum.cpp @@ -142,7 +142,7 @@ static void reverse_data(sample_t *sp, int ls, int le) TODO: do reverse loops right */ static Instrument *load_instrument(Renderer *song, const char *name, int percussion, - int panning, int amp, int note_to_use, + int panning, int note_to_use, int strip_loop, int strip_envelope, int strip_tail) { @@ -159,16 +159,16 @@ static Instrument *load_instrument(Renderer *song, const char *name, int percuss if (!name) return 0; /* Open patch file */ - if ((fp = open_filereader(name, openmode, NULL)) == NULL) + if ((fp = pathExpander.openFileReader(name, NULL)) == NULL) { /* Try with various extensions */ FString tmp = name; tmp += ".pat"; - if ((fp = open_filereader(tmp, openmode, NULL)) == NULL) + if ((fp = pathExpander.openFileReader(tmp, NULL)) == NULL) { #ifdef __unix__ // Windows isn't case-sensitive. tmp.ToUpper(); - if ((fp = open_filereader(tmp, openmode, NULL)) == NULL) + if ((fp = pathExpander.openFileReader(tmp, NULL)) == NULL) #endif { noluck = true; @@ -372,7 +372,6 @@ fail: { sp->modes &= ~(PATCH_SUSTAIN | PATCH_LOOPEN | PATCH_BIDIR | PATCH_BACKWARD); } - sp->modes |= PATCH_T_NO_LOOP; } if (strip_envelope == 1) @@ -398,37 +397,6 @@ fail: patch_data.EnvelopeOffset[k] = patch_data.EnvelopeOffset[0]; } } - sp->modes |= PATCH_T_NO_ENVELOPE; - } - else if (strip_envelope != 0) - { - /* Have to make a guess. */ - if (!(sp->modes & (PATCH_LOOPEN | PATCH_BIDIR | PATCH_BACKWARD))) - { - /* No loop? Then what's there to sustain? No envelope needed either... */ - sp->modes |= PATCH_T_NO_ENVELOPE; - cmsg(CMSG_INFO, VERB_DEBUG, " - No loop, removing sustain and envelope\n"); - } - else if (memcmp(patch_data.EnvelopeRate, "??????", 6) == 0 || patch_data.EnvelopeOffset[GF1_RELEASEC] >= 100) - { - /* Envelope rates all maxed out? Envelope end at a high "offset"? - That's a weird envelope. Take it out. */ - sp->modes |= PATCH_T_NO_ENVELOPE; - cmsg(CMSG_INFO, VERB_DEBUG, " - Weirdness, removing envelope\n"); - } - else if (!(sp->modes & PATCH_SUSTAIN)) - { - /* No sustain? Then no envelope. I don't know if this is - justified, but patches without sustain usually don't need the - envelope either... at least the Gravis ones. They're mostly - drums. I think. */ - sp->modes |= PATCH_T_NO_ENVELOPE; - cmsg(CMSG_INFO, VERB_DEBUG, " - No sustain, removing envelope\n"); - } - } - if (!(sp->modes & PATCH_NO_SRELEASE)) - { // TiMidity thinks that this is an envelope enable flag. - sp->modes |= PATCH_T_NO_ENVELOPE; } for (j = 0; j < 6; j++) @@ -470,29 +438,6 @@ fail: sp->modes |= PATCH_LOOPEN; /* just in case */ } - if (amp != -1) - { - sp->volume = (amp) / 100.f; - } - else - { - /* Try to determine a volume scaling factor for the sample. - This is a very crude adjustment, but things sound more - balanced with it. Still, this should be a runtime option. - (This is ignored unless midi_timiditylike is turned on.) */ - int i; - sample_t maxamp = 0, a; - sample_t *tmp; - for (i = sp->data_length, tmp = sp->data; i; --i) - { - a = fabsf(*tmp++); - if (a > maxamp) - maxamp = a; - } - sp->volume = 1 / maxamp; - cmsg(CMSG_INFO, VERB_DEBUG, " * volume comp: %f\n", sp->volume); - } - /* Then fractional samples */ sp->data_length <<= FRACTION_BITS; sp->loop_start <<= FRACTION_BITS; @@ -653,7 +598,6 @@ static int fill_bank(Renderer *song, int dr, int b) ip = load_instrument(song, bank->tone[i].name, (dr) ? 1 : 0, bank->tone[i].pan, - bank->tone[i].amp, (bank->tone[i].note != -1) ? bank->tone[i].note : ((dr) ? i : -1), (bank->tone[i].strip_loop != -1) ? bank->tone[i].strip_loop : ((dr) ? 1 : -1), (bank->tone[i].strip_envelope != -1) ? bank->tone[i].strip_envelope : ((dr) ? 1 : -1), @@ -731,7 +675,7 @@ void free_instruments() int Renderer::set_default_instrument(const char *name) { Instrument *ip; - if ((ip = load_instrument(this, name, 0, -1, -1, -1, 0, 0, 0)) == NULL) + if ((ip = load_instrument(this, name, 0, -1, -1, 0, 0, 0)) == NULL) { return -1; } diff --git a/src/timidity/instrum_dls.cpp b/src/timidity/instrum_dls.cpp index fe5e4fdcd..02b8e59c0 100644 --- a/src/timidity/instrum_dls.cpp +++ b/src/timidity/instrum_dls.cpp @@ -1126,7 +1126,7 @@ static void load_region_dls(Renderer *song, Sample *sample, DLS_Instrument *ins, sample->key_group = (SBYTE)rgn->header->usKeyGroup; sample->low_freq = note_to_freq(rgn->header->RangeKey.usLow); sample->high_freq = note_to_freq(rgn->header->RangeKey.usHigh); - sample->root_freq = note_to_freq(rgn->wsmp->usUnityNote); + sample->root_freq = note_to_freq(rgn->wsmp->usUnityNote + rgn->wsmp->sFineTune * .01f); sample->low_vel = (BYTE)rgn->header->RangeVelocity.usLow; sample->high_vel = (BYTE)rgn->header->RangeVelocity.usHigh; @@ -1137,16 +1137,17 @@ static void load_region_dls(Renderer *song, Sample *sample, DLS_Instrument *ins, convert_sample_data(sample, wave->data); if (rgn->wsmp->cSampleLoops) { - sample->modes |= (PATCH_LOOPEN | PATCH_SUSTAIN); + sample->modes |= (PATCH_LOOPEN | PATCH_SUSTAIN/* | PATCH_NO_SRELEASE*/); sample->loop_start = rgn->wsmp_loop->ulStart / 2; sample->loop_end = sample->loop_start + (rgn->wsmp_loop->ulLength / 2); } - sample->volume = 1.0f; + sample->scale_factor = 1024; + sample->scale_note = rgn->wsmp->usUnityNote; if (sample->modes & PATCH_SUSTAIN) { int value; - double attack, hold, decay, release; int sustain; + int attack, hold, decay, release; int sustain; CONNECTIONLIST *art = NULL; CONNECTION *artList = NULL; @@ -1158,16 +1159,11 @@ static void load_region_dls(Renderer *song, Sample *sample, DLS_Instrument *ins, artList = rgn->artList; } - value = load_connection(art->cConnections, artList, CONN_DST_EG1_ATTACKTIME); - attack = to_msec(value); - value = load_connection(art->cConnections, artList, CONN_DST_EG1_HOLDTIME); - hold = to_msec(value); - value = load_connection(art->cConnections, artList, CONN_DST_EG1_DECAYTIME); - decay = to_msec(value); - value = load_connection(art->cConnections, artList, CONN_DST_EG1_RELEASETIME); - release = to_msec(value); - value = load_connection(art->cConnections, artList, CONN_DST_EG1_SUSTAINLEVEL); - sustain = (int)((1.0 - to_normalized_percent(value)) * 250.0); + attack = load_connection(art->cConnections, artList, CONN_DST_EG1_ATTACKTIME); + hold = load_connection(art->cConnections, artList, CONN_DST_EG1_HOLDTIME); + decay = load_connection(art->cConnections, artList, CONN_DST_EG1_DECAYTIME); + release = load_connection(art->cConnections, artList, CONN_DST_EG1_RELEASETIME); + sustain = load_connection(art->cConnections, artList, CONN_DST_EG1_SUSTAINLEVEL); value = load_connection(art->cConnections, artList, CONN_DST_PAN); sample->panning = (int)((0.5 + to_normalized_percent(value)) * 16383.f); @@ -1175,12 +1171,12 @@ static void load_region_dls(Renderer *song, Sample *sample, DLS_Instrument *ins, printf("%d, Rate=%d LV=%d HV=%d Low=%d Hi=%d Root=%d Pan=%d Attack=%f Hold=%f Sustain=%d Decay=%f Release=%f\n", index, sample->sample_rate, rgn->header->RangeVelocity.usLow, rgn->header->RangeVelocity.usHigh, sample->low_freq, sample->high_freq, sample->root_freq, sample->panning, attack, hold, sustain, decay, release); */ - sample->envelope.sf2.decay_vol = 0; - sample->envelope.sf2.attack_vol = (short)attack; - sample->envelope.sf2.hold_vol = (short)hold; - sample->envelope.sf2.decay_vol = (short)decay; - sample->envelope.sf2.release_vol = (short)release; - sample->envelope.sf2.sustain_vol = (short)sustain; + sample->envelope.sf2.delay_vol = -32768; + sample->envelope.sf2.attack_vol = (short)(attack >> 16); + sample->envelope.sf2.hold_vol = (short)(hold >> 16); + sample->envelope.sf2.decay_vol = (short)(decay >> 16); + sample->envelope.sf2.release_vol = (short)(release >> 16); + sample->envelope.sf2.sustain_vol = (short)(sustain >> 16); } sample->data_length <<= FRACTION_BITS; diff --git a/src/timidity/instrum_font.cpp b/src/timidity/instrum_font.cpp index 995558bd4..069eb9c84 100644 --- a/src/timidity/instrum_font.cpp +++ b/src/timidity/instrum_font.cpp @@ -54,7 +54,7 @@ void font_add(const char *filename, int load_order) } else { - FileReader *fp = open_filereader(filename, openmode, NULL); + FileReader *fp = pathExpander.openFileReader(filename, NULL); if (fp != NULL) { diff --git a/src/timidity/instrum_sf2.cpp b/src/timidity/instrum_sf2.cpp index dae330644..01576e64c 100644 --- a/src/timidity/instrum_sf2.cpp +++ b/src/timidity/instrum_sf2.cpp @@ -1441,7 +1441,6 @@ void SFFile::ApplyGeneratorsToRegion(SFGenComposite *gen, SFSample *sfsamp, Rend sp->root_freq = note_to_freq(sp->scale_note); sp->sample_rate = sfsamp->SampleRate; sp->key_group = gen->exclusiveClass; - sp->volume = 1; // Set key scaling if (gen->keynum >= 0 && gen->keynum <= 127) @@ -1502,7 +1501,7 @@ void SFFile::ApplyGeneratorsToRegion(SFGenComposite *gen, SFSample *sfsamp, Rend void SFFile::LoadSample(SFSample *sample) { - FileReader *fp = open_filereader(Filename, openmode, NULL); + FileReader *fp = pathExpander.openFileReader(Filename, NULL); DWORD i; if (fp == NULL) diff --git a/src/timidity/mix.cpp b/src/timidity/mix.cpp index b4fc0f818..beda91e16 100644 --- a/src/timidity/mix.cpp +++ b/src/timidity/mix.cpp @@ -29,8 +29,6 @@ #include "templates.h" #include "c_cvars.h" -EXTERN_CVAR(Bool, midi_timiditylike) - namespace Timidity { @@ -78,16 +76,7 @@ void GF1Envelope::Init(Renderer *song, Voice *v) void GF1Envelope::Release(Voice *v) { - if (midi_timiditylike) - { - if (!(v->sample->modes & PATCH_T_NO_ENVELOPE)) - { - stage = GF1_RELEASE; - Recompute(v); - } - // else ... loop was already turned off by the caller - } - else if (!(v->sample->modes & PATCH_NO_SRELEASE) || (v->sample->modes & PATCH_FAST_REL)) + if (!(v->sample->modes & PATCH_NO_SRELEASE) || (v->sample->modes & PATCH_FAST_REL)) { /* ramp out to minimum volume with rate from final release stage */ stage = GF1_RELEASEC+1; @@ -119,23 +108,11 @@ bool GF1Envelope::Recompute(Voice *v) bUpdating = false; v->status &= ~(VOICE_SUSTAINING | VOICE_LPE); v->status |= VOICE_RELEASING; - if (midi_timiditylike) - { /* kill the voice ... or not */ - if (volume <= 0) - { - v->status |= VOICE_STOPPING; - } - return 1; - } - else - { /* play sampled release */ - } + /* play sampled release */ return 0; } - if (newstage == GF1_RELEASE && !(v->status & VOICE_RELEASING) && - ((!midi_timiditylike && (v->sample->modes & PATCH_SUSTAIN)) || - (midi_timiditylike && !(v->sample->modes & PATCH_T_NO_ENVELOPE)))) + if (newstage == GF1_RELEASE && !(v->status & VOICE_RELEASING) && (v->sample->modes & PATCH_SUSTAIN)) { v->status |= VOICE_SUSTAINING; /* Freeze envelope until note turns off. Trumpets want this. */ @@ -161,10 +138,6 @@ bool GF1Envelope::Recompute(Voice *v) bool GF1Envelope::Update(Voice *v) { - if (midi_timiditylike && (v->sample->modes & PATCH_T_NO_ENVELOPE)) - { - return 0; - } volume += increment; if (((increment < 0) && (volume <= target)) || ((increment > 0) && (volume >= target))) { @@ -182,36 +155,14 @@ void GF1Envelope::ApplyToAmp(Voice *v) double env_vol = v->attenuation; double final_amp; - if (midi_timiditylike) - { - final_amp = v->sample->volume * FINAL_MIX_TIMIDITY_SCALE; - if (v->tremolo_phase_increment != 0) - { - env_vol *= v->tremolo_volume; - } - if (!(v->sample->modes & PATCH_T_NO_ENVELOPE)) - { - if (stage > GF1_ATTACK) - { - env_vol *= pow(2.0, volume * (6.0 / (1 << 30)) - 6.0); - } - else - { - env_vol *= volume / float(1 << 30); - } - } - } - else - { - final_amp = FINAL_MIX_SCALE; - if (v->tremolo_phase_increment != 0) - { // [RH] FIXME: This is wrong. Tremolo should offset the - // envelope volume, not scale it. - env_vol *= v->tremolo_volume; - } - env_vol *= volume / float(1 << 30); - env_vol = calc_gf1_amp(env_vol); + final_amp = FINAL_MIX_SCALE; + if (v->tremolo_phase_increment != 0) + { // [RH] FIXME: This is wrong. Tremolo should offset the + // envelope volume, not scale it. + env_vol *= v->tremolo_volume; } + env_vol *= volume / float(1 << 30); + env_vol = calc_gf1_amp(env_vol); env_vol *= final_amp; v->left_mix = float(env_vol * v->left_offset); v->right_mix = float(env_vol * v->right_offset); @@ -280,6 +231,10 @@ bool SF2Envelope::Update(Voice *v) double sec; double newvolume = 0; + // NOTE! The volume scale is different for different stages of the + // envelope generator: + // Attack stage goes from 0.0 -> 1.0, multiplied directly to the output. + // The following stages go from 0 -> -1000 cB (but recorded positively) switch (stage) { case SF2_DELAY: @@ -382,6 +337,11 @@ bool SF2Envelope::Update(Voice *v) #define FLUID_ATTEN_POWER_FACTOR (-531.509) #define atten2amp(x) pow(10.0, (x) / FLUID_ATTEN_POWER_FACTOR) +static double cb_to_amp(double x) // centibels to amp +{ + return pow(10, x / -200.f); +} + void SF2Envelope::ApplyToAmp(Voice *v) { double amp; @@ -392,13 +352,21 @@ void SF2Envelope::ApplyToAmp(Voice *v) v->right_mix = 0; return; } - else if (stage == SF2_ATTACK) + + amp = v->sample->type == INST_SF2 ? atten2amp(v->attenuation) : cb_to_amp(v->attenuation); + + switch (stage) { - amp = atten2amp(v->attenuation) * volume; - } - else - { - amp = atten2amp(v->attenuation) * cb_to_amp(volume); + case SF2_ATTACK: + amp *= volume; + break; + + case SF2_HOLD: + break; + + default: + amp *= cb_to_amp(volume); + break; } amp *= FINAL_MIX_SCALE * 0.5; v->left_mix = float(amp * v->left_offset); diff --git a/src/timidity/playmidi.cpp b/src/timidity/playmidi.cpp index 5db4f61bc..7d8294384 100644 --- a/src/timidity/playmidi.cpp +++ b/src/timidity/playmidi.cpp @@ -29,8 +29,6 @@ #include "timidity.h" #include "c_cvars.h" -EXTERN_CVAR(Bool, midi_timiditylike) - namespace Timidity { @@ -118,7 +116,7 @@ void Renderer::recompute_freq(int v) voice[v].sample_increment = (int)(a); } -static BYTE vol_table[] = { +static const BYTE vol_table[] = { 000 /* 000 */, 129 /* 001 */, 145 /* 002 */, 155 /* 003 */, 161 /* 004 */, 166 /* 005 */, 171 /* 006 */, 174 /* 007 */, 177 /* 008 */, 180 /* 009 */, 182 /* 010 */, 185 /* 011 */, @@ -161,16 +159,7 @@ void Renderer::recompute_amp(Voice *v) if (v->sample->type == INST_GUS) { - if (midi_timiditylike) - { - v->attenuation = float(timidityxx_perceived_vol(v->velocity / 127.0) * - timidityxx_perceived_vol(chanvol / 127.0) * - timidityxx_perceived_vol(chanexpr / 127.0)); - } - else - { - v->attenuation = (vol_table[(chanvol * chanexpr) / 127] * vol_table[v->velocity]) * ((127 + 64) / 12419775.f); - } + v->attenuation = (vol_table[(chanvol * chanexpr) / 127] * vol_table[v->velocity]) * ((127 + 64) / 12419775.f); } else { @@ -199,7 +188,7 @@ void Renderer::compute_pan(double pan, int type, float &left_offset, float &righ } else { - if (type == INST_GUS && !midi_timiditylike) + if (type == INST_GUS) { /* Original amp equation looks like this: * calc_gf1_amp(atten + offset) @@ -218,9 +207,7 @@ void Renderer::compute_pan(double pan, int type, float &left_offset, float &righ } else { - /* I have no idea what equation, if any, will reproduce the sc_pan_table - * that TiMidity++ uses, so midi_timiditylike gets the same Equal Power - * Panning as SF2/DLS. + /* Equal Power Panning for SF2/DLS. */ left_offset = (float)sqrt(1 - pan); right_offset = (float)sqrt(pan); @@ -561,7 +548,7 @@ void Renderer::finish_note(int i) v->status &= ~VOICE_SUSTAINING; v->status |= VOICE_RELEASING; - if (!(v->sample->modes & PATCH_NO_SRELEASE) || midi_timiditylike) + if (!(v->sample->modes & PATCH_NO_SRELEASE)) { v->status &= ~VOICE_LPE; /* sampled release */ } diff --git a/src/timidity/resample.cpp b/src/timidity/resample.cpp index 0ee6aa856..6b9bdb9f5 100644 --- a/src/timidity/resample.cpp +++ b/src/timidity/resample.cpp @@ -28,8 +28,6 @@ #include "timidity.h" #include "c_cvars.h" -EXTERN_CVAR(Bool, midi_timiditylike) - namespace Timidity { @@ -522,7 +520,7 @@ sample_t *resample_voice(Renderer *song, Voice *vp, int *countptr) if (vp->vibrato_control_ratio) { - if (vp->status & VOICE_LPE && !(midi_timiditylike && vp->sample->modes & PATCH_T_NO_LOOP)) + if (vp->status & VOICE_LPE) { if (modes & PATCH_BIDIR) return rs_vib_bidir(song->resample_buffer, song->rate, vp, *countptr); @@ -536,7 +534,7 @@ sample_t *resample_voice(Renderer *song, Voice *vp, int *countptr) } else { - if (vp->status & VOICE_LPE && !(midi_timiditylike && vp->sample->modes & PATCH_T_NO_LOOP)) + if (vp->status & VOICE_LPE) { if (modes & PATCH_BIDIR) return rs_bidir(song->resample_buffer, vp, *countptr); diff --git a/src/timidity/timidity.cpp b/src/timidity/timidity.cpp index 0f0fcdeb5..267edbb7e 100644 --- a/src/timidity/timidity.cpp +++ b/src/timidity/timidity.cpp @@ -34,7 +34,6 @@ CVAR(String, midi_config, CONFIG_FILE, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(Int, midi_voices, 32, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR(Bool, midi_timiditylike, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(String, gus_patchdir, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(Bool, midi_dmxgus, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(Int, gus_memsize, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) @@ -42,10 +41,10 @@ CVAR(Int, gus_memsize, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) namespace Timidity { +PathExpander pathExpander; ToneBank *tonebank[MAXBANK], *drumset[MAXBANK]; static FString def_instr_name; -int openmode = OM_FILEORLUMP; static int read_config_file(const char *name, bool ismain) { @@ -62,21 +61,21 @@ static int read_config_file(const char *name, bool ismain) return (-1); } - if (ismain) openmode = OM_FILEORLUMP; + if (ismain) pathExpander.openmode = PathExpander::OM_FILEORLUMP; - if (!(fp = open_filereader(name, openmode, &lumpnum))) + if (!(fp = pathExpander.openFileReader(name, &lumpnum))) return -1; if (ismain) { if (lumpnum > 0) { - openmode = OM_LUMP; - clear_pathlist(); // when reading from a PK3 we won't want to use any external path + pathExpander.openmode = PathExpander::OM_LUMP; + pathExpander.clearPathlist(); // when reading from a PK3 we don't want to use any external path } else { - openmode = OM_FILE; + pathExpander.openmode = PathExpander::OM_FILE; } } @@ -288,7 +287,7 @@ static int read_config_file(const char *name, bool ismain) return -2; } for (i = 1; i < words; i++) - add_to_pathlist(w[i]); + pathExpander.addToPathlist(w[i]); } else if (!strcmp(w[0], "source")) { @@ -377,7 +376,7 @@ static int read_config_file(const char *name, bool ismain) delete fp; return -2; } - bank->tone[i].note = bank->tone[i].amp = bank->tone[i].pan = + bank->tone[i].note = bank->tone[i].pan = bank->tone[i].fontbank = bank->tone[i].fontpreset = bank->tone[i].fontnote = bank->tone[i].strip_loop = bank->tone[i].strip_envelope = bank->tone[i].strip_tail = -1; @@ -415,14 +414,7 @@ static int read_config_file(const char *name, bool ismain) *cp++ = 0; if (!strcmp(w[j], "amp")) { - k = atoi(cp); - if ((k < 0 || k > MAX_AMPLIFICATION) || (*cp < '0' || *cp > '9')) - { - Printf("%s: line %d: amplification must be between 0 and %d\n", name, line, MAX_AMPLIFICATION); - delete fp; - return -2; - } - bank->tone[i].amp = k; + /* Ignored */ } else if (!strcmp(w[j], "note")) { @@ -532,15 +524,15 @@ int LoadConfig(const char *filename) * file itself since that file should contain any other directory * that needs to be added to the search path. */ - clear_pathlist(); + pathExpander.clearPathlist(); #ifdef _WIN32 - add_to_pathlist("C:\\TIMIDITY"); - add_to_pathlist("\\TIMIDITY"); - add_to_pathlist(progdir); + pathExpander.addToPathlist("C:\\TIMIDITY"); + pathExpander.addToPathlist("\\TIMIDITY"); + pathExpander.addToPathlist(progdir); #else - add_to_pathlist("/usr/local/lib/timidity"); - add_to_pathlist("/etc/timidity"); - add_to_pathlist("/etc"); + pathExpander.addToPathlist("/usr/local/lib/timidity"); + pathExpander.addToPathlist("/etc/timidity"); + pathExpander.addToPathlist("/etc"); #endif /* Some functions get aggravated if not even the standard banks are available. */ @@ -579,10 +571,10 @@ int LoadDMXGUS() if (ultradir.IsNotEmpty()) { ultradir += "/midi"; - add_to_pathlist(ultradir.GetChars()); + pathExpander.addToPathlist(ultradir.GetChars()); } // Load DMXGUS lump and patches from gus_patchdir - add_to_pathlist(gus_patchdir); + pathExpander.addToPathlist(gus_patchdir); char readbuffer[1024]; long size = data.GetLength(); @@ -676,7 +668,7 @@ int LoadDMXGUS() continue; int val = k % 128; - bank->tone[val].note = bank->tone[val].amp = bank->tone[val].pan = + bank->tone[val].note = bank->tone[val].pan = bank->tone[val].fontbank = bank->tone[val].fontpreset = bank->tone[val].fontnote = bank->tone[val].strip_loop = bank->tone[val].strip_envelope = bank->tone[val].strip_tail = -1; @@ -686,8 +678,12 @@ int LoadDMXGUS() return 0; } -Renderer::Renderer(float sample_rate) +DLS_Data *LoadDLS(FILE *src); +void FreeDLS(DLS_Data *data); + +Renderer::Renderer(float sample_rate, const char *args) { + // 'args' should be used to load a custom config or DMXGUS, but since setup currently requires a snd_reset call, this will need some refactoring first rate = sample_rate; patches = NULL; resample_buffer_size = 0; @@ -705,9 +701,14 @@ Renderer::Renderer(float sample_rate) if (def_instr_name.IsNotEmpty()) set_default_instrument(def_instr_name); - voices = clamp(midi_voices, 16, 256); + voices = MAX(*midi_voices, 16); voice = new Voice[voices]; drumchannels = DEFAULT_DRUMCHANNELS; +#if 0 + FILE *f = fopen("c:\\windows\\system32\\drivers\\gm.dls", "rb"); + patches = LoadDLS(f); + fclose(f); +#endif } Renderer::~Renderer() @@ -720,6 +721,10 @@ Renderer::~Renderer() { delete[] voice; } + if (patches != NULL) + { + FreeDLS(patches); + } } void Renderer::ComputeOutput(float *buffer, int count) diff --git a/src/timidity/timidity.h b/src/timidity/timidity.h index 6c46317dd..ac423c1e2 100644 --- a/src/timidity/timidity.h +++ b/src/timidity/timidity.h @@ -21,6 +21,7 @@ #define TIMIDITY_H #include "doomtype.h" +#include "pathexpander.h" class FileReader; @@ -54,10 +55,6 @@ config.h volume level of FMOD's built-in MIDI player. */ #define FINAL_MIX_SCALE 0.5 -/* This value is used instead when midi_timiditylike is turned on, - because TiMidity++ is louder than a GUS. */ -#define FINAL_MIX_TIMIDITY_SCALE 0.3 - /* How many bits to use for the fractional part of sample positions. This affects tonal accuracy. The entire position counter must fit in 32 bits, so with FRACTION_BITS equal to 12, the maximum size of @@ -172,17 +169,8 @@ extern __inline__ double pow_x87_inline(double x,double y) common.h */ -#define OM_FILEORLUMP 0 -#define OM_LUMP 1 -#define OM_FILE 2 - -extern void add_to_pathlist(const char *s); -extern void clear_pathlist(); extern void *safe_malloc(size_t count); -FileReader *open_filereader(const char *name, int open, int *plumpnum); -extern int openmode; - /* controls.h */ @@ -219,9 +207,6 @@ enum PATCH_SUSTAIN = (1<<5), PATCH_NO_SRELEASE = (1<<6), PATCH_FAST_REL = (1<<7), - - PATCH_T_NO_ENVELOPE = (1<<8), - PATCH_T_NO_LOOP = (1<<9) }; struct Sample @@ -247,8 +232,6 @@ struct Sample short release_vol; } sf2; } envelope; - float - volume; sample_t *data; SDWORD tremolo_sweep_increment, tremolo_phase_increment, @@ -324,11 +307,12 @@ struct Instrument struct ToneBankElement { ToneBankElement() : - note(0), amp(0), pan(0), strip_loop(0), strip_envelope(0), strip_tail(0) + note(0), pan(0), strip_loop(0), strip_envelope(0), strip_tail(0) {} FString name; - int note, amp, pan, fontbank, fontpreset, fontnote, strip_loop, strip_envelope, strip_tail; + int note, pan, fontbank, fontpreset, fontnote; + SBYTE strip_loop, strip_envelope, strip_tail; }; /* A hack to delay instrument loading until after reading the entire MIDI file. */ @@ -461,7 +445,7 @@ struct Channel struct MinEnvelope { - int stage; + BYTE stage; BYTE bUpdating; }; @@ -615,9 +599,6 @@ const double log_of_2 = 0.69314718055994529; #define freq_to_note(x) (log((x) / 8175.7989473096690661233836992789) * (12.0 / log_of_2)) #define calc_gf1_amp(x) (pow(2.0,((x)*16.0 - 16.0))) // Actual GUS equation -#define cb_to_amp(x) (pow(10.0, (x) * (1 / -200.0))) // centibels to amp -#define db_to_amp(x) (pow(10.0, (x) * (1 / -20.0))) // decibels to map -#define timidityxx_perceived_vol(x) (pow((x), 1.66096404744)) /* timidity.h @@ -627,6 +608,7 @@ int LoadConfig(const char *filename); int LoadDMXGUS(); extern int LoadConfig(); extern void FreeAll(); +extern PathExpander pathExpander; extern ToneBank *tonebank[MAXBANK]; extern ToneBank *drumset[MAXBANK]; @@ -647,7 +629,7 @@ struct Renderer int voices; int lost_notes, cut_notes; - Renderer(float sample_rate); + Renderer(float sample_rate, const char *args); ~Renderer(); void HandleEvent(int status, int parm1, int parm2); diff --git a/src/version.h b/src/version.h index 168cb7519..b8c4facb0 100644 --- a/src/version.h +++ b/src/version.h @@ -76,7 +76,7 @@ const char *GetVersionString(); // Use 4500 as the base git save version, since it's higher than the // SVN revision ever got. -#define SAVEVER 4525 +#define SAVEVER 4531 #define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) diff --git a/src/w_wad.cpp b/src/w_wad.cpp index efeb38571..42e5c17b9 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -184,6 +184,7 @@ void FWadCollection::InitMultipleFiles (TArray &filenames) } RenameNerve(); RenameSprites(); + FixMacHexen(); // [RH] Set up hash table FirstLumpIndex = new DWORD[NumLumps]; @@ -956,6 +957,72 @@ void FWadCollection::RenameNerve () } } +//========================================================================== +// +// FixMacHexen +// +// Discard all extra lumps in Mac version of Hexen IWAD (demo or full) +// to avoid any issues caused by names of these lumps, including: +// * Wrong height of small font +// * Broken life bar of mage class +// +//========================================================================== + +void FWadCollection::FixMacHexen() +{ + if (GAME_Hexen != gameinfo.gametype) + { + return; + } + + FileReader* const reader = GetFileReader(IWAD_FILENUM); + const long iwadSize = reader->GetLength(); + + static const long DEMO_SIZE = 13596228; + static const long FULL_SIZE = 21078584; + + if ( DEMO_SIZE != iwadSize + && FULL_SIZE != iwadSize) + { + return; + } + + reader->Seek(0, SEEK_SET); + + BYTE checksum[16]; + MD5Context md5; + md5.Update(reader, iwadSize); + md5.Final(checksum); + + static const BYTE HEXEN_DEMO_MD5[16] = + { + 0x92, 0x5f, 0x9f, 0x50, 0x00, 0xe1, 0x7d, 0xc8, + 0x4b, 0x0a, 0x6a, 0x3b, 0xed, 0x3a, 0x6f, 0x31 + }; + + static const BYTE HEXEN_FULL_MD5[16] = + { + 0xb6, 0x81, 0x40, 0xa7, 0x96, 0xf6, 0xfd, 0x7f, + 0x3a, 0x5d, 0x32, 0x26, 0xa3, 0x2b, 0x93, 0xbe + }; + + if ( 0 != memcmp(HEXEN_DEMO_MD5, checksum, sizeof checksum) + && 0 != memcmp(HEXEN_FULL_MD5, checksum, sizeof checksum)) + { + return; + } + + static const int EXTRA_LUMPS = 299; + + const int lastLump = GetLastLump(IWAD_FILENUM); + assert(GetFirstLump(IWAD_FILENUM) + 299 < lastLump); + + for (int i = lastLump - EXTRA_LUMPS + 1; i <= lastLump; ++i) + { + LumpInfo[i].lump->Name[0] = '\0'; + } +} + //========================================================================== // // W_FindLump diff --git a/src/w_wad.h b/src/w_wad.h index 323f12df2..dcac6a1b2 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -238,6 +238,7 @@ protected: private: void RenameSprites(); void RenameNerve(); + void FixMacHexen(); void DeleteAll(); }; diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index 653f6b907..e931b33fd 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -1228,7 +1228,7 @@ void WI_initDeathmatchStats (void) acceleratestage = 0; memset(playerready, 0, sizeof(playerready)); memset(cnt_frags, 0, sizeof(cnt_frags)); - memset(cnt_deaths, 0, sizeof(cnt_frags)); + memset(cnt_deaths, 0, sizeof(cnt_deaths)); memset(player_deaths, 0, sizeof(player_deaths)); total_frags = 0; total_deaths = 0; diff --git a/src/wi_stuff.h b/src/wi_stuff.h index dee36e736..a594d17af 100644 --- a/src/wi_stuff.h +++ b/src/wi_stuff.h @@ -33,7 +33,7 @@ class FTexture; struct wbplayerstruct_t { bool in; // whether the player is in game - + // Player stats, kills, collected items etc. int skills; int sitems; @@ -41,7 +41,6 @@ struct wbplayerstruct_t int stime; int frags[MAXPLAYERS]; int fragcount; // [RH] Cumulative frags for this player - }; struct wbstartstruct_t @@ -54,7 +53,7 @@ struct wbstartstruct_t FTexture *LName0; FTexture *LName1; - + int maxkills; int maxitems; int maxsecret; @@ -63,19 +62,19 @@ struct wbstartstruct_t // the par time and sucktime int partime; // in tics int sucktime; // in minutes - + // total time for the entire current game int totaltime; // index of this player in game - int pnum; + int pnum; wbplayerstruct_t plyr[MAXPLAYERS]; }; // Intermission stats. // Parameters for world map / intermission. -extern wbstartstruct_t wminfo; +extern wbstartstruct_t wminfo; // Called by main loop, animate the intermission. diff --git a/src/wildmidi/common.h b/src/wildmidi/common.h new file mode 100644 index 000000000..a089329e0 --- /dev/null +++ b/src/wildmidi/common.h @@ -0,0 +1,94 @@ +/* + common.h + + Midi Wavetable Processing library + + Copyright (C) Chris Ison 2001-2011 + Copyright (C) Bret Curtis 2013-2014 + + This file is part of WildMIDI. + + WildMIDI is free software: you can redistribute and/or modify the player + under the terms of the GNU General Public License and you can redistribute + and/or modify the library under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, either version 3 of + the licenses, or(at your option) any later version. + + WildMIDI 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 and + the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License and the + GNU Lesser General Public License along with WildMIDI. If not, see + . +*/ + +#ifndef __COMMON_H +#define __COMMON_H + +#define SAMPLE_16BIT 0x01 +#define SAMPLE_UNSIGNED 0x02 +#define SAMPLE_LOOP 0x04 +#define SAMPLE_PINGPONG 0x08 +#define SAMPLE_REVERSE 0x10 +#define SAMPLE_SUSTAIN 0x20 +#define SAMPLE_ENVELOPE 0x40 +#define SAMPLE_CLAMPED 0x80 + +#ifdef DEBUG_SAMPLES +#define SAMPLE_CONVERT_DEBUG(dx) printf("\r%s\n",dx) +#else +#define SAMPLE_CONVERT_DEBUG(dx) +#endif + +extern unsigned short int _WM_SampleRate; + +struct _sample { + unsigned int data_length; + unsigned int loop_start; + unsigned int loop_end; + unsigned int loop_size; + unsigned char loop_fraction; + unsigned short rate; + unsigned int freq_low; + unsigned int freq_high; + unsigned int freq_root; + unsigned char modes; + signed int env_rate[7]; + signed int env_target[7]; + unsigned int inc_div; + signed short *data; + struct _sample *next; +}; + +struct _env { + float time; + float level; + unsigned char set; +}; + +struct _patch { + unsigned short patchid; + unsigned char loaded; + char *filename; + signed short int amp; + unsigned char keep; + unsigned char remove; + struct _env env[6]; + unsigned char note; + unsigned long int inuse_count; + struct _sample *first_sample; + struct _patch *next; +}; + +/* Set our global defines here */ +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 +#endif + +#endif /* __COMMON_H */ diff --git a/src/wildmidi/file_io.cpp b/src/wildmidi/file_io.cpp new file mode 100644 index 000000000..be34b4622 --- /dev/null +++ b/src/wildmidi/file_io.cpp @@ -0,0 +1,112 @@ +/* +** file_io.cpp +** ZDoom compatible file IO interface for WildMIDI +** (This file was completely redone to remove the low level IO code references) +** +**--------------------------------------------------------------------------- +** Copyright 2010 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include + +#include "../files.h" +#include "wm_error.h" +#include "file_io.h" +#include "pathexpander.h" +#include "cmdlib.h" + +static PathExpander wmPathExpander; + +unsigned char *_WM_BufferFile(const char *filename, unsigned long int *size, bool ismain) +{ + FileReader *fp; + int lumpnum; + + if (ismain) + { + wmPathExpander.openmode = PathExpander::OM_FILEORLUMP; + wmPathExpander.clearPathlist(); +#ifdef _WIN32 + wmPathExpander.addToPathlist("C:\\TIMIDITY"); + wmPathExpander.addToPathlist("\\TIMIDITY"); + wmPathExpander.addToPathlist(progdir); +#else + wmPathExpander.addToPathlist("/usr/local/lib/timidity"); + wmPathExpander.addToPathlist("/etc/timidity"); + wmPathExpander.addToPathlist("/etc"); +#endif + } + + if (!(fp = wmPathExpander.openFileReader(filename, &lumpnum))) + return NULL; + + if (ismain) + { + if (lumpnum > 0) + { + wmPathExpander.openmode = PathExpander::OM_LUMP; + wmPathExpander.clearPathlist(); // when reading from a PK3 we don't want to use any external path + } + else + { + wmPathExpander.openmode = PathExpander::OM_FILE; + } + } + + + + if (fp == NULL) + { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, errno); + return NULL; + } + + long fsize = fp->GetLength(); + + if (fsize > WM_MAXFILESIZE) + { + /* don't bother loading suspiciously long files */ + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LONGFIL, filename, 0); + return NULL; + } + + unsigned char *data = (unsigned char*)malloc(fsize+1); + if (data == NULL) + { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, errno); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, errno); + return NULL; + } + + fp->Read(data, fsize); + delete fp; + data[fsize] = 0; + *size = fsize; + return data; +} diff --git a/src/wildmidi/file_io.h b/src/wildmidi/file_io.h new file mode 100644 index 000000000..550a8a4b2 --- /dev/null +++ b/src/wildmidi/file_io.h @@ -0,0 +1,33 @@ +/* + file_io.c + + file handling + + Copyright (C) Chris Ison 2001-2011 + Copyright (C) Bret Curtis 2013-2014 + + This file is part of WildMIDI. + + WildMIDI is free software: you can redistribute and/or modify the player + under the terms of the GNU General Public License and you can redistribute + and/or modify the library under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, either version 3 of + the licenses, or(at your option) any later version. + + WildMIDI 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 and + the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License and the + GNU Lesser General Public License along with WildMIDI. If not, see + . +*/ + +#ifndef __FILE_IO_H +#define __FILE_IO_H + +#define WM_MAXFILESIZE 0x1fffffff +extern unsigned char *_WM_BufferFile (const char *filename, unsigned long int *size, bool mainfile = false); + +#endif /* __FILE_IO_H */ diff --git a/src/wildmidi/gus_pat.cpp b/src/wildmidi/gus_pat.cpp new file mode 100644 index 000000000..8f4824dc5 --- /dev/null +++ b/src/wildmidi/gus_pat.cpp @@ -0,0 +1,981 @@ +/* + * gus_pat.c -- Midi Wavetable Processing library + * + * Copyright (C) WildMIDI Developers 2001-2015 + * + * This file is part of WildMIDI. + * + * WildMIDI is free software: you can redistribute and/or modify the player + * under the terms of the GNU General Public License and you can redistribute + * and/or modify the library under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either version 3 of + * the licenses, or(at your option) any later version. + * + * WildMIDI 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 and + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License and the + * GNU Lesser General Public License along with WildMIDI. If not, see + * . + */ + +#include +#include +#include +#include + +#include "gus_pat.h" +#include "common.h" +#include "wm_error.h" +#include "file_io.h" + +#ifdef DEBUG_GUSPAT +#define GUSPAT_FILENAME_DEBUG(dx) fprintf(stderr,"\r%s\n",dx) + +#define GUSPAT_INT_DEBUG(dx,dy) fprintf(stderr,"\r%s: %i\n",dx,dy) +#define GUSPAT_FLOAT_DEBUG(dx,dy) fprintf(stderr,"\r%s: %f\n",dx,dy) +#define GUSPAT_START_DEBUG() fprintf(stderr,"\r") +#define GUSPAT_MODE_DEBUG(dx,dy,dz) if (dx & dy) fprintf(stderr,"%s",dz) +#define GUSPAT_END_DEBUG() fprintf(stderr,"\n") +#else +#define GUSPAT_FILENAME_DEBUG(dx) +#define GUSPAT_INT_DEBUG(dx,dy) +#define GUSPAT_FLOAT_DEBUG(dx,dy) +#define GUSPAT_START_DEBUG() +#define GUSPAT_MODE_DEBUG(dx,dy,dz) +#define GUSPAT_END_DEBUG() +#endif + +/* + * sample data conversion functions + * convert data to signed shorts + */ + +/* 8bit signed */ +static int convert_8s(unsigned char *data, struct _sample *gus_sample) { + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->data_length; + signed short int *write_data = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc((gus_sample->data_length + 2), + sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data; + do { + *write_data++ = (*read_data++) << 8; + } while (read_data != read_end); + return 0; + } + + _WM_ERROR_NEW("(%s:%i) ERROR: calloc failed (%s)", __FUNCTION__, __LINE__, + strerror(errno)); + return -1; +} + +/* 8bit signed ping pong */ +static int convert_8sp(unsigned char *data, struct _sample *gus_sample) { + unsigned long int loop_length = gus_sample->loop_end + - gus_sample->loop_start; + unsigned long int dloop_length = loop_length * 2; + unsigned long int new_length = gus_sample->data_length + dloop_length; + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->loop_start; + signed short int *write_data = NULL; + signed short int *write_data_a = NULL; + signed short int *write_data_b = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc((new_length + 2), sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data; + do { + *write_data++ = (*read_data++) << 8; + } while (read_data != read_end); + + *write_data = (*read_data++ << 8); + write_data_a = write_data + dloop_length; + *write_data_a-- = *write_data; + write_data++; + write_data_b = write_data + dloop_length; + read_end = data + gus_sample->loop_end; + do { + *write_data = (*read_data++) << 8; + *write_data_a-- = *write_data; + *write_data_b++ = *write_data; + write_data++; + } while (read_data != read_end); + + *write_data = (*read_data++ << 8); + *write_data_b++ = *write_data; + read_end = data + gus_sample->data_length; + if (read_data != read_end) { + do { + *write_data_b++ = (*read_data++) << 8; + } while (read_data != read_end); + } + gus_sample->loop_start += loop_length; + gus_sample->loop_end += dloop_length; + gus_sample->data_length = new_length; + gus_sample->modes ^= SAMPLE_PINGPONG; + return 0; + } + + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 8bit signed reverse */ +static int convert_8sr(unsigned char *data, struct _sample *gus_sample) { + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->data_length; + signed short int *write_data = NULL; + unsigned long int tmp_loop = 0; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc((gus_sample->data_length + 2), + sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data + gus_sample->data_length - 1; + do { + *write_data-- = (*read_data++) << 8; + } while (read_data != read_end); + tmp_loop = gus_sample->loop_end; + gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start; + gus_sample->loop_start = gus_sample->data_length - tmp_loop; + gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) + | ((gus_sample->loop_fraction & 0xf0) >> 4); + gus_sample->modes ^= SAMPLE_REVERSE; + return 0; + } + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 8bit signed reverse ping pong */ +static int convert_8srp(unsigned char *data, struct _sample *gus_sample) { + unsigned long int loop_length = gus_sample->loop_end + - gus_sample->loop_start; + unsigned long int dloop_length = loop_length * 2; + unsigned long int new_length = gus_sample->data_length + dloop_length; + unsigned char *read_data = data + gus_sample->data_length - 1; + unsigned char *read_end = data + gus_sample->loop_end; + signed short int *write_data = NULL; + signed short int *write_data_a = NULL; + signed short int *write_data_b = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc((new_length + 2), sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data; + do { + *write_data++ = (*read_data--) << 8; + } while (read_data != read_end); + + *write_data = (*read_data-- << 8); + write_data_a = write_data + dloop_length; + *write_data_a-- = *write_data; + write_data++; + write_data_b = write_data + dloop_length; + read_end = data + gus_sample->loop_start; + do { + *write_data = (*read_data--) << 8; + *write_data_a-- = *write_data; + *write_data_b++ = *write_data; + write_data++; + } while (read_data != read_end); + + *write_data = (*read_data-- << 8); + *write_data_b++ = *write_data; + read_end = data - 1; + do { + *write_data_b++ = (*read_data--) << 8; + write_data_b++; + } while (read_data != read_end); + gus_sample->loop_start += loop_length; + gus_sample->loop_end += dloop_length; + gus_sample->data_length = new_length; + gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE; + return 0; + } + + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 8bit unsigned */ +static int convert_8u(unsigned char *data, struct _sample *gus_sample) { + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->data_length; + signed short int *write_data = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc((gus_sample->data_length + 2), + sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data; + do { + *write_data++ = ((*read_data++) ^ 0x80) << 8; + } while (read_data != read_end); + gus_sample->modes ^= SAMPLE_UNSIGNED; + return 0; + } + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 8bit unsigned ping pong */ +static int convert_8up(unsigned char *data, struct _sample *gus_sample) { + unsigned long int loop_length = gus_sample->loop_end + - gus_sample->loop_start; + unsigned long int dloop_length = loop_length * 2; + unsigned long int new_length = gus_sample->data_length + dloop_length; + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->loop_start; + signed short int *write_data = NULL; + signed short int *write_data_a = NULL; + signed short int *write_data_b = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc((new_length + 2), sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data; + do { + *write_data++ = ((*read_data++) ^ 0x80) << 8; + } while (read_data != read_end); + + *write_data = ((*read_data++) ^ 0x80) << 8; + write_data_a = write_data + dloop_length; + *write_data_a-- = *write_data; + write_data++; + write_data_b = write_data + dloop_length; + read_end = data + gus_sample->loop_end; + do { + *write_data = ((*read_data++) ^ 0x80) << 8; + *write_data_a-- = *write_data; + *write_data_b++ = *write_data; + write_data++; + } while (read_data != read_end); + + *write_data = ((*read_data++) ^ 0x80) << 8; + *write_data_b++ = *write_data; + read_end = data + gus_sample->data_length; + if (read_data != read_end) { + do { + *write_data_b++ = ((*read_data++) ^ 0x80) << 8; + } while (read_data != read_end); + } + gus_sample->loop_start += loop_length; + gus_sample->loop_end += dloop_length; + gus_sample->data_length = new_length; + gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_UNSIGNED; + return 0; + } + + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 8bit unsigned reverse */ +static int convert_8ur(unsigned char *data, struct _sample *gus_sample) { + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->data_length; + signed short int *write_data = NULL; + unsigned long int tmp_loop = 0; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc((gus_sample->data_length + 2), + sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data + gus_sample->data_length - 1; + do { + *write_data-- = ((*read_data++) ^ 0x80) << 8; + } while (read_data != read_end); + tmp_loop = gus_sample->loop_end; + gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start; + gus_sample->loop_start = gus_sample->data_length - tmp_loop; + gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) + | ((gus_sample->loop_fraction & 0xf0) >> 4); + gus_sample->modes ^= SAMPLE_REVERSE | SAMPLE_UNSIGNED; + return 0; + } + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 8bit unsigned reverse ping pong */ +static int convert_8urp(unsigned char *data, struct _sample *gus_sample) { + unsigned long int loop_length = gus_sample->loop_end + - gus_sample->loop_start; + unsigned long int dloop_length = loop_length * 2; + unsigned long int new_length = gus_sample->data_length + dloop_length; + unsigned char *read_data = data + gus_sample->data_length - 1; + unsigned char *read_end = data + gus_sample->loop_end; + signed short int *write_data = NULL; + signed short int *write_data_a = NULL; + signed short int *write_data_b = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc((new_length + 2), sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data; + do { + *write_data++ = ((*read_data--) ^ 0x80) << 8; + } while (read_data != read_end); + + *write_data = ((*read_data--) ^ 0x80) << 8; + write_data_a = write_data + dloop_length; + *write_data_a-- = *write_data; + write_data++; + write_data_b = write_data + dloop_length; + read_end = data + gus_sample->loop_start; + do { + *write_data = ((*read_data--) ^ 0x80) << 8; + *write_data_a-- = *write_data; + *write_data_b++ = *write_data; + write_data++; + } while (read_data != read_end); + + *write_data = ((*read_data--) ^ 0x80) << 8; + *write_data_b++ = *write_data; + read_end = data - 1; + do { + *write_data_b++ = ((*read_data--) ^ 0x80) << 8; + } while (read_data != read_end); + gus_sample->loop_start += loop_length; + gus_sample->loop_end += dloop_length; + gus_sample->data_length = new_length; + gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE | SAMPLE_UNSIGNED; + return 0; + } + + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 16bit signed */ +static int convert_16s(unsigned char *data, struct _sample *gus_sample) { + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->data_length; + signed short int *write_data = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc(((gus_sample->data_length >> 1) + 2), + sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data; + do { + *write_data = *read_data++; + *write_data++ |= (*read_data++) << 8; + } while (read_data < read_end); + + gus_sample->loop_start >>= 1; + gus_sample->loop_end >>= 1; + gus_sample->data_length >>= 1; + return 0; + } + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 16bit signed ping pong */ +static int convert_16sp(unsigned char *data, struct _sample *gus_sample) { + unsigned long int loop_length = gus_sample->loop_end + - gus_sample->loop_start; + unsigned long int dloop_length = loop_length * 2; + unsigned long int new_length = gus_sample->data_length + dloop_length; + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->loop_start; + signed short int *write_data = NULL; + signed short int *write_data_a = NULL; + signed short int *write_data_b = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc(((new_length >> 1) + 2), + sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data; + do { + *write_data = (*read_data++); + *write_data++ |= (*read_data++) << 8; + } while (read_data < read_end); + + *write_data = (*read_data++); + *write_data |= (*read_data++) << 8; + write_data_a = write_data + (dloop_length >> 1); + *write_data_a-- = *write_data; + write_data++; + write_data_b = write_data + (dloop_length >> 1); + read_end = data + gus_sample->loop_end; + do { + *write_data = (*read_data++); + *write_data |= (*read_data++) << 8; + *write_data_a-- = *write_data; + *write_data_b++ = *write_data; + write_data++; + } while (read_data < read_end); + + *write_data = *(read_data++); + *write_data |= (*read_data++) << 8; + *write_data_b++ = *write_data; + read_end = data + gus_sample->data_length; + if (read_data != read_end) { + do { + *write_data_b = *(read_data++); + *write_data_b++ |= (*read_data++) << 8; + } while (read_data < read_end); + } + gus_sample->loop_start += loop_length; + gus_sample->loop_end += dloop_length; + gus_sample->data_length = new_length; + gus_sample->modes ^= SAMPLE_PINGPONG; + gus_sample->loop_start >>= 1; + gus_sample->loop_end >>= 1; + gus_sample->data_length >>= 1; + return 0; + } + + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 16bit signed reverse */ +static int convert_16sr(unsigned char *data, struct _sample *gus_sample) { + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->data_length; + signed short int *write_data = NULL; + unsigned long int tmp_loop = 0; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc(((gus_sample->data_length >> 1) + 2), + sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data + (gus_sample->data_length >> 1) - 1; + do { + *write_data = *read_data++; + *write_data-- |= (*read_data++) << 8; + } while (read_data < read_end); + tmp_loop = gus_sample->loop_end; + gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start; + gus_sample->loop_start = gus_sample->data_length - tmp_loop; + gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) + | ((gus_sample->loop_fraction & 0xf0) >> 4); + gus_sample->loop_start >>= 1; + gus_sample->loop_end >>= 1; + gus_sample->data_length >>= 1; + gus_sample->modes ^= SAMPLE_REVERSE; + return 0; + } + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 16bit signed reverse ping pong */ +static int convert_16srp(unsigned char *data, struct _sample *gus_sample) { + unsigned long int loop_length = gus_sample->loop_end + - gus_sample->loop_start; + unsigned long int dloop_length = loop_length * 2; + unsigned long int new_length = gus_sample->data_length + dloop_length; + unsigned char *read_data = data + gus_sample->data_length - 1; + unsigned char *read_end = data + gus_sample->loop_end; + signed short int *write_data = NULL; + signed short int *write_data_a = NULL; + signed short int *write_data_b = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc(((new_length >> 1) + 2), + sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data; + do { + *write_data = (*read_data--) << 8; + *write_data++ |= *read_data--; + } while (read_data < read_end); + + *write_data = (*read_data-- << 8); + *write_data |= *read_data--; + write_data_a = write_data + (dloop_length >> 1); + *write_data_a-- = *write_data; + write_data++; + write_data_b = write_data + (dloop_length >> 1); + read_end = data + gus_sample->loop_start; + do { + *write_data = (*read_data--) << 8; + *write_data |= *read_data--; + *write_data_a-- = *write_data; + *write_data_b++ = *write_data; + write_data++; + } while (read_data < read_end); + + *write_data = ((*read_data--) << 8); + *write_data |= *read_data--; + *write_data_b++ = *write_data; + read_end = data - 1; + do { + *write_data_b = (*read_data--) << 8; + *write_data_b++ |= *read_data--; + } while (read_data < read_end); + gus_sample->loop_start += loop_length; + gus_sample->loop_end += dloop_length; + gus_sample->data_length = new_length; + gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE; + return 0; + } + + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 16bit unsigned */ +static int convert_16u(unsigned char *data, struct _sample *gus_sample) { + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->data_length; + signed short int *write_data = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc(((gus_sample->data_length >> 1) + 2), + sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data; + do { + *write_data = *read_data++; + *write_data++ |= ((*read_data++) ^ 0x80) << 8; + } while (read_data < read_end); + gus_sample->loop_start >>= 1; + gus_sample->loop_end >>= 1; + gus_sample->data_length >>= 1; + gus_sample->modes ^= SAMPLE_UNSIGNED; + return 0; + } + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 16bit unsigned ping pong */ +static int convert_16up(unsigned char *data, struct _sample *gus_sample) { + unsigned long int loop_length = gus_sample->loop_end + - gus_sample->loop_start; + unsigned long int dloop_length = loop_length * 2; + unsigned long int new_length = gus_sample->data_length + dloop_length; + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->loop_start; + signed short int *write_data = NULL; + signed short int *write_data_a = NULL; + signed short int *write_data_b = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc(((new_length >> 1) + 2), + sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data; + do { + *write_data = (*read_data++); + *write_data++ |= ((*read_data++) ^ 0x80) << 8; + } while (read_data < read_end); + + *write_data = (*read_data++); + *write_data |= ((*read_data++) ^ 0x80) << 8; + write_data_a = write_data + (dloop_length >> 1); + *write_data_a-- = *write_data; + write_data++; + write_data_b = write_data + (dloop_length >> 1); + read_end = data + gus_sample->loop_end; + do { + *write_data = (*read_data++); + *write_data |= ((*read_data++) ^ 0x80) << 8; + *write_data_a-- = *write_data; + *write_data_b++ = *write_data; + write_data++; + } while (read_data < read_end); + + *write_data = (*read_data++); + *write_data |= ((*read_data++) ^ 0x80) << 8; + *write_data_b++ = *write_data; + read_end = data + gus_sample->data_length; + if (read_data != read_end) { + do { + *write_data_b = (*read_data++); + *write_data_b++ |= ((*read_data++) ^ 0x80) << 8; + } while (read_data < read_end); + } + gus_sample->loop_start += loop_length; + gus_sample->loop_end += dloop_length; + gus_sample->data_length = new_length; + gus_sample->modes ^= SAMPLE_PINGPONG; + gus_sample->loop_start >>= 1; + gus_sample->loop_end >>= 1; + gus_sample->data_length >>= 1; + return 0; + } + + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 16bit unsigned reverse */ +static int convert_16ur(unsigned char *data, struct _sample *gus_sample) { + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->data_length; + signed short int *write_data = NULL; + unsigned long int tmp_loop = 0; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc(((gus_sample->data_length >> 1) + 2), + sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data + (gus_sample->data_length >> 1) - 1; + do { + *write_data = *read_data++; + *write_data-- |= ((*read_data++) ^ 0x80) << 8; + } while (read_data < read_end); + tmp_loop = gus_sample->loop_end; + gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start; + gus_sample->loop_start = gus_sample->data_length - tmp_loop; + gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) + | ((gus_sample->loop_fraction & 0xf0) >> 4); + gus_sample->loop_start >>= 1; + gus_sample->loop_end >>= 1; + gus_sample->data_length >>= 1; + gus_sample->modes ^= SAMPLE_REVERSE | SAMPLE_UNSIGNED; + return 0; + } + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 16bit unsigned reverse ping pong */ +static int convert_16urp(unsigned char *data, struct _sample *gus_sample) { + unsigned long int loop_length = gus_sample->loop_end + - gus_sample->loop_start; + unsigned long int dloop_length = loop_length * 2; + unsigned long int new_length = gus_sample->data_length + dloop_length; + unsigned char *read_data = data + gus_sample->data_length - 1; + unsigned char *read_end = data + gus_sample->loop_end; + signed short int *write_data = NULL; + signed short int *write_data_a = NULL; + signed short int *write_data_b = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = (short*)calloc(((new_length >> 1) + 2), + sizeof(signed short int)); + if (gus_sample->data != NULL) { + write_data = gus_sample->data; + do { + *write_data = ((*read_data--) ^ 0x80) << 8; + *write_data++ |= *read_data--; + } while (read_data < read_end); + + *write_data = ((*read_data--) ^ 0x80) << 8; + *write_data |= *read_data--; + write_data_a = write_data + (dloop_length >> 1); + *write_data_a-- = *write_data; + write_data++; + write_data_b = write_data + (dloop_length >> 1); + read_end = data + gus_sample->loop_start; + do { + *write_data = ((*read_data--) ^ 0x80) << 8; + *write_data |= *read_data--; + *write_data_a-- = *write_data; + *write_data_b++ = *write_data; + write_data++; + } while (read_data < read_end); + + *write_data = ((*read_data--) ^ 0x80) << 8; + *write_data |= *read_data--; + *write_data_b++ = *write_data; + read_end = data - 1; + do { + *write_data_b = ((*read_data--) ^ 0x80) << 8; + *write_data_b++ |= *read_data--; + } while (read_data < read_end); + gus_sample->loop_start += loop_length; + gus_sample->loop_end += dloop_length; + gus_sample->data_length = new_length; + gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE | SAMPLE_UNSIGNED; + return 0; + } + + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* sample loading */ + +struct _sample * _WM_load_gus_pat(const char *filename, int fix_release) { + unsigned char *gus_patch; + unsigned long int gus_size; + unsigned long int gus_ptr; + unsigned char no_of_samples; + struct _sample *gus_sample = NULL; + struct _sample *first_gus_sample = NULL; + unsigned long int i = 0; + + int (*do_convert[])(unsigned char *data, struct _sample *gus_sample) = { + convert_8s, + convert_16s, + convert_8u, + convert_16u, + convert_8sp, + convert_16sp, + convert_8up, + convert_16up, + convert_8sr, + convert_16sr, + convert_8ur, + convert_16ur, + convert_8srp, + convert_16srp, + convert_8urp, + convert_16urp + }; + unsigned long int tmp_loop; + + /*unused*/fix_release; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); SAMPLE_CONVERT_DEBUG(filename); + + if ((gus_patch = _WM_BufferFile(filename, &gus_size)) == NULL) { + return NULL; + } + if (gus_size < 239) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0); + free(gus_patch); + return NULL; + } + if (memcmp(gus_patch, "GF1PATCH110\0ID#000002", 22) + && memcmp(gus_patch, "GF1PATCH100\0ID#000002", 22)) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(unsupported format)", + 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0); + free(gus_patch); + return NULL; + } + if (gus_patch[82] > 1) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(unsupported format)", + 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0); + free(gus_patch); + return NULL; + } + if (gus_patch[151] > 1) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(unsupported format)", + 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0); + free(gus_patch); + return NULL; + } + + GUSPAT_FILENAME_DEBUG(filename); GUSPAT_INT_DEBUG("voices",gus_patch[83]); + + no_of_samples = gus_patch[198]; + gus_ptr = 239; + while (no_of_samples) { + unsigned long int tmp_cnt; + if (first_gus_sample == NULL) { + first_gus_sample = (struct _sample*)malloc(sizeof(struct _sample)); + gus_sample = first_gus_sample; + } else { + gus_sample->next = (struct _sample*)malloc(sizeof(struct _sample)); + gus_sample = gus_sample->next; + } + if (gus_sample == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0); + free(gus_patch); + return NULL; + } + + gus_sample->next = NULL; + gus_sample->loop_fraction = gus_patch[gus_ptr + 7]; + gus_sample->data_length = (gus_patch[gus_ptr + 11] << 24) + | (gus_patch[gus_ptr + 10] << 16) + | (gus_patch[gus_ptr + 9] << 8) | gus_patch[gus_ptr + 8]; + gus_sample->loop_start = (gus_patch[gus_ptr + 15] << 24) + | (gus_patch[gus_ptr + 14] << 16) + | (gus_patch[gus_ptr + 13] << 8) | gus_patch[gus_ptr + 12]; + gus_sample->loop_end = (gus_patch[gus_ptr + 19] << 24) + | (gus_patch[gus_ptr + 18] << 16) + | (gus_patch[gus_ptr + 17] << 8) | gus_patch[gus_ptr + 16]; + gus_sample->rate = (gus_patch[gus_ptr + 21] << 8) + | gus_patch[gus_ptr + 20]; + gus_sample->freq_low = ((gus_patch[gus_ptr + 25] << 24) + | (gus_patch[gus_ptr + 24] << 16) + | (gus_patch[gus_ptr + 23] << 8) | gus_patch[gus_ptr + 22]); + gus_sample->freq_high = ((gus_patch[gus_ptr + 29] << 24) + | (gus_patch[gus_ptr + 28] << 16) + | (gus_patch[gus_ptr + 27] << 8) | gus_patch[gus_ptr + 26]); + gus_sample->freq_root = ((gus_patch[gus_ptr + 33] << 24) + | (gus_patch[gus_ptr + 32] << 16) + | (gus_patch[gus_ptr + 31] << 8) | gus_patch[gus_ptr + 30]); + + /* This is done this way instead of ((freq * 1024) / rate) to avoid 32bit overflow. */ + /* Result is 0.001% inacurate */ + gus_sample->inc_div = ((gus_sample->freq_root * 512) / gus_sample->rate) * 2; + +#if 0 + /* We dont use this info at this time, kept in here for info */ + printf("\rTremolo Sweep: %i, Rate: %i, Depth %i\n", + gus_patch[gus_ptr+49], gus_patch[gus_ptr+50], gus_patch[gus_ptr+51]); + printf("\rVibrato Sweep: %i, Rate: %i, Depth %i\n", + gus_patch[gus_ptr+52], gus_patch[gus_ptr+53], gus_patch[gus_ptr+54]); +#endif + gus_sample->modes = gus_patch[gus_ptr + 55]; + GUSPAT_START_DEBUG(); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_16BIT, "16bit "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_UNSIGNED, "Unsigned "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_LOOP, "Loop "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_PINGPONG, "PingPong "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_REVERSE, "Reverse "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_SUSTAIN, "Sustain "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_ENVELOPE, "Envelope "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_CLAMPED, "Clamped "); GUSPAT_END_DEBUG(); + + if (gus_sample->loop_start > gus_sample->loop_end) { + tmp_loop = gus_sample->loop_end; + gus_sample->loop_end = gus_sample->loop_start; + gus_sample->loop_start = tmp_loop; + gus_sample->loop_fraction = + ((gus_sample->loop_fraction & 0x0f) << 4) + | ((gus_sample->loop_fraction & 0xf0) >> 4); + } + + /* + FIXME: Experimental Hacky Fix + + This looks for "dodgy" release envelope settings that faulty editors + may have set and attempts to corrects it. + if (fix_release) + Lets make this automatic ... + */ + { + /* + After studying faulty gus_pats this way may work better + Testing to determine if any further adjustments are required + */ + if (env_time_table[gus_patch[gus_ptr + 40]] < env_time_table[gus_patch[gus_ptr + 41]]) { + unsigned char tmp_hack_rate = 0; + + if (env_time_table[gus_patch[gus_ptr + 41]] < env_time_table[gus_patch[gus_ptr + 42]]) { + // 1 2 3 + tmp_hack_rate = gus_patch[gus_ptr + 40]; + gus_patch[gus_ptr + 40] = gus_patch[gus_ptr + 42]; + gus_patch[gus_ptr + 42] = tmp_hack_rate; + } else if (env_time_table[gus_patch[gus_ptr + 41]] == env_time_table[gus_patch[gus_ptr + 42]]) { + // 1 2 2 + tmp_hack_rate = gus_patch[gus_ptr + 40]; + gus_patch[gus_ptr + 40] = gus_patch[gus_ptr + 42]; + gus_patch[gus_ptr + 41] = gus_patch[gus_ptr + 42]; + gus_patch[gus_ptr + 42] = tmp_hack_rate; + + } else { + if (env_time_table[gus_patch[gus_ptr + 40]] < env_time_table[gus_patch[gus_ptr + 42]]) { + // 1 3 2 + tmp_hack_rate = gus_patch[gus_ptr + 40]; + gus_patch[gus_ptr + 40] = gus_patch[gus_ptr + 41]; + gus_patch[gus_ptr + 41] = gus_patch[gus_ptr + 42]; + gus_patch[gus_ptr + 42] = tmp_hack_rate; + } else { + // 2 3 1 or 1 2 1 + tmp_hack_rate = gus_patch[gus_ptr + 40]; + gus_patch[gus_ptr + 40] = gus_patch[gus_ptr + 41]; + gus_patch[gus_ptr + 41] = tmp_hack_rate; + } + } + } else if (env_time_table[gus_patch[gus_ptr + 41]] < env_time_table[gus_patch[gus_ptr + 42]]) { + unsigned char tmp_hack_rate = 0; + + if (env_time_table[gus_patch[gus_ptr + 40]] < env_time_table[gus_patch[gus_ptr + 42]]) { + // 2 1 3 + tmp_hack_rate = gus_patch[gus_ptr + 40]; + gus_patch[gus_ptr + 40] = gus_patch[gus_ptr + 42]; + gus_patch[gus_ptr + 42] = gus_patch[gus_ptr + 41]; + gus_patch[gus_ptr + 41] = tmp_hack_rate; + } else { + // 3 1 2 + tmp_hack_rate = gus_patch[gus_ptr + 41]; + gus_patch[gus_ptr + 41] = gus_patch[gus_ptr + 42]; + gus_patch[gus_ptr + 42] = tmp_hack_rate; + } + } + +#if 0 + if ((env_time_table[gus_patch[gus_ptr + 40]] < env_time_table[gus_patch[gus_ptr + 41]]) && (env_time_table[gus_patch[gus_ptr + 41]] == env_time_table[gus_patch[gus_ptr + 42]])) { + uint8_t tmp_hack_rate = 0; + tmp_hack_rate = gus_patch[gus_ptr + 41]; + gus_patch[gus_ptr + 41] = gus_patch[gus_ptr + 40]; + gus_patch[gus_ptr + 42] = gus_patch[gus_ptr + 40]; + gus_patch[gus_ptr + 40] = tmp_hack_rate; + tmp_hack_rate = gus_patch[gus_ptr + 47]; + gus_patch[gus_ptr + 47] = gus_patch[gus_ptr + 46]; + gus_patch[gus_ptr + 48] = gus_patch[gus_ptr + 46]; + gus_patch[gus_ptr + 46] = tmp_hack_rate; + } +#endif + } + + for (i = 0; i < 6; i++) { + GUSPAT_INT_DEBUG("Envelope #",i); + if (gus_sample->modes & SAMPLE_ENVELOPE) { + unsigned char env_rate = gus_patch[gus_ptr + 37 + i]; + gus_sample->env_target[i] = 16448 * gus_patch[gus_ptr + 43 + i]; + GUSPAT_INT_DEBUG("Envelope Level",gus_patch[gus_ptr+43+i]); GUSPAT_FLOAT_DEBUG("Envelope Time",env_time_table[env_rate]); + gus_sample->env_rate[i] = (signed long int) (4194303.0 + / ((float) _WM_SampleRate * env_time_table[env_rate])); + GUSPAT_INT_DEBUG("Envelope Rate",gus_sample->env_rate[i]); GUSPAT_INT_DEBUG("GUSPAT Rate",env_rate); + if (gus_sample->env_rate[i] == 0) { + _WM_ERROR_NEW("%s: Warning: found invalid envelope(%lu) rate setting in %s. Using %f instead.", + __FUNCTION__, i, filename, env_time_table[63]); + gus_sample->env_rate[i] = (signed long int) (4194303.0 + / ((float) _WM_SampleRate * env_time_table[63])); + GUSPAT_FLOAT_DEBUG("Envelope Time",env_time_table[63]); + } + } else { + gus_sample->env_target[i] = 4194303; + gus_sample->env_rate[i] = (signed long int) (4194303.0 + / ((float) _WM_SampleRate * env_time_table[63])); + GUSPAT_FLOAT_DEBUG("Envelope Time",env_time_table[63]); + } + } + + gus_sample->env_target[6] = 0; + gus_sample->env_rate[6] = (signed long int) (4194303.0 + / ((float) _WM_SampleRate * env_time_table[63])); + + gus_ptr += 96; + tmp_cnt = gus_sample->data_length; + + if (do_convert[(((gus_sample->modes & 0x18) >> 1) + | (gus_sample->modes & 0x03))](&gus_patch[gus_ptr], gus_sample) + == -1) { + free(gus_patch); + return NULL; + } + + /* + Test and set decay expected decay time after a note off + NOTE: This sets samples for full range decay + */ + if (gus_sample->modes & SAMPLE_ENVELOPE) { + double samples_f = 0.0; + + if (gus_sample->modes & SAMPLE_CLAMPED) { + samples_f = (4194301.0 - (float)gus_sample->env_target[5]) / gus_sample->env_rate[5]; + } else { + if (gus_sample->modes & SAMPLE_SUSTAIN) { + samples_f = (4194301.0 - (float)gus_sample->env_target[3]) / gus_sample->env_rate[3]; + samples_f += (float)(gus_sample->env_target[3] - gus_sample->env_target[4]) / gus_sample->env_rate[4]; + } else { + samples_f = (4194301.0 - (float)gus_sample->env_target[4]) / gus_sample->env_rate[4]; + } + samples_f += (float)(gus_sample->env_target[4] - gus_sample->env_target[5]) / gus_sample->env_rate[5]; + } + samples_f += (float)gus_sample->env_target[5] / gus_sample->env_rate[6]; + } + + gus_ptr += tmp_cnt; + gus_sample->loop_start = (gus_sample->loop_start << 10) + | (((gus_sample->loop_fraction & 0x0f) << 10) / 16); + gus_sample->loop_end = (gus_sample->loop_end << 10) + | (((gus_sample->loop_fraction & 0xf0) << 6) / 16); + gus_sample->loop_size = gus_sample->loop_end - gus_sample->loop_start; + gus_sample->data_length = gus_sample->data_length << 10; + no_of_samples--; + } + free(gus_patch); + return first_gus_sample; +} diff --git a/src/wildmidi/gus_pat.h b/src/wildmidi/gus_pat.h new file mode 100644 index 000000000..084b8473a --- /dev/null +++ b/src/wildmidi/gus_pat.h @@ -0,0 +1,77 @@ +/* + gus_pat.h + + Midi Wavetable Processing library + + Copyright (C) Chris Ison 2001-2011 + Copyright (C) Bret Curtis 2013-2014 + + This file is part of WildMIDI. + + WildMIDI is free software: you can redistribute and/or modify the player + under the terms of the GNU General Public License and you can redistribute + and/or modify the library under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, either version 3 of + the licenses, or(at your option) any later version. + + WildMIDI 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 and + the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License and the + GNU Lesser General Public License along with WildMIDI. If not, see + . +*/ + +#ifndef __GUS_PAT_H +#define __GUS_PAT_H + +/* Guspat Envelope Rate Timings */ + +static float env_time_table[] = { +/* Row 1 = (4095.0 / (x * ( 1.0 / (1.6 * 14.0) ))) / 1000000.0 */ + 0.0f, 0.091728000f, 0.045864000f, 0.030576000f, 0.022932000f, 0.018345600f, 0.015288000f, 0.013104000f, + 0.011466000f, 0.010192000f, 0.009172800f, 0.008338909f, 0.007644000f, 0.007056000f, 0.006552000f, 0.006115200f, + 0.005733000f, 0.005395765f, 0.005096000f, 0.004827789f, 0.004586400f, 0.004368000f, 0.004169455f, 0.003988174f, + 0.003822000f, 0.003669120f, 0.003528000f, 0.003397333f, 0.003276000f, 0.003163034f, 0.003057600f, 0.002958968f, + 0.002866500f, 0.002779636f, 0.002697882f, 0.002620800f, 0.002548000f, 0.002479135f, 0.002413895f, 0.002352000f, + 0.002293200f, 0.002237268f, 0.002184000f, 0.002133209f, 0.002084727f, 0.002038400f, 0.001994087f, 0.001951660f, + 0.001911000f, 0.001872000f, 0.001834560f, 0.001798588f, 0.001764000f, 0.001730717f, 0.001698667f, 0.001667782f, + 0.001638000f, 0.001609263f, 0.001581517f, 0.001554712f, 0.001528800f, 0.001503738f, 0.001479484f, 0.001456000f, + +/* Row 2 = (4095.0 / (x * ((1.0 / (1.6 * 14.0)) / 8.0 ))) / 1000000.0 */ + 0.0f, 0.733824000f, 0.366912000f, 0.244608000f, 0.183456000f, 0.146764800f, 0.122304000f, 0.104832000f, + 0.091728000f, 0.081536000f, 0.073382400f, 0.066711273f, 0.061152000f, 0.056448000f, 0.052416000f, 0.048921600f, + 0.045864000f, 0.043166118f, 0.040768000f, 0.038622316f, 0.036691200f, 0.034944000f, 0.033355636f, 0.031905391f, + 0.030576000f, 0.029352960f, 0.028224000f, 0.027178667f, 0.026208000f, 0.025304276f, 0.024460800f, 0.023671742f, + 0.022932000f, 0.022237091f, 0.021583059f, 0.020966400f, 0.020384000f, 0.019833081f, 0.019311158f, 0.018816000f, + 0.018345600f, 0.017898146f, 0.017472000f, 0.017065674f, 0.016677818f, 0.016307200f, 0.015952696f, 0.015613277f, + 0.015288000f, 0.014976000f, 0.014676480f, 0.014388706f, 0.014112000f, 0.013845736f, 0.013589333f, 0.013342255f, + 0.013104000f, 0.012874105f, 0.012652138f, 0.012437695f, 0.012230400f, 0.012029902f, 0.011835871f, 0.011648000f, + +/* Row 3 = (4095.0 / (x * ((1.0 / (1.6 * 14.0)) / 64.0 ))) / 1000000.0 */ + 0.0f, 5.870592000f, 2.935296000f, 1.956864000f, 1.467648000f, 1.174118400f, 0.978432000f, 0.838656000f, + 0.733824000f, 0.652288000f, 0.587059200f, 0.533690182f, 0.489216000f, 0.451584000f, 0.419328000f, 0.391372800f, + 0.366912000f, 0.345328941f, 0.326144000f, 0.308978526f, 0.293529600f, 0.279552000f, 0.266845091f, 0.255243130f, + 0.244608000f, 0.234823680f, 0.225792000f, 0.217429333f, 0.209664000f, 0.202434207f, 0.195686400f, 0.189373935f, + 0.183456000f, 0.177896727f, 0.172664471f, 0.167731200f, 0.163072000f, 0.158664649f, 0.154489263f, 0.150528000f, + 0.146764800f, 0.143185171f, 0.139776000f, 0.136525395f, 0.133422545f, 0.130457600f, 0.127621565f, 0.124906213f, + 0.122304000f, 0.119808000f, 0.117411840f, 0.115109647f, 0.112896000f, 0.110765887f, 0.108714667f, 0.106738036f, + 0.104832000f, 0.102992842f, 0.101217103f, 0.099501559f, 0.097843200f, 0.096239213f, 0.094686968f, 0.093184000f, + +/* Row 4 = (4095.0 / (x * ((1.0 / (1.6 * 14.0)) / 512.0))) / 1000000.0 */ + 0.0f, 46.964736000f,23.482368000f,15.654912000f,11.741184000f, 9.392947200f, 7.827456000f, 6.709248000f, + 5.870592000f, 5.218304000f, 4.696473600f, 4.269521455f, 3.913728000f, 3.612672000f, 3.354624000f, 3.130982400f, + 2.935296000f, 2.762631529f, 2.609152000f, 2.471828211f, 2.348236800f, 2.236416000f, 2.134760727f, 2.041945043f, + 1.956864000f, 1.878589440f, 1.806336000f, 1.739434667f, 1.677312000f, 1.619473655f, 1.565491200f, 1.514991484f, + 1.467648000f, 1.423173818f, 1.381315765f, 1.341849600f, 1.304576000f, 1.269317189f, 1.235914105f, 1.204224000f, + 1.174118400f, 1.145481366f, 1.118208000f, 1.092203163f, 1.067380364f, 1.043660800f, 1.020972522f, 0.999249702f, + 0.978432000f, 0.958464000f, 0.939294720f, 0.920877176f, 0.903168000f, 0.886127094f, 0.869717333f, 0.853904291f, + 0.838656000f, 0.823942737f, 0.809736828f, 0.796012475f, 0.782745600f, 0.769913705f, 0.757495742f, 0.745472000f +}; + +extern struct _sample * _WM_load_gus_pat (const char *filename, int _fix_release); + +#endif /* __GUS_PAT_H */ + diff --git a/src/wildmidi/reverb.cpp b/src/wildmidi/reverb.cpp new file mode 100644 index 000000000..6c6af88d4 --- /dev/null +++ b/src/wildmidi/reverb.cpp @@ -0,0 +1,398 @@ +/* + reverb.c + + Midi Wavetable Processing library + + Copyright (C) Chris Ison 2001-2011 + Copyright (C) Bret Curtis 2013-2014 + + This file is part of WildMIDI. + + WildMIDI is free software: you can redistribute and/or modify the player + under the terms of the GNU General Public License and you can redistribute + and/or modify the library under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, either version 3 of + the licenses, or(at your option) any later version. + + WildMIDI 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 and + the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License and the + GNU Lesser General Public License along with WildMIDI. If not, see + . + */ + +//#include "config.h" + +#include +#include + +#include "common.h" +#include "reverb.h" + +/* + reverb function + */ +void _WM_reset_reverb(struct _rvb *rvb) { + int i, j, k; + for (i = 0; i < rvb->l_buf_size; i++) { + rvb->l_buf[i] = 0; + } + for (i = 0; i < rvb->r_buf_size; i++) { + rvb->r_buf[i] = 0; + } + for (k = 0; k < 8; k++) { + for (i = 0; i < 6; i++) { + for (j = 0; j < 2; j++) { + rvb->l_buf_flt_in[k][i][j] = 0; + rvb->l_buf_flt_out[k][i][j] = 0; + rvb->r_buf_flt_in[k][i][j] = 0; + rvb->r_buf_flt_out[k][i][j] = 0; + } + } + } +} + +/* + _WM_init_reverb + + ========================= + Engine Description + + 8 reflective points around the room + 2 speaker positions + 1 listener position + + Sounds come from the speakers to all points and to the listener. + Sound comes from the reflective points to the listener. + These sounds are combined, put through a filter that mimics surface absorbtion. + The combined sounds are also sent to the reflective points on the opposite side. + + */ +struct _rvb * +_WM_init_reverb(int rate, float room_x, float room_y, float listen_x, + float listen_y) { + + /* filters set at 125Hz, 250Hz, 500Hz, 1000Hz, 2000Hz, 4000Hz */ + double Freq[] = {125.0, 250.0, 500.0, 1000.0, 2000.0, 4000.0}; + + /* numbers calculated from + * 101.325 kPa, 20 deg C, 50% relative humidity */ + double dbAirAbs[] = {-0.00044, -0.00131, -0.002728, -0.004665, -0.009887, -0.029665}; + + /* modify these to adjust the absorption qualities of the surface. + * Remember that lower frequencies are less effected by surfaces + * Note: I am currently playing with the values and finding the ideal surfaces + * for nice default reverb. + */ + double dbAttn[8][6] = { + {-1.839, -6.205, -8.891, -12.059, -15.935, -20.942}, + {-0.131, -6.205, -12.059, -20.933, -20.933, -15.944}, + {-0.131, -6.205, -12.059, -20.933, -20.933, -15.944}, + {-1.839, -6.205, -8.891, -12.059, -15.935, -20.942}, + {-1.839, -6.205, -8.891, -12.059, -15.935, -20.942}, + {-0.131, -6.205, -12.059, -20.933, -20.933, -15.944}, + {-0.131, -6.205, -12.059, -20.933, -20.933, -15.944}, + {-1.839, -6.205, -8.891, -12.059, -15.935, -20.942} + }; + /* + double dbAttn[6] = { + // concrete covered in carpet + // -0.175, -0.537, -1.412, -4.437, -7.959, -7.959 + // pleated drapes + -0.630, -3.223, -5.849, -12.041, -10.458, -7.959 + }; + */ + + /* distance */ + double SPL_DST[8] = {0.0}; + double SPR_DST[8] = {0.0}; + double RFN_DST[8] = {0.0}; + + double MAXL_DST = 0.0; + double MAXR_DST = 0.0; + + double SPL_LSN_XOFS = 0.0; + double SPL_LSN_YOFS = 0.0; + double SPL_LSN_DST = 0.0; + + double SPR_LSN_XOFS = 0.0; + double SPR_LSN_YOFS = 0.0; + double SPR_LSN_DST = 0.0; + + + struct _rvb *rtn_rvb = (struct _rvb*)malloc(sizeof(struct _rvb)); + int j = 0; + int i = 0; + + struct _coord { + double x; + double y; + }; + +#if 0 + struct _coord SPL = {2.5, 5.0}; /* Left Speaker Position */ + struct _coord SPR = {7.5, 5.0}; /* Right Speaker Position */ + /* position of the reflective points */ + struct _coord RFN[] = { + { 5.0, 0.0}, + { 0.0, 6.66666}, + { 0.0, 13.3333}, + { 5.0, 20.0}, + { 10.0, 20.0}, + { 15.0, 13.3333}, + { 15.0, 6.66666}, + { 10.0, 0.0} + }; +#else + struct _coord SPL; /* Left Speaker Position */ + struct _coord SPR; /* Right Speaker Position */ + /* position of the reflective points */ + struct _coord RFN[8]; + + SPL.x = room_x / 4.0; + SPR.x = room_x / 4.0 * 3.0; + SPL.y = room_y / 10.0; + SPR.y = room_y / 10.0; + + RFN[0].x = room_x / 3.0; + RFN[0].y = 0.0; + RFN[1].x = 0.0; + RFN[1].y = room_y / 3.0; + RFN[2].x = 0.0; + RFN[2].y = room_y / 3.0 * 2.0; + RFN[3].x = room_x / 3.0; + RFN[3].y = room_y; + RFN[4].x = room_x / 3.0 * 2.0; + RFN[4].y = room_y; + RFN[5].x = room_x; + RFN[5].y = room_y / 3.0 * 2.0; + RFN[6].x = room_x; + RFN[6].y = room_y / 3.0; + RFN[7].x = room_x / 3.0 * 2.0; + RFN[7].y = 0.0; +#endif + + SPL_LSN_XOFS = SPL.x - listen_x; + SPL_LSN_YOFS = SPL.y - listen_y; + SPL_LSN_DST = sqrt((SPL_LSN_XOFS * SPL_LSN_XOFS) + (SPL_LSN_YOFS * SPL_LSN_YOFS)); + + if (SPL_LSN_DST > MAXL_DST) + MAXL_DST = SPL_LSN_DST; + + SPR_LSN_XOFS = SPR.x - listen_x; + SPR_LSN_YOFS = SPR.y - listen_y; + SPR_LSN_DST = sqrt((SPR_LSN_XOFS * SPR_LSN_XOFS) + (SPR_LSN_YOFS * SPR_LSN_YOFS)); + + if (SPR_LSN_DST > MAXR_DST) + MAXR_DST = SPR_LSN_DST; + + if (rtn_rvb == NULL) { + return NULL; + } + + for (j = 0; j < 8; j++) { + double SPL_RFL_XOFS = 0; + double SPL_RFL_YOFS = 0; + double SPR_RFL_XOFS = 0; + double SPR_RFL_YOFS = 0; + double RFN_XOFS = listen_x - RFN[j].x; + double RFN_YOFS = listen_y - RFN[j].y; + RFN_DST[j] = sqrt((RFN_XOFS * RFN_XOFS) + (RFN_YOFS * RFN_YOFS)); + + SPL_RFL_XOFS = SPL.x - RFN[i].x; + SPL_RFL_YOFS = SPL.y - RFN[i].y; + SPR_RFL_XOFS = SPR.x - RFN[i].x; + SPR_RFL_YOFS = SPR.y - RFN[i].y; + SPL_DST[i] = sqrt( + (SPL_RFL_XOFS * SPL_RFL_XOFS) + (SPL_RFL_YOFS * SPL_RFL_YOFS)); + SPR_DST[i] = sqrt( + (SPR_RFL_XOFS * SPR_RFL_XOFS) + (SPR_RFL_YOFS * SPR_RFL_YOFS)); + /* + add the 2 distances together and remove the speaker to listener distance + so we dont have to delay the initial output + */ + SPL_DST[i] += RFN_DST[i]; + + /* so i dont have to delay speaker output */ + SPL_DST[i] -= SPL_LSN_DST; + + if (i < 4) { + if (SPL_DST[i] > MAXL_DST) + MAXL_DST = SPL_DST[i]; + } else { + if (SPL_DST[i] > MAXR_DST) + MAXR_DST = SPL_DST[i]; + } + + SPR_DST[i] += RFN_DST[i]; + + /* so i dont have to delay speaker output */ + SPR_DST[i] -= SPR_LSN_DST; + + if (i < 4) { + if (SPR_DST[i] > MAXL_DST) + MAXL_DST = SPR_DST[i]; + } else { + if (SPR_DST[i] > MAXR_DST) + MAXR_DST = SPR_DST[i]; + } + + RFN_DST[j] *= 2.0; + + if (j < 4) { + if (RFN_DST[j] > MAXL_DST) + MAXL_DST = RFN_DST[j]; + } else { + if (RFN_DST[j] > MAXR_DST) + MAXR_DST = RFN_DST[j]; + } + + for (i = 0; i < 6; i++) { + double srate = (double) rate; + double bandwidth = 2.0; + double omega = 2.0 * M_PI * Freq[i] / srate; + double sn = sin(omega); + double cs = cos(omega); + double alpha = sn * sinh(M_LN2 / 2 * bandwidth * omega / sn); + double A = pow(10.0, ((/*dbAttn[i]*/dbAttn[j][i] + + (dbAirAbs[i] * RFN_DST[j])) / 40.0) ); + /* + Peaking band EQ filter + */ + double b0 = 1 + (alpha * A); + double b1 = -2 * cs; + double b2 = 1 - (alpha * A); + double a0 = 1 + (alpha / A); + double a1 = -2 * cs; + double a2 = 1 - (alpha / A); + + rtn_rvb->coeff[j][i][0] = (signed int) ((b0 / a0) * 1024.0); + rtn_rvb->coeff[j][i][1] = (signed int) ((b1 / a0) * 1024.0); + rtn_rvb->coeff[j][i][2] = (signed int) ((b2 / a0) * 1024.0); + rtn_rvb->coeff[j][i][3] = (signed int) ((a1 / a0) * 1024.0); + rtn_rvb->coeff[j][i][4] = (signed int) ((a2 / a0) * 1024.0); + } + } + + /* init the reverb buffers */ + rtn_rvb->l_buf_size = (int) ((float) rate * (MAXL_DST / 340.29)); + rtn_rvb->l_buf = (int*)malloc( + sizeof(signed int) * (rtn_rvb->l_buf_size + 1)); + rtn_rvb->l_out = 0; + + rtn_rvb->r_buf_size = (int) ((float) rate * (MAXR_DST / 340.29)); + rtn_rvb->r_buf = (int*)malloc( + sizeof(signed int) * (rtn_rvb->r_buf_size + 1)); + rtn_rvb->r_out = 0; + + for (i = 0; i < 4; i++) { + rtn_rvb->l_sp_in[i] = (int) ((float) rate * (SPL_DST[i] / 340.29)); + rtn_rvb->l_sp_in[i + 4] = (int) ((float) rate + * (SPL_DST[i + 4] / 340.29)); + rtn_rvb->r_sp_in[i] = (int) ((float) rate * (SPR_DST[i] / 340.29)); + rtn_rvb->r_sp_in[i + 4] = (int) ((float) rate + * (SPR_DST[i + 4] / 340.29)); + rtn_rvb->l_in[i] = (int) ((float) rate * (RFN_DST[i] / 340.29)); + rtn_rvb->r_in[i] = (int) ((float) rate * (RFN_DST[i + 4] / 340.29)); + } + + rtn_rvb->gain = 4; + + _WM_reset_reverb(rtn_rvb); + return rtn_rvb; +} + +/* _WM_free_reverb - free up memory used for reverb */ +void _WM_free_reverb(struct _rvb *rvb) { + if (!rvb) return; + free(rvb->l_buf); + free(rvb->r_buf); + free(rvb); +} + +void _WM_do_reverb(struct _rvb *rvb, signed int *buffer, int size) { + int i, j, k; + signed int l_buf_flt = 0; + signed int r_buf_flt = 0; + signed int l_rfl = 0; + signed int r_rfl = 0; + int vol_div = 64; + + for (i = 0; i < size; i += 2) { + signed int tmp_l_val = 0; + signed int tmp_r_val = 0; + /* + add the initial reflections + from each speaker, 4 to go the left, 4 go to the right buffers + */ + tmp_l_val = buffer[i] / vol_div; + tmp_r_val = buffer[i + 1] / vol_div; + for (j = 0; j < 4; j++) { + rvb->l_buf[rvb->l_sp_in[j]] += tmp_l_val; + rvb->l_sp_in[j] = (rvb->l_sp_in[j] + 1) % rvb->l_buf_size; + rvb->l_buf[rvb->r_sp_in[j]] += tmp_r_val; + rvb->r_sp_in[j] = (rvb->r_sp_in[j] + 1) % rvb->l_buf_size; + + rvb->r_buf[rvb->l_sp_in[j + 4]] += tmp_l_val; + rvb->l_sp_in[j + 4] = (rvb->l_sp_in[j + 4] + 1) % rvb->r_buf_size; + rvb->r_buf[rvb->r_sp_in[j + 4]] += tmp_r_val; + rvb->r_sp_in[j + 4] = (rvb->r_sp_in[j + 4] + 1) % rvb->r_buf_size; + } + + /* + filter the reverb output and add to buffer + */ + l_rfl = rvb->l_buf[rvb->l_out]; + rvb->l_buf[rvb->l_out] = 0; + rvb->l_out = (rvb->l_out + 1) % rvb->l_buf_size; + + r_rfl = rvb->r_buf[rvb->r_out]; + rvb->r_buf[rvb->r_out] = 0; + rvb->r_out = (rvb->r_out + 1) % rvb->r_buf_size; + + for (k = 0; k < 8; k++) { + for (j = 0; j < 6; j++) { + l_buf_flt = ((l_rfl * rvb->coeff[k][j][0]) + + (rvb->l_buf_flt_in[k][j][0] * rvb->coeff[k][j][1]) + + (rvb->l_buf_flt_in[k][j][1] * rvb->coeff[k][j][2]) + - (rvb->l_buf_flt_out[k][j][0] * rvb->coeff[k][j][3]) + - (rvb->l_buf_flt_out[k][j][1] * rvb->coeff[k][j][4])) + / 1024; + rvb->l_buf_flt_in[k][j][1] = rvb->l_buf_flt_in[k][j][0]; + rvb->l_buf_flt_in[k][j][0] = l_rfl; + rvb->l_buf_flt_out[k][j][1] = rvb->l_buf_flt_out[k][j][0]; + rvb->l_buf_flt_out[k][j][0] = l_buf_flt; + buffer[i] += l_buf_flt / 8; + + r_buf_flt = ((r_rfl * rvb->coeff[k][j][0]) + + (rvb->r_buf_flt_in[k][j][0] * rvb->coeff[k][j][1]) + + (rvb->r_buf_flt_in[k][j][1] * rvb->coeff[k][j][2]) + - (rvb->r_buf_flt_out[k][j][0] * rvb->coeff[k][j][3]) + - (rvb->r_buf_flt_out[k][j][1] * rvb->coeff[k][j][4])) + / 1024; + rvb->r_buf_flt_in[k][j][1] = rvb->r_buf_flt_in[k][j][0]; + rvb->r_buf_flt_in[k][j][0] = r_rfl; + rvb->r_buf_flt_out[k][j][1] = rvb->r_buf_flt_out[k][j][0]; + rvb->r_buf_flt_out[k][j][0] = r_buf_flt; + buffer[i + 1] += r_buf_flt / 8; + } + } + + /* + add filtered result back into the buffers but on the opposite side + */ + tmp_l_val = buffer[i + 1] / vol_div; + tmp_r_val = buffer[i] / vol_div; + for (j = 0; j < 4; j++) { + rvb->l_buf[rvb->l_in[j]] += tmp_l_val; + rvb->l_in[j] = (rvb->l_in[j] + 1) % rvb->l_buf_size; + + rvb->r_buf[rvb->r_in[j]] += tmp_r_val; + rvb->r_in[j] = (rvb->r_in[j] + 1) % rvb->r_buf_size; + } + } +} + diff --git a/src/wildmidi/reverb.h b/src/wildmidi/reverb.h new file mode 100644 index 000000000..162de61eb --- /dev/null +++ b/src/wildmidi/reverb.h @@ -0,0 +1,57 @@ +/* + reverb.h + + Midi Wavetable Processing library + + Copyright (C) Chris Ison 2001-2011 + Copyright (C) Bret Curtis 2013-2014 + + This file is part of WildMIDI. + + WildMIDI is free software: you can redistribute and/or modify the player + under the terms of the GNU General Public License and you can redistribute + and/or modify the library under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, either version 3 of + the licenses, or(at your option) any later version. + + WildMIDI 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 and + the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License and the + GNU Lesser General Public License along with WildMIDI. If not, see + . +*/ + +#ifndef __REVERB_H +#define __REVERB_H + +struct _rvb { + /* filter data */ + signed int l_buf_flt_in[8][6][2]; + signed int l_buf_flt_out[8][6][2]; + signed int r_buf_flt_in[8][6][2]; + signed int r_buf_flt_out[8][6][2]; + signed int coeff[8][6][5]; + /* buffer data */ + signed int *l_buf; + signed int *r_buf; + int l_buf_size; + int r_buf_size; + int l_out; + int r_out; + int l_sp_in[8]; + int r_sp_in[8]; + int l_in[4]; + int r_in[4]; + int gain; + unsigned long int max_reverb_time; +}; + + extern void _WM_reset_reverb (struct _rvb *rvb); + extern struct _rvb *_WM_init_reverb(int rate, float room_x, float room_y, float listen_x, float listen_y); + extern void _WM_free_reverb (struct _rvb *rvb); + extern void _WM_do_reverb (struct _rvb *rvb, signed int *buffer, int size); + +#endif /* __REVERB_H */ diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp new file mode 100644 index 000000000..5f711bf35 --- /dev/null +++ b/src/wildmidi/wildmidi_lib.cpp @@ -0,0 +1,2954 @@ +/* + wildmidi_lib.c + + Midi Wavetable Processing library + + Copyright (C) Chris Ison 2001-2014 + Copyright (C) Bret Curtis 2013-2014 + + This file is part of WildMIDI. + + WildMIDI is free software: you can redistribute and/or modify the player + under the terms of the GNU General Public License and you can redistribute + and/or modify the library under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, either version 3 of + the licenses, or(at your option) any later version. + + WildMIDI 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 and + the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License and the + GNU Lesser General Public License along with WildMIDI. If not, see + . + */ + +//#include "config.h" + +#define UNUSED(x) (void)(x) + +#include +#include +#include +#ifndef _WIN32 +#include +#include +#include +#endif +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "wm_error.h" +#include "file_io.h" +#include "reverb.h" +#include "gus_pat.h" +#include "wildmidi_lib.h" +#include "critsec.h" + +#define IS_DIR_SEPARATOR(c) ((c) == '/' || (c) == '\\') +#ifdef _WIN32 +#define HAS_DRIVE_SPEC(f) ((f)[0] && ((f)[1] == ':')) +#else +#define HAS_DRIVE_SPEC(f) (0) +#endif +#define IS_ABSOLUTE_PATH(f) (IS_DIR_SEPARATOR((f)[0]) || HAS_DRIVE_SPEC((f))) + + +/* + * ========================= + * Global Data and Data Structs + * ========================= + */ + +#define MEM_CHUNK 8192 + +static int WM_Initialized = 0; +static signed short int WM_MasterVolume = 948; +static unsigned short int WM_MixerOptions = 0; + +static char WM_Version[] = "WildMidi Processing Library"; + +unsigned short int _WM_SampleRate; + +static struct _patch *patch[128]; + +static float reverb_room_width = 16.875f; +static float reverb_room_length = 22.5f; + +static float reverb_listen_posx = 8.4375f; +static float reverb_listen_posy = 16.875f; + +static int fix_release = 0; +static int auto_amp = 0; +static int auto_amp_with_amp = 0; + +static FCriticalSection patch_lock; + +struct _channel { + unsigned char bank; + struct _patch *patch; + unsigned char hold; + unsigned char volume; + unsigned char pressure; + unsigned char expression; + signed char balance; + signed char pan; + signed short int left_adjust; + signed short int right_adjust; + signed short int pitch; + signed short int pitch_range; + signed long int pitch_adjust; + unsigned short reg_data; + unsigned char reg_non; + unsigned char isdrum; +}; + +#define HOLD_OFF 0x02 + +struct _note { + unsigned short noteid; + unsigned char velocity; + struct _patch *patch; + struct _sample *sample; + unsigned int sample_pos; + unsigned int sample_inc; + signed int env_inc; + unsigned char env; + signed int env_level; + unsigned char modes; + unsigned char hold; + unsigned char active; + struct _note *replay; + struct _note *next; + unsigned int left_mix_volume; + unsigned int right_mix_volume; + unsigned char is_off; +}; + +struct _event_data { + unsigned char channel; + unsigned int data; +}; + +struct _mdi { + _mdi() + { + samples_to_mix = 0; + midi_master_vol = 0; + memset(&info, 0, sizeof(info)); + tmp_info = NULL; + memset(&channel, 0, sizeof(channel)); + note = NULL; + memset(note_table, 0, sizeof(note_table)); + patches = NULL; + patch_count = 0; + amp = 0; + mix_buffer = NULL; + mix_buffer_size = 0; + reverb = NULL; + } + + FCriticalSection lock; + unsigned long int samples_to_mix; + + unsigned short midi_master_vol; + struct _WM_Info info; + struct _WM_Info *tmp_info; + struct _channel channel[16]; + struct _note *note; + struct _note note_table[2][16][128]; + + struct _patch **patches; + unsigned long int patch_count; + signed short int amp; + + signed int *mix_buffer; + unsigned long int mix_buffer_size; + + struct _rvb *reverb; +}; + +#define FPBITS 10 +#define FPMASK ((1L<> 1); + int j; + int sign; + double ck; + double x, x_inc, xz; + double z[35]; + double *gptr, *t; + + gauss_lock.Enter(); + if (gauss_table) { + gauss_lock.Leave(); + return; + } + + newt_coeffs[0][0] = 1; + for (i = 0; i <= n; i++) { + newt_coeffs[i][0] = 1; + newt_coeffs[i][i] = 1; + + if (i > 1) { + newt_coeffs[i][0] = newt_coeffs[i - 1][0] / i; + newt_coeffs[i][i] = newt_coeffs[i - 1][0] / i; + } + + for (j = 1; j < i; j++) { + newt_coeffs[i][j] = newt_coeffs[i - 1][j - 1] + + newt_coeffs[i - 1][j]; + if (i > 1) + newt_coeffs[i][j] /= i; + } + z[i] = i / (4 * M_PI); + } + + for (i = 0; i <= n; i++) + for (j = 0, sign = (int)pow(-1., i); j <= i; j++, sign *= -1) + newt_coeffs[i][j] *= sign; + + t = (double*)malloc((1<first_sample) { + tmp_sample = patch[i]->first_sample->next; + free(patch[i]->first_sample->data); + free(patch[i]->first_sample); + patch[i]->first_sample = tmp_sample; + } + free(patch[i]->filename); + tmp_patch = patch[i]->next; + free(patch[i]); + patch[i] = tmp_patch; + } + } + patch_lock.Leave(); +} + +/* wm_strdup -- adds extra space for appending up to 4 chars */ +static char *wm_strdup (const char *str) { + size_t l = strlen(str) + 5; + char *d = (char *) malloc(l * sizeof(char)); + if (d) { + strcpy(d, str); + return d; + } + return NULL; +} + +static inline int wm_isdigit(int c) { + return (c >= '0' && c <= '9'); +} + +#define TOKEN_CNT_INC 8 +static char** WM_LC_Tokenize_Line(char *line_data) +{ + int line_length = (int)strlen(line_data); + int token_data_length = 0; + int line_ofs = 0; + int token_start = 0; + char **token_data = NULL; + int token_count = 0; + bool in_quotes = false; + + if (line_length == 0) + return NULL; + + do { + /* ignore everything after # */ + if (line_data[line_ofs] == '#') { + break; + } + if (line_data[line_ofs] == '"') + { + in_quotes = !in_quotes; + } + else if (!in_quotes && ((line_data[line_ofs] == ' ') || (line_data[line_ofs] == '\t'))) { + /* whitespace means we aren't in a token */ + if (token_start) { + token_start = 0; + line_data[line_ofs] = '\0'; + } + } else { + if (!token_start) { + /* the start of a token in the line */ + token_start = 1; + if (token_count >= token_data_length) { + token_data_length += TOKEN_CNT_INC; + token_data = (char**)realloc(token_data, token_data_length * sizeof(char *)); + if (token_data == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM,"to parse config", errno); + return NULL; + } + } + + token_data[token_count] = &line_data[line_ofs]; + token_count++; + } + } + line_ofs++; + } while (line_ofs != line_length); + + /* if we have found some tokens then add a null token to the end */ + if (token_count) { + if (token_count >= token_data_length) { + token_data = (char**)realloc(token_data, + ((token_count + 1) * sizeof(char *))); + } + token_data[token_count] = NULL; + } + + return token_data; +} + +static int WM_LoadConfig(const char *config_file) { + unsigned long int config_size = 0; + char *config_buffer = NULL; + const char *dir_end = NULL; + char *config_dir = NULL; + unsigned long int config_ptr = 0; + unsigned long int line_start_ptr = 0; + unsigned short int patchid = 0; + struct _patch * tmp_patch; + char **line_tokens = NULL; + int token_count = 0; + + config_buffer = (char *) _WM_BufferFile(config_file, &config_size, true); + if (!config_buffer) { + WM_FreePatches(); + return -1; + } + + + // This part was rewritten because the original depended on a header that was GPL'd. + dir_end = strrchr(config_file, '/'); +#ifdef _WIN32 + const char *dir_end2 = strrchr(config_file, '\\'); + if (dir_end2 > dir_end) dir_end = dir_end2; +#endif + + if (dir_end) { + config_dir = (char*)malloc((dir_end - config_file + 2)); + if (config_dir == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse config", + errno); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0); + WM_FreePatches(); + free(config_buffer); + return -1; + } + strncpy(config_dir, config_file, (dir_end - config_file + 1)); + config_dir[dir_end - config_file + 1] = '\0'; + } + + config_ptr = 0; + line_start_ptr = 0; + + /* handle files without a newline at the end: this relies on + * _WM_BufferFile() allocating the buffer with one extra byte */ + config_buffer[config_size] = '\n'; + + while (config_ptr <= config_size) { + if (config_buffer[config_ptr] == '\r' || + config_buffer[config_ptr] == '\n') + { + config_buffer[config_ptr] = '\0'; + + if (config_ptr != line_start_ptr) { + line_tokens = WM_LC_Tokenize_Line(&config_buffer[line_start_ptr]); + if (line_tokens) { + if (stricmp(line_tokens[0], "dir") == 0) { + free(config_dir); + if (!line_tokens[1]) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(missing name in dir line)", 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(line_tokens); + free(config_buffer); + return -1; + } else if (!(config_dir = wm_strdup(line_tokens[1]))) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, + "to parse config", errno); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(line_tokens); + free(config_buffer); + return -1; + } + if (!IS_DIR_SEPARATOR(config_dir[strlen(config_dir) - 1])) { + config_dir[strlen(config_dir) + 1] = '\0'; + config_dir[strlen(config_dir)] = '/'; + } + } else if (stricmp(line_tokens[0], "source") == 0) { + char *new_config = NULL; + if (!line_tokens[1]) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(missing name in source line)", 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(line_tokens); + free(config_buffer); + return -1; + } else if (!IS_ABSOLUTE_PATH(line_tokens[1]) && config_dir) { + new_config = (char*)malloc( + strlen(config_dir) + strlen(line_tokens[1]) + + 1); + if (new_config == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, + "to parse config", errno); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(config_dir); + free(line_tokens); + free(config_buffer); + return -1; + } + strcpy(new_config, config_dir); + strcpy(&new_config[strlen(config_dir)], line_tokens[1]); + } else { + if (!(new_config = wm_strdup(line_tokens[1]))) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, + "to parse config", errno); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(line_tokens); + free(config_buffer); + return -1; + } + } + if (WM_LoadConfig(new_config) == -1) { + free(new_config); + free(line_tokens); + free(config_buffer); + free(config_dir); + return -1; + } + free(new_config); + } else if (stricmp(line_tokens[0], "bank") == 0) { + if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(syntax error in bank line)", 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(config_dir); + free(line_tokens); + free(config_buffer); + return -1; + } + patchid = (atoi(line_tokens[1]) & 0xFF) << 8; + } else if (stricmp(line_tokens[0], "drumset") == 0) { + if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(syntax error in drumset line)", 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(config_dir); + free(line_tokens); + free(config_buffer); + return -1; + } + patchid = ((atoi(line_tokens[1]) & 0xFF) << 8) | 0x80; + } else if (stricmp(line_tokens[0], "reverb_room_width") == 0) { + if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(syntax error in reverb_room_width line)", + 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(config_dir); + free(line_tokens); + free(config_buffer); + return -1; + } + reverb_room_width = (float) atof(line_tokens[1]); + if (reverb_room_width < 1.0f) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(reverb_room_width < 1 meter, setting to minimum of 1 meter)", + 0); + reverb_room_width = 1.0f; + } else if (reverb_room_width > 100.0f) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(reverb_room_width > 100 meters, setting to maximum of 100 meters)", + 0); + reverb_room_width = 100.0f; + } + } else if (stricmp(line_tokens[0], "reverb_room_length") == 0) { + if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(syntax error in reverb_room_length line)", + 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(config_dir); + free(line_tokens); + free(config_buffer); + return -1; + } + reverb_room_length = (float) atof(line_tokens[1]); + if (reverb_room_length < 1.0f) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(reverb_room_length < 1 meter, setting to minimum of 1 meter)", + 0); + reverb_room_length = 1.0f; + } else if (reverb_room_length > 100.0f) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(reverb_room_length > 100 meters, setting to maximum of 100 meters)", + 0); + reverb_room_length = 100.0f; + } + } else if (stricmp(line_tokens[0], "reverb_listener_posx") == 0) { + if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(syntax error in reverb_listen_posx line)", + 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(config_dir); + free(line_tokens); + free(config_buffer); + return -1; + } + reverb_listen_posx = (float) atof(line_tokens[1]); + if ((reverb_listen_posx > reverb_room_width) + || (reverb_listen_posx < 0.0f)) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(reverb_listen_posx set outside of room)", + 0); + reverb_listen_posx = reverb_room_width / 2.0f; + } + } else if (stricmp(line_tokens[0], + "reverb_listener_posy") == 0) { + if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(syntax error in reverb_listen_posy line)", + 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(config_dir); + free(line_tokens); + free(config_buffer); + return -1; + } + reverb_listen_posy = (float) atof(line_tokens[1]); + if ((reverb_listen_posy > reverb_room_width) + || (reverb_listen_posy < 0.0f)) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(reverb_listen_posy set outside of room)", + 0); + reverb_listen_posy = reverb_room_length * 0.75f; + } + } else if (stricmp(line_tokens[0], + "guspat_editor_author_cant_read_so_fix_release_time_for_me") + == 0) { + fix_release = 1; + } else if (stricmp(line_tokens[0], "auto_amp") == 0) { + auto_amp = 1; + } else if (stricmp(line_tokens[0], "auto_amp_with_amp") + == 0) { + auto_amp = 1; + auto_amp_with_amp = 1; + } else if (wm_isdigit(line_tokens[0][0])) { + patchid = (patchid & 0xFF80) + | (atoi(line_tokens[0]) & 0x7F); + if (patch[(patchid & 0x7F)] == NULL) { + patch[(patchid & 0x7F)] = (struct _patch*)malloc( + sizeof(struct _patch)); + if (patch[(patchid & 0x7F)] == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, + NULL, errno); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(config_dir); + free(line_tokens); + free(config_buffer); + return -1; + } + tmp_patch = patch[(patchid & 0x7F)]; + tmp_patch->patchid = patchid; + tmp_patch->filename = NULL; + tmp_patch->amp = 1024; + tmp_patch->note = 0; + tmp_patch->next = NULL; + tmp_patch->first_sample = NULL; + tmp_patch->loaded = 0; + tmp_patch->inuse_count = 0; + } else { + tmp_patch = patch[(patchid & 0x7F)]; + if (tmp_patch->patchid == patchid) { + free(tmp_patch->filename); + tmp_patch->filename = NULL; + tmp_patch->amp = 1024; + tmp_patch->note = 0; + } else { + if (tmp_patch->next) { + while (tmp_patch->next) { + if (tmp_patch->next->patchid == patchid) + break; + tmp_patch = tmp_patch->next; + } + if (tmp_patch->next == NULL) { + if ((tmp_patch->next = (struct _patch*)malloc( + sizeof(struct _patch))) + == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, + WM_ERR_MEM, NULL, 0); + _WM_ERROR(__FUNCTION__, __LINE__, + WM_ERR_LOAD, config_file, + 0); + WM_FreePatches(); + free(config_dir); + free(line_tokens); + free(config_buffer); + return -1; + } + tmp_patch = tmp_patch->next; + tmp_patch->patchid = patchid; + tmp_patch->filename = NULL; + tmp_patch->amp = 1024; + tmp_patch->note = 0; + tmp_patch->next = NULL; + tmp_patch->first_sample = NULL; + tmp_patch->loaded = 0; + tmp_patch->inuse_count = 0; + } else { + tmp_patch = tmp_patch->next; + free(tmp_patch->filename); + tmp_patch->filename = NULL; + tmp_patch->amp = 1024; + tmp_patch->note = 0; + } + } else { + tmp_patch->next = (struct _patch*)malloc( + sizeof(struct _patch)); + if (tmp_patch->next == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, + WM_ERR_MEM, NULL, errno); + _WM_ERROR(__FUNCTION__, __LINE__, + WM_ERR_LOAD, config_file, 0); + WM_FreePatches(); + free(config_dir); + free(line_tokens); + free(config_buffer); + return -1; + } + tmp_patch = tmp_patch->next; + tmp_patch->patchid = patchid; + tmp_patch->filename = NULL; + tmp_patch->amp = 1024; + tmp_patch->note = 0; + tmp_patch->next = NULL; + tmp_patch->first_sample = NULL; + tmp_patch->loaded = 0; + tmp_patch->inuse_count = 0; + } + } + } + if (!line_tokens[1]) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(missing name in patch line)", 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(config_dir); + free(line_tokens); + free(config_buffer); + return -1; + } else if (!IS_ABSOLUTE_PATH(line_tokens[1]) && config_dir) { + tmp_patch->filename = (char*)malloc( + strlen(config_dir) + strlen(line_tokens[1]) + + 5); + if (tmp_patch->filename == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, + NULL, 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(config_dir); + free(line_tokens); + free(config_buffer); + return -1; + } + strcpy(tmp_patch->filename, config_dir); + strcat(tmp_patch->filename, line_tokens[1]); + } else { + if (!(tmp_patch->filename = wm_strdup(line_tokens[1]))) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, + NULL, 0); + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, + config_file, 0); + WM_FreePatches(); + free(config_dir); + free(line_tokens); + free(config_buffer); + return -1; + } + } + if (strnicmp( + &tmp_patch->filename[strlen(tmp_patch->filename) + - 4], ".pat", 4) != 0) { + strcat(tmp_patch->filename, ".pat"); + } + tmp_patch->env[0].set = 0x00; + tmp_patch->env[1].set = 0x00; + tmp_patch->env[2].set = 0x00; + tmp_patch->env[3].set = 0x00; + tmp_patch->env[4].set = 0x00; + tmp_patch->env[5].set = 0x00; + tmp_patch->keep = 0; + tmp_patch->remove = 0; + + token_count = 0; + while (line_tokens[token_count]) { + if (strnicmp(line_tokens[token_count], "amp=", 4) + == 0) { + if (!wm_isdigit(line_tokens[token_count][4])) { + _WM_ERROR(__FUNCTION__, __LINE__, + WM_ERR_INVALID_ARG, + "(syntax error in patch line)", 0); + } else { + tmp_patch->amp = (atoi( + &line_tokens[token_count][4]) << 10) + / 100; + } + } else if (strnicmp(line_tokens[token_count], + "note=", 5) == 0) { + if (!wm_isdigit(line_tokens[token_count][5])) { + _WM_ERROR(__FUNCTION__, __LINE__, + WM_ERR_INVALID_ARG, + "(syntax error in patch line)", 0); + } else { + tmp_patch->note = atoi( + &line_tokens[token_count][5]); + } + } else if (strnicmp(line_tokens[token_count], + "env_time", 8) == 0) { + if ((!wm_isdigit(line_tokens[token_count][8])) + || (!wm_isdigit( + line_tokens[token_count][10])) + || (line_tokens[token_count][9] != '=')) { + _WM_ERROR(__FUNCTION__, __LINE__, + WM_ERR_INVALID_ARG, + "(syntax error in patch line)", 0); + } else { + unsigned int env_no = atoi( + &line_tokens[token_count][8]); + if (env_no > 5) { + _WM_ERROR(__FUNCTION__, __LINE__, + WM_ERR_INVALID_ARG, + "(syntax error in patch line)", + 0); + } else { + tmp_patch->env[env_no].time = + (float) atof( + &line_tokens[token_count][10]); + if ((tmp_patch->env[env_no].time + > 45000.0f) + || (tmp_patch->env[env_no].time + < 1.47f)) { + _WM_ERROR(__FUNCTION__, __LINE__, + WM_ERR_INVALID_ARG, + "(range error in patch line)", + 0); + tmp_patch->env[env_no].set &= 0xFE; + } else { + tmp_patch->env[env_no].set |= 0x01; + } + } + } + } else if (strnicmp(line_tokens[token_count], + "env_level", 9) == 0) { + if ((!wm_isdigit(line_tokens[token_count][9])) + || (!wm_isdigit( + line_tokens[token_count][11])) + || (line_tokens[token_count][10] != '=')) { + _WM_ERROR(__FUNCTION__, __LINE__, + WM_ERR_INVALID_ARG, + "(syntax error in patch line)", 0); + } else { + unsigned int env_no = atoi( + &line_tokens[token_count][9]); + if (env_no > 5) { + _WM_ERROR(__FUNCTION__, __LINE__, + WM_ERR_INVALID_ARG, + "(syntax error in patch line)", + 0); + } else { + tmp_patch->env[env_no].level = + (float) atof( + &line_tokens[token_count][11]); + if ((tmp_patch->env[env_no].level > 1.0f) + || (tmp_patch->env[env_no].level + < 0.0f)) { + _WM_ERROR(__FUNCTION__, __LINE__, + WM_ERR_INVALID_ARG, + "(range error in patch line)", + 0); + tmp_patch->env[env_no].set &= 0xFD; + } else { + tmp_patch->env[env_no].set |= 0x02; + } + } + } + } else if (stricmp(line_tokens[token_count], + "keep=loop") == 0) { + tmp_patch->keep |= SAMPLE_LOOP; + } else if (stricmp(line_tokens[token_count], + "keep=env") == 0) { + tmp_patch->keep |= SAMPLE_ENVELOPE; + } else if (stricmp(line_tokens[token_count], + "remove=sustain") == 0) { + tmp_patch->remove |= SAMPLE_SUSTAIN; + } else if (stricmp(line_tokens[token_count], + "remove=clamped") == 0) { + tmp_patch->remove |= SAMPLE_CLAMPED; + } + token_count++; + } + } + } + /* free up tokens */ + free(line_tokens); + } + line_start_ptr = config_ptr + 1; + } + config_ptr++; + } + + free(config_buffer); + free(config_dir); + + return 0; +} + +/* sample loading */ + +static int load_sample(struct _patch *sample_patch) { + struct _sample *guspat = NULL; + struct _sample *tmp_sample = NULL; + unsigned int i = 0; + + /* we only want to try loading the guspat once. */ + sample_patch->loaded = 1; + + if ((guspat = _WM_load_gus_pat(sample_patch->filename, fix_release)) == NULL) { + return -1; + } + + if (auto_amp) { + signed short int tmp_max = 0; + signed short int tmp_min = 0; + signed short samp_max = 0; + signed short samp_min = 0; + tmp_sample = guspat; + do { + samp_max = 0; + samp_min = 0; + for (i = 0; i < (tmp_sample->data_length >> 10); i++) { + if (tmp_sample->data[i] > samp_max) + samp_max = tmp_sample->data[i]; + if (tmp_sample->data[i] < samp_min) + samp_min = tmp_sample->data[i]; + } + if (samp_max > tmp_max) + tmp_max = samp_max; + if (samp_min < tmp_min) + tmp_min = samp_min; + tmp_sample = tmp_sample->next; + } while (tmp_sample); + if (auto_amp_with_amp) { + if (tmp_max >= -tmp_min) { + sample_patch->amp = (sample_patch->amp + * ((32767 << 10) / tmp_max)) >> 10; + } else { + sample_patch->amp = (sample_patch->amp + * ((32768 << 10) / -tmp_min)) >> 10; + } + } else { + if (tmp_max >= -tmp_min) { + sample_patch->amp = (32767 << 10) / tmp_max; + } else { + sample_patch->amp = (32768 << 10) / -tmp_min; + } + } + } + + sample_patch->first_sample = guspat; + + if (sample_patch->patchid & 0x0080) { + if (!(sample_patch->keep & SAMPLE_LOOP)) { + do { + guspat->modes &= 0xFB; + guspat = guspat->next; + } while (guspat); + } + guspat = sample_patch->first_sample; + if (!(sample_patch->keep & SAMPLE_ENVELOPE)) { + do { + guspat->modes &= 0xBF; + guspat = guspat->next; + } while (guspat); + } + guspat = sample_patch->first_sample; + } + + if (sample_patch->patchid == 47) { + do { + if (!(guspat->modes & SAMPLE_LOOP)) { + for (i = 3; i < 6; i++) { + guspat->env_target[i] = guspat->env_target[2]; + guspat->env_rate[i] = guspat->env_rate[2]; + } + } + guspat = guspat->next; + } while (guspat); + guspat = sample_patch->first_sample; + } + + do { + if ((sample_patch->remove & SAMPLE_SUSTAIN) + && (guspat->modes & SAMPLE_SUSTAIN)) { + guspat->modes ^= SAMPLE_SUSTAIN; + } + if ((sample_patch->remove & SAMPLE_CLAMPED) + && (guspat->modes & SAMPLE_CLAMPED)) { + guspat->modes ^= SAMPLE_CLAMPED; + } + if (sample_patch->keep & SAMPLE_ENVELOPE) { + guspat->modes |= SAMPLE_ENVELOPE; + } + + for (i = 0; i < 6; i++) { + if (guspat->modes & SAMPLE_ENVELOPE) { + if (sample_patch->env[i].set & 0x02) { + guspat->env_target[i] = 16448 + * (signed long int) (255.0 + * sample_patch->env[i].level); + } + + if (sample_patch->env[i].set & 0x01) { + guspat->env_rate[i] = (signed long int) (4194303.0 + / ((float) _WM_SampleRate + * (sample_patch->env[i].time / 1000.0))); + } + } else { + guspat->env_target[i] = 4194303; + guspat->env_rate[i] = (signed long int) (4194303.0 + / ((float) _WM_SampleRate * env_time_table[63])); + } + } + + guspat = guspat->next; + } while (guspat); + return 0; +} + +static struct _patch * +get_patch_data(unsigned short patchid) { + struct _patch *search_patch; + + patch_lock.Enter(); + + search_patch = patch[patchid & 0x007F]; + + if (search_patch == NULL) { + patch_lock.Leave(); + return NULL; + } + + while (search_patch) { + if (search_patch->patchid == patchid) { + patch_lock.Leave(); + return search_patch; + } + search_patch = search_patch->next; + } + if ((patchid >> 8) != 0) { + patch_lock.Leave(); + return (get_patch_data(patchid & 0x00FF)); + } + patch_lock.Leave(); + return NULL; +} + +static void load_patch(struct _mdi *mdi, unsigned short patchid) { + unsigned int i; + struct _patch *tmp_patch = NULL; + + for (i = 0; i < mdi->patch_count; i++) { + if (mdi->patches[i]->patchid == patchid) { + return; + } + } + + tmp_patch = get_patch_data(patchid); + if (tmp_patch == NULL) { + return; + } + + patch_lock.Enter(); + if (!tmp_patch->loaded) { + if (load_sample(tmp_patch) == -1) { + patch_lock.Leave(); + return; + } + } + + if (tmp_patch->first_sample == NULL) { + patch_lock.Leave(); + return; + } + + mdi->patch_count++; + mdi->patches = (struct _patch**)realloc(mdi->patches, + (sizeof(struct _patch*) * mdi->patch_count)); + mdi->patches[mdi->patch_count - 1] = tmp_patch; + tmp_patch->inuse_count++; + patch_lock.Leave(); +} + +static struct _sample * +get_sample_data(struct _patch *sample_patch, unsigned long int freq) { + struct _sample *last_sample = NULL; + struct _sample *return_sample = NULL; + + patch_lock.Enter(); + if (sample_patch == NULL) { + patch_lock.Leave(); + return NULL; + } + if (sample_patch->first_sample == NULL) { + patch_lock.Leave(); + return NULL; + } + if (freq == 0) { + patch_lock.Leave(); + return sample_patch->first_sample; + } + + return_sample = sample_patch->first_sample; + last_sample = sample_patch->first_sample; + while (last_sample) { + if (freq > last_sample->freq_low) { + if (freq < last_sample->freq_high) { + patch_lock.Leave(); + return last_sample; + } else { + return_sample = last_sample; + } + } + last_sample = last_sample->next; + } + patch_lock.Leave(); + return return_sample; +} + +/* Should be called in any function that effects note volumes */ +void _WM_AdjustNoteVolumes(struct _mdi *mdi, unsigned char ch, struct _note *nte) { + double premix_dBm; + double premix_lin; + int pan_ofs; + double premix_dBm_left; + double premix_dBm_right; + double premix_left; + double premix_right; + double volume_adj; + unsigned vol_ofs; + + /* + Pointless CPU heating checks to shoosh up a compiler + */ + if (ch > 0x0f) ch = 0x0f; + + pan_ofs = mdi->channel[ch].balance + mdi->channel[ch].pan - 64; + + vol_ofs = (nte->velocity * ((mdi->channel[ch].expression * mdi->channel[ch].volume) / 127)) / 127; + + /* + This value is to reduce the chance of clipping. + Higher value means lower overall volume, + Lower value means higher overall volume. + NOTE: The lower the value the higher the chance of clipping. + FIXME: Still needs tuning. Clipping heard at a value of 3.75 + */ +#define VOL_DIVISOR 4.0 + volume_adj = ((float)WM_MasterVolume / 1024.0) / VOL_DIVISOR; + + // Pan 0 and 1 are both hard left so 64 can be centered + if (pan_ofs > 127) pan_ofs = 127; + if (--pan_ofs < 0) pan_ofs = 0; + premix_dBm_left = dBm_pan_volume[126-pan_ofs]; + premix_dBm_right = dBm_pan_volume[pan_ofs]; + + if (mdi->info.mixer_options & WM_MO_LOG_VOLUME) { + premix_dBm = dBm_volume[vol_ofs]; + + premix_dBm_left += premix_dBm; + premix_dBm_right += premix_dBm; + + premix_left = (pow(10.0,(premix_dBm_left / 20.0))) * volume_adj; + premix_right = (pow(10.0,(premix_dBm_right / 20.0))) * volume_adj; + } else { + premix_lin = (float)(lin_volume[vol_ofs]) / 1024.0; + + premix_left = premix_lin * pow(10.0, (premix_dBm_left / 20)) * volume_adj; + premix_right = premix_lin * pow(10.0, (premix_dBm_right / 20)) * volume_adj; + } + nte->left_mix_volume = (int)(premix_left * 1024.0); + nte->right_mix_volume = (int)(premix_right * 1024.0); +} + +/* Should be called in any function that effects channel volumes */ +/* Calling this function with a value > 15 will make it adjust notes on all channels */ +void _WM_AdjustChannelVolumes(struct _mdi *mdi, unsigned char ch) { + struct _note *nte = mdi->note; + if (nte != NULL) { + do { + if (ch <= 15) { + if ((nte->noteid >> 8) == ch) { + goto _DO_ADJUST; + } + } else { + _DO_ADJUST: + _WM_AdjustNoteVolumes(mdi, ch, nte); + if (nte->replay) _WM_AdjustNoteVolumes(mdi, ch, nte->replay); + } + nte = nte->next; + } while (nte != NULL); + } +} + +static void do_note_off_extra(struct _note *nte) { + + nte->is_off = 0; + + + if (!(nte->modes & SAMPLE_ENVELOPE)) { + if (nte->modes & SAMPLE_LOOP) { + nte->modes ^= SAMPLE_LOOP; + } + nte->env_inc = 0; + + } else if (nte->hold) { + nte->hold |= HOLD_OFF; + + } else if (nte->modes & SAMPLE_SUSTAIN) { + if (nte->env < 3) { + nte->env = 3; + if (nte->env_level > nte->sample->env_target[3]) { + nte->env_inc = -nte->sample->env_rate[3]; + } else { + nte->env_inc = nte->sample->env_rate[3]; + } + } + + } else if (nte->modes & SAMPLE_CLAMPED) { + if (nte->env < 5) { + nte->env = 5; + if (nte->env_level > nte->sample->env_target[5]) { + nte->env_inc = -nte->sample->env_rate[5]; + } else { + nte->env_inc = nte->sample->env_rate[5]; + } + } + } else if (nte->env < 4) { + nte->env = 4; + if (nte->env_level > nte->sample->env_target[4]) { + nte->env_inc = -nte->sample->env_rate[4]; + } else { + nte->env_inc = nte->sample->env_rate[4]; + } + } +} + +static void do_note_off(struct _mdi *mdi, struct _event_data *data) { + struct _note *nte; + unsigned char ch = data->channel; + + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + + nte = &mdi->note_table[0][ch][(data->data >> 8)]; + if (!nte->active) + nte = &mdi->note_table[1][ch][(data->data >> 8)]; + if (!nte->active) { + return; + } + + if ((mdi->channel[ch].isdrum) && (!(nte->modes & SAMPLE_LOOP))) { + return; + } + + if ((nte->modes & SAMPLE_ENVELOPE) && (nte->env == 0)) { + // This is a fix for notes that end before the + // initial step of the envelope has completed + // making it impossible to hear them at times. + nte->is_off = 1; + } else { + do_note_off_extra(nte); + } +} + +static inline unsigned long int get_inc(struct _mdi *mdi, struct _note *nte) { + int ch = nte->noteid >> 8; + signed long int note_f; + unsigned long int freq; + + if (nte->patch->note != 0) { + note_f = nte->patch->note * 100; + } else { + note_f = (nte->noteid & 0x7f) * 100; + } + note_f += mdi->channel[ch].pitch_adjust; + if (note_f < 0) { + note_f = 0; + } else if (note_f > 12700) { + note_f = 12700; + } + freq = freq_table[(note_f % 1200)] >> (10 - (note_f / 1200)); + return (((freq / ((_WM_SampleRate * 100) / 1024)) * 1024 + / nte->sample->inc_div)); +} + +static void do_note_on(struct _mdi *mdi, struct _event_data *data) { + struct _note *nte; + struct _note *prev_nte; + struct _note *nte_array; + unsigned long int freq = 0; + struct _patch *patch; + struct _sample *sample; + unsigned char ch = data->channel; + unsigned char note = (unsigned char)(data->data >> 8); + unsigned char velocity = (unsigned char)(data->data & 0xFF); + + if (velocity == 0x00) { + do_note_off(mdi, data); + return; + } + + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + + if (!mdi->channel[ch].isdrum) { + patch = mdi->channel[ch].patch; + if (patch == NULL) { + return; + } + freq = freq_table[(note % 12) * 100] >> (10 - (note / 12)); + } else { + patch = get_patch_data(((mdi->channel[ch].bank << 8) | note | 0x80)); + if (patch == NULL) { + return; + } + if (patch->note) { + freq = freq_table[(patch->note % 12) * 100] + >> (10 - (patch->note / 12)); + } else { + freq = freq_table[(note % 12) * 100] >> (10 - (note / 12)); + } + } + + sample = get_sample_data(patch, (freq / 100)); + if (sample == NULL) { + return; + } + + nte = &mdi->note_table[0][ch][note]; + + if (nte->active) { + if ((nte->modes & SAMPLE_ENVELOPE) && (nte->env < 3) + && (!(nte->hold & HOLD_OFF))) + return; + nte->replay = &mdi->note_table[1][ch][note]; + nte->env = 6; + nte->env_inc = -nte->sample->env_rate[6]; + nte = nte->replay; + } else { + if (mdi->note_table[1][ch][note].active) { + if ((nte->modes & SAMPLE_ENVELOPE) && (nte->env < 3) + && (!(nte->hold & HOLD_OFF))) + return; + mdi->note_table[1][ch][note].replay = nte; + mdi->note_table[1][ch][note].env = 6; + mdi->note_table[1][ch][note].env_inc = + -mdi->note_table[1][ch][note].sample->env_rate[6]; + } else { + nte_array = mdi->note; + if (nte_array == NULL) { + mdi->note = nte; + } else { + do { + prev_nte = nte_array; + nte_array = nte_array->next; + } while (nte_array); + prev_nte->next = nte; + } + nte->active = 1; + nte->next = NULL; + } + } + nte->noteid = (ch << 8) | note; + nte->patch = patch; + nte->sample = sample; + nte->sample_pos = 0; + nte->sample_inc = get_inc(mdi, nte); + nte->velocity = velocity; + nte->env = 0; + nte->env_inc = nte->sample->env_rate[0]; + nte->env_level = 0; + nte->modes = sample->modes; + nte->hold = mdi->channel[ch].hold; + nte->replay = NULL; + nte->is_off = 0; + _WM_AdjustNoteVolumes(mdi, ch, nte); +} + +static void do_aftertouch(struct _mdi *mdi, struct _event_data *data) { + struct _note *nte; + unsigned char ch = data->channel; + + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + + nte = &mdi->note_table[0][ch][(data->data >> 8)]; + if (!nte->active) { + nte = &mdi->note_table[1][ch][(data->data >> 8)]; + if (!nte->active) { + return; + } + } + + nte->velocity = (unsigned char)data->data; + _WM_AdjustNoteVolumes(mdi, ch, nte); + if (nte->replay) { + nte->replay->velocity = (unsigned char)data->data; + _WM_AdjustNoteVolumes(mdi, ch, nte->replay); + } +} + +static void do_control_bank_select(struct _mdi *mdi, struct _event_data *data) { + unsigned char ch = data->channel; + mdi->channel[ch].bank = (unsigned char)data->data; +} + +static void do_control_data_entry_course(struct _mdi *mdi, + struct _event_data *data) { + unsigned char ch = data->channel; + int data_tmp; + + if ((mdi->channel[ch].reg_non == 0) + && (mdi->channel[ch].reg_data == 0x0000)) { /* Pitch Bend Range */ + data_tmp = mdi->channel[ch].pitch_range % 100; + mdi->channel[ch].pitch_range = short(data->data * 100 + data_tmp); + /* printf("Data Entry Course: pitch_range: %i\n\r",mdi->channel[ch].pitch_range);*/ + /* printf("Data Entry Course: data %li\n\r",data->data);*/ + } +} + +static void do_control_channel_volume(struct _mdi *mdi, + struct _event_data *data) { + struct _note *note_data = mdi->note; + unsigned char ch = data->channel; + + mdi->channel[ch].volume = (unsigned char)data->data; + _WM_AdjustChannelVolumes(mdi, ch); +} + +static void do_control_channel_balance(struct _mdi *mdi, + struct _event_data *data) { + unsigned char ch = data->channel; + + mdi->channel[ch].balance = (signed char)(data->data); + _WM_AdjustChannelVolumes(mdi, ch); +} + +static void do_control_channel_pan(struct _mdi *mdi, struct _event_data *data) { + unsigned char ch = data->channel; + + mdi->channel[ch].pan = (signed char)(data->data); + _WM_AdjustChannelVolumes(mdi, ch); +} + +static void do_control_channel_expression(struct _mdi *mdi, + struct _event_data *data) { + struct _note *note_data = mdi->note; + unsigned char ch = data->channel; + + mdi->channel[ch].expression = (unsigned char)data->data; + _WM_AdjustChannelVolumes(mdi, ch); +} + +static void do_control_data_entry_fine(struct _mdi *mdi, + struct _event_data *data) { + unsigned char ch = data->channel; + int data_tmp; + + if ((mdi->channel[ch].reg_non == 0) + && (mdi->channel[ch].reg_data == 0x0000)) { /* Pitch Bend Range */ + data_tmp = mdi->channel[ch].pitch_range / 100; + mdi->channel[ch].pitch_range = short((data_tmp * 100) + data->data); + /* printf("Data Entry Fine: pitch_range: %i\n\r",mdi->channel[ch].pitch_range);*/ + /* printf("Data Entry Fine: data: %li\n\r", data->data);*/ + } + +} + +static void do_control_channel_hold(struct _mdi *mdi, struct _event_data *data) { + struct _note *note_data = mdi->note; + unsigned char ch = data->channel; + + if (data->data > 63) { + mdi->channel[ch].hold = 1; + } else { + mdi->channel[ch].hold = 0; + if (note_data) { + do { + if ((note_data->noteid >> 8) == ch) { + if (note_data->hold & HOLD_OFF) { + if (note_data->modes & SAMPLE_ENVELOPE) { + if (note_data->modes & SAMPLE_CLAMPED) { + if (note_data->env < 5) { + note_data->env = 5; + if (note_data->env_level + > note_data->sample->env_target[5]) { + note_data->env_inc = + -note_data->sample->env_rate[5]; + } else { + note_data->env_inc = + note_data->sample->env_rate[5]; + } + } + } else if (note_data->env < 4) { + note_data->env = 4; + if (note_data->env_level + > note_data->sample->env_target[4]) { + note_data->env_inc = + -note_data->sample->env_rate[4]; + } else { + note_data->env_inc = + note_data->sample->env_rate[4]; + } + } + } else { + if (note_data->modes & SAMPLE_LOOP) { + note_data->modes ^= SAMPLE_LOOP; + } + note_data->env_inc = 0; + } + } + note_data->hold = 0x00; + } + note_data = note_data->next; + } while (note_data); + } + } +} + +static void do_control_data_increment(struct _mdi *mdi, + struct _event_data *data) { + unsigned char ch = data->channel; + + if ((mdi->channel[ch].reg_non == 0) + && (mdi->channel[ch].reg_data == 0x0000)) { /* Pitch Bend Range */ + if (mdi->channel[ch].pitch_range < 0x3FFF) + mdi->channel[ch].pitch_range++; + } +} + +static void do_control_data_decrement(struct _mdi *mdi, + struct _event_data *data) { + unsigned char ch = data->channel; + + if ((mdi->channel[ch].reg_non == 0) + && (mdi->channel[ch].reg_data == 0x0000)) { /* Pitch Bend Range */ + if (mdi->channel[ch].pitch_range > 0) + mdi->channel[ch].pitch_range--; + } +} +static void do_control_non_registered_param_fine(struct _mdi *mdi, + struct _event_data *data) { + unsigned char ch = data->channel; + mdi->channel[ch].reg_data = (mdi->channel[ch].reg_data & 0x3F80) + | data->data; + mdi->channel[ch].reg_non = 1; +} + +static void do_control_non_registered_param_course(struct _mdi *mdi, + struct _event_data *data) { + unsigned char ch = data->channel; + mdi->channel[ch].reg_data = (mdi->channel[ch].reg_data & 0x7F) + | (data->data << 7); + mdi->channel[ch].reg_non = 1; +} + +static void do_control_registered_param_fine(struct _mdi *mdi, + struct _event_data *data) { + unsigned char ch = data->channel; + mdi->channel[ch].reg_data = (unsigned short) ((mdi->channel[ch].reg_data & 0x3F80) + | data->data); + mdi->channel[ch].reg_non = 0; +} + +static void do_control_registered_param_course(struct _mdi *mdi, + struct _event_data *data) { + unsigned char ch = data->channel; + mdi->channel[ch].reg_data = (unsigned short) ((mdi->channel[ch].reg_data & 0x7F) + | (data->data << 7)); + mdi->channel[ch].reg_non = 0; +} + +static void do_control_channel_sound_off(struct _mdi *mdi, + struct _event_data *data) { + struct _note *note_data = mdi->note; + unsigned char ch = data->channel; + + if (note_data) { + do { + if ((note_data->noteid >> 8) == ch) { + note_data->active = 0; + if (note_data->replay) { + note_data->replay = NULL; + } + } + note_data = note_data->next; + } while (note_data); + } +} + +static void do_control_channel_controllers_off(struct _mdi *mdi, + struct _event_data *data) { + struct _note *note_data = mdi->note; + unsigned char ch = data->channel; + + mdi->channel[ch].expression = 127; + mdi->channel[ch].pressure = 127; + mdi->channel[ch].reg_data = 0xffff; + mdi->channel[ch].pitch_range = 200; + mdi->channel[ch].pitch = 0; + mdi->channel[ch].pitch_adjust = 0; + mdi->channel[ch].hold = 0; + + _WM_AdjustChannelVolumes(mdi, ch); +} + +static void do_control_channel_notes_off(struct _mdi *mdi, + struct _event_data *data) { + struct _note *note_data = mdi->note; + unsigned char ch = data->channel; + + if (mdi->channel[ch].isdrum) + return; + if (note_data) { + do { + if ((note_data->noteid >> 8) == ch) { + if (!note_data->hold) { + if (note_data->modes & SAMPLE_ENVELOPE) { + if (note_data->env < 5) { + if (note_data->env_level + > note_data->sample->env_target[5]) { + note_data->env_inc = + -note_data->sample->env_rate[5]; + } else { + note_data->env_inc = + note_data->sample->env_rate[5]; + } + note_data->env = 5; + } + } + } else { + note_data->hold |= HOLD_OFF; + } + } + note_data = note_data->next; + } while (note_data); + } +} + +static void do_patch(struct _mdi *mdi, struct _event_data *data) { + unsigned char ch = data->channel; + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + if (!mdi->channel[ch].isdrum) { + mdi->channel[ch].patch = get_patch_data((unsigned short)(((mdi->channel[ch].bank << 8) | data->data))); + } else { + mdi->channel[ch].bank = (unsigned char)data->data; + } +} + +static void do_channel_pressure(struct _mdi *mdi, struct _event_data *data) { + struct _note *note_data = mdi->note; + unsigned char ch = data->channel; + + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + + while (note_data) { + if ((note_data->noteid >> 8) == ch) { + note_data->velocity = (unsigned char)data->data; + _WM_AdjustNoteVolumes(mdi, ch, note_data); + if (note_data->replay) { + note_data->replay->velocity = (unsigned char)data->data; + _WM_AdjustNoteVolumes(mdi, ch, note_data->replay); + } + } + note_data = note_data->next; + } +} + +static void do_pitch(struct _mdi *mdi, struct _event_data *data) { + struct _note *note_data = mdi->note; + unsigned char ch = data->channel; + + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + mdi->channel[ch].pitch = short(data->data - 0x2000); + + if (mdi->channel[ch].pitch < 0) { + mdi->channel[ch].pitch_adjust = mdi->channel[ch].pitch_range + * mdi->channel[ch].pitch / 8192; + } else { + mdi->channel[ch].pitch_adjust = mdi->channel[ch].pitch_range + * mdi->channel[ch].pitch / 8191; + } + + if (note_data) { + do { + if ((note_data->noteid >> 8) == ch) { + note_data->sample_inc = get_inc(mdi, note_data); + } + note_data = note_data->next; + } while (note_data); + } +} + +static void do_sysex_roland_drum_track(struct _mdi *mdi, + struct _event_data *data) { + unsigned char ch = data->channel; + + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + + if (data->data > 0) { + mdi->channel[ch].isdrum = 1; + mdi->channel[ch].patch = NULL; + } else { + mdi->channel[ch].isdrum = 0; + mdi->channel[ch].patch = get_patch_data(0); + } +} + +static void do_sysex_gm_reset(struct _mdi *mdi, struct _event_data *data) { + int i; + for (i = 0; i < 16; i++) { + mdi->channel[i].bank = 0; + if (i != 9) { + mdi->channel[i].patch = get_patch_data(0); + } else { + mdi->channel[i].patch = NULL; + } + mdi->channel[i].hold = 0; + mdi->channel[i].volume = 100; + mdi->channel[i].pressure = 127; + mdi->channel[i].expression = 127; + mdi->channel[i].balance = 64; + mdi->channel[i].pan = 64; + mdi->channel[i].pitch = 0; + mdi->channel[i].pitch_range = 200; + mdi->channel[i].reg_data = 0xFFFF; + mdi->channel[i].isdrum = 0; + } + /* I would not expect notes to be active when this event + triggers but we'll adjust active notes as well just in case */ + _WM_AdjustChannelVolumes(mdi,16); // A setting > 15 adjusts all channels + + mdi->channel[9].isdrum = 1; + UNUSED(data); /* NOOP, to please the compiler gods */ +} + +static void do_sysex_roland_reset(struct _mdi *mdi, struct _event_data *data) { + do_sysex_gm_reset(mdi, data); +} + +static void do_sysex_yamaha_reset(struct _mdi *mdi, struct _event_data *data) { + do_sysex_gm_reset(mdi, data); +} + +static int add_handle(void * handle) { + struct _hndl *tmp_handle = NULL; + + if (first_handle == NULL) { + first_handle = (struct _hndl*)malloc(sizeof(struct _hndl)); + if (first_handle == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, " to get ram", errno); + return -1; + } + first_handle->handle = handle; + first_handle->prev = NULL; + first_handle->next = NULL; + } else { + tmp_handle = first_handle; + if (tmp_handle->next) { + while (tmp_handle->next) + tmp_handle = tmp_handle->next; + } + tmp_handle->next = (struct _hndl*)malloc(sizeof(struct _hndl)); + if (tmp_handle->next == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, " to get ram", errno); + return -1; + } + tmp_handle->next->prev = tmp_handle; + tmp_handle = tmp_handle->next; + tmp_handle->next = NULL; + tmp_handle->handle = handle; + } + return 0; +} + +static struct _mdi * +Init_MDI(void) { + struct _mdi *mdi; + + mdi = new _mdi; + + mdi->info.copyright = NULL; + mdi->info.mixer_options = WM_MixerOptions; + + load_patch(mdi, 0x0000); + + mdi->samples_to_mix = 0; + mdi->info.current_sample = 0; + mdi->info.total_midi_time = 0; + mdi->info.approx_total_samples = 0; + + do_sysex_roland_reset(mdi, NULL); + + return mdi; +} + +static void freeMDI(struct _mdi *mdi) { + struct _sample *tmp_sample; + unsigned long int i; + + if (mdi->patch_count != 0) { + patch_lock.Enter(); + for (i = 0; i < mdi->patch_count; i++) { + mdi->patches[i]->inuse_count--; + if (mdi->patches[i]->inuse_count == 0) { + /* free samples here */ + while (mdi->patches[i]->first_sample) { + tmp_sample = mdi->patches[i]->first_sample->next; + free(mdi->patches[i]->first_sample->data); + free(mdi->patches[i]->first_sample); + mdi->patches[i]->first_sample = tmp_sample; + } + mdi->patches[i]->loaded = 0; + } + } + patch_lock.Leave(); + free(mdi->patches); + } + + free(mdi->tmp_info); + _WM_free_reverb(mdi->reverb); + free(mdi->mix_buffer); + free(mdi); +} + +static int *WM_Mix_Linear(midi * handle, int * buffer, unsigned long int count) +{ + struct _mdi *mdi = (struct _mdi *)handle; + unsigned long int data_pos; + signed int premix, left_mix, right_mix; + struct _note *note_data = NULL; + + do { + note_data = mdi->note; + left_mix = right_mix = 0; + if (note_data != NULL) { + while (note_data) { + /* + * =================== + * resample the sample + * =================== + */ + data_pos = note_data->sample_pos >> FPBITS; + premix = ((note_data->sample->data[data_pos] + (((note_data->sample->data[data_pos + 1] - note_data->sample->data[data_pos]) * (int)(note_data->sample_pos & FPMASK)) / 1024)) * (note_data->env_level >> 12)) / 1024; + + + left_mix += (premix * (int)note_data->left_mix_volume) / 1024; + right_mix += (premix * (int)note_data->right_mix_volume) / 1024; + + /* + * ======================== + * sample position checking + * ======================== + */ + note_data->sample_pos += note_data->sample_inc; + if (note_data->modes & SAMPLE_LOOP) { + if (note_data->sample_pos > note_data->sample->loop_end) { + note_data->sample_pos = + note_data->sample->loop_start + + ((note_data->sample_pos + - note_data->sample->loop_start) + % note_data->sample->loop_size); + } + } else if (note_data->sample_pos >= note_data->sample->data_length) { + goto END_THIS_NOTE; + } + + if (note_data->env_inc == 0) { + note_data = note_data->next; + continue; + } + + note_data->env_level += note_data->env_inc; + if (note_data->env_inc < 0) { + if (note_data->env_level > note_data->sample->env_target[note_data->env]) { + note_data = note_data->next; + continue; + } + } else if (note_data->env_inc > 0) { + if (note_data->env_level < note_data->sample->env_target[note_data->env]) { + note_data = note_data->next; + continue; + } + } + + // Yes could have a condition here but + // it would create another bottleneck + note_data->env_level = + note_data->sample->env_target[note_data->env]; + switch (note_data->env) { + case 0: + if (!(note_data->modes & SAMPLE_ENVELOPE)) { + note_data->env_inc = 0; + note_data = note_data->next; + continue; + } + break; + case 2: + if (note_data->modes & SAMPLE_SUSTAIN /*|| note_data->hold*/) { + note_data->env_inc = 0; + note_data = note_data->next; + continue; + } else if (note_data->modes & SAMPLE_CLAMPED) { + note_data->env = 5; + if (note_data->env_level + > note_data->sample->env_target[5]) { + note_data->env_inc = + -note_data->sample->env_rate[5]; + } else { + note_data->env_inc = + note_data->sample->env_rate[5]; + } + continue; + } + break; + case 5: + if (note_data->env_level == 0) { + goto END_THIS_NOTE; + } + /* sample release */ + if (note_data->modes & SAMPLE_LOOP) + note_data->modes ^= SAMPLE_LOOP; + note_data->env_inc = 0; + note_data = note_data->next; + continue; + case 6: + END_THIS_NOTE: + if (note_data->replay != NULL) { + note_data->active = 0; + { + struct _note *prev_note = NULL; + struct _note *nte_array = mdi->note; + + if (nte_array != note_data) { + do { + prev_note = nte_array; + nte_array = nte_array->next; + } while (nte_array != note_data); + } + if (prev_note) { + prev_note->next = note_data->replay; + } else { + mdi->note = note_data->replay; + } + note_data->replay->next = note_data->next; + note_data = note_data->replay; + note_data->active = 1; + } + } else { + note_data->active = 0; + { + struct _note *prev_note = NULL; + struct _note *nte_array = mdi->note; + + if (nte_array != note_data) { + do { + prev_note = nte_array; + nte_array = nte_array->next; + } while ((nte_array != note_data) + && (nte_array)); + } + if (prev_note) { + prev_note->next = note_data->next; + } else { + mdi->note = note_data->next; + } + note_data = note_data->next; + } + } + continue; + } + note_data->env++; + + if (note_data->is_off == 1) { + do_note_off_extra(note_data); + } + + if (note_data->env_level + > note_data->sample->env_target[note_data->env]) { + note_data->env_inc = + -note_data->sample->env_rate[note_data->env]; + } else { + note_data->env_inc = + note_data->sample->env_rate[note_data->env]; + } + note_data = note_data->next; + continue; + } + + /* + * ========================= + * mix the channels together + * ========================= + */ + } + *buffer++ = left_mix; + *buffer++ = right_mix; + } while (--count); + return buffer; +} + +static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count) +{ + if (!gauss_table) init_gauss(); + + struct _mdi *mdi = (struct _mdi *)handle; + unsigned long int data_pos; + signed int premix, left_mix, right_mix; + struct _note *note_data = NULL; + signed short int *sptr; + double y, xd; + double *gptr, *gend; + int left, right, temp_n; + int ii, jj; + + do { + note_data = mdi->note; + left_mix = right_mix = 0; + if (note_data != NULL) { + while (note_data) { + /* + * =================== + * resample the sample + * =================== + */ + data_pos = note_data->sample_pos >> FPBITS; + + /* check to see if we're near one of the ends */ + left = data_pos; + right = (note_data->sample->data_length >> FPBITS) - left + - 1; + temp_n = (right << 1) - 1; + if (temp_n <= 0) + temp_n = 1; + if (temp_n > (left << 1) + 1) + temp_n = (left << 1) + 1; + + /* use Newton if we can't fill the window */ + if (temp_n < gauss_n) { + xd = note_data->sample_pos & FPMASK; + xd /= (1L << FPBITS); + xd += temp_n >> 1; + y = 0; + sptr = note_data->sample->data + + (note_data->sample_pos >> FPBITS) + - (temp_n >> 1); + for (ii = temp_n; ii;) { + for (jj = 0; jj <= ii; jj++) + y += sptr[jj] * newt_coeffs[ii][jj]; + y *= xd - --ii; + } + y += *sptr; + } else { /* otherwise, use Gauss as usual */ + y = 0; + gptr = &gauss_table[(note_data->sample_pos & FPMASK) * + (gauss_n + 1)]; + gend = gptr + gauss_n; + sptr = note_data->sample->data + + (note_data->sample_pos >> FPBITS) + - (gauss_n >> 1); + do { + y += *(sptr++) * *(gptr++); + } while (gptr <= gend); + } + + premix = (int)((y * (note_data->env_level >> 12)) / 1024); + + left_mix += (premix * (int)note_data->left_mix_volume) / 1024; + right_mix += (premix * (int)note_data->right_mix_volume) / 1024; + + /* + * ======================== + * sample position checking + * ======================== + */ + note_data->sample_pos += note_data->sample_inc; + if (note_data->sample_pos > note_data->sample->loop_end) + { + if (note_data->modes & SAMPLE_LOOP) { + note_data->sample_pos = + note_data->sample->loop_start + + ((note_data->sample_pos + - note_data->sample->loop_start) + % note_data->sample->loop_size); + } else if (note_data->sample_pos >= note_data->sample->data_length) { + goto END_THIS_NOTE; + } + } + + if (note_data->env_inc == 0) { + note_data = note_data->next; + continue; + } + + note_data->env_level += note_data->env_inc; + if (note_data->env_inc < 0) { + if (note_data->env_level + > note_data->sample->env_target[note_data->env]) { + note_data = note_data->next; + continue; + } + } else if (note_data->env_inc > 0) { + if (note_data->env_level + < note_data->sample->env_target[note_data->env]) { + note_data = note_data->next; + continue; + } + } + + // Yes could have a condition here but + // it would create another bottleneck + + note_data->env_level = + note_data->sample->env_target[note_data->env]; + switch (note_data->env) { + case 0: + if (!(note_data->modes & SAMPLE_ENVELOPE)) { + note_data->env_inc = 0; + note_data = note_data->next; + continue; + } + break; + case 2: + if (note_data->modes & SAMPLE_SUSTAIN) { + note_data->env_inc = 0; + note_data = note_data->next; + continue; + } else if (note_data->modes & SAMPLE_CLAMPED) { + note_data->env = 5; + if (note_data->env_level + > note_data->sample->env_target[5]) { + note_data->env_inc = + -note_data->sample->env_rate[5]; + } else { + note_data->env_inc = + note_data->sample->env_rate[5]; + } + continue; + } + break; + case 5: + if (note_data->env_level == 0) { + goto END_THIS_NOTE; + } + /* sample release */ + if (note_data->modes & SAMPLE_LOOP) + note_data->modes ^= SAMPLE_LOOP; + note_data->env_inc = 0; + note_data = note_data->next; + continue; + case 6: + END_THIS_NOTE: + if (note_data->replay != NULL) { + note_data->active = 0; + { + struct _note *prev_note = NULL; + struct _note *nte_array = mdi->note; + + if (nte_array != note_data) { + do { + prev_note = nte_array; + nte_array = nte_array->next; + } while (nte_array != note_data); + } + if (prev_note) { + prev_note->next = note_data->replay; + } else { + mdi->note = note_data->replay; + } + note_data->replay->next = note_data->next; + note_data = note_data->replay; + note_data->active = 1; + } + } else { + note_data->active = 0; + { + struct _note *prev_note = NULL; + struct _note *nte_array = mdi->note; + + if (nte_array != note_data) { + do { + prev_note = nte_array; + nte_array = nte_array->next; + } while ((nte_array != note_data) + && (nte_array)); + } + if (prev_note) { + prev_note->next = note_data->next; + } else { + mdi->note = note_data->next; + } + note_data = note_data->next; + } + } + continue; + } + note_data->env++; + + if (note_data->is_off == 1) { + do_note_off_extra(note_data); + } + + if (note_data->env_level + > note_data->sample->env_target[note_data->env]) { + note_data->env_inc = + -note_data->sample->env_rate[note_data->env]; + } else { + note_data->env_inc = + note_data->sample->env_rate[note_data->env]; + } + note_data = note_data->next; + continue; + } + + /* + * ========================= + * mix the channels together + * ========================= + */ + } + *buffer++ = left_mix; + *buffer++ = right_mix; + } while (--count); + return buffer; +} + +int *WM_Mix(midi *handle, int *buffer, unsigned long count) +{ + if (((struct _mdi *)handle)->info.mixer_options & WM_MO_ENHANCED_RESAMPLING) + { + return WM_Mix_Gauss(handle, buffer, count); + } + else + { + return WM_Mix_Linear(handle, buffer, count); + } +} + +/* + * ========================= + * External Functions + * ========================= + */ + +WM_SYMBOL const char * +WildMidi_GetString(unsigned short int info) { + switch (info) { + case WM_GS_VERSION: + return WM_Version; + } + return NULL; +} + +WM_SYMBOL int WildMidi_Init(const char * config_file, unsigned short int rate, + unsigned short int options) { + if (WM_Initialized) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_ALR_INIT, NULL, 0); + return -1; + } + + if (config_file == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(NULL config file pointer)", 0); + return -1; + } + WM_InitPatches(); + if (WM_LoadConfig(config_file) == -1) { + return -1; + } + + if (options & 0x5FF8) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(invalid option)", + 0); + WM_FreePatches(); + return -1; + } + WM_MixerOptions = options; + + if (rate < 11025) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(rate out of bounds, range is 11025 - 65535)", 0); + WM_FreePatches(); + return -1; + } + _WM_SampleRate = rate; + WM_Initialized = 1; + + return 0; +} + +WM_SYMBOL int WildMidi_GetSampleRate(void) +{ + return _WM_SampleRate; +} + +WM_SYMBOL int WildMidi_MasterVolume(unsigned char master_volume) { + struct _mdi *mdi = NULL; + struct _hndl * tmp_handle = first_handle; + int i = 0; + + if (!WM_Initialized) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return -1; + } + if (master_volume > 127) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(master volume out of range, range is 0-127)", 0); + return -1; + } + + WM_MasterVolume = lin_volume[master_volume]; + + return 0; +} + +WM_SYMBOL int WildMidi_Close(midi * handle) { + struct _mdi *mdi = (struct _mdi *) handle; + struct _hndl * tmp_handle; + + if (!WM_Initialized) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return -1; + } + if (handle == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", + 0); + return -1; + } + if (first_handle == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(no midi's open)", + 0); + return -1; + } + mdi->lock.Enter(); + if (first_handle->handle == handle) { + tmp_handle = first_handle->next; + free(first_handle); + first_handle = tmp_handle; + if (first_handle) + first_handle->prev = NULL; + } else { + tmp_handle = first_handle; + while (tmp_handle->handle != handle) { + tmp_handle = tmp_handle->next; + if (tmp_handle == NULL) { + break; + } + } + if (tmp_handle) { + tmp_handle->prev->next = tmp_handle->next; + if (tmp_handle->next) { + tmp_handle->next->prev = tmp_handle->prev; + } + free(tmp_handle); + } + } + + freeMDI(mdi); + + return 0; +} + +midi *WildMidi_NewMidi() { + midi * ret = NULL; + + if (!WM_Initialized) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return NULL; + } + ret = Init_MDI(); + if (ret) { + if (add_handle(ret) != 0) { + WildMidi_Close(ret); + ret = NULL; + } + } + + if ((((_mdi*)ret)->reverb = _WM_init_reverb(_WM_SampleRate, reverb_room_width, + reverb_room_length, reverb_listen_posx, reverb_listen_posy)) + == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to init reverb", 0); + WildMidi_Close(ret); + ret = NULL; + } + + + return ret; +} + +WM_SYMBOL int WildMidi_SetOption(midi * handle, unsigned short int options, + unsigned short int setting) { + struct _mdi *mdi; + + if (!WM_Initialized) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return -1; + } + if (handle == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", + 0); + return -1; + } + + mdi = (struct _mdi *) handle; + mdi->lock.Enter(); + if ((!(options & 0x0007)) || (options & 0xFFF8)) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(invalid option)", + 0); + mdi->lock.Leave(); + return -1; + } + if (setting & 0xFFF8) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, + "(invalid setting)", 0); + mdi->lock.Leave(); + return -1; + } + + mdi->info.mixer_options = ((mdi->info.mixer_options & (0x00FF ^ options)) + | (options & setting)); + + if (options & WM_MO_LOG_VOLUME) { + _WM_AdjustChannelVolumes(mdi, 16); // Settings greater than 15 + // adjust all channels + } else if (options & WM_MO_REVERB) { + _WM_reset_reverb(mdi->reverb); + } + + mdi->lock.Leave(); + return 0; +} + +WM_SYMBOL struct _WM_Info * +WildMidi_GetInfo(midi * handle) { + struct _mdi *mdi = (struct _mdi *) handle; + if (!WM_Initialized) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return NULL; + } + if (handle == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", + 0); + return NULL; + } + mdi->lock.Enter(); + if (mdi->tmp_info == NULL) { + mdi->tmp_info = (struct _WM_Info*)malloc(sizeof(struct _WM_Info)); + if (mdi->tmp_info == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to set info", 0); + mdi->lock.Leave(); + return NULL; + } + mdi->tmp_info->copyright = NULL; + } + mdi->tmp_info->current_sample = mdi->info.current_sample; + mdi->tmp_info->approx_total_samples = mdi->info.approx_total_samples; + mdi->tmp_info->mixer_options = mdi->info.mixer_options; + if (mdi->info.copyright) { + free(mdi->tmp_info->copyright); + mdi->tmp_info->copyright = (char*)malloc(strlen(mdi->info.copyright) + 1); + strcpy(mdi->tmp_info->copyright, mdi->info.copyright); + } else { + mdi->tmp_info->copyright = NULL; + } + mdi->lock.Leave(); + return mdi->tmp_info; +} + +WM_SYMBOL int WildMidi_Shutdown(void) { + if (!WM_Initialized) { + // No error if trying to shut down an uninitialized device. + return 0; + } + while (first_handle) { + /* closes open handle and rotates the handles list. */ + WildMidi_Close((struct _mdi *) first_handle->handle); + } + WM_FreePatches(); + free_gauss(); + + /* reset the globals */ + WM_MasterVolume = 948; + WM_MixerOptions = 0; + fix_release = 0; + auto_amp = 0; + auto_amp_with_amp = 0; + reverb_room_width = 16.875f; + reverb_room_length = 22.5f; + reverb_listen_posx = 8.4375f; + reverb_listen_posy = 16.875f; + + WM_Initialized = 0; + + return 0; +} + +WildMidi_Renderer::WildMidi_Renderer() +{ + handle = WildMidi_NewMidi(); +} + +WildMidi_Renderer::~WildMidi_Renderer() +{ + WildMidi_Close((midi *)handle); +} + +void WildMidi_Renderer::ShortEvent(int status, int parm1, int parm2) +{ + _mdi *mdi = (_mdi *)handle; + _event_data ev; + + ev.channel = status & 0x0F; + switch ((status & 0xF0) >> 4) // command + { + case 0x8: + ev.data = (parm1 << 8) | parm2; + do_note_off(mdi, &ev); + break; + + case 0x9: + ev.data = (parm1 << 8) | parm2; + do_note_on(mdi, &ev); + break; + + case 0xA: + ev.data = (parm1 << 8) | parm2; + do_aftertouch(mdi, &ev); + break; + + case 0xC: + ev.data = parm1; + do_patch(mdi, &ev); + break; + + case 0xD: + ev.data = parm1; + do_channel_pressure(mdi, &ev); + break; + + case 0xE: + ev.data = parm1 | (parm2 << 7); + do_pitch(mdi, &ev); + break; + + case 0xB: // Controllers + ev.data = parm2; + switch (parm1) + { + case 0: do_control_bank_select(mdi, &ev); break; + case 6: do_control_data_entry_course(mdi, &ev); break; // [sic] + case 7: do_control_channel_volume(mdi, &ev); break; + case 8: do_control_channel_balance(mdi, &ev); break; + case 10: do_control_channel_pan(mdi, &ev); break; + case 11: do_control_channel_expression(mdi, &ev); break; + case 38: do_control_data_entry_fine(mdi, &ev); break; + case 64: do_control_channel_hold(mdi, &ev); break; + case 96: do_control_data_increment(mdi, &ev); break; + case 97: do_control_data_decrement(mdi, &ev); break; + case 98: do_control_non_registered_param_fine(mdi, &ev); break; + case 99: do_control_non_registered_param_course(mdi, &ev); break; // [sic] + case 100: do_control_registered_param_fine(mdi, &ev); break; + case 101: do_control_registered_param_course(mdi, &ev); break; // [sic] + case 120: do_control_channel_sound_off(mdi, &ev); break; + case 121: do_control_channel_controllers_off(mdi, &ev); break; + case 123: do_control_channel_notes_off(mdi, &ev); break; + } + } +} + +void WildMidi_Renderer::LongEvent(const unsigned char *data, int len) +{ + // Check for Roland SysEx + if (len >= 11 && // Must be at least 11 bytes + data[len-1] == 0xF7 && // SysEx end + data[0] == 0xF0 && // SysEx + data[1] == 0x41 && // Roland + data[2] == 0x10 && // Device ID, defaults to 0x10 + data[3] == 0x42 && // Model ID, 0x42 indicates a GS synth + data[4] == 0x12 && // The other end is sending data to us + data[5] == 0x40) // We only care about addresses with this first byte + { + // Calculate checksum + int cksum = 0; + for (int i = 5; i < len - 2; ++i) + { + cksum += data[i]; + } + cksum = 128 - (cksum & 0x7F); + if (data[len-2] == cksum) + { // Check destination address + if (((data[6] & 0xF0) == 0x10) && data[7] == 0x15) + { // Roland drum track setting + unsigned char sysex_ch = data[6] & 0x0F; + if (sysex_ch == 0) + { + sysex_ch = 9; + } + else if (sysex_ch <= 9) + { + sysex_ch -= 1; + } + _event_data ev = { sysex_ch, data[8] }; + do_sysex_roland_drum_track((_mdi *)handle, &ev); + } + else if (data[6] == 0x00 && data[7] == 0x7F && data[8] == 0x00) + { // Roland GS reset + do_sysex_roland_reset((_mdi *)handle, NULL); + } + } + } + // For non-Roland Sysex messages */ + else + { + const unsigned char gm_reset[] = { 0xf0, 0x7e, 0x7f, 0x09, 0x01, 0xf7 }; + const unsigned char yamaha_reset[] = { 0xf0, 0x43, 0x10, 0x4c, 0x00, 0x00, 0x7e, 0x00, 0xf7}; + if (len == 6 && memcmp(gm_reset, data, 6) == 0) + { + do_sysex_gm_reset((_mdi *)handle, NULL); + } + else if (len == 9 && memcmp(yamaha_reset, data, 9) == 0) + { + do_sysex_yamaha_reset((_mdi *)handle, NULL); + } + } +} + +void WildMidi_Renderer::ComputeOutput(float *fbuffer, int len) +{ + _mdi *mdi = (_mdi *)handle; + int *buffer = (int *)fbuffer; + int *newbuf = WM_Mix(handle, buffer, len); +// assert(newbuf - buffer == len); + if (mdi->info.mixer_options & WM_MO_REVERB) { + _WM_do_reverb(mdi->reverb, buffer, len * 2); + } + for (; buffer < newbuf; ++buffer) + { + *(float *)buffer = (float)*buffer / 32768.f; + } +} + +void WildMidi_Renderer::LoadInstrument(int bank, int percussion, int instr) +{ + load_patch((_mdi *)handle, (bank << 8) | instr | (percussion ? 0x80 : 0)); +} + +int WildMidi_Renderer::GetVoiceCount() +{ + int count = 0; + for (_note *note_data = ((_mdi *)handle)->note; note_data != NULL; note_data = note_data->next) + { + count++; + } + return count; +} + +void WildMidi_Renderer::SetOption(int opt, int set) +{ + WildMidi_SetOption((_mdi*)handle, (unsigned short)opt, (unsigned short)set); +} diff --git a/src/wildmidi/wildmidi_lib.h b/src/wildmidi/wildmidi_lib.h new file mode 100644 index 000000000..b5aa79849 --- /dev/null +++ b/src/wildmidi/wildmidi_lib.h @@ -0,0 +1,87 @@ +/* + wildmidi_lib.h + + Midi Wavetable Processing library + + Copyright (C) Chris Ison 2001-2011 + Copyright (C) Bret Curtis 2013-2014 + + This file is part of WildMIDI. + + WildMIDI is free software: you can redistribute and/or modify the player + under the terms of the GNU General Public License and you can redistribute + and/or modify the library under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, either version 3 of + the licenses, or(at your option) any later version. + + WildMIDI 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 and + the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License and the + GNU Lesser General Public License along with WildMIDI. If not, see + . +*/ + +#ifndef WILDMIDI_LIB_H +#define WILDMIDI_LIB_H + +#define WM_MO_LOG_VOLUME 0x0001 +#define WM_MO_ENHANCED_RESAMPLING 0x0002 +#define WM_MO_REVERB 0x0004 +#define WM_MO_WHOLETEMPO 0x8000 +#define WM_MO_ROUNDTEMPO 0x2000 + +#define WM_GS_VERSION 0x0001 + +#define WM_SYMBOL // we do not need this in ZDoom + +/* +#if defined(__cplusplus) +extern "C" { +#endif +*/ + +struct _WM_Info { + char *copyright; + unsigned long int current_sample; + unsigned long int approx_total_samples; + unsigned short int mixer_options; + unsigned long int total_midi_time; +}; + +typedef void midi; + +WM_SYMBOL const char * WildMidi_GetString (unsigned short int info); +WM_SYMBOL int WildMidi_Init (const char * config_file, unsigned short int rate, unsigned short int options); +WM_SYMBOL int WildMidi_MasterVolume (unsigned char master_volume); +WM_SYMBOL int WildMidi_SetOption (midi * handle, unsigned short int options, unsigned short int setting); +WM_SYMBOL int WildMidi_Close (midi * handle); +WM_SYMBOL int WildMidi_Shutdown (void); +WM_SYMBOL int WildMidi_GetSampleRate (void); + +/* +#if defined(__cplusplus) +} +#endif +*/ + +class WildMidi_Renderer +{ +public: + WildMidi_Renderer(); + ~WildMidi_Renderer(); + + void ShortEvent(int status, int parm1, int parm2); + void LongEvent(const unsigned char *data, int len); + void ComputeOutput(float *buffer, int len); + void LoadInstrument(int bank, int percussion, int instr); + int GetVoiceCount(); + void SetOption(int opt, int set); +private: + void *handle; +}; + +#endif /* WILDMIDI_LIB_H */ + diff --git a/src/wildmidi/wm_error.cpp b/src/wildmidi/wm_error.cpp new file mode 100644 index 000000000..eab56c437 --- /dev/null +++ b/src/wildmidi/wm_error.cpp @@ -0,0 +1,86 @@ +/* + wm_error.c + error reporting + + Copyright (C) Chris Ison 2001-2011 + Copyright (C) Bret Curtis 2013-2014 + + This file is part of WildMIDI. + + WildMIDI is free software: you can redistribute and/or modify the player + under the terms of the GNU General Public License and you can redistribute + and/or modify the library under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, either version 3 of + the licenses, or(at your option) any later version. + + WildMIDI 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 and + the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License and the + GNU Lesser General Public License along with WildMIDI. If not, see + . + */ + +//#include "config.h" + +#include +#include +#include +#include "wm_error.h" +#include "doomtype.h" +#include "v_text.h" + +void _WM_ERROR_NEW(const char * wmfmt, ...) { + va_list args; + fprintf(stderr, "\r"); + va_start(args, wmfmt); + vfprintf(stderr, wmfmt, args); + va_end(args); + fprintf(stderr, "\n"); +} + +void _WM_ERROR(const char * func, unsigned int lne, int wmerno, + const char * wmfor, int error) { + + static const char *errors[WM_ERR_MAX+1] = { + "No error", + "Unable to obtain memory", + "Unable to stat", + "Unable to load", + "Unable to open", + "Unable to read", + "Invalid or Unsuported file format", + "File corrupt", + "Library not Initialized", + "Invalid argument", + "Library Already Initialized", + "Not a midi file", + "Refusing to load unusually long file", + + "Invalid error code" + }; + + if (wmerno < 0 || wmerno > WM_ERR_MAX) + wmerno = WM_ERR_MAX; + + if (wmfor != NULL) { + if (error != 0) { + Printf(TEXTCOLOR_RED "libWildMidi(%s:%u): ERROR %s %s (%s)\n", func, + lne, errors[wmerno], wmfor, strerror(error)); + } else { + Printf(TEXTCOLOR_RED "libWildMidi(%s:%u): ERROR %s %s\n", func, lne, + errors[wmerno], wmfor); + } + } else { + if (error != 0) { + Printf(TEXTCOLOR_RED "libWildMidi(%s:%u): ERROR %s (%s)\n", func, lne, + errors[wmerno], strerror(error)); + } else { + Printf(TEXTCOLOR_RED "libWildMidi(%s:%u): ERROR %s\n", func, lne, + errors[wmerno]); + } + } +} + diff --git a/src/wildmidi/wm_error.h b/src/wildmidi/wm_error.h new file mode 100644 index 000000000..316924648 --- /dev/null +++ b/src/wildmidi/wm_error.h @@ -0,0 +1,56 @@ +/* + wm_error.h + + error reporting + + Copyright (C) Chris Ison 2001-2011 + Copyright (C) Bret Curtis 2013-2014 + + This file is part of WildMIDI. + + WildMIDI is free software: you can redistribute and/or modify the player + under the terms of the GNU General Public License and you can redistribute + and/or modify the library under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, either version 3 of + the licenses, or(at your option) any later version. + + WildMIDI 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 and + the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License and the + GNU Lesser General Public License along with WildMIDI. If not, see + . + */ + +#ifndef __WM_ERROR_H +#define __WM_ERROR_H + +enum { + WM_ERR_NONE = 0, + WM_ERR_MEM, + WM_ERR_STAT, + WM_ERR_LOAD, + WM_ERR_OPEN, + WM_ERR_READ, + WM_ERR_INVALID, + WM_ERR_CORUPT, + WM_ERR_NOT_INIT, + WM_ERR_INVALID_ARG, + WM_ERR_ALR_INIT, + WM_ERR_NOT_MIDI, + WM_ERR_LONGFIL, + + WM_ERR_MAX +}; + + extern void _WM_ERROR_NEW(const char * wmfmt, ...) +#ifdef __GNUC__ + __attribute__((format(printf, 1, 2))) +#endif + ; + extern void _WM_ERROR(const char * func, unsigned int lne, int wmerno, + const char * wmfor, int error); + +#endif /* __WM_ERROR_H */ diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index e23275734..4e3a14c18 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -72,6 +72,7 @@ #include "v_palette.h" #include "w_wad.h" #include "r_data/colormaps.h" +#include "SkylineBinPack.h" // MACROS ------------------------------------------------------------------ @@ -84,15 +85,19 @@ // The number of quads we can batch together. #define MAX_QUAD_BATCH (NUM_INDEXES / 6) +// The default size for a texture atlas. +#define DEF_ATLAS_WIDTH 512 +#define DEF_ATLAS_HEIGHT 512 + // TYPES ------------------------------------------------------------------- IMPLEMENT_CLASS(D3DFB) struct D3DFB::PackedTexture { - D3DFB::PackingTexture *Owner; + D3DFB::Atlas *Owner; - PackedTexture *Next, **Prev; + PackedTexture **Prev, *Next; // Pixels this image covers RECT Area; @@ -104,23 +109,19 @@ struct D3DFB::PackedTexture bool Padded; }; -struct D3DFB::PackingTexture +struct D3DFB::Atlas { - PackingTexture(D3DFB *fb, int width, int height, D3DFORMAT format); - ~PackingTexture(); + Atlas(D3DFB *fb, int width, int height, D3DFORMAT format); + ~Atlas(); - PackedTexture *GetBestFit(int width, int height, int &area); - void AllocateImage(PackedTexture *box, int width, int height); - PackedTexture *AllocateBox(); - void AddEmptyBox(int left, int top, int right, int bottom); + PackedTexture *AllocateImage(const Rect &rect, bool padded); void FreeBox(PackedTexture *box); - PackingTexture *Next; + SkylineBinPack Packer; + Atlas *Next; IDirect3DTexture9 *Tex; D3DFORMAT Format; PackedTexture *UsedList; // Boxes that contain images - PackedTexture *EmptyList; // Boxes that contain empty space - PackedTexture *FreeList; // Boxes that are just waiting to be used int Width, Height; bool OneUse; }; @@ -283,7 +284,7 @@ D3DFB::D3DFB (UINT adapter, int width, int height, bool fullscreen) ScreenWipe = NULL; InScene = false; QuadExtra = new BufferedTris[MAX_QUAD_BATCH]; - Packs = NULL; + Atlases = NULL; PixelDoubling = 0; SkipAt = -1; CurrRenderTexture = 0; @@ -496,7 +497,7 @@ void D3DFB::FillPresentParameters (D3DPRESENT_PARAMETERS *pp, bool fullscreen, b bool D3DFB::CreateResources() { - Packs = NULL; + Atlases = NULL; if (!Windowed) { // Remove the window border in fullscreen mode @@ -624,8 +625,8 @@ void D3DFB::ReleaseResources () delete ScreenWipe; ScreenWipe = NULL; } - PackingTexture *pack, *next; - for (pack = Packs; pack != NULL; pack = next) + Atlas *pack, *next; + for (pack = Atlases; pack != NULL; pack = next) { next = pack->Next; delete pack; @@ -1826,8 +1827,9 @@ IDirect3DTexture9 *D3DFB::GetCurrentScreen(D3DPOOL pool) // // D3DFB :: DrawPackedTextures // -// DEBUG: Draws the packing textures to the screen, starting with the -// 1-based packnum. +// DEBUG: Draws the texture atlases to the screen, starting with the +// 1-based packnum. Ignores atlases that are flagged for use by one +// texture only. // //========================================================================== @@ -1835,38 +1837,53 @@ void D3DFB::DrawPackedTextures(int packnum) { D3DCOLOR empty_colors[8] = { - 0xFFFF9999, 0xFF99FF99, 0xFF9999FF, 0xFFFFFF99, - 0xFFFF99FF, 0xFF99FFFF, 0xFFFFCC99, 0xFF99CCFF + 0x50FF0000, 0x5000FF00, 0x500000FF, 0x50FFFF00, + 0x50FF00FF, 0x5000FFFF, 0x50FF8000, 0x500080FF }; - PackingTexture *pack; + Atlas *pack; int x = 8, y = 8; if (packnum <= 0) { return; } - pack = Packs; + pack = Atlases; + // Find the first texture atlas that is an actual atlas. while (pack != NULL && pack->OneUse) - { // Skip textures that aren't used as packing containers + { // Skip textures that aren't used as atlases pack = pack->Next; } + // Skip however many atlases we would have otherwise drawn + // until we've skipped of them. while (pack != NULL && packnum != 1) { if (!pack->OneUse) - { // Skip textures that aren't used as packing containers + { // Skip textures that aren't used as atlases packnum--; } pack = pack->Next; } + // Draw atlases until we run out of room on the screen. while (pack != NULL) { if (pack->OneUse) - { // Skip textures that aren't used as packing containers + { // Skip textures that aren't used as atlases pack = pack->Next; continue; } - AddColorOnlyQuad(x-1, y-1-LBOffsetI, 258, 258, D3DCOLOR_XRGB(255,255,0)); + AddColorOnlyRect(x-1, y-1-LBOffsetI, 258, 258, D3DCOLOR_XRGB(255,255,0)); + int back = 0; + for (PackedTexture *box = pack->UsedList; box != NULL; box = box->Next) + { + AddColorOnlyQuad( + x + box->Area.left * 256 / pack->Width, + y + box->Area.top * 256 / pack->Height, + (box->Area.right - box->Area.left) * 256 / pack->Width, + (box->Area.bottom - box->Area.top) * 256 / pack->Height, empty_colors[back]); + back = (back + 1) & 7; + } +// AddColorOnlyQuad(x, y-LBOffsetI, 256, 256, D3DCOLOR_ARGB(180,0,0,0)); CheckQuadBatch(); @@ -1876,12 +1893,12 @@ void D3DFB::DrawPackedTextures(int packnum) quad->Group1 = 0; if (pack->Format == D3DFMT_L8/* && !tex->IsGray*/) { - quad->Flags = BQF_WrapUV | BQF_GamePalette | BQF_DisableAlphaTest; + quad->Flags = BQF_WrapUV | BQF_GamePalette/* | BQF_DisableAlphaTest*/; quad->ShaderNum = BQS_PalTex; } else { - quad->Flags = BQF_WrapUV | BQF_DisableAlphaTest; + quad->Flags = BQF_WrapUV/* | BQF_DisableAlphaTest*/; quad->ShaderNum = BQS_Plain; } quad->Palette = NULL; @@ -1941,16 +1958,6 @@ void D3DFB::DrawPackedTextures(int packnum) VertexPos += 4; IndexPos += 6; - // Draw entries in the empty list. - PackedTexture *box; - int emptynum; - for (box = pack->EmptyList, emptynum = 0; box != NULL; box = box->Next, emptynum++) - { - AddColorOnlyQuad(x + box->Area.left, y + box->Area.top - LBOffsetI, - box->Area.right - box->Area.left, box->Area.bottom - box->Area.top, - empty_colors[emptynum & 7]); - } - x += 256 + 8; if (x > Width - 256) { @@ -1969,82 +1976,76 @@ void D3DFB::DrawPackedTextures(int packnum) // // D3DFB :: AllocPackedTexture // -// Finds space to pack an image inside a packing texture and returns it. +// Finds space to pack an image inside a texture atlas and returns it. // Large images and those that need to wrap always get their own textures. // //========================================================================== D3DFB::PackedTexture *D3DFB::AllocPackedTexture(int w, int h, bool wrapping, D3DFORMAT format) { - PackingTexture *bestpack; - PackedTexture *bestbox; - int area; + Atlas *pack; + Rect box; + bool padded; - // check for 254 to account for padding - if (w > 254 || h > 254 || wrapping) - { // Create a new packing texture. - bestpack = new PackingTexture(this, w, h, format); - bestpack->OneUse = true; - bestbox = bestpack->GetBestFit(w, h, area); - bestbox->Padded = false; + // The - 2 to account for padding + if (w > 256 - 2 || h > 256 - 2 || wrapping) + { // Create a new texture atlas. + pack = new Atlas(this, w, h, format); + pack->OneUse = true; + box = pack->Packer.Insert(w, h); + padded = false; } else - { // Try to find space in an existing packing texture. + { // Try to find space in an existing texture atlas. w += 2; // Add padding h += 2; - int bestarea = INT_MAX; - int bestareaever = w * h; - bestpack = NULL; - bestbox = NULL; - for (PackingTexture *pack = Packs; pack != NULL; pack = pack->Next) + for (pack = Atlases; pack != NULL; pack = pack->Next) { + // Use the first atlas it fits in. if (pack->Format == format) { - PackedTexture *box = pack->GetBestFit(w, h, area); - if (area == bestareaever) - { // An exact fit! Use it! - bestpack = pack; - bestbox = box; - break; - } - if (area < bestarea) + box = pack->Packer.Insert(w, h); + if (box.width != 0) { - bestarea = area; - bestpack = pack; - bestbox = box; + break; } } } - if (bestpack == NULL) - { // Create a new packing texture. - bestpack = new PackingTexture(this, 256, 256, format); - bestbox = bestpack->GetBestFit(w, h, bestarea); + if (pack == NULL) + { // Create a new texture atlas. + pack = new Atlas(this, DEF_ATLAS_WIDTH, DEF_ATLAS_HEIGHT, format); + box = pack->Packer.Insert(w, h); } - bestbox->Padded = true; + padded = true; } - bestpack->AllocateImage(bestbox, w, h); - return bestbox; + assert(box.width != 0 && box.height != 0); + return pack->AllocateImage(box, padded); } //========================================================================== // -// PackingTexture Constructor +// Atlas Constructor // //========================================================================== -D3DFB::PackingTexture::PackingTexture(D3DFB *fb, int w, int h, D3DFORMAT format) +D3DFB::Atlas::Atlas(D3DFB *fb, int w, int h, D3DFORMAT format) + : Packer(w, h, true) { Tex = NULL; Format = format; UsedList = NULL; - EmptyList = NULL; - FreeList = NULL; OneUse = false; Width = 0; Height = 0; + Next = NULL; - Next = fb->Packs; - fb->Packs = this; + // Attach to the end of the atlas list + Atlas **prev = &fb->Atlases; + while (*prev != NULL) + { + prev = &((*prev)->Next); + } + *prev = this; #if 1 if (FAILED(fb->D3DDevice->CreateTexture(w, h, 1, 0, format, D3DPOOL_MANAGED, &Tex, NULL))) @@ -2061,18 +2062,15 @@ D3DFB::PackingTexture::PackingTexture(D3DFB *fb, int w, int h, D3DFORMAT format) } Width = w; Height = h; - - // The whole texture is initially empty. - AddEmptyBox(0, 0, w, h); } //========================================================================== // -// PackingTexture Destructor +// Atlas Destructor // //========================================================================== -D3DFB::PackingTexture::~PackingTexture() +D3DFB::Atlas::~Atlas() { PackedTexture *box, *next; @@ -2082,85 +2080,36 @@ D3DFB::PackingTexture::~PackingTexture() next = box->Next; delete box; } - for (box = EmptyList; box != NULL; box = next) - { - next = box->Next; - delete box; - } - for (box = FreeList; box != NULL; box = next) - { - next = box->Next; - delete box; - } } //========================================================================== // -// PackingTexture :: GetBestFit -// -// Returns the empty box that provides the best fit for the requested -// dimensions, or NULL if none of them are large enough. -// -//========================================================================== - -D3DFB::PackedTexture *D3DFB::PackingTexture::GetBestFit(int w, int h, int &area) -{ - PackedTexture *box; - int smallestarea = INT_MAX; - PackedTexture *smallestbox = NULL; - - for (box = EmptyList; box != NULL; box = box->Next) - { - int boxw = box->Area.right - box->Area.left; - int boxh = box->Area.bottom - box->Area.top; - if (boxw >= w && boxh >= h) - { - int boxarea = boxw * boxh; - if (boxarea < smallestarea) - { - smallestarea = boxarea; - smallestbox = box; - if (boxw == w && boxh == h) - { // An exact fit! Use it! - break; - } - } - } - } - area = smallestarea; - return smallestbox; -} - -//========================================================================== -// -// PackingTexture :: AllocateImage +// Atlas :: AllocateImage // // Moves the box from the empty list to the used list, sizing it to the // requested dimensions and adding additional boxes to the empty list if // needed. // -// The passed box *MUST* be in this packing texture's empty list. +// The passed box *MUST* be in this texture atlas's empty list. // //========================================================================== -void D3DFB::PackingTexture::AllocateImage(D3DFB::PackedTexture *box, int w, int h) +D3DFB::PackedTexture *D3DFB::Atlas::AllocateImage(const Rect &rect, bool padded) { - RECT start = box->Area; + PackedTexture *box = new PackedTexture; - box->Area.right = box->Area.left + w; - box->Area.bottom = box->Area.top + h; + box->Owner = this; + box->Area.left = rect.x; + box->Area.top = rect.y; + box->Area.right = rect.x + rect.width; + box->Area.bottom = rect.y + rect.height; - box->Left = float(box->Area.left + box->Padded) / Width; - box->Right = float(box->Area.right - box->Padded) / Width; - box->Top = float(box->Area.top + box->Padded) / Height; - box->Bottom = float(box->Area.bottom - box->Padded) / Height; + box->Left = float(box->Area.left + padded) / Width; + box->Right = float(box->Area.right - padded) / Width; + box->Top = float(box->Area.top + padded) / Height; + box->Bottom = float(box->Area.bottom - padded) / Height; - // Remove it from the empty list. - *(box->Prev) = box->Next; - if (box->Next != NULL) - { - box->Next->Prev = box->Prev; - } + box->Padded = padded; // Add it to the used list. box->Next = UsedList; @@ -2171,158 +2120,36 @@ void D3DFB::PackingTexture::AllocateImage(D3DFB::PackedTexture *box, int w, int UsedList = box; box->Prev = &UsedList; - // If we didn't use the whole box, split the remainder into the empty list. - if (box->Area.bottom + 7 < start.bottom && box->Area.right + 7 < start.right) - { - // Split like this: - // +---+------+ - // |###| | - // +---+------+ - // | | - // | | - // +----------+ - if (box->Area.bottom < start.bottom) - { - AddEmptyBox(start.left, box->Area.bottom, start.right, start.bottom); - } - if (box->Area.right < start.right) - { - AddEmptyBox(box->Area.right, start.top, start.right, box->Area.bottom); - } - } - else - { - // Split like this: - // +---+------+ - // |###| | - // +---+ | - // | | | - // | | | - // +---+------+ - if (box->Area.bottom < start.bottom) - { - AddEmptyBox(start.left, box->Area.bottom, box->Area.right, start.bottom); - } - if (box->Area.right < start.right) - { - AddEmptyBox(box->Area.right, start.top, start.right, start.bottom); - } - } -} - -//========================================================================== -// -// PackingTexture :: AddEmptyBox -// -// Adds a box with the specified dimensions to the empty list. -// -//========================================================================== - -void D3DFB::PackingTexture::AddEmptyBox(int left, int top, int right, int bottom) -{ - PackedTexture *box = AllocateBox(); - box->Area.left = left; - box->Area.top = top; - box->Area.right = right; - box->Area.bottom = bottom; - box->Next = EmptyList; - if (box->Next != NULL) - { - box->Next->Prev = &box->Next; - } - box->Prev = &EmptyList; - EmptyList = box; -} - -//========================================================================== -// -// PackingTexture :: AllocateBox -// -// Returns a new PackedTexture box, either by retrieving one off the free -// list or by creating a new one. The box is not linked into a list. -// -//========================================================================== - -D3DFB::PackedTexture *D3DFB::PackingTexture::AllocateBox() -{ - PackedTexture *box; - - if (FreeList != NULL) - { - box = FreeList; - FreeList = box->Next; - if (box->Next != NULL) - { - box->Next->Prev = &FreeList; - } - } - else - { - box = new PackedTexture; - box->Owner = this; - } return box; } //========================================================================== // -// PackingTexture :: FreeBox +// Atlas :: FreeBox // -// Removes a box from its current list and adds it to the empty list, -// updating EmptyArea. If there are no boxes left in the used list, then -// the empty list is replaced with a single box, so the texture can be -// subdivided again. +// Removes a box from the used list and deletes it. Space is returned to the +// waste list. Once all boxes for this atlas are freed, the entire bin +// packer is reinitialized for maximum efficiency. // //========================================================================== -void D3DFB::PackingTexture::FreeBox(D3DFB::PackedTexture *box) +void D3DFB::Atlas::FreeBox(D3DFB::PackedTexture *box) { *(box->Prev) = box->Next; if (box->Next != NULL) { box->Next->Prev = box->Prev; } - box->Next = EmptyList; - box->Prev = &EmptyList; - if (EmptyList != NULL) - { - EmptyList->Prev = &box->Next; - } - EmptyList = box; + Rect waste; + waste.x = box->Area.left; + waste.y = box->Area.top; + waste.width = box->Area.right - box->Area.left; + waste.height = box->Area.bottom - box->Area.top; + box->Owner->Packer.AddWaste(waste); + delete box; if (UsedList == NULL) - { // No more space in use! Move all but this into the free list. - if (box->Next != NULL) - { - D3DFB::PackedTexture *lastbox; - - // Find the last box in the free list. - lastbox = FreeList; - if (lastbox != NULL) - { - while (lastbox->Next != NULL) - { - lastbox = lastbox->Next; - } - } - // Chain the empty list to the end of the free list. - if (lastbox != NULL) - { - lastbox->Next = box->Next; - box->Next->Prev = &lastbox->Next; - } - else - { - FreeList = box->Next; - box->Next->Prev = &FreeList; - } - box->Next = NULL; - } - // Now this is the only box in the empty list, so it should - // contain the whole texture. - box->Area.left = 0; - box->Area.top = 0; - box->Area.right = Width; - box->Area.bottom = Height; + { + Packer.Init(Width, Height, true); } } @@ -2407,6 +2234,7 @@ bool D3DTex::CheckWrapping(bool wrapping) bool D3DTex::Create(D3DFB *fb, bool wrapping) { + assert(Box == NULL); if (Box != NULL) { Box->Owner->FreeBox(Box); @@ -3436,6 +3264,22 @@ void D3DFB::AddColorOnlyQuad(int left, int top, int width, int height, D3DCOLOR IndexPos += 6; } +//========================================================================== +// +// D3DFB :: AddColorOnlyRect +// +// Like AddColorOnlyQuad, except it's hollow. +// +//========================================================================== + +void D3DFB::AddColorOnlyRect(int left, int top, int width, int height, D3DCOLOR color) +{ + AddColorOnlyQuad(left, top, width - 1, 1, color); // top + AddColorOnlyQuad(left + width - 1, top, 1, height - 1, color); // right + AddColorOnlyQuad(left + 1, top + height - 1, width - 1, 1, color); // bottom + AddColorOnlyQuad(left, top + 1, 1, height - 1, color); // left +} + //========================================================================== // // D3DFB :: CheckQuadBatch @@ -4004,7 +3848,7 @@ void D3DFB::SetPaletteTexture(IDirect3DTexture9 *texture, int count, D3DCOLOR bo SetTexture(1, texture); } -void D3DFB::SetPalTexBilinearConstants(PackingTexture *tex) +void D3DFB::SetPalTexBilinearConstants(Atlas *tex) { #if 0 float con[8]; diff --git a/src/win32/win32iface.h b/src/win32/win32iface.h index 934931ea0..8b0c88f45 100644 --- a/src/win32/win32iface.h +++ b/src/win32/win32iface.h @@ -279,7 +279,7 @@ private: friend class D3DPal; struct PackedTexture; - struct PackingTexture; + struct Atlas; struct FBVERTEX { @@ -375,6 +375,7 @@ private: static void SetColorOverlay(DWORD color, float alpha, D3DCOLOR &color0, D3DCOLOR &color1); void DoWindowedGamma(); void AddColorOnlyQuad(int left, int top, int width, int height, D3DCOLOR color); + void AddColorOnlyRect(int left, int top, int width, int height, D3DCOLOR color); void CheckQuadBatch(int numtris=2, int numverts=4); void BeginQuadBatch(); void EndQuadBatch(); @@ -392,7 +393,7 @@ private: void SetPixelShader(IDirect3DPixelShader9 *shader); void SetTexture(int tnum, IDirect3DTexture9 *texture); void SetPaletteTexture(IDirect3DTexture9 *texture, int count, D3DCOLOR border_color); - void SetPalTexBilinearConstants(PackingTexture *texture); + void SetPalTexBilinearConstants(Atlas *texture); BOOL AlphaTestEnabled; BOOL AlphaBlendEnabled; @@ -431,7 +432,7 @@ private: BYTE BlockNum; D3DPal *Palettes; D3DTex *Textures; - PackingTexture *Packs; + Atlas *Atlases; HRESULT LastHR; UINT Adapter; diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 956ed119f..213e2109d 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -129,6 +129,10 @@ const int WRF_NOFIRE = WRF_NOPRIMARY | WRF_NOSECONDARY; const int WRF_ALLOWRELOAD = 16; const int WRF_ALLOWZOOM = 32; const int WRF_DISABLESWITCH = 64; +const int WRF_ALLOWUSER1 = 128; +const int WRF_ALLOWUSER2 = 256; +const int WRF_ALLOWUSER3 = 512; +const int WRF_ALLOWUSER4 = 1024; // Morph constants const int MRF_ADDSTAMINA = 1; diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index 1bd031ed8..13f0d22a7 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -403,6 +403,7 @@ D0139194F7817BF06F3988DFC47DB38D // Whispers of Satan map29 } D7F6E9F08C39A17026349A04F8C0B0BE // Return to Hadron, e1m9 +19D03FFC875589E21EDBB7AB74EF4AEF // Return to Hadron, e1m9, 2016.01.03 update { pointonline } diff --git a/wadsrc/static/filter/doom.freedoom/decaldef.z b/wadsrc/static/filter/doom.freedoom/decaldef.z new file mode 100644 index 000000000..5939680cf --- /dev/null +++ b/wadsrc/static/filter/doom.freedoom/decaldef.z @@ -0,0 +1,29 @@ + +/***** BFG Scorches ********************************************************/ + +decal BFGLightning1 +{ + pic BFGLITE1 + shade "80 80 ff" + fullbright + randomflipx + animator GoAway2 + lowerdecal BFGScorch +} + +decal BFGLightning2 +{ + pic BFGLITE2 + shade "80 80 ff" + fullbright + randomflipy + animator GoAway2 + lowerdecal BFGScorch +} + +decalgroup BFGLightning +{ + BFGLightning1 1 + BFGLightning2 1 +} + diff --git a/wadsrc/static/iwadinfo.txt b/wadsrc/static/iwadinfo.txt index 6c958ddfa..401f3ca4c 100644 --- a/wadsrc/static/iwadinfo.txt +++ b/wadsrc/static/iwadinfo.txt @@ -370,6 +370,7 @@ Names "doom.wad" "doom1.wad" "heretic.wad" + "hereticsr.wad" "heretic1.wad" "hexen.wad" "hexdd.wad" diff --git a/wadsrc/static/mapinfo/common.txt b/wadsrc/static/mapinfo/common.txt index f26ca6731..4b663047c 100644 --- a/wadsrc/static/mapinfo/common.txt +++ b/wadsrc/static/mapinfo/common.txt @@ -118,70 +118,70 @@ DoomEdNums 9997 = SecActExit 9998 = SecActEnter 9999 = SecActHitFloor - 14001 = AmbientSound, 1 - 14002 = AmbientSound, 2 - 14003 = AmbientSound, 3 - 14004 = AmbientSound, 4 - 14005 = AmbientSound, 5 - 14006 = AmbientSound, 6 - 14007 = AmbientSound, 7 - 14008 = AmbientSound, 8 - 14009 = AmbientSound, 9 - 14010 = AmbientSound, 10 - 14011 = AmbientSound, 11 - 14012 = AmbientSound, 12 - 14013 = AmbientSound, 13 - 14014 = AmbientSound, 14 - 14015 = AmbientSound, 15 - 14016 = AmbientSound, 16 - 14017 = AmbientSound, 17 - 14018 = AmbientSound, 18 - 14019 = AmbientSound, 19 - 14020 = AmbientSound, 20 - 14021 = AmbientSound, 21 - 14022 = AmbientSound, 22 - 14023 = AmbientSound, 23 - 14024 = AmbientSound, 24 - 14025 = AmbientSound, 25 - 14026 = AmbientSound, 26 - 14027 = AmbientSound, 27 - 14028 = AmbientSound, 28 - 14029 = AmbientSound, 29 - 14030 = AmbientSound, 30 - 14031 = AmbientSound, 31 - 14032 = AmbientSound, 32 - 14033 = AmbientSound, 33 - 14034 = AmbientSound, 34 - 14035 = AmbientSound, 35 - 14036 = AmbientSound, 36 - 14037 = AmbientSound, 37 - 14038 = AmbientSound, 38 - 14039 = AmbientSound, 39 - 14040 = AmbientSound, 40 - 14041 = AmbientSound, 41 - 14042 = AmbientSound, 42 - 14043 = AmbientSound, 43 - 14044 = AmbientSound, 44 - 14045 = AmbientSound, 45 - 14046 = AmbientSound, 46 - 14047 = AmbientSound, 47 - 14048 = AmbientSound, 48 - 14049 = AmbientSound, 49 - 14050 = AmbientSound, 50 - 14051 = AmbientSound, 51 - 14052 = AmbientSound, 52 - 14053 = AmbientSound, 53 - 14054 = AmbientSound, 54 - 14055 = AmbientSound, 55 - 14056 = AmbientSound, 56 - 14057 = AmbientSound, 57 - 14058 = AmbientSound, 58 - 14059 = AmbientSound, 59 - 14060 = AmbientSound, 60 - 14061 = AmbientSound, 61 - 14062 = AmbientSound, 62 - 14063 = AmbientSound, 63 - 14064 = AmbientSound, 64 + 14001 = AmbientSound, 1, + + 14002 = AmbientSound, 2, + + 14003 = AmbientSound, 3, + + 14004 = AmbientSound, 4, + + 14005 = AmbientSound, 5, + + 14006 = AmbientSound, 6, + + 14007 = AmbientSound, 7, + + 14008 = AmbientSound, 8, + + 14009 = AmbientSound, 9, + + 14010 = AmbientSound, 10, + + 14011 = AmbientSound, 11, + + 14012 = AmbientSound, 12, + + 14013 = AmbientSound, 13, + + 14014 = AmbientSound, 14, + + 14015 = AmbientSound, 15, + + 14016 = AmbientSound, 16, + + 14017 = AmbientSound, 17, + + 14018 = AmbientSound, 18, + + 14019 = AmbientSound, 19, + + 14020 = AmbientSound, 20, + + 14021 = AmbientSound, 21, + + 14022 = AmbientSound, 22, + + 14023 = AmbientSound, 23, + + 14024 = AmbientSound, 24, + + 14025 = AmbientSound, 25, + + 14026 = AmbientSound, 26, + + 14027 = AmbientSound, 27, + + 14028 = AmbientSound, 28, + + 14029 = AmbientSound, 29, + + 14030 = AmbientSound, 30, + + 14031 = AmbientSound, 31, + + 14032 = AmbientSound, 32, + + 14033 = AmbientSound, 33, + + 14034 = AmbientSound, 34, + + 14035 = AmbientSound, 35, + + 14036 = AmbientSound, 36, + + 14037 = AmbientSound, 37, + + 14038 = AmbientSound, 38, + + 14039 = AmbientSound, 39, + + 14040 = AmbientSound, 40, + + 14041 = AmbientSound, 41, + + 14042 = AmbientSound, 42, + + 14043 = AmbientSound, 43, + + 14044 = AmbientSound, 44, + + 14045 = AmbientSound, 45, + + 14046 = AmbientSound, 46, + + 14047 = AmbientSound, 47, + + 14048 = AmbientSound, 48, + + 14049 = AmbientSound, 49, + + 14050 = AmbientSound, 50, + + 14051 = AmbientSound, 51, + + 14052 = AmbientSound, 52, + + 14053 = AmbientSound, 53, + + 14054 = AmbientSound, 54, + + 14055 = AmbientSound, 55, + + 14056 = AmbientSound, 56, + + 14057 = AmbientSound, 57, + + 14058 = AmbientSound, 58, + + 14059 = AmbientSound, 59, + + 14060 = AmbientSound, 60, + + 14061 = AmbientSound, 61, + + 14062 = AmbientSound, 62, + + 14063 = AmbientSound, 63, + + 14064 = AmbientSound, 64, + 14065 = AmbientSound 14066 = SoundSequence 14067 = AmbientSoundNoGravity diff --git a/wadsrc/static/mapinfo/doom2bfg.txt b/wadsrc/static/mapinfo/doom2bfg.txt index cc82c4e19..28bea129d 100644 --- a/wadsrc/static/mapinfo/doom2bfg.txt +++ b/wadsrc/static/mapinfo/doom2bfg.txt @@ -3,7 +3,7 @@ include "mapinfo/doom2.txt" gameinfo { - titlepage = "INTERPIC" + titlepage = "DMENUPIC" } clearepisodes diff --git a/wadsrc/static/mapinfo/mindefaults.txt b/wadsrc/static/mapinfo/mindefaults.txt index cbb3fa06b..0d7b16209 100644 --- a/wadsrc/static/mapinfo/mindefaults.txt +++ b/wadsrc/static/mapinfo/mindefaults.txt @@ -56,4 +56,12 @@ gameinfo statscreen_enteringpatch = "WIENTER" } +DoomEdNums +{ + 4001 = "$Player5Start" + 4002 = "$Player6Start" + 4003 = "$Player7Start" + 4004 = "$Player8Start" +} + include "mapinfo/common.txt" diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index eef2629d3..add844455 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -435,8 +435,12 @@ OptionMenu "CustomizeControls" StaticText "Controls", 1 Control "Fire", "+attack" Control "Secondary Fire", "+altattack" - Control "Weapon Reload", "+reload" - Control "Weapon Zoom", "+zoom" + Control "Weapon Reload", "+reload" + Control "Weapon Zoom", "+zoom" + Control "Weapon State 1", "+user1" + Control "Weapon State 2", "+user2" + Control "Weapon State 3", "+user3" + Control "Weapon State 4", "+user4" Control "Use / Open", "+use" Control "Move forward", "+forward" Control "Move backward", "+back" @@ -444,6 +448,7 @@ OptionMenu "CustomizeControls" Control "Strafe right", "+moveright" Control "Turn left", "+left" Control "Turn right", "+right" + Control "Quick Turn", "turn180" Control "Jump", "+jump" Control "Crouch", "+crouch" Control "Crouch Toggle", "crouch" @@ -1592,7 +1597,6 @@ OptionMenu AdvSoundOptions StaticText "GUS Emulation", 1 TextField "GUS config file", "midi_config" Slider "MIDI voices", "midi_voices", 16, 256, 4, 0 - Option "Emulate TiMidity", "midi_timiditylike", "OnOff" Option "Read DMXGUS lumps", "midi_dmxgus", "OnOff" Option "GUS memory size", "gus_memsize", "GusMemory" StaticText " " @@ -1608,6 +1612,10 @@ OptionMenu AdvSoundOptions Option "Reverb", "timidity_reverb", "OnOff" Option "Chorus", "timidity_chorus", "OnOff" Slider "Relative volume", "timidity_mastervolume", 0, 4, 0.2, 1 + StaticText " " + StaticText "WildMidi", 1 + TextField "WildMidi config file", "wildmidi_config" + Option "Reverb", "wildmidi_reverb", "OnOff" } /*======================================= diff --git a/wadsrc/static/xlat/eternity.txt b/wadsrc/static/xlat/eternity.txt index ad270beb4..7b4367ee3 100644 --- a/wadsrc/static/xlat/eternity.txt +++ b/wadsrc/static/xlat/eternity.txt @@ -170,7 +170,7 @@ define Unsupported (0) 384 = 0, Static_Init(0, 3, 0, 10) // "Attach_MirrorCeilingToControl" // Attach tagged portal to front sector -385 = 0, Sector_SetPortal(0, 1, 2, tag) // "Apply_PortalToFrontsector" +385 = 0, Sector_SetPortal(0, 1, 3, tag) // "Apply_PortalToFrontsector" // Slopes! 386 = 0, Plane_Align (1, 0) // "Slope_FrontsectorFloor" diff --git a/zdoom.vcproj b/zdoom.vcproj index d802fc61c..597b56f2f 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -106,6 +106,7 @@ MapExports="true" SubSystem="2" StackReserveSize="0" + LargeAddressAware="2" TerminalServerAware="2" OptimizeReferences="2" EnableCOMDATFolding="2" @@ -223,6 +224,7 @@ MapExports="true" SubSystem="2" StackReserveSize="0" + LargeAddressAware="2" TerminalServerAware="2" OptimizeReferences="2" EnableCOMDATFolding="2" @@ -332,6 +334,7 @@ ProgramDatabaseFile=".\Debug/zdoomd.pdb" SubSystem="2" StackReserveSize="0" + LargeAddressAware="2" TerminalServerAware="2" SetChecksum="false" TargetMachine="0" @@ -440,6 +443,7 @@ ProgramDatabaseFile=".\Debug/zdoomd.pdb" SubSystem="2" StackReserveSize="0" + LargeAddressAware="2" TerminalServerAware="2" SetChecksum="false" TargetMachine="17" @@ -662,6 +666,10 @@ RelativePath=".\src\gitinfo.cpp" > + + @@ -938,6 +946,10 @@ RelativePath=".\src\parsecontext.cpp" > + + @@ -1018,6 +1030,10 @@ RelativePath=".\src\skins.cpp" > + + @@ -1303,6 +1319,10 @@ RelativePath=".\src\gstrings.h" > + + @@ -1475,10 +1495,18 @@ RelativePath=".\src\parsecontext.h" > + + + + @@ -1503,6 +1531,10 @@ RelativePath=".\src\skins.h" > + + @@ -2589,6 +2621,10 @@ RelativePath=".\src\sound\music_timidity_mididevice.cpp" > + + @@ -2785,6 +2821,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + +