www.pudn.com > fatmap2.zip > TXTTIL.CPP


 
/* 
 *      Tiled texture mapper 
 * 
 *      This source is part of the fatmap2.txt document by 
 *      Mats Byggmastar, mri@penti.sit.fi 
 *      17.4.1997 Jakobstad, Finland 
 * 
 *      Companies with self respect are encouraged to contact me if 
 *      any of this code is to be used as part of a commercial product. 
 */ 
 
 
#include "misc.h" 
 
static vertexuv * max_vtx;                  // Max y vertex (ending vertex) 
static vertexuv * start_vtx, * end_vtx;     // First and last vertex in array 
static vertexuv * right_vtx, * left_vtx;    // Current right and left vertex 
 
static long right_height, left_height; 
static long right_x, right_dxdy, left_x, left_dxdy; 
static long left_u, left_dudy, left_v, left_dvdy; 
static long tildudx, tildvdx; 
 
void inner(void * dst, int width, void * src, long u, long v); 
#pragma aux inner = \ 
    "    push  ebp                                      "\ 
    "    mov   edx, eax                                 "\ 
    "    shl   eax, 8                                   "\ 
    "    mov   ebp, edx                                 "\ 
    "    shr   edx, 1                                   "\ 
    "    and   eax, 11111000000000000000000000000000b   "\ 
    "    and   edx, 00000000000000000111111111111111b   "\ 
    "    and   ebp, 00000000000001110000000000000000b   "\ 
    "    add   eax, edx                                 "\ 
    "    mov   edx, ebx                                 "\ 
    "    add   eax, ebp                                 "\ 
    "    lea   edi, [edi+ecx-1]                         "\ 
    "    shl   ebx, 3                                   "\ 
    "    xor   ecx, -1                                  "\ 
    "    shr   edx, 1                                   "\ 
    "    and   ebx, 00000111111110000000000000000000b   "\ 
    "    and   edx, 00000000000000000111111111111111b   "\ 
    "    inc   ecx                                      "\ 
    "    add   ebx, edx                                 "\ 
    "    mov   ebp, eax                                 "\ 
    "    add   ebp, ebx                                 "\ 
    " next:                                             "\ 
    "    add   eax, [tildudx]                           "\ 
    "    add   ebx, [tildvdx]                           "\ 
    "    shr   ebp, 16                                  "\ 
    "    and   eax, 11111000000001110111111111111111b   "\ 
    "    and   ebx, 00000111111110000111111111111111b   "\ 
    "    inc   ecx                                      "\ 
    "    mov   dl, [esi+ebp]                            "\ 
    "    lea   ebp, [eax+ebx]                           "\ 
    "    mov   [edi+ecx], dl                            "\ 
    "    jnz   next                                     "\ 
    "    pop   ebp                                      "\ 
    parm [edi] [ecx] [esi] [eax] [ebx] modify [eax ebx ecx edx esi edi] 
 
 
static void RightSection(void) 
{ 
    // Walk backwards trough the vertex array 
 
    vertexuv * v2, * v1 = right_vtx; 
    if(right_vtx > start_vtx) v2 = right_vtx-1;      
    else                      v2 = end_vtx;         // Wrap to end of array 
    right_vtx = v2; 
 
    // v1 = top vertex 
    // v2 = bottom vertex  
 
    // Calculate number of scanlines in this section 
 
    right_height = ceil(v2->y) - ceil(v1->y); 
    if(right_height <= 0) return; 
 
    // Guard against possible div overflows 
 
    if(right_height > 1) { 
        // OK, no worries, we have a section that is at least 
        // one pixel high. Calculate slope as usual. 
 
        long height = v2->y - v1->y; 
        right_dxdy  = idiv16(v2->x - v1->x, height); 
    } 
    else { 
        // Height is less or equal to one pixel. 
        // Calculate slope = width * 1/height 
        // using 18:14 bit precision to avoid overflows. 
 
        long inv_height = (0x10000 << 14) / (v2->y - v1->y);   
        right_dxdy = imul14(v2->x - v1->x, inv_height); 
    } 
 
    // Prestep initial values 
 
    long prestep = (ceil(v1->y) << 16) - v1->y; 
    right_x = v1->x + imul16(prestep, right_dxdy); 
} 
 
