//--------------------------------------------------------------------------- static void createTextureCompositePatch(int id) { rpatch_t *composite_patch; texture_t *texture; texpatch_t *texpatch; int patchNum; const patch_t *oldPatch; const column_t *oldColumn, *oldPrevColumn, *oldNextColumn; int i, x, y; int oy, count; int pixelDataSize; int columnsDataSize; int postsDataSize; int dataSize; int numPostsTotal; const unsigned char *oldColumnPixelData; int numPostsUsedSoFar; int edgeSlope; count_t *countsInColumn; #ifdef RANGECHECK if (id >= numtextures) I_Error("createTextureCompositePatch: %i >= numtextures", id); #endif composite_patch = &texture_composites[id]; texture = textures[id]; composite_patch->width = texture->width; composite_patch->height = texture->height; composite_patch->widthmask = texture->widthmask; composite_patch->leftoffset = 0; composite_patch->topoffset = 0; composite_patch->isNotTileable = 0; // work out how much memory we need to allocate for this patch's data pixelDataSize = (composite_patch->width * composite_patch->height + 4) & ~3; columnsDataSize = sizeof(rcolumn_t) * composite_patch->width; // count the number of posts in each column countsInColumn = (count_t *)calloc(sizeof(count_t), composite_patch->width); numPostsTotal = 0; for (i=0; i<texture->patchcount; i++) { texpatch = &texture->patches[i]; patchNum = texpatch->patch; oldPatch = (const patch_t*)W_CacheLumpNum(patchNum); for (x=0; x<SHORT(oldPatch->width); x++) { int tx = texpatch->originx + x; if (tx < 0) continue; if (tx >= composite_patch->width) break; countsInColumn[tx].patches++; oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x])); while (oldColumn->topdelta != 0xff) { countsInColumn[tx].posts++; numPostsTotal++; oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4); } } W_UnlockLumpNum(patchNum); } postsDataSize = numPostsTotal * sizeof(rpost_t); // allocate our data chunk dataSize = pixelDataSize + columnsDataSize + postsDataSize; composite_patch->data = (unsigned char*)Z_Malloc(dataSize, PU_STATIC, (void **)&composite_patch->data); memset(composite_patch->data, 0, dataSize); // set out pixel, column, and post pointers into our data array composite_patch->pixels = composite_patch->data; composite_patch->columns = (rcolumn_t*)((unsigned char*)composite_patch->pixels + pixelDataSize); composite_patch->posts = (rpost_t*)((unsigned char*)composite_patch->columns + columnsDataSize); // sanity check that we've got all the memory allocated we need assert((((byte*)composite_patch->posts + numPostsTotal*sizeof(rpost_t)) - (byte*)composite_patch->data) == dataSize); memset(composite_patch->pixels, 0xff, (composite_patch->width*composite_patch->height)); numPostsUsedSoFar = 0; for (x=0; x<texture->width; x++) { // setup the column's data composite_patch->columns[x].pixels = composite_patch->pixels + (x*composite_patch->height); composite_patch->columns[x].numPosts = countsInColumn[x].posts; composite_patch->columns[x].posts = composite_patch->posts + numPostsUsedSoFar; numPostsUsedSoFar += countsInColumn[x].posts; } // fill in the pixels, posts, and columns for (i=0; i<texture->patchcount; i++) { texpatch = &texture->patches[i]; patchNum = texpatch->patch; oldPatch = (const patch_t*)W_CacheLumpNum(patchNum); for (x=0; x<SHORT(oldPatch->width); x++) { int tx = texpatch->originx + x; if (tx < 0) continue; if (tx >= composite_patch->width) break; oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x])); { // tiling int prevColumnIndex = x-1; int nextColumnIndex = x+1; while (prevColumnIndex < 0) prevColumnIndex += SHORT(oldPatch->width); while (nextColumnIndex >= SHORT(oldPatch->width)) nextColumnIndex -= SHORT(oldPatch->width); oldPrevColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[prevColumnIndex])); oldNextColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[nextColumnIndex])); } while (oldColumn->topdelta != 0xff) { rpost_t *post = &composite_patch->columns[tx].posts[countsInColumn[tx].posts_used]; oldColumnPixelData = (const byte *)oldColumn + 3; oy = texpatch->originy; count = oldColumn->length; // the original renderer had several bugs which we reproduce here if (countsInColumn[tx].patches > 1) { // when there are multiple patches, then we need to handle the // column differently if (i == 0) { // draw first patch at original position, it will be partly // overdrawn below for (y=0; y<count; y++) { int ty = oy + oldColumn->topdelta + y; if (ty < 0) continue; if (ty >= composite_patch->height) break; composite_patch->pixels[tx * composite_patch->height + ty] = oldColumnPixelData[y]; } } // do the buggy clipping if ((oy + oldColumn->topdelta) < 0) { count += oy; oy = 0; } } else { // with a single patch only negative y origins are wrong oy = 0; } // set up the post's data post->topdelta = oldColumn->topdelta + oy; post->length = count; if ((post->topdelta + post->length) > composite_patch->height) { if (post->topdelta > composite_patch->height) post->length = 0; else post->length = composite_patch->height - post->topdelta; } if (post->topdelta < 0) { if ((post->topdelta + post->length) <= 0) post->length = 0; else post->length -= post->topdelta; post->topdelta = 0; } post->slope = 0; edgeSlope = getColumnEdgeSlope(oldPrevColumn, oldNextColumn, oldColumn->topdelta); if (edgeSlope == 1) post->slope |= RDRAW_EDGESLOPE_TOP_UP; else if (edgeSlope == -1) post->slope |= RDRAW_EDGESLOPE_TOP_DOWN; edgeSlope = getColumnEdgeSlope(oldPrevColumn, oldNextColumn, oldColumn->topdelta+count); if (edgeSlope == 1) post->slope |= RDRAW_EDGESLOPE_BOT_UP; else if (edgeSlope == -1) post->slope |= RDRAW_EDGESLOPE_BOT_DOWN; // fill in the post's pixels for (y=0; y<count; y++) { int ty = oy + oldColumn->topdelta + y; if (ty < 0) continue; if (ty >= composite_patch->height) break; composite_patch->pixels[tx * composite_patch->height + ty] = oldColumnPixelData[y]; } oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4); countsInColumn[tx].posts_used++; assert(countsInColumn[tx].posts_used <= countsInColumn[tx].posts); } } W_UnlockLumpNum(patchNum); } for (x=0; x<texture->width; x++) { rcolumn_t *column; if (countsInColumn[x].patches <= 1) continue; // cleanup posts on multipatch columns column = &composite_patch->columns[x]; i = 0; while (i<(column->numPosts-1)) { rpost_t *post1 = &column->posts[i]; rpost_t *post2 = &column->posts[i+1]; int length; if ((post2->topdelta - post1->topdelta) < 0) switchPosts(post1, post2); if ((post1->topdelta + post1->length) >= post2->topdelta) { length = (post1->length + post2->length) - ((post1->topdelta + post1->length) - post2->topdelta); if (post1->length < length) { post1->slope = post2->slope; post1->length = length; } removePostFromColumn(column, i+1); i = 0; continue; } i++; } } if (1 || composite_patch->isNotTileable) { const rcolumn_t *column, *prevColumn; // copy the patch image down and to the right where there are // holes to eliminate the black halo from bilinear filtering for (x=0; x<composite_patch->width; x++) { //oldColumn = (const column_t *)((const byte *)oldPatch + oldPatch->columnofs[x]); column = R_GetPatchColumnClamped(composite_patch, x); prevColumn = R_GetPatchColumnClamped(composite_patch, x-1); if (column->pixels[0] == 0xff) { // force the first pixel (which is a hole), to use // the color from the next solid spot in the column for (y=0; y<composite_patch->height; y++) { if (column->pixels[y] != 0xff) { column->pixels[0] = column->pixels[y]; break; } } } // copy from above or to the left for (y=1; y<composite_patch->height; y++) { //if (getIsSolidAtSpot(oldColumn, y)) continue; if (column->pixels[y] != 0xff) continue; // this pixel is a hole if (x && prevColumn->pixels[y-1] != 0xff) { // copy the color from the left column->pixels[y] = prevColumn->pixels[y]; } else { // copy the color from above column->pixels[y] = column->pixels[y-1]; } } } // verify that the patch truly is non-rectangular since // this determines tiling later on } free(countsInColumn); }
static void createTextureCompositePatch(int id) { rpatch_t *composite_patch = &texture_composites[id]; texture_t *texture = textures[id]; texpatch_t *texpatch; int patchNum; const patch_t *oldPatch; const column_t *oldColumn; int i, x, y; int oy, count; int pixelDataSize; int columnsDataSize; int postsDataSize; int dataSize; int numPostsTotal; const unsigned char *oldColumnPixelData; int numPostsUsedSoFar; count_t *countsInColumn; composite_patch->width = texture->width; composite_patch->height = texture->height; composite_patch->widthmask = texture->widthmask; composite_patch->leftoffset = 0; composite_patch->topoffset = 0; composite_patch->flags = 0; // work out how much memory we need to allocate for this patch's data pixelDataSize = (composite_patch->width * composite_patch->height + 4) & ~3; columnsDataSize = sizeof(rcolumn_t) * composite_patch->width; // count the number of posts in each column countsInColumn = (count_t *)calloc(sizeof(count_t), composite_patch->width); numPostsTotal = 0; for (i = 0; i < texture->patchcount; ++i) { texpatch = &texture->patches[i]; patchNum = texpatch->patch; oldPatch = (const patch_t *)W_CacheLumpNum(patchNum, PU_STATIC); for (x = 0; x < SHORT(oldPatch->width); ++x) { int tx = texpatch->originx + x; if (tx < 0) continue; if (tx >= composite_patch->width) break; countsInColumn[tx].patches++; oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x])); while (oldColumn->topdelta != 0xFF) { countsInColumn[tx].posts++; numPostsTotal++; oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4); } } W_ReleaseLumpNum(patchNum); } postsDataSize = numPostsTotal * sizeof(rpost_t); // allocate our data chunk dataSize = pixelDataSize + columnsDataSize + postsDataSize; composite_patch->data = (unsigned char *)Z_Malloc(dataSize, PU_STATIC, (void **)&composite_patch->data); memset(composite_patch->data, 0, dataSize); // set out pixel, column, and post pointers into our data array composite_patch->pixels = composite_patch->data; composite_patch->columns = (rcolumn_t*)((unsigned char*)composite_patch->pixels + pixelDataSize); composite_patch->posts = (rpost_t*)((unsigned char*)composite_patch->columns + columnsDataSize); // sanity check that we've got all the memory allocated we need assert((((byte *)composite_patch->posts + numPostsTotal * sizeof(rpost_t)) - (byte *)composite_patch->data) == dataSize); memset(composite_patch->pixels, 0xFF, (composite_patch->width * composite_patch->height)); numPostsUsedSoFar = 0; for (x = 0; x < texture->width; ++x) { // setup the column's data composite_patch->columns[x].pixels = composite_patch->pixels + (x * composite_patch->height); composite_patch->columns[x].numPosts = countsInColumn[x].posts; composite_patch->columns[x].posts = composite_patch->posts + numPostsUsedSoFar; numPostsUsedSoFar += countsInColumn[x].posts; } // fill in the pixels, posts, and columns for (i = 0; i < texture->patchcount; ++i) { texpatch = &texture->patches[i]; patchNum = texpatch->patch; oldPatch = (const patch_t *)W_CacheLumpNum(patchNum, PU_STATIC); for (x = 0; x < SHORT(oldPatch->width); ++x) { int top = -1; int tx = texpatch->originx + x; if (tx < 0) continue; if (tx >= composite_patch->width) break; oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x])); while (oldColumn->topdelta != 0xFF) { rpost_t *post = &composite_patch->columns[tx].posts[countsInColumn[tx].posts_used]; // e6y: support for DeePsea's true tall patches if (oldColumn->topdelta <= top) top += oldColumn->topdelta; else top = oldColumn->topdelta; oldColumnPixelData = (const byte *)oldColumn + 3; oy = texpatch->originy; count = oldColumn->length; // the original renderer had several bugs which we reproduce here if (countsInColumn[tx].patches > 1) { // when there are multiple patches, then we need to handle the // column differently if (!i) { // draw first patch at original position, it will be partly // overdrawn below for (y = 0; y < count; ++y) { int ty = oy + top + y; if (ty < 0) continue; if (ty >= composite_patch->height) break; composite_patch->pixels[tx * composite_patch->height + ty] = oldColumnPixelData[y]; } } // do the buggy clipping if (oy + top < 0) { count += oy; oy = 0; } } else oy = 0; // with a single patch only negative y origins are wrong // set up the post's data post->topdelta = top + oy; post->length = count; if ((post->topdelta + post->length) > composite_patch->height) { if (post->topdelta > composite_patch->height) post->length = 0; else post->length = composite_patch->height - post->topdelta; } if (post->topdelta < 0) { if ((post->topdelta + post->length) <= 0) post->length = 0; else post->length -= post->topdelta; post->topdelta = 0; } // fill in the post's pixels for (y = 0; y < count; ++y) { int ty = oy + top + y; if (ty < 0) continue; if (ty >= composite_patch->height) break; composite_patch->pixels[tx * composite_patch->height + ty] = oldColumnPixelData[y]; } oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4); countsInColumn[tx].posts_used++; assert(countsInColumn[tx].posts_used <= countsInColumn[tx].posts); } } W_ReleaseLumpNum(patchNum); } for (x = 0; x < texture->width; ++x) { rcolumn_t *column; if (countsInColumn[x].patches <= 1) continue; // cleanup posts on multipatch columns column = &composite_patch->columns[x]; i = 0; while (i < column->numPosts - 1) { rpost_t *post1 = &column->posts[i]; rpost_t *post2 = &column->posts[i + 1]; if (post2->topdelta - post1->topdelta < 0) switchPosts(post1, post2); if (post1->topdelta + post1->length >= post2->topdelta) { int length = (post1->length + post2->length) - ((post1->topdelta + post1->length) - post2->topdelta); if (post1->length < length) post1->length = length; removePostFromColumn(column, i + 1); i = 0; continue; } i++; } } { const rcolumn_t *column; const rcolumn_t *prevColumn; // copy the patch image down and to the right where there are // holes to eliminate the black halo from bilinear filtering for (x = 0; x < composite_patch->width; ++x) { column = R_GetPatchColumnClamped(composite_patch, x); prevColumn = R_GetPatchColumnClamped(composite_patch, x - 1); if (column->pixels[0] == 0xFF) { // e6y: marking of all patches with holes composite_patch->flags |= PATCH_HASHOLES; // force the first pixel (which is a hole), to use // the color from the next solid spot in the column for (y = 0; y < composite_patch->height; ++y) { if (column->pixels[y] != 0xFF) { column->pixels[0] = column->pixels[y]; break; } } } // copy from above or to the left for (y = 1; y < composite_patch->height; ++y) { if (column->pixels[y] != 0xFF) continue; // this pixel is a hole // e6y: marking of all patches with holes composite_patch->flags |= PATCH_HASHOLES; if (x && prevColumn->pixels[y - 1] != 0xFF) column->pixels[y] = prevColumn->pixels[y]; // copy the color from the left else column->pixels[y] = column->pixels[y - 1]; // copy the color from above } } } free(countsInColumn); }