static void createPatch(int id) { rpatch_t *patch; const int patchNum = id; const patch_t *oldPatch; const column_t *oldColumn; int x, y; int pixelDataSize; int columnsDataSize; int postsDataSize; int dataSize; int *numPostsInColumn; int numPostsTotal; const unsigned char *oldColumnPixelData; int numPostsUsedSoFar; if (!CheckIfPatch(patchNum)) I_Error("createPatch: Unknown patch format %s.", (patchNum < numlumps ? lumpinfo[patchNum]->name : NULL)); oldPatch = (const patch_t*)W_CacheLumpNum(patchNum, PU_STATIC); patch = &patches[id]; patch->width = SHORT(oldPatch->width); patch->widthmask = 0; patch->height = SHORT(oldPatch->height); patch->leftoffset = SHORT(oldPatch->leftoffset); patch->topoffset = SHORT(oldPatch->topoffset); patch->flags = 0; if (getPatchIsNotTileable(oldPatch)) patch->flags |= PATCH_ISNOTTILEABLE; // work out how much memory we need to allocate for this patch's data pixelDataSize = (patch->width * patch->height + 4) & ~3; columnsDataSize = sizeof(rcolumn_t) * patch->width; // count the number of posts in each column numPostsInColumn = malloc(sizeof(int) * patch->width); numPostsTotal = 0; for (x = 0; x < patch->width; ++x) { oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x])); numPostsInColumn[x] = 0; while (oldColumn->topdelta != 0xFF) { numPostsInColumn[x]++; numPostsTotal++; oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4); } } postsDataSize = numPostsTotal * sizeof(rpost_t); // allocate our data chunk dataSize = pixelDataSize + columnsDataSize + postsDataSize; patch->data = (unsigned char *)Z_Malloc(dataSize, PU_CACHE, (void **)&patch->data); memset(patch->data, 0, dataSize); // set out pixel, column, and post pointers into our data array patch->pixels = patch->data; patch->columns = (rcolumn_t *)((unsigned char *)patch->pixels + pixelDataSize); patch->posts = (rpost_t *)((unsigned char *)patch->columns + columnsDataSize); // sanity check that we've got all the memory allocated we need assert((((byte*)patch->posts + numPostsTotal * sizeof(rpost_t)) - (byte *)patch->data) == dataSize); memset(patch->pixels, 0xFF, (patch->width*patch->height)); // fill in the pixels, posts, and columns numPostsUsedSoFar = 0; for (x = 0; x < patch->width; ++x) { int top = -1; oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x])); // setup the column's data patch->columns[x].pixels = patch->pixels + x * patch->height; patch->columns[x].numPosts = numPostsInColumn[x]; patch->columns[x].posts = patch->posts + numPostsUsedSoFar; while (oldColumn->topdelta != 0xFF) { int len = oldColumn->length; //e6y: support for DeePsea's true tall patches if (oldColumn->topdelta <= top) top += oldColumn->topdelta; else top = oldColumn->topdelta; // Clip posts that extend past the bottom if (top + oldColumn->length > patch->height) len = patch->height - top; if (len > 0) { // set up the post's data patch->posts[numPostsUsedSoFar].topdelta = top; patch->posts[numPostsUsedSoFar].length = len; // fill in the post's pixels oldColumnPixelData = (const byte *)oldColumn + 3; for (y = 0; y < len; y++) patch->pixels[x * patch->height + top + y] = oldColumnPixelData[y]; } oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4); numPostsUsedSoFar++; } } { 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 < patch->width; ++x) { column = R_GetPatchColumnClamped(patch, x); prevColumn = R_GetPatchColumnClamped(patch, x - 1); if (column->pixels[0] == 0xFF) { // e6y: marking of all patches with holes 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 < 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 < patch->height; ++y) { //if (getIsSolidAtSpot(oldColumn, y)) continue; if (column->pixels[y] != 0xFF) continue; // this pixel is a hole // e6y: marking of all patches with holes 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 } } } W_ReleaseLumpNum(patchNum); free(numPostsInColumn); }
//--------------------------------------------------------------------------- static void createPatch(int id) { rpatch_t *patch; const int patchNum = id; const patch_t *oldPatch = (const patch_t*)W_CacheLumpNum(patchNum); const column_t *oldColumn, *oldPrevColumn, *oldNextColumn; int x, y; int pixelDataSize; int columnsDataSize; int postsDataSize; int dataSize; int *numPostsInColumn; int numPostsTotal; const unsigned char *oldColumnPixelData; int numPostsUsedSoFar; int edgeSlope; #ifdef RANGECHECK if (id >= numlumps) I_Error("createPatch: %i >= numlumps", id); #endif patch = &patches[id]; // proff - 2003-02-16 What about endianess? patch->width = SHORT(oldPatch->width); patch->widthmask = 0; patch->height = SHORT(oldPatch->height); patch->leftoffset = SHORT(oldPatch->leftoffset); patch->topoffset = SHORT(oldPatch->topoffset); patch->isNotTileable = getPatchIsNotTileable(oldPatch); // work out how much memory we need to allocate for this patch's data pixelDataSize = (patch->width * patch->height + 4) & ~3; columnsDataSize = sizeof(rcolumn_t) * patch->width; // count the number of posts in each column numPostsInColumn = (int*)malloc(sizeof(int) * patch->width); numPostsTotal = 0; for (x=0; x<patch->width; x++) { oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x])); numPostsInColumn[x] = 0; while (oldColumn->topdelta != 0xff) { numPostsInColumn[x]++; numPostsTotal++; oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4); } } postsDataSize = numPostsTotal * sizeof(rpost_t); // allocate our data chunk dataSize = pixelDataSize + columnsDataSize + postsDataSize; patch->data = (unsigned char*)Z_Malloc(dataSize, PU_CACHE, (void **)&patch->data); memset(patch->data, 0, dataSize); // set out pixel, column, and post pointers into our data array patch->pixels = patch->data; patch->columns = (rcolumn_t*)((unsigned char*)patch->pixels + pixelDataSize); patch->posts = (rpost_t*)((unsigned char*)patch->columns + columnsDataSize); // sanity check that we've got all the memory allocated we need assert((((byte*)patch->posts + numPostsTotal*sizeof(rpost_t)) - (byte*)patch->data) == dataSize); memset(patch->pixels, 0xff, (patch->width*patch->height)); // fill in the pixels, posts, and columns numPostsUsedSoFar = 0; for (x=0; x<patch->width; x++) { oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x])); if (patch->isNotTileable) { // non-tiling if (x == 0) oldPrevColumn = 0; else oldPrevColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x-1])); if (x == patch->width-1) oldNextColumn = 0; else oldNextColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x+1])); } else { // tiling int prevColumnIndex = x-1; int nextColumnIndex = x+1; while (prevColumnIndex < 0) prevColumnIndex += patch->width; while (nextColumnIndex >= patch->width) nextColumnIndex -= patch->width; oldPrevColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[prevColumnIndex])); oldNextColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[nextColumnIndex])); } // setup the column's data patch->columns[x].pixels = patch->pixels + (x*patch->height) + 0; patch->columns[x].numPosts = numPostsInColumn[x]; patch->columns[x].posts = patch->posts + numPostsUsedSoFar; while (oldColumn->topdelta != 0xff) { // set up the post's data patch->posts[numPostsUsedSoFar].topdelta = oldColumn->topdelta; patch->posts[numPostsUsedSoFar].length = oldColumn->length; patch->posts[numPostsUsedSoFar].slope = 0; edgeSlope = getColumnEdgeSlope(oldPrevColumn, oldNextColumn, oldColumn->topdelta); if (edgeSlope == 1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_TOP_UP; else if (edgeSlope == -1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_TOP_DOWN; edgeSlope = getColumnEdgeSlope(oldPrevColumn, oldNextColumn, oldColumn->topdelta+oldColumn->length); if (edgeSlope == 1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_BOT_UP; else if (edgeSlope == -1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_BOT_DOWN; // fill in the post's pixels oldColumnPixelData = (const byte *)oldColumn + 3; for (y=0; y<oldColumn->length; y++) { patch->pixels[x * patch->height + oldColumn->topdelta + y] = oldColumnPixelData[y]; } oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4); numPostsUsedSoFar++; } } if (1 || 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<patch->width; x++) { //oldColumn = (const column_t *)((const byte *)oldPatch + oldPatch->columnofs[x]); column = R_GetPatchColumnClamped(patch, x); prevColumn = R_GetPatchColumnClamped(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<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<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 } W_UnlockLumpNum(patchNum); free(numPostsInColumn); }
//--------------------------------------------------------------------------- static void createPatch(int id) { rpatch_t *patch; const int patchNum = id; const patch_t *oldPatch; const column_t *oldColumn, *oldPrevColumn, *oldNextColumn; int x, y; int pixelDataSize; int columnsDataSize; int postsDataSize; int dataSize; int *numPostsInColumn; int numPostsTotal; const unsigned char *oldColumnPixelData; int numPostsUsedSoFar; int edgeSlope; #ifdef RANGECHECK if (id >= numlumps) I_Error("createPatch: %i >= numlumps", id); #endif if (!CheckIfPatch(patchNum)) { I_Error("createPatch: Unknown patch format %s.", (patchNum < numlumps ? lumpinfo[patchNum].name : NULL)); } oldPatch = (const patch_t*)W_CacheLumpNum(patchNum); patch = &patches[id]; // proff - 2003-02-16 What about endianess? patch->width = LittleShort(oldPatch->width); patch->widthmask = 0; patch->height = LittleShort(oldPatch->height); patch->leftoffset = LittleShort(oldPatch->leftoffset); patch->topoffset = LittleShort(oldPatch->topoffset); patch->flags = 0; if (getPatchIsNotTileable(oldPatch)) patch->flags |= PATCH_ISNOTTILEABLE; #ifdef GL_DOOM // Width of M_THERMM patch is 9, but Doom interprets it as 8-columns lump // during drawing. It is not a problem for software mode and GL_NEAREST, // but looks wrong with filtering. So I need to patch it during loading. if (V_GetMode() == VID_MODEGL) { if (!strncasecmp(lumpinfo[id].name, "M_THERMM", 8) && patch->width > 8) { patch->width--; } } #endif // work out how much memory we need to allocate for this patch's data pixelDataSize = (patch->width * patch->height + 4) & ~3; columnsDataSize = sizeof(rcolumn_t) * patch->width; // count the number of posts in each column numPostsInColumn = malloc(sizeof(int) * patch->width); numPostsTotal = 0; for (x=0; x<patch->width; x++) { oldColumn = (const column_t *)((const byte *)oldPatch + LittleLong(oldPatch->columnofs[x])); numPostsInColumn[x] = 0; while (oldColumn->topdelta != 0xff) { numPostsInColumn[x]++; numPostsTotal++; oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4); } } postsDataSize = numPostsTotal * sizeof(rpost_t); // allocate our data chunk dataSize = pixelDataSize + columnsDataSize + postsDataSize; patch->data = (unsigned char*)Z_Malloc(dataSize, PU_CACHE, (void **)&patch->data); memset(patch->data, 0, dataSize); // set out pixel, column, and post pointers into our data array patch->pixels = patch->data; patch->columns = (rcolumn_t*)((unsigned char*)patch->pixels + pixelDataSize); patch->posts = (rpost_t*)((unsigned char*)patch->columns + columnsDataSize); // sanity check that we've got all the memory allocated we need assert((((byte*)patch->posts + numPostsTotal*sizeof(rpost_t)) - (byte*)patch->data) == dataSize); memset(patch->pixels, 0xff, (patch->width*patch->height)); // fill in the pixels, posts, and columns numPostsUsedSoFar = 0; for (x=0; x<patch->width; x++) { int top = -1; oldColumn = (const column_t *)((const byte *)oldPatch + LittleLong(oldPatch->columnofs[x])); if (patch->flags&PATCH_ISNOTTILEABLE) { // non-tiling if (x == 0) oldPrevColumn = 0; else oldPrevColumn = (const column_t *)((const byte *)oldPatch + LittleLong(oldPatch->columnofs[x-1])); if (x == patch->width-1) oldNextColumn = 0; else oldNextColumn = (const column_t *)((const byte *)oldPatch + LittleLong(oldPatch->columnofs[x+1])); } else { // tiling int prevColumnIndex = x-1; int nextColumnIndex = x+1; while (prevColumnIndex < 0) prevColumnIndex += patch->width; while (nextColumnIndex >= patch->width) nextColumnIndex -= patch->width; oldPrevColumn = (const column_t *)((const byte *)oldPatch + LittleLong(oldPatch->columnofs[prevColumnIndex])); oldNextColumn = (const column_t *)((const byte *)oldPatch + LittleLong(oldPatch->columnofs[nextColumnIndex])); } // setup the column's data patch->columns[x].pixels = patch->pixels + (x*patch->height) + 0; patch->columns[x].numPosts = numPostsInColumn[x]; patch->columns[x].posts = patch->posts + numPostsUsedSoFar; while (oldColumn->topdelta != 0xff) { int len = oldColumn->length; //e6y: support for DeePsea's true tall patches if (oldColumn->topdelta <= top) { top += oldColumn->topdelta; } else { top = oldColumn->topdelta; } // Clip posts that extend past the bottom if (top + oldColumn->length > patch->height) { len = patch->height - top; } if (len > 0) { // set up the post's data patch->posts[numPostsUsedSoFar].topdelta = top; patch->posts[numPostsUsedSoFar].length = len; patch->posts[numPostsUsedSoFar].slope = 0; edgeSlope = getColumnEdgeSlope(oldPrevColumn, oldNextColumn, top); if (edgeSlope == 1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_TOP_UP; else if (edgeSlope == -1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_TOP_DOWN; edgeSlope = getColumnEdgeSlope(oldPrevColumn, oldNextColumn, top+len); if (edgeSlope == 1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_BOT_UP; else if (edgeSlope == -1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_BOT_DOWN; // fill in the post's pixels oldColumnPixelData = (const byte *)oldColumn + 3; for (y=0; y<len; y++) { patch->pixels[x * patch->height + top + y] = oldColumnPixelData[y]; } } oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4); numPostsUsedSoFar++; } } if (1 || (patch->flags&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<patch->width; x++) { //oldColumn = (const column_t *)((const byte *)oldPatch + oldPatch->columnofs[x]); column = R_GetPatchColumnClamped(patch, x); prevColumn = R_GetPatchColumnClamped(patch, x-1); if (column->pixels[0] == 0xff) { // e6y: marking of all patches with holes 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<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<patch->height; y++) { //if (getIsSolidAtSpot(oldColumn, y)) continue; if (column->pixels[y] != 0xff) continue; // this pixel is a hole // e6y: marking of all patches with holes patch->flags |= PATCH_HASHOLES; 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 } W_UnlockLumpNum(patchNum); free(numPostsInColumn); }