diff --git a/src/dehacked.c b/src/dehacked.c index 347bae8c9..6cda21aa7 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -2778,7 +2778,7 @@ static void readpatch(MYFILE *f, const char *name, UINT16 wad) char *word2; char *tmp; INT32 i = 0, j = 0, value; - texpatch_t patch = {0, 0, UINT16_MAX, UINT16_MAX}; + texpatch_t patch = {0, 0, UINT16_MAX, UINT16_MAX, 0}; // Jump to the texture this patch belongs to, which, // coincidentally, is always the last one on the buffer cache. diff --git a/src/doomdef.h b/src/doomdef.h index f599b5f81..83576a12c 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -407,6 +407,7 @@ void M_StartupLocale(void); extern void *(*M_Memcpy)(void* dest, const void* src, size_t n) FUNCNONNULL; char *va(const char *format, ...) FUNCPRINTF; char *M_GetToken(const char *inputString); +void M_UnGetToken(void); char *sizeu1(size_t num); char *sizeu2(size_t num); char *sizeu3(size_t num); diff --git a/src/m_misc.c b/src/m_misc.c index cfe73d88f..d6ab40196 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -1617,6 +1617,11 @@ INT32 axtoi(const char *hexStg) return intValue; } +// Token parser variables + +static UINT32 oldendPos = 0; // old value of endPos, used by M_UnGetToken +static UINT32 endPos = 0; // now external to M_GetToken, but still static + /** Token parser for TEXTURES, ANIMDEFS, and potentially other lumps later down the line. * Was originally R_GetTexturesToken when I was coding up the TEXTURES parser, until I realized I needed it for ANIMDEFS too. * Parses up to the next whitespace character or comma. When finding the start of the next token, whitespace is skipped. @@ -1631,7 +1636,7 @@ char *M_GetToken(const char *inputString) { static const char *stringToUse = NULL; // Populated if inputString != NULL; used otherwise static UINT32 startPos = 0; - static UINT32 endPos = 0; +// static UINT32 endPos = 0; static UINT32 stringLength = 0; static UINT8 inComment = 0; // 0 = not in comment, 1 = // Single-line, 2 = /* Multi-line */ char *texturesToken = NULL; @@ -1641,12 +1646,12 @@ char *M_GetToken(const char *inputString) { stringToUse = inputString; startPos = 0; - endPos = 0; + oldendPos = endPos = 0; stringLength = strlen(inputString); } else { - startPos = endPos; + startPos = oldendPos = endPos; } if (stringToUse == NULL) return NULL; @@ -1777,6 +1782,16 @@ char *M_GetToken(const char *inputString) return texturesToken; } +/** Undoes the last M_GetToken call + * The current position along the string being parsed is reset to the last saved position. + * This exists mostly because of R_ParseTexture/R_ParsePatch honestly, but could be useful elsewhere? + * -Monster Iestyn (22/10/16) + */ +void M_UnGetToken(void) +{ + endPos = oldendPos; +} + /** Count bits in a number. */ UINT8 M_CountBits(UINT32 num, UINT8 size) diff --git a/src/r_data.c b/src/r_data.c index b92d88f19..350bd4175 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -160,6 +160,7 @@ static inline void R_DrawColumnInCache(column_t *patch, UINT8 *cache, INT32 orig if (position < 0) { count += position; + source -= position; // start further down the column position = 0; } @@ -173,6 +174,44 @@ static inline void R_DrawColumnInCache(column_t *patch, UINT8 *cache, INT32 orig } } +static inline void R_DrawFlippedColumnInCache(column_t *patch, UINT8 *cache, INT32 originy, INT32 cacheheight, INT32 patchheight) +{ + INT32 count, position; + UINT8 *source, *dest; + INT32 topdelta, prevdelta = -1; + + while (patch->topdelta != 0xff) + { + topdelta = patch->topdelta; + if (topdelta <= prevdelta) + topdelta += prevdelta; + prevdelta = topdelta; + topdelta = patchheight-patch->length-topdelta; + source = (UINT8 *)patch + 2 + patch->length; // patch + 3 + (patch->length-1) + count = patch->length; + position = originy + topdelta; + + if (position < 0) + { + count += position; + source += position; // start further UP the column + position = 0; + } + + if (position + count > cacheheight) + count = cacheheight - position; + + dest = cache + position; + if (count > 0) + { + for (; dest < cache + position + count; --source) + *dest++ = *source; + } + + patch = (column_t *)((UINT8 *)patch + patch->length + 4); + } +} + // // R_GenerateTexture // @@ -191,7 +230,7 @@ static UINT8 *R_GenerateTexture(size_t texnum) texture_t *texture; texpatch_t *patch; patch_t *realpatch; - int x, x1, x2, i; + int x, x1, x2, i, width, height; size_t blocksize; column_t *patchcol; UINT32 *colofs; @@ -239,6 +278,7 @@ static UINT8 *R_GenerateTexture(size_t texnum) if (holey) { texture->holes = true; + texture->flip = patch->flip; blocksize = W_LumpLengthPwad(patch->wad, patch->lump); block = Z_Calloc(blocksize, PU_STATIC, // will change tag at end of this function &texturecache[texnum]); @@ -249,6 +289,14 @@ static UINT8 *R_GenerateTexture(size_t texnum) colofs = (UINT32 *)(void *)(block + 8); texturecolumnofs[texnum] = colofs; blocktex = block; + if (patch->flip & 1) // flip the patch horizontally + { + UINT32 *realcolofs = (UINT32 *)realpatch->columnofs; + for (x = 0; x < texture->width; x++) + colofs[x] = realcolofs[texture->width-1-x]; // swap with the offset of the other side of the texture + } + // we can't as easily flip the patch vertically sadly though, + // we have wait until the texture itself is drawn to do that for (x = 0; x < texture->width; x++) colofs[x] = LONG(LONG(colofs[x]) + 3); goto done; @@ -259,6 +307,7 @@ static UINT8 *R_GenerateTexture(size_t texnum) // multi-patch textures (or 'composite') texture->holes = false; + texture->flip = 0; blocksize = (texture->width * 4) + (texture->width * texture->height); texturememory += blocksize; block = Z_Malloc(blocksize+1, PU_STATIC, &texturecache[texnum]); @@ -277,7 +326,9 @@ static UINT8 *R_GenerateTexture(size_t texnum) { realpatch = W_CacheLumpNumPwad(patch->wad, patch->lump, PU_CACHE); x1 = patch->originx; - x2 = x1 + SHORT(realpatch->width); + width = SHORT(realpatch->width); + height = SHORT(realpatch->height); + x2 = x1 + width; if (x1 < 0) x = 0; @@ -289,11 +340,17 @@ static UINT8 *R_GenerateTexture(size_t texnum) for (; x < x2; x++) { - patchcol = (column_t *)((UINT8 *)realpatch + LONG(realpatch->columnofs[x-x1])); + if (patch->flip & 1) + patchcol = (column_t *)((UINT8 *)realpatch + LONG(realpatch->columnofs[(x1+width-1)-x])); + else + patchcol = (column_t *)((UINT8 *)realpatch + LONG(realpatch->columnofs[x-x1])); // generate column ofset lookup colofs[x] = LONG((x * texture->height) + (texture->width*4)); - R_DrawColumnInCache(patchcol, block + LONG(colofs[x]), patch->originy, texture->height); + if (patch->flip & 2) + R_DrawFlippedColumnInCache(patchcol, block + LONG(colofs[x]), patch->originy, texture->height, height); + else + R_DrawColumnInCache(patchcol, block + LONG(colofs[x]), patch->originy, texture->height); } } @@ -469,6 +526,7 @@ void R_LoadTextures(void) texture->height = SHORT(patchlump->height)*patchcount; texture->patchcount = patchcount; texture->holes = false; + texture->flip = 0; // Allocate information for the texture's patches. for (k = 0; k < patchcount; k++) @@ -479,6 +537,7 @@ void R_LoadTextures(void) patch->originy = (INT16)(k*patchlump->height); patch->wad = (UINT16)w; patch->lump = texstart + j; + patch->flip = 0; } Z_Unlock(patchlump); @@ -502,6 +561,7 @@ static texpatch_t *R_ParsePatch(boolean actuallyLoadPatch) char *patchName = NULL; INT16 patchXPos; INT16 patchYPos; + UINT8 flip = 0; texpatch_t *resultPatch = NULL; lumpnum_t patchLumpNum; @@ -598,6 +658,47 @@ static texpatch_t *R_ParsePatch(boolean actuallyLoadPatch) } Z_Free(texturesToken); + // Patch parameters block (OPTIONAL) + // added by Monster Iestyn (22/10/16) + + // Left Curly Brace + texturesToken = M_GetToken(NULL); + if (texturesToken == NULL) + ; // move on and ignore, R_ParseTextures will deal with this + else + { + if (strcmp(texturesToken,"{")==0) + { + Z_Free(texturesToken); + texturesToken = M_GetToken(NULL); + if (texturesToken == NULL) + { + I_Error("Error parsing TEXTURES lump: Unexpected end of file where patch \"%s\"'s parameters should be",patchName); + } + while (strcmp(texturesToken,"}")!=0) + { + if (stricmp(texturesToken, "FLIPX")==0) + flip |= 1; + else if (stricmp(texturesToken, "FLIPY")==0) + flip |= 2; + Z_Free(texturesToken); + + texturesToken = M_GetToken(NULL); + if (texturesToken == NULL) + { + I_Error("Error parsing TEXTURES lump: Unexpected end of file where patch \"%s\"'s parameters or right curly brace should be",patchName); + } + } + } + else + { + // this is not what we wanted... + // undo last read so R_ParseTextures can re-get the token for its own purposes + M_UnGetToken(); + } + Z_Free(texturesToken); + } + if (actuallyLoadPatch == true) { // Check lump exists @@ -608,6 +709,7 @@ static texpatch_t *R_ParsePatch(boolean actuallyLoadPatch) resultPatch->originy = patchYPos; resultPatch->lump = patchLumpNum & 65535; resultPatch->wad = patchLumpNum>>16; + resultPatch->flip = flip; // Clean up a little after ourselves Z_Free(patchName); // Then return it diff --git a/src/r_data.h b/src/r_data.h index 69a2882af..72054da5d 100644 --- a/src/r_data.h +++ b/src/r_data.h @@ -31,6 +31,7 @@ typedef struct // Block origin (always UL), which has already accounted for the internal origin of the patch. INT16 originx, originy; UINT16 wad, lump; + UINT8 flip; // 1 = flipx, 2 = flipy, 3 = both } texpatch_t; // A maptexturedef_t describes a rectangular texture, @@ -42,6 +43,7 @@ typedef struct char name[8]; INT16 width, height; boolean holes; + UINT8 flip; // 1 = flipx, 2 = flipy, 3 = both // All the patches[patchcount] are drawn back to front into the cached texture. INT16 patchcount; diff --git a/src/r_segs.c b/src/r_segs.c index 257be2989..91fb0e5bd 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -276,6 +276,13 @@ static void R_Render2sidedMultiPatchColumn(column_t *column) } } +// quick wrapper for R_DrawFlippedMaskedColumn so it can be set as a colfunc_2s value +// uses column2s_length for texture->height as above +static void R_DrawFlippedMaskedSegColumn(column_t *column) +{ + R_DrawFlippedMaskedColumn(column, column2s_length); +} + void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) { size_t pindex; @@ -347,7 +354,15 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) // handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures // are not stored per-column with post info in SRB2 if (textures[texnum]->holes) - colfunc_2s = R_DrawMaskedColumn; // render the usual 2sided single-patch packed texture + { + if (textures[texnum]->flip & 2) // vertically flipped? + { + colfunc_2s = R_DrawFlippedMaskedSegColumn; + column2s_length = textures[texnum]->height; + } + else + colfunc_2s = R_DrawMaskedColumn; // render the usual 2sided single-patch packed texture + } else { colfunc_2s = R_Render2sidedMultiPatchColumn; // render multipatch with no holes (no post_t info) @@ -700,6 +715,14 @@ static void R_DrawRepeatMaskedColumn(column_t *col) } while (sprtopscreen < sprbotscreen); } +static void R_DrawRepeatFlippedMaskedColumn(column_t *col) +{ + do { + R_DrawFlippedMaskedColumn(col, column2s_length); + sprtopscreen += dc_texheight*spryscale; + } while (sprtopscreen < sprbotscreen); +} + // // R_RenderThickSideRange // Renders all the thick sides in the given range. @@ -1027,7 +1050,15 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) //faB: handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures // are not stored per-column with post info anymore in Doom Legacy if (textures[texnum]->holes) - colfunc_2s = R_DrawRepeatMaskedColumn; //render the usual 2sided single-patch packed texture + { + if (textures[texnum]->flip & 2) // vertically flipped? + { + colfunc_2s = R_DrawRepeatFlippedMaskedColumn; + column2s_length = textures[texnum]->height; + } + else + colfunc_2s = R_DrawRepeatMaskedColumn; // render the usual 2sided single-patch packed texture + } else { colfunc_2s = R_Render2sidedMultiPatchColumn; //render multipatch with no holes (no post_t info) diff --git a/src/r_things.c b/src/r_things.c index 9f6cad529..5d560b53d 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -712,7 +712,7 @@ void R_DrawMaskedColumn(column_t *column) dc_texturemid = basetexturemid; } -static void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight) +void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight) { INT32 topscreen; INT32 bottomscreen; diff --git a/src/r_things.h b/src/r_things.h index 20dd25abf..572884d21 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -46,6 +46,7 @@ extern fixed_t windowtop; extern fixed_t windowbottom; void R_DrawMaskedColumn(column_t *column); +void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight); void R_SortVisSprites(void); //faB: find sprites in wadfile, replace existing, add new ones