view src/l_align.cc @ 66:794b7bb40d7f

Initial work on cleaning up and improving the texture alignment functionality.
author Matti Hamalainen <ccr@tnsp.org>
date Mon, 26 Sep 2011 10:16:55 +0300
parents 2898afb3c9a0
children df543ecd0746
line wrap: on
line source

/*
 *        l_align.cc
 *        Linedef/sidedef texture alignment
 *        AYM 1998-02-03
 */


/*
This file is part of Yadex.

Yadex incorporates code from DEU 5.21 that was put in the public domain in
1994 by Raphaël Quinet and Brendon Wyber.

The rest of Yadex is Copyright © 1997-2003 André Majorel and others.

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307, USA.
*/


#include "yadex.h"
#include "dialog.h"
#include "entry.h"
#include "gfx.h"
#include "levels.h"
#include "objid.h"
#include "oldmenus.h"
#include "selectn.h"
#include "textures.h"


/*
   get the absolute height from which the textures are drawn
*/

int GetTextureRefHeight(int sidedef)
{
    int l, sector;
    int otherside = OBJ_NO_NONE;

    /* find the sidedef on the other side of the LineDef, if any */
    for (l = 0; l < NumLineDefs; l++)
    {
        if (LineDefs[l].sidedef1 == sidedef)
        {
            otherside = LineDefs[l].sidedef2;
            break;
        }
        if (LineDefs[l].sidedef2 == sidedef)
        {
            otherside = LineDefs[l].sidedef1;
            break;
        }
    }

    /* get the Sector number */
    sector = SideDefs[sidedef].sector;

    /* if the upper texture is displayed, then the reference
     * is taken from the other Sector */
    if (otherside >= 0)
    {
        l = SideDefs[otherside].sector;
        if (l > 0)
        {
            if (Sectors[l].ceilh < Sectors[sector].ceilh
                && Sectors[l].ceilh > Sectors[sector].floorh)
                sector = l;
        }
    }

    /* return the altitude of the ceiling */
    if (sector >= 0)
        return Sectors[sector].ceilh;        /* textures are drawn from the ceiling down */
    else
        return 0;                /* yuck! */
}




/*
   Align all textures for the given SideDefs

   Note from RQ:
      This function should be improved!
      But what should be improved first is the way the SideDefs are selected.
      It is stupid to change both sides of a wall when only one side needs
      to be changed.  But with the current selection method, there is no
      way to select only one side of a two-sided wall.
*/

void AlignTexturesY(SelPtr * sdlist, int opt_sdef, bool opt_check)
{
    int h, refh;

    if (!*sdlist)
        return;

    /* get the reference height from the first sidedef */
    refh = GetTextureRefHeight((*sdlist)->objnum);
    SideDefs[(*sdlist)->objnum].yoff = 0;
    UnSelectObject(sdlist, (*sdlist)->objnum);

    /* adjust Y offset in all other SideDefs */
    while (*sdlist)
    {
        h = GetTextureRefHeight((*sdlist)->objnum);
        SideDefs[(*sdlist)->objnum].yoff = (refh - h) % 128;
        UnSelectObject(sdlist, (*sdlist)->objnum);
    }
    
    MadeChanges = 1;
}



/*
   Function is to align all highlighted textures in the X-axis

   Note from RJH:
   LineDefs highlighted are read off in reverse order of highlighting.
   The '*sdlist' is in the reverse order of the above mentioned LineDefs
   i.e. the first linedef sidedefs you highlighted will be processed first.

   Note from RQ:
   See also the note for the previous function.

   Note from RJH:
   For the menu for aligning textures 'X' NOW operates upon the fact that
   ALL the SIDEDEFS from the selected LINEDEFS are in the *SDLIST, 2nd
   sidedef is first, 1st sidedef is 2nd). Aligning textures X now does
   SIDEDEF 1's and SIDEDEF 2's.  If the selection process is changed,
   the following needs to be altered radically.
*/

