home *** CD-ROM | disk | FTP | other *** search
/ Toolkit for DOOM / DOOMTOOL.ISO / editors / dme301.zip / SOURCE.ZIP / TEXTURES.C < prev    next >
C/C++ Source or Header  |  1994-07-25  |  26KB  |  1,109 lines

  1. /*
  2.     This is a DMapEdit source code module.  Though it is copyrighted, you
  3.     may modify it and use it for your own personal use, meaning that new
  4.     modified code and anything derived from it (such as exe files) doesn't
  5.     get distributed to anyone, unless you get my permission first.  Code
  6.     from this file, or code based on ideas from this file may be used with
  7.     other programs, provided that you give credit for it in the source code,
  8.     documentation, and 'about' windows or screens, if one exists, for the
  9.     programs using it.  Giving credit means something like this:
  10.  
  11.     Code from DMapEdit was used in this program
  12.  
  13.                               or
  14.  
  15.     Some code for this program was based on ideas presented in DMapEdit
  16.  
  17.     Whatever.  Just be sure to mention "DMapEdit" in such a way that it's
  18.     self-evident how it was useful to the new program, and be sure to have
  19.     "DMapEdit is a trademark of Jason Hoffoss" in the docs.  That's all..
  20. */
  21.  
  22. #include <stdio.h>
  23. #include <mem.h>
  24. #include <alloc.h>
  25. #include <string.h>
  26. #include <graphics.h>
  27. #include <stdlib.h>
  28. #include "dme.h"
  29. #include "dme2.h"
  30.  
  31. typedef unsigned char uchar;
  32.  
  33. int load_textures1(void);
  34. void buffer_pic(uchar far *buffer, int width, int height, int xoffset,
  35.     int yoffset, struct pic_struct far *pic);
  36. void draw_fc_texture(int xpos, int ypos, int xsize, int ysize,
  37.     int xshift, int yshift, char *name);
  38. void draw_textr(uchar far *ptr, int xpos, int ypos, int xsize, int ysize,
  39.     int xshift, int yshift);
  40.  
  41. char last_name[9]="";
  42. int wall_textr_max=0;
  43. int fc_textr_max=0;
  44. int first_patch;
  45. int last_patch;
  46.  
  47. extern uchar huge doom_color[256];
  48. extern char doom_path[60]; /* path to doom.wad */
  49.  
  50. struct texture {
  51.     char name[9];
  52.     int width;
  53.     int height;
  54.     struct texture far *next;
  55.     int p_size;
  56.     struct {
  57.         int xoffset;
  58.         int yoffset;
  59.         int p_index;
  60.     } patch[9]; /* actually of variable length */
  61. } far *first_texture;
  62.  
  63. struct texture far * far *prev_link;
  64.  
  65. struct patch_struct {
  66.     int prev; /* link to previous index */
  67.     int next; /* link to next index */
  68.     char far *addr;
  69.     long offset;
  70.     uint len;
  71. } far *ptable;
  72.  
  73. struct pic_struct {
  74.     int xsize;
  75.     int ysize;
  76.     uint xoffset;
  77.     uint yoffset;
  78.     long offsets[9]; /* variable size array */
  79. };
  80.  
  81. struct fc_texture {
  82.     char name[9];
  83.     long offset;
  84.     struct fc_texture far *next;
  85. } far *first_fc_textr;
  86.  
  87. void load_textures(void)
  88. {
  89.     char name[9], *pnames;
  90.     int i;
  91.     long size;
  92.  
  93.     struct texture far *blank;
  94.     struct fc_texture far *ptr, far *tptr, far * far *last_ptr;
  95.  
  96.     struct
  97.     {
  98.         long ptr;
  99.         long len;
  100.         char fname[8];
  101.     } dir;
  102.  
  103.     first_texture = get_farmem(19, "blank texture");
  104.     _fstrcpy(first_texture->name, "-");
  105.     first_texture->width = 64;
  106.     first_texture->height = 64;
  107.     first_texture->p_size = 0;
  108.  
  109.     first_texture->next = NULL;
  110.     prev_link = &(first_texture->next);
  111.     wall_textr_max = 1;
  112.  
  113.     if (open_wad_seekto("rb", "TEXTURE1"))
  114.         goto fatal1;
  115.     if (load_textures1() == -1)
  116.         goto fatal1;
  117.  
  118.     fseek(fp, dir_ptr, SEEK_SET);
  119.     entry_count = dir_size;
  120.     if (!wad_seek("TEXTURE2"))
  121.     {
  122.         fseek(fp, entry_ptr, SEEK_SET);
  123.         if (load_textures1() == -1)
  124.         {
  125.             fclose(fp);
  126.             fatal_error("Can't load \"texture2\" subfile");
  127.         }
  128.     }
  129.     fclose(fp);
  130.  
  131.     first_patch = last_patch = -1;
  132.     if (open_wad_seekto("rb", "PNAMES"))
  133.         goto fatal2;
  134.  
  135.     if ((size = fread_long()) == -1)
  136.         goto fatal2;
  137.     ptable = get_farmem(size * sizeof(struct patch_struct), "ptable");
  138.     pnames = get_mem(size * 8, "pnames");
  139.     fread(pnames, 8, size, fp);
  140.  
  141.     for (i=0; i<size; i++)
  142.     {
  143.         ptable[i].addr = NULL;
  144.         ptable[i].offset = 0L;
  145.     }
  146.  
  147.     fseek(fp, dir_ptr, SEEK_SET);
  148.     entry_count = dir_size;
  149.     if (wad_seek("P_START"))
  150.     {
  151.         fclose(fp);
  152.         fatal_error("Texture patch wad entries not found");
  153.     }
  154.  
  155.     while (entry_count--)
  156.     {
  157.         if (!fread(&dir, sizeof(dir), 1, fp))
  158.             dir_error();
  159.  
  160.         if (!dir.len)
  161.             continue; /* else, read registered patches too */
  162.  
  163.         if (!cmp_entry("P_END", dir.fname))
  164.             break;
  165.  
  166.         for (i=0; i<size; i++)
  167.         {
  168.             if (!cmp_entry(pnames+(i<<3), dir.fname))
  169.             {
  170.                 ptable[i].offset = dir.ptr;
  171.                 ptable[i].len = dir.len;
  172.                 break;
  173.             }
  174.         }
  175.     }
  176.     fclose(fp);
  177.  
  178.     if (open_wad_seek("rb", "F_START"))
  179.         fatal_error("Floor/Ceiling texture entries not found");
  180.  
  181.     last_ptr = &first_fc_textr;
  182.     first_fc_textr = NULL;
  183.     while (entry_count--)
  184.     {
  185.         if (!fread(&dir, sizeof(dir), 1, fp))
  186.             dir_error();
  187.  
  188.         if (!cmp_entry("F_END", dir.fname))
  189.             break;
  190.  
  191.         if (!dir.len)
  192.             continue; /* skip headers */
  193.  
  194.         ptr = get_farmem(sizeof(struct fc_texture), "floor/ceiling texture");
  195.         if (_fstricmp(dir.fname, name) < 0)
  196.         {
  197.             last_ptr = &first_fc_textr;
  198.             for (tptr=first_fc_textr; tptr; tptr=tptr->next)
  199.             {
  200.                 if (_fstricmp(dir.fname, tptr->name) < 0)
  201.                     break;
  202.                 last_ptr = &(tptr->next);
  203.             }
  204.         }
  205.  
  206.         while (*last_ptr && _fstricmp(dir.fname, (*last_ptr)->name) > 0)
  207.             last_ptr = &((*last_ptr)->next);
  208.  
  209.         ptr->next = *last_ptr;
  210.         *last_ptr = ptr;
  211.         last_ptr = &(ptr->next);
  212.  
  213.         for (i=0; i<8; i++)
  214.             ptr->name[i] = name[i] = dir.fname[i];
  215.  
  216.         ptr->name[8] = 0;
  217.         ptr->offset = dir.ptr;
  218.         fc_textr_max++;
  219.     }
  220.     fclose(fp);
  221.  
  222.     for (i=0; i<size; i++)
  223.         if (!ptable[i].offset)
  224.         {
  225.             strncpy(name, pnames + (i << 3), 8);
  226.             name[8] = 0;
  227.             fatal_error("texture list patch \"%s\" not found is wad directory",
  228.                 name);
  229.         }
  230.  
  231.     free_mem(pnames, "pnames");
  232.     return;
  233.  
  234. fatal1:
  235.     fclose(fp);
  236.     fatal_error("Can't load \"texture1\" subfile");
  237.  
  238. fatal2:
  239.     fclose(fp);
  240.     fatal_error("Can't load \"pnames\" subfile");
  241. }
  242.  
  243. int load_textures1(void)
  244. {
  245.     int i, p, p_size;
  246.     long size, file_index, offsets[512];
  247.     struct texture far *cur_texture, far *tptr;
  248.  
  249.     struct {
  250.         char name[8];
  251.         long unused1;
  252.         int width;
  253.         int height;
  254.         long unused2;
  255.         int p_size;
  256.     } header;
  257.  
  258.     struct {
  259.         int xoffset;
  260.         int yoffset;
  261.         int p_index;
  262.         int stepdir;
  263.         int colormap;
  264.     } patch;
  265.  
  266.     file_index = ftell(fp);
  267.     if ((size = fread_long()) == -1)
  268.         return -1;
  269.  
  270.     if (size > 512)
  271.     {
  272.         error("Too many textures to track");
  273.         return -1;
  274.     }
  275.     fread(offsets, 4, size, fp); /* get offsets */
  276.  
  277.     for (i=0; i<size; i++)
  278.     {
  279.         if (ftell(fp) != file_index + offsets[i])
  280.             fseek(fp, file_index + offsets[i], SEEK_SET);
  281.  
  282.         fread(&header, sizeof(header), 1, fp);
  283.         p = 19 + header.p_size * 6; /* # of bytes for entry */
  284.  
  285.         cur_texture = get_farmem(p, "texture list");
  286.         if (_fstricmp(header.name, last_name) < 0)
  287.         {
  288.             prev_link = &first_texture;
  289.             for (tptr=first_texture; tptr; tptr=tptr->next)
  290.             {
  291.                 if (_fstricmp(header.name, tptr->name) < 0)
  292.                     break;
  293.                 prev_link = &(tptr->next);
  294.             }
  295.         }
  296.  
  297.         while (*prev_link && _fstricmp(header.name, (*prev_link)->name) > 0)
  298.             prev_link = &((*prev_link)->next);
  299.  
  300.         cur_texture->next = *prev_link; /* insert a link */
  301.         *prev_link = cur_texture; /* link last texture to this one */
  302.         prev_link = &(cur_texture->next); /* get address to link next */
  303.  
  304.         wall_textr_max++;
  305.  
  306.         _fmemcpy(cur_texture->name, header.name, 8);
  307.         _fmemcpy(last_name, header.name, 8);
  308.         cur_texture->name[8] = 0;
  309.         cur_texture->width = header.width;
  310.         cur_texture->height = header.height;
  311.         cur_texture->p_size = p_size = header.p_size;
  312.  
  313.         for (p=0; p<p_size; p++)
  314.         {
  315.             fread(&patch, sizeof(patch), 1, fp);
  316.             cur_texture->patch[p].xoffset = patch.xoffset;
  317.             cur_texture->patch[p].yoffset = patch.yoffset;
  318.             cur_texture->patch[p].p_index = patch.p_index;
  319.         }
  320.     }
  321.     return 0;
  322. }
  323.  
  324. /* draws a wall texture at screen coord (xpos,ypos).  This function has been
  325.     written to support multitasking */
  326.  
  327. int draw_wall_texture(int xpos, int ypos, int xsize, int ysize,
  328.     int xshift, int yshift, char *name)
  329. {
  330.     static uchar far *ptr=NULL;
  331.     static int status=-1;
  332.  
  333.     uchar far *buffer, far *buffer2, far *ptr2;
  334.     int i, index, m, width, width2, height, x, y, xx, yy;
  335.     long len;
  336.     struct texture huge *tptr;
  337.     struct pic_struct huge *addr;
  338.  
  339.     if (!name)
  340.         goto finished; /* reset call */
  341.  
  342.     tptr = first_texture;
  343.     while (_fstricmp(name, tptr->name))
  344.     {
  345.         tptr = tptr->next;
  346.         if (!tptr)
  347.             return 1; /* didn't find it */
  348.     }
  349.  
  350.     width = tptr->width;
  351.     height = tptr->height;
  352.  
  353.     if (status == -1)
  354.     {
  355.         len = (long) width * height + 4;
  356.         ptr = get_farmem(len, "texture image buffer");
  357.         buffer = ptr + 4;
  358.         if (!ptr)
  359.             goto finished;
  360.  
  361.         while (len--)
  362.             *(ptr + len) = 0; /* clear image buffer */
  363.         *ptr = width - 1; /* setup putimage() parameters */
  364.         *(ptr+2) = height - 1;
  365.         status++;
  366.         return 0;
  367.     }
  368.     buffer = ptr + 4;
  369.  
  370.     if (status < tptr->p_size)
  371.     {
  372.         index = tptr->patch[status].p_index;
  373.         addr = ptable[index].addr;
  374.         if (!addr)
  375.         {
  376.             len = ptable[index].len;
  377.             addr = ptable[index].addr = get_farmem(len, "texture patch");
  378.  
  379.             fp = fopen(iwad, "rb");
  380.             fseek(fp, ptable[index].offset, SEEK_SET);
  381.             far_read(addr, len);
  382.             fclose(fp);
  383.         } else { /* is in memory, thus already in list, so take it out */
  384.             if (index != last_patch)
  385.             {
  386.                 if (first_patch == index)
  387.                     first_patch = ptable[index].next;
  388.                 else
  389.                 {
  390.                     ptable[ptable[index].prev].next = ptable[index].next;
  391.                     ptable[ptable[index].next].prev = ptable[index].prev;
  392.                 }
  393.             }
  394.         }
  395.  
  396.         if (index != last_patch)
  397.         {
  398.             if (first_patch == -1)
  399.                 first_patch = index;
  400.             else
  401.                 ptable[last_patch].next = index;
  402.  
  403.             ptable[index].prev = last_patch;
  404.             last_patch = index;
  405.             ptable[index].next = -1; /* new end of list */
  406.         }
  407.  
  408.         buffer_pic(buffer, width, height, tptr->patch[status].xoffset,
  409.             tptr->patch[status].yoffset, addr);
  410.         status++;
  411.         return 0;
  412.     }
  413.  
  414.     len = (long) width * height;
  415.     while (len--)
  416.         *(buffer + len) = *(doom_color + *(buffer + len)); /* fix colors */
  417.  
  418.     draw_textr(ptr, xpos, ypos, xsize, ysize, xshift, yshift);
  419.  
  420. finished:
  421.     if (ptr)
  422.         free_farmem(ptr, "texture image buffer");
  423.     ptr = NULL;
  424.     status = -1;
  425.     return 1;
  426. }
  427.  
  428. /* called by the memory management routines, this will remove the oldest
  429.     patch from memory, freeing it's memory to make room for some block we
  430.     need, but don't have the memory for */
  431.  
  432. int free_patch(void)
  433. {
  434.     if (first_patch == -1)
  435.         return -1; /* all patches released, but still not enough memory */
  436.  
  437.     free_farmem(ptable[first_patch].addr, "texture patch");
  438.     ptable[first_patch].addr = NULL;
  439.     first_patch = ptable[first_patch].next;
  440.     return 0; /* return to try again to allocate the memory */
  441. }
  442.  
  443. /* draws a picture (wall patch) image into the image buffer
  444.  
  445.     More detailed description: This function will draw the patch (pointed to
  446.         with *pic) into the image holding buffer (pointed to with *buffer).
  447.         It will not wrap around horizontally or vertically.
  448.  
  449.     width = width of the image holding buffer
  450.     height = height of the image holding buffer
  451.     xoffset = patch x offset from upper left corner of the image holding buffer
  452.     yoffset = patch y   "     "     ...
  453.  
  454.     I've highly optimized this from how it originally started, so I'll try
  455.     and comment it a bit so you can follow the logic..
  456. */
  457.  
  458. void buffer_pic(uchar far *buffer, int width, int height, int xoffset,
  459.     int yoffset, struct pic_struct far *pic)
  460. { /* since both buffers were <64k, I switched to from huge ptrs to far ptrs
  461.       This improved the speed quite a bit */
  462.     uchar far *ptr, far *end_ptr, far *buf_ptr;
  463.     int i, count, x, y, z, xsize;
  464.  
  465.     xsize = pic->xsize; /* faster to use a single variable than to
  466.     weave through a structure at every reference */
  467.  
  468.     for (i=0; i<xsize; i++)
  469.     {
  470.         x = xoffset + i;
  471.         if (x >= 0 && x < width) /* if x is out of bounds, skip column */
  472.         {
  473.             ptr = ((uchar huge *) pic) + pic->offsets[i]; /* set ptr to
  474.     column data.  Column data is made up of a collection of vertical, one
  475.     pixel wide strands.  Each strand can have it's own length. */
  476.  
  477. /* ok, up to this point, iterations hasn't been too bad, but now we need to
  478.     start thinking about speed.  This code gets run though a lot of times */
  479.  
  480.             while ((y = *ptr++) != 255) /* no more strands, goto next column */
  481.             {
  482.                 y += yoffset;
  483.                 count = *ptr++;
  484.                 ptr++; /* skip unused byte */
  485.                 end_ptr = ptr + count + 1; /* this is where we will find the
  486.     next strand */
  487.  
  488.                 if (y >= height)
  489.                     goto next_strand; /* not much chance of this happening, but
  490.     if we can take it, it'll save us some time.  Even so, we really need it
  491.     here for error checking anyway.  If the row does start below it's drawing
  492.     space, then whoever made the patch did so poorly. */
  493.  
  494.                 if (y < 0)
  495.                 {
  496.                     if (-y >= count)
  497.                         goto next_strand; /* this means that the image strand is
  498.     above the drawing space, and won't drop into view.  So, we can skip to
  499.     the next strand. */
  500.  
  501.                     count += y; /* adjust pointers, etc */
  502.                     ptr -= y;
  503.                     y = 0;
  504.                 }
  505.  
  506.                 buf_ptr = buffer + y * width + x;
  507.                 if ((z = height - y) < count)
  508.                     count = z; /* cut strand short */
  509.  
  510. /* This is the most critical point for speed.  Even slightly less efficient
  511.     code can cause a noticable difference in speed.  So, we want to do as few
  512.     checks and well, anything as possible. */
  513.  
  514.                 while (count--)
  515.                 { /* debugging routines..
  516.                     if (y < 0)
  517.                         fatal_error("bug1");
  518.                     if (y >= height)
  519.                         fatal_error("bug2");
  520.  
  521.                     if (buf_ptr < buffer || buf_ptr > buffer + width * height)
  522.                         fatal_error("bug3"); */
  523.  
  524.                     *buf_ptr = *ptr++;
  525.                     buf_ptr += width; /* point to next column addr in buffer */
  526. /*                    y++;  ya, this is debugging too */
  527.                 }
  528. next_strand:
  529.                 ptr = end_ptr; /* move ptr to the next strand */
  530.             }
  531.         }
  532.     }
  533.     return;
  534. }
  535.  
  536. void wall_textr_pick(char *name)
  537. {
  538.     char chr, *names;
  539.     int i, j, idx, list_num, list_size, columns, rows, type, repos=0;
  540.     int old_num, new_num, cross_status, priority, working_on;
  541.     int x, y, tx, ty, *xx, *yy;
  542.     struct texture far *tptr;
  543.  
  544.     rows = (maxy / 20) * 2 - 2; /* make sure it's an odd number */
  545.     columns = 20;
  546.     list_size = (rows - 7) / 2;
  547.     cross_status = cross_on;
  548.     cross_on = 0;
  549.  
  550.     xx = get_mem(list_size * 2, "xpos_list");
  551.     yy = get_mem(list_size * 2, "ypos_list");
  552.     names = get_mem(list_size * 9 + 1, "textr_name_list");
  553.  
  554.     list_num = i = 0;
  555.     tptr = first_texture;
  556.     while (tptr != NULL)
  557.     {
  558.         if (!_fstricmp(name, tptr->name)) /* found it */
  559.         {
  560.             list_num = i - list_size / 2;
  561.             repos = list_size / 2 + 1;
  562.             break;
  563.         }
  564.         tptr = tptr->next;
  565.         i++;
  566.     }
  567.  
  568. re_list:
  569.     if (list_num < 0)
  570.         list_num += wall_textr_max; /* wrap around */
  571.     tptr = first_texture;
  572.     for (i=0; i<list_num; i++)
  573.         tptr = tptr->next;
  574.  
  575. re_list1:
  576.     set_window1(254, 127, 2);
  577.     tx = win.left + 2;
  578.     ty = win.top + 2;
  579.     setviewport(0, 0, maxx, maxy, 1);
  580.  
  581.     set_window(columns, rows, 0);
  582.     text_to_window(0, 0, "Select texture:\t\n\n[ Back ]\t", columns);
  583.     text_to_window(0, rows-2, "[ More ]\t", columns);
  584.     for (i=0; i<list_size; i++)
  585.     {
  586.         for (j=0; j<8; j++)
  587.             if (chr = tptr->name[j])
  588.                 *(names + i*9 + j) = chr;
  589.             else
  590.                 break;
  591.  
  592.         *(names + i*9 + j) = '\n';
  593.         *(names + i*9 + j + 1) = 0;
  594.         text_to_window(11, i*2+5, names + i*9, 0);
  595.         *(names + i*9 + j) = 0;
  596.  
  597.         xx[i] = win.left + (i & 1) * 40 + 22;
  598.         yy[i] = win.top + i * 20 + 58;
  599.         tptr = tptr->next;
  600.         if (++list_num == wall_textr_max)
  601.         {
  602.             list_num = 0;
  603.             tptr = first_texture;
  604.         }
  605.     }
  606.     draw_buttons();
  607.     set_cancel_bar();
  608.     if (repos)
  609.     {
  610.         mousex = xx[repos-1];
  611.         mousey = yy[repos-1];
  612.         repos = 0;
  613.     }
  614.  
  615.     mouse_on();
  616.     draw_wall_texture(0, 0, 0, 0, 0, 0, NULL); /* reset */
  617.     working_on = priority = idx = 0;
  618.     old_num = -1;
  619.  
  620.     while (mouse_check()); /* wait for mouse button release */
  621.     while (1)
  622.     {
  623.         while (!mouse_check() && !keypress)
  624.         {
  625.             new_num = -1;
  626.             for (i=0; i<list_size; i++)
  627.             {
  628.                 if (mousex > win.left + 90 && abs(mousey - yy[i]) < 10)
  629.                     new_num = i;
  630.                 if (abs(mousex - xx[i]) < 19 && abs(mousey - yy[i]) < 19)
  631.                     new_num = i;
  632.             }
  633.  
  634.             if (new_num != old_num)
  635.             {
  636.                 if (old_num != -1)
  637.                 {
  638.                     mouse_off();
  639.                     box_textr(xx[old_num], yy[old_num], 0);
  640.                     setcolor(255);
  641.                     erase_text(win.left + 92, yy[old_num] - 4, 8);
  642.                     outtextxy(win.left + 92, yy[old_num] - 4, names + old_num * 9);
  643.                     mouse_on();
  644.                 }
  645.                 if (new_num != -1)
  646.                 {
  647.                     mouse_off();
  648.                     box_textr(xx[new_num], yy[new_num], 255);
  649.                     setcolor(254);
  650.                     erase_text(win.left + 92, yy[new_num] - 4, 8);
  651.                     outtextxy(win.left + 92, yy[new_num] - 4, names + new_num*9);
  652.                     if (mousex < win.left + 89)
  653.                     {
  654.                         if (!working_on && priority)
  655.                             draw_wall_texture(0, 0, 0, 0, 0, 0, NULL);
  656.                         priority = new_num * 9 + 1; /* set up a priority task */
  657.                     }
  658.                     mouse_on();
  659.                 }
  660.                 old_num = new_num;
  661.             }
  662.  
  663.             if (!working_on && priority)
  664.             {
  665.                 if (draw_wall_texture(tx, ty, 256, 128, 0, 0, names+priority-1))
  666.                     priority = 0;
  667.                 continue;
  668.             }
  669.  
  670.             if (idx < list_size)
  671.             {
  672.                 working_on = 1;
  673.                 if (draw_wall_texture(xx[idx]-18, yy[idx]-18, 36, 36, 0, 0,
  674.                     names + idx*9))
  675.                 {
  676.                     idx++;
  677.                     working_on = 0;
  678.                 }
  679.             }
  680.         }
  681.  
  682.         if (keypress)
  683.         {
  684.             if (keypress == 27)
  685.                 goto leave;
  686.  
  687.             if (keypress == 13 && new_num != -1)
  688.             {
  689.                 mouse_off();
  690.                 goto select;
  691.             }
  692.  
  693.             if (keypress == 1073) /* page up */
  694.             {
  695.                 list_num -= list_size * 2;
  696.                 mouse_off();
  697.                 goto re_list;
  698.             }
  699.  
  700.             if (keypress == 1081) /* page down */
  701.             {
  702.                 mouse_off();
  703.                 goto re_list1;
  704.             }
  705.  
  706.             if (keypress == 1071) /* home */
  707.             {
  708.                 list_num = 0;
  709.                 tptr = first_texture;
  710.                 mouse_off();
  711.                 goto re_list1;
  712.             }
  713.             continue; /* end of key checks, below is mouse button pressed */
  714.         }
  715.  
  716.         if (mousex < win.canbar + 47 &&
  717.             mousex > win.canbar + 2 &&
  718.             mousey < win.bottom + 9 &&
  719.             mousey > win.bottom - 2)
  720.                 goto leave;
  721.  
  722.         if (line_dist(bigb.pos[0].x1, bigb.pos[0].y,
  723.             bigb.pos[0].x2, bigb.pos[0].y) < 7)
  724.         {
  725.             list_num -= list_size * 2;
  726.             mouse_off();
  727.             goto re_list;
  728.         }
  729.  
  730.         if (line_dist(bigb.pos[1].x1, bigb.pos[1].y,
  731.             bigb.pos[1].x2, bigb.pos[1].y) < 7)
  732.         {
  733.             mouse_off();
  734.             goto re_list1;
  735.         }
  736.  
  737.         if (new_num != -1)
  738.         {
  739.             mouse_off();
  740.             break;
  741.         }
  742.     }
  743.  
  744. select:
  745.     memcpy(name, names + new_num*9, 8);
  746.     name[8] = 0;
  747.  
  748. leave:
  749.     free_mem(names, "textr_name_list");
  750.     free_mem(yy, "ypos_list");
  751.     free_mem(xx, "xpos_list");
  752.  
  753.     cross_on = cross_status;
  754.     mouse_off();
  755.     draw_map();
  756.     return;
  757. }
  758.  
  759. void box_textr(int x1, int y1, int color)
  760. {
  761.     int x2, y2;
  762.  
  763.     x1 -= 19;
  764.     y1 -= 19;
  765.     x2 = x1 + 37;
  766.     y2 = y1 + 37;
  767.  
  768.     setcolor(color);
  769.     line(x1, y1, x2, y1);
  770.     line(x1, y1, x1, y2);
  771.     line(x1, y2, x2, y2);
  772.     line(x2, y1, x2, y2);
  773.     return;
  774. }
  775.  
  776. void fc_textr_pick(char *name)
  777. {
  778.     char *names;
  779.     int i, idx, list_num, list_size, columns, rows, type;
  780.     int old_num, new_num, cross_status, priority, repos=0;
  781.     int x, y, tx, ty, *xx, *yy;
  782.     struct fc_texture far *tptr;
  783.  
  784.     rows = (maxy / 20) * 2 - 2; /* make sure it's an odd number */
  785.     columns = 20;
  786.     list_size = (rows - 7) / 2;
  787.     cross_status = cross_on;
  788.     cross_on = 0;
  789.  
  790.     xx = get_mem(list_size * 2, "xpos_list");
  791.     yy = get_mem(list_size * 2, "ypos_list");
  792.     names = get_mem(list_size * 9 + 1, "textr_name_list");
  793.  
  794.     list_num = i = 0;
  795.     tptr = first_fc_textr;
  796.     while (tptr != NULL)
  797.     {
  798.         if (!_fstricmp(name, tptr->name)) /* found it */
  799.         {
  800.             list_num = i - list_size / 2;
  801.             repos = list_size / 2 + 1;
  802.             break;
  803.         }
  804.         tptr = tptr->next;
  805.         i++;
  806.     }
  807.  
  808. re_list:
  809.     if (list_num < 0)
  810.         list_num += fc_textr_max; /* wrap around */
  811.     tptr = first_fc_textr;
  812.     for (i=0; i<list_num; i++)
  813.         tptr = tptr->next;
  814.  
  815. re_list1:
  816.     set_window1(254, 127, 2);
  817.     tx = win.left + 2;
  818.     ty = win.top + 2;
  819.     setviewport(0, 0, maxx, maxy, 1);
  820.  
  821.     set_window(columns, rows, 0);
  822.     text_to_window(0, 0, "Select texture:\t\n\n[ Back ]\t", columns);
  823.     text_to_window(0, rows-2, "[ More ]\t", columns);
  824.     for (i=0; i<list_size; i++)
  825.     {
  826.         _fmemcpy(names + i*9, tptr->name, 8);
  827.         *(names + i*9 + 8) = '\n';
  828.         *(names + i*9 + 9) = 0;
  829.         text_to_window(11, i*2+5, names + i*9, 0);
  830.         *(names + i*9 + 8) = 0;
  831.  
  832.         xx[i] = win.left + (i & 1) * 40 + 22;
  833.         yy[i] = win.top + i * 20 + 58;
  834.         tptr = tptr->next;
  835.         if (++list_num == fc_textr_max)
  836.         {
  837.             list_num = 0;
  838.             tptr = first_fc_textr;
  839.         }
  840.     }
  841.     draw_buttons();
  842.     set_cancel_bar();
  843.     if (repos)
  844.     {
  845.         mousex = xx[repos-1];
  846.         mousey = yy[repos-1];
  847.         repos = 0;
  848.     }
  849.  
  850.     mouse_on();
  851.     priority = idx = 0;
  852.     old_num = -1;
  853.  
  854.     while (mouse_check()); /* wait for mouse button release */
  855.     while (1)
  856.     {
  857.         while (!mouse_check() && !keypress)
  858.         {
  859.             new_num = -1;
  860.             for (i=0; i<list_size; i++)
  861.             {
  862.                 if (mousex > win.left + 90 && abs(mousey - yy[i]) < 10)
  863.                     new_num = i;
  864.                 if (abs(mousex - xx[i]) < 19 && abs(mousey - yy[i]) < 19)
  865.                     new_num = i;
  866.             }
  867.  
  868.             if (new_num != old_num)
  869.             {
  870.                 if (old_num != -1)
  871.                 {
  872.                     mouse_off();
  873.                     box_textr(xx[old_num], yy[old_num], 0);
  874.                     setcolor(255);
  875.                     erase_text(win.left + 92, yy[old_num] - 4, 8);
  876.                     outtextxy(win.left + 92, yy[old_num] - 4, names + old_num * 9);
  877.                     mouse_on();
  878.                 }
  879.                 if (new_num != -1)
  880.                 {
  881.                     mouse_off();
  882.                     box_textr(xx[new_num], yy[new_num], 255);
  883.                     setcolor(254);
  884.                     erase_text(win.left + 92, yy[new_num] - 4, 8);
  885.                     outtextxy(win.left + 92, yy[new_num] - 4, names + new_num*9);
  886.                     if (mousex < win.left + 89)
  887.                         priority = new_num * 9 + 1; /* set up a priority task */
  888.                     mouse_on();
  889.                 }
  890.                 old_num = new_num;
  891.             }
  892.  
  893.             if (priority)
  894.             {
  895.                 draw_fc_texture(tx, ty, 256, 128, 0, 0, names+priority-1);
  896.                 priority = 0;
  897.                 continue;
  898.             }
  899.  
  900.             if (idx < list_size)
  901.             {
  902.                 draw_fc_texture(xx[idx]-18, yy[idx]-18, 36, 36, 0, 0,
  903.                     names + idx*9);
  904.                 idx++;
  905.             }
  906.         }
  907.  
  908.         if (keypress)
  909.         {
  910.             if (keypress == 27)
  911.                 goto leave;
  912.  
  913.             if (keypress == 13 && new_num != -1)
  914.             {
  915.                 mouse_off();
  916.                 goto select;
  917.             }
  918.  
  919.             if (keypress == 1073) /* page up */
  920.             {
  921.                 list_num -= list_size * 2;
  922.                 mouse_off();
  923.                 goto re_list;
  924.             }
  925.  
  926.             if (keypress == 1081) /* page down */
  927.             {
  928.                 mouse_off();
  929.                 goto re_list1;
  930.             }
  931.  
  932.             if (keypress == 1071) /* home */
  933.             {
  934.                 list_num = 0;
  935.                 tptr = first_fc_textr;
  936.                 mouse_off();
  937.                 goto re_list1;
  938.             }
  939.             continue; /* end of key checks, below is mouse button pressed */
  940.         }
  941.  
  942.         if (mousex < win.canbar + 47 &&
  943.             mousex > win.canbar + 2 &&
  944.             mousey < win.bottom + 9 &&
  945.             mousey > win.bottom - 2)
  946.                 goto leave;
  947.  
  948.         if (line_dist(bigb.pos[0].x1, bigb.pos[0].y,
  949.             bigb.pos[0].x2, bigb.pos[0].y) < 7)
  950.         {
  951.             list_num -= list_size * 2;
  952.             mouse_off();
  953.             goto re_list;
  954.         }
  955.  
  956.         if (line_dist(bigb.pos[1].x1, bigb.pos[1].y,
  957.             bigb.pos[1].x2, bigb.pos[1].y) < 7)
  958.         {
  959.             mouse_off();
  960.             goto re_list1;
  961.         }
  962.  
  963.         if (new_num != -1)
  964.         {
  965.             mouse_off();
  966.             break;
  967.         }
  968.     }
  969.  
  970. select:
  971.     memcpy(name, names + new_num*9, 8);
  972.     name[8] = 0;
  973.  
  974. leave:
  975.     free_mem(names, "textr_name_list");
  976.     free_mem(yy, "ypos_list");
  977.     free_mem(xx, "xpos_list");
  978.  
  979.     cross_on = cross_status;
  980.     mouse_off();
  981.     draw_map();
  982.     return;
  983. }
  984.  
  985. void draw_fc_texture(int xpos, int ypos, int xsize, int ysize,
  986.     int xshift, int yshift, char *name)
  987. {
  988.     uchar far *buffer;
  989.     int i, far *buffer2;
  990.     struct fc_texture far *ptr;
  991.  
  992.     ptr = first_fc_textr;
  993.     while (_fstricmp(ptr->name, name))
  994.         ptr = ptr->next;
  995.  
  996.     buffer2 = buffer = get_farmem(4100, "texture image buffer");
  997.     *buffer2 = *(buffer2 + 1) = 63;
  998.  
  999.     if (!(fp = fopen(iwad, "rb")))
  1000.         error("error!");
  1001.     fseek(fp, ptr->offset, SEEK_SET);
  1002.     far_read(buffer+4, 4096L);
  1003.     fclose(fp);
  1004.  
  1005.     for (i=4; i<4100; i++)
  1006.         *(buffer + i) = *(doom_color + *(buffer + i)); /* fix colors */
  1007.  
  1008.     draw_textr(buffer, xpos, ypos, xsize, ysize, xshift, yshift);
  1009.     free_farmem(buffer, "texture image buffer");
  1010.     return;
  1011. }
  1012.  
  1013. void draw_textr(uchar far *ptr, int xpos, int ypos, int xsize, int ysize,
  1014.     int xshift, int yshift)
  1015. {
  1016.     uchar far *buffer, far *buffer2, far *ptr2;
  1017.     int m, width, width2, height, x, y;
  1018.  
  1019.     width = *ptr + 1;
  1020.     height = *(ptr + 2) + 1;
  1021.     buffer = ptr + 4;
  1022.     width2 = xsize % width;
  1023.  
  1024.     if (width2)
  1025.     {
  1026.         ptr2 = get_farmem((long) width2 * height + 4, "texture image buffer");
  1027.         buffer2 = ptr2 + 4;
  1028.         _fmemcpy(ptr2, ptr, 4);
  1029.         *ptr2 = width2 - 1;
  1030.         for (y=0; y<height; y++)
  1031.             _fmemcpy(buffer2 + y*width2, buffer + y*width, width2);
  1032.     }
  1033.  
  1034.     if (m = mouse)
  1035.         mouse_off();
  1036.  
  1037.     y = 0;
  1038.     while (y < ysize)
  1039.     {
  1040.         if (y + height > ysize)
  1041.             *(ptr+2) = *(ptr2+2) = ysize - y - 1;
  1042.  
  1043.         x = 0;
  1044.         while (x + width <= xsize)
  1045.         {
  1046.             putimage(xpos + x, ypos + y, ptr, 0);
  1047.             x += width;
  1048.         }
  1049.  
  1050.         if (x != xsize)
  1051.             putimage(xpos + x, ypos + y, ptr2, 0);
  1052.  
  1053.         y += height;
  1054.     }
  1055.     if (m)
  1056.         mouse_on();
  1057.  
  1058.     if (width2)
  1059.         free_farmem(ptr2, "texture image buffer");
  1060.     return;
  1061. }
  1062.  
  1063. /*  Future expansion..
  1064.  
  1065. void draw_textr(char far *buffer, int xpos, int ypos, int xsize, int ysize,
  1066.     int xshift, int yshift)
  1067. {
  1068.     char far *tl_buf, far *t_buf, far *tr_buf, far *l_buf, far *r_buf;
  1069.     int height, width, width2;
  1070.  
  1071.     width = *buffer;
  1072.     height = *(buffer + 2);
  1073.  
  1074.     yy = yshift % height;
  1075.     xshift %= width;
  1076.     width2 = xsize % width;
  1077.  
  1078.     ptr2 = get_farmem((long) width2 * height + 4, "texture image buffer");
  1079.     buffer2 = ptr2 + 4;
  1080.     _fmemcpy(ptr2, ptr, 4);
  1081.     *ptr2 = width2 - 1;
  1082.     for (y=0; y<height; y++)
  1083.         _fmemcpy(buffer2 + y*width2, buffer + y*width, width2);
  1084.  
  1085.     if (m = mouse)
  1086.         mouse_off();
  1087.  
  1088.     y = 0;
  1089.     while (y < ysize)
  1090.     {
  1091.         if (y + height > ysize)
  1092.             *(ptr+2) = *(ptr2+2) = ysize - y - 1;
  1093.  
  1094.         x = 0;
  1095.         while (x + width <= xsize)
  1096.         {
  1097.             putimage(xpos + x, ypos + y, ptr, 0);
  1098.             x += width;
  1099.         }
  1100.  
  1101.         if (x != xsize)
  1102.             putimage(xpos + x, ypos + y, ptr2, 0);
  1103.  
  1104.         y += height;
  1105.     }
  1106.     if (m)
  1107.         mouse_on();
  1108. } */
  1109.