static void LeftSection(void) 
{ 
    // Walk forward trough the vertex array 
 
    vertexuv * v2, * v1 = left_vtx; 
    if(left_vtx < end_vtx) v2 = left_vtx+1; 
    else                   v2 = start_vtx;      // Wrap to start of array 
    left_vtx = v2; 
 
    // v1 = top vertex 
    // v2 = bottom vertex  
 
    // Calculate number of scanlines in this section 
 
    left_height = ceil(v2->y) - ceil(v1->y); 
    if(left_height <= 0) return; 
 
    // Guard against possible div overflows 
 
    if(left_height > 1) { 
        // OK, no worries, we have a section that is at least 
        // one pixel high. Calculate slope as usual. 
 
        long height = v2->y - v1->y; 
        left_dxdy = idiv16(v2->x - v1->x, height); 
        left_dudy = idiv16(v2->u - v1->u, height); 
        left_dvdy = idiv16(v2->v - v1->v, height); 
    } 
    else { 
        // Height is less or equal to one pixel. 
        // Calculate slope = width * 1/height 
        // using 18:14 bit precision to avoid overflows. 
 
        long inv_height = (0x10000 << 14) / (v2->y - v1->y); 
        left_dxdy = imul14(v2->x - v1->x, inv_height); 
        left_dudy = imul14(v2->u - v1->u, inv_height); 
        left_dvdy = imul14(v2->v - v1->v, inv_height); 
    } 
 
    // Prestep initial values 
 
    long prestep = (ceil(v1->y) << 16) - v1->y; 
    left_x = v1->x + imul16(prestep, left_dxdy); 
    left_u = v1->u + imul16(prestep, left_dudy); 
    left_v = v1->v + imul16(prestep, left_dvdy); 
} 
 
 
void DrawTiledTexturePoly(vertexuv * vtx, int vertices, 
                          char * bitmap, long dudx, long dvdx) 
{ 
    start_vtx = vtx;        // First vertex in array 
 
    // Search trough the vtx array to find min y, max y 
    // and the location of these structures. 
 
    vertexuv * min_vtx = vtx; 
    max_vtx = vtx; 
 
    long min_y = vtx->y; 
    long max_y = vtx->y; 
 
    vtx++; 
 
    for(int n=1; ny < min_y) { 
            min_y = vtx->y; 
            min_vtx = vtx; 
        } 
        else 
        if(vtx->y > max_y) { 
            max_y = vtx->y; 
            max_vtx = vtx; 
        } 
        vtx++; 
    } 
 
    // OK, now we know where in the array we should start and 
    // where to end while scanning the edges of the polygon 
 
    left_vtx  = min_vtx;    // Left side starting vertex 
    right_vtx = min_vtx;    // Right side starting vertex 
    end_vtx   = vtx-1;      // Last vertex in array 
 
    // Search for the first usable right section 
 
    do { 
        if(right_vtx == max_vtx) return; 
        RightSection(); 
    } while(right_height <= 0); 
 
    // Search for the first usable left section 
 
    do { 
        if(left_vtx == max_vtx) return; 
        LeftSection(); 
    } while(left_height <= 0); 
 
    char * destptr = WritePagePtr + ceil(min_y) * WritePageWidth; 
 
    tildudx = (((dudx << 8) & 0xf8000000) + 
               ((dudx >> 1) & 0x00007fff) + (dudx & 0x00070000)) | 0x07f88000; 
    tildvdx = (((dvdx << 3) & 0x07f80000) + 
               ((dvdx >> 1) & 0x00007fff)) | 0xf8078000; 
 
    // tildudx = wwwww11111111www1fffffffffffffff 
    // tildvdx = 11111wwwwwwww1111fffffffffffffff 
 
    for(;;) 
    { 
        long x1 = ceil(left_x); 
        long width = ceil(right_x) - x1; 
 
        if(width > 0) { 
 
            // Prestep initial texture u,v 
     
            long prestep = (x1 << 16) - left_x; 
            long u = left_u + imul16(prestep, dudx); 
            long v = left_v + imul16(prestep, dvdx); 
 
            inner(destptr+x1, width, bitmap, u, v); 
        } 
 
        destptr += WritePageWidth; 
 
        // Scan the right side 
 
        if(--right_height <= 0) {               // End of this section? 
            do { 
                if(right_vtx == max_vtx) return; 
                RightSection(); 
            } while(right_height <= 0); 
        } 
        else  
            right_x += right_dxdy; 
 
        // Scan the left side 
 
        if(--left_height <= 0) {                // End of this section? 
            do { 
                if(left_vtx == max_vtx) return; 
                LeftSection(); 
            } while(left_height <= 0); 
        } 
        else { 
            left_x += left_dxdy; 
            left_u += left_dudy; 
            left_v += left_dvdy; 
        } 
    } 
}