void AlignTexturesX(SelPtr * sdlist, int opt_sdef, bool opt_check, bool opt_offset, int opt_mode)
{
    /* FIRST texture name used in the highlited objects */
    char texname[WAD_TEX_NAME + 1];
    char errormessage[128];          /* area to hold the error messages produced */
    int ldef;                        /* linedef number */
    int sdef;                         /* current sidedef in *sdlist */
    int vert1, vert2;                /* vertex 1 and 2 for the linedef under scrutiny */
    int xoffset;                     /* xoffset accumulator */
    int useroffset;                  /* user input offset for first input */
    i16 texlength;                   /* the length of texture to format to */
    int length;                      /* length of linedef under scrutiny */
    i16 dummy;                       /* holds useless data */

    vert1 = -1;
    vert2 = -1;                      /* 1st time round the while loop the -1 value is needed */
    texlength = 0;
    xoffset = 0;
    useroffset = 0;

    if (!*sdlist)
    {
        Notify(-1, -1, "Error in AlignTexturesX: list is empty", 0);
        return;
    }

    if (opt_mode == -1)
    {
        /* No defined mode, we will try to "guess" which texture
         * the user wants to align ... and choose the operating mode
         * based on that.
         */
        SDPtr pdef = &SideDefs[(*sdlist)->objnum];
        if (ValidTextureName(pdef->tex3))
        {
            strncpy(texname, pdef->tex3, WAD_TEX_NAME);
            opt_mode = 3;
        }
        else if (ValidTextureName(pdef->tex2))
        {
            strncpy(texname, pdef->tex2, WAD_TEX_NAME);
            opt_mode = 2;
        }
        else if (ValidTextureName(pdef->tex1))
        {
            strncpy(texname, pdef->tex1, WAD_TEX_NAME);
            opt_mode = 1;
        }
        else
        {
            sprintf(errormessage, "No texture(s) for sidedef #%d.",
                    (*sdlist)->objnum);
            Notify(-1, -1, errormessage, 0);
            return;
        }
    }
    else
    {
        /* Find first sidedef that has desired texture set */

        // FIXME! Not implemented yet ... -ccr
    }

    /* Get texture width, do some sanity checking as the
     * WAD reading may fail.
     */
    GetWallTextureSize(&texlength, &dummy, texname);

    if (texlength < 4)
    {
        sprintf(errormessage, "Texture length for texture '%s' is %d. Not continuing.",
                texname, texlength);
        Notify(-1, -1, errormessage, 0);
        return;
    }

    /* Get initial offset to use, if requested */
    if (opt_offset)
    {
        int x0, y0, key;
        char prompt[80];

        sprintf(prompt, "Enter initial offset between 0 and %d:", texlength);

        x0 = (ScrMaxX - 25 - 8 * strlen(prompt)) / 2;
        y0 = (ScrMaxY - 55) / 2;

        DrawScreenBox3D(x0, y0, x0 + 25 + 8 * strlen(prompt), y0 + 55);
        set_colour(WHITE);
        DrawScreenText(x0 + 10, y0 + 8, prompt);

        while ((key = InputInteger(x0 + 10, y0 + 28, &useroffset, 0,
               (int) texlength)) != YK_RETURN && key != YK_ESC)
            Beep();

        if (key == YK_ESC)
            return;
    }

    /* Main processing loop */
    while (*sdlist)
    {
        ldef = 0;
        sdef = (*sdlist)->objnum;

        if (opt_sdef == 1)        /* throw out all 2nd SideDefs untill a 1st is found */
        {
            while (LineDefs[ldef].sidedef1 != sdef && ldef <= NumLineDefs)
            {
                ldef++;
                if (LineDefs[ldef].sidedef2 == sdef)
                {
                    UnSelectObject(sdlist, (*sdlist)->objnum);
                    if (*sdlist == NULL)
                    {
                        sprintf(errormessage, "Error in opt_sdef==1, *sdlist == NULL");
                        Notify(-1, -1, errormessage, 0);
                        return;
                    }
                    sdef = (*sdlist)->objnum;
                    ldef = 0;
                }
            }
        }
        else
        if (opt_sdef == 2)        /* throw out all 1st SideDefs untill a 2nd is found */
        {
            while (LineDefs[ldef].sidedef2 != sdef && ldef <= NumLineDefs)
            {
                ldef++;
                if (LineDefs[ldef].sidedef1 == sdef)
                {
                    UnSelectObject(sdlist, (*sdlist)->objnum);
                    if (*sdlist == NULL)
                    {
                        sprintf(errormessage, "Error in opt_sdef==2, *sdlist == NULL");
                        Notify(-1, -1, errormessage, 0);
                        return;
                    }
                    sdef = (*sdlist)->objnum;
                    ldef = 0;
                }
            }
        }

        /* do we test for same textures for the sidedef in question?? */
        sdef = (*sdlist)->objnum;
        if (opt_check)
        {
            SDPtr pdef = &SideDefs[sdef];
            if ((opt_mode == 3 && strncmp(pdef->tex3, texname, WAD_TEX_NAME)) ||
                (opt_mode == 2 && strncmp(pdef->tex2, texname, WAD_TEX_NAME)) ||
                (opt_mode == 1 && strncmp(pdef->tex1, texname, WAD_TEX_NAME)))
            {
                sprintf(errormessage, "No texture or discontinuous texture on sidedef #%d.",
                        sdef);
                Notify(-1, -1, errormessage, 0);
                return;
            }
        }

        /* find out which linedef holds that sidedef */
        int n;
        for (ldef = -1, n = 0; n < NumLineDefs; n++)
            if ((opt_sdef == 1 && LineDefs[n].sidedef1 == sdef) ||
                (opt_sdef == 2 && LineDefs[n].sidedef2 == sdef)) 
            {
                ldef = n;
                break;
            }

        if (ldef < 0)
        {
            sprintf(errormessage, "Linedef for sidedef #%d not found?!",
                    sdef);
            Notify(-1, -1, errormessage, 0);
            return;
        }

        /* test for linedef highlight continuity */
        vert1 = LineDefs[ldef].start;
        if (vert1 != vert2 && vert2 != -1)
        {
            sprintf(errormessage, "Linedef #%d is not contiguous"
                    " with the previous linedef, please reselect.",
                    (*sdlist)->objnum);
            Notify(-1, -1, errormessage, 0);
            return;
        }

        /* is this the first time round here */
        if (vert1 != vert2)
        {
            /* Do we have an initial offset? */
            xoffset = opt_offset ? useroffset : 0;
        }

        SideDefs[sdef].xoff = xoffset;

        /* calculate length of linedef */
        vert2 = LineDefs[ldef].end;
        length = ComputeDist(Vertices[vert2].x - Vertices[vert1].x,
                             Vertices[vert2].y - Vertices[vert1].y);

        xoffset += length;

        /* remove multiples of texlength from xoffset */
        xoffset = xoffset % texlength;

        /* move to next object in selected list */
        UnSelectObject(sdlist, (*sdlist)->objnum);
    }

    MadeChanges = 1;
}