mirror of
https://github.com/ZDoom/gzdoom-last-svn.git
synced 2025-05-31 01:10:52 +00:00
- Gave the intermission screen sounds their own SNDINFO entries. - Removed obsolete snd_surround cvar. - Changing screen resolution now adjusts the automap scale to be constant relative to screen resolution. - Fixed: When FMultiPatchTexture::MakeTexture() needed to work in RGB colorspace, it didn't zero out the temporary buffer. - Fixed memory leak from leftover code for 7z loading and added the LUMPF_ZIPFILE flag to their contents so they have the same semantics as zips. - Added support for 7z archives. - Added -noautoload option. - Added default Raven automap colors set. Needs to be tested because I can't compare against the DOS version myself. - Extened A_PlaySound and A_StopSound to be able to set all parameters of the internal sound code. - Changed gravity doubling so that it only happens when you run off a ledge. - Fixed: World panning was ignored for the X offset of masked midtextures. - Extended MF5_MOVEWITHSECTOR so that it always keeps the actor on the ground of a moving floor, regardless of movement speed. For NOBLOCKMAP items this is necessary because otherwise they can be left in the air and it also adds some options for other things. - Changed A_FreezeDeathChunks() so that instead of directly destroying an actor, it sets it to the "Null" state, which will make it invisible and destroy it one tic later. - Added a NULL pointer check to A_Fire() and copied the target to a local variable inside A_VileAttack() so that if P_DamageMobj() destroys the target, the function will still have a valid pointer to it (since reading it from the actor's instance data invokes the read barrier, which would return NULL). - Added NOBLOCKMAP/MOVEWITHSECTOR combination to a few items that had their NOBLOCKMAP flag taken away previously to make them move with a sector. This should fix the performance problem Claustrophobia had with recent ZDoom versions. - Added MF5_MOVEWITHSECTOR flag, so you can have the benefits of MF_NOBLOCKMAP but still have actors that will move up and down with the floor. IceChunk now uses both of these flags. - Performance optimization for FBlockThingsIterator::Next(): Actors that exist in only one block don't need to be added to the CheckArray or scanned for in it. Also changed the array used to keep track of visited actors into a hash table. - added some default definitions for constants that may miss in some headers. - replaced __va_copy with va_copy per Chris's suggestion. - replaced #include <malloc.h> with #include <stdlib.h> where possible. git-svn-id: http://mancubus.net/svn/hosted/gzdoom/trunk@322 b0f79afe-0144-0410-b225-9a4edf0717df
426 lines
9 KiB
C++
426 lines
9 KiB
C++
/*
|
|
** v_text.cpp
|
|
** Draws text to a canvas. Also has a text line-breaker thingy.
|
|
**
|
|
**---------------------------------------------------------------------------
|
|
** Copyright 1998-2006 Randy Heit
|
|
** All rights reserved.
|
|
**
|
|
** Redistribution and use in source and binary forms, with or without
|
|
** modification, are permitted provided that the following conditions
|
|
** are met:
|
|
**
|
|
** 1. Redistributions of source code must retain the above copyright
|
|
** notice, this list of conditions and the following disclaimer.
|
|
** 2. Redistributions in binary form must reproduce the above copyright
|
|
** notice, this list of conditions and the following disclaimer in the
|
|
** documentation and/or other materials provided with the distribution.
|
|
** 3. The name of the author may not be used to endorse or promote products
|
|
** derived from this software without specific prior written permission.
|
|
**
|
|
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
**---------------------------------------------------------------------------
|
|
**
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <ctype.h>
|
|
|
|
#include "v_text.h"
|
|
|
|
#include "i_system.h"
|
|
#include "v_video.h"
|
|
#include "hu_stuff.h"
|
|
#include "w_wad.h"
|
|
#include "m_swap.h"
|
|
|
|
#include "doomstat.h"
|
|
#include "templates.h"
|
|
|
|
//
|
|
// DrawChar
|
|
//
|
|
// Write a single character using the given font
|
|
//
|
|
void STACK_ARGS DCanvas::DrawChar (FFont *font, int normalcolor, int x, int y, BYTE character, ...)
|
|
{
|
|
if (font == NULL)
|
|
return;
|
|
|
|
if (normalcolor >= NumTextColors)
|
|
normalcolor = CR_UNTRANSLATED;
|
|
|
|
FTexture *pic;
|
|
int dummy;
|
|
|
|
if (NULL != (pic = font->GetChar (character, &dummy)))
|
|
{
|
|
const FRemapTable *range = font->GetColorTranslation ((EColorRange)normalcolor);
|
|
va_list taglist;
|
|
va_start (taglist, character);
|
|
DrawTexture (pic, x, y, DTA_Translation, range, TAG_MORE, &taglist);
|
|
va_end (taglist);
|
|
}
|
|
}
|
|
|
|
//
|
|
// DrawText
|
|
//
|
|
// Write a string using the given font
|
|
//
|
|
void STACK_ARGS DCanvas::DrawText (FFont *font, int normalcolor, int x, int y, const char *string, ...)
|
|
{
|
|
va_list tags;
|
|
DWORD tag;
|
|
INTBOOL boolval;
|
|
|
|
int maxstrlen = INT_MAX;
|
|
int w, maxwidth;
|
|
const BYTE *ch;
|
|
int c;
|
|
int cx;
|
|
int cy;
|
|
int boldcolor;
|
|
const FRemapTable *range;
|
|
int height;
|
|
int forcedwidth = 0;
|
|
int scalex, scaley;
|
|
int kerning;
|
|
FTexture *pic;
|
|
|
|
if (font == NULL || string == NULL)
|
|
return;
|
|
|
|
if (normalcolor >= NumTextColors)
|
|
normalcolor = CR_UNTRANSLATED;
|
|
boldcolor = normalcolor ? normalcolor - 1 : NumTextColors - 1;
|
|
|
|
range = font->GetColorTranslation ((EColorRange)normalcolor);
|
|
height = font->GetHeight () + 1;
|
|
kerning = font->GetDefaultKerning ();
|
|
|
|
ch = (const BYTE *)string;
|
|
cx = x;
|
|
cy = y;
|
|
|
|
// Parse the tag list to see if we need to adjust for scaling.
|
|
maxwidth = Width;
|
|
scalex = scaley = 1;
|
|
|
|
va_start (tags, string);
|
|
tag = va_arg (tags, DWORD);
|
|
|
|
while (tag != TAG_DONE)
|
|
{
|
|
va_list *more_p;
|
|
DWORD data;
|
|
void *ptrval;
|
|
|
|
switch (tag)
|
|
{
|
|
case TAG_IGNORE:
|
|
default:
|
|
data = va_arg (tags, DWORD);
|
|
break;
|
|
|
|
case TAG_MORE:
|
|
more_p = va_arg (tags, va_list*);
|
|
va_end (tags);
|
|
#ifndef NO_VA_COPY
|
|
va_copy (tags, *more_p);
|
|
#else
|
|
tags = *more_p;
|
|
#endif
|
|
break;
|
|
|
|
// We don't handle these. :(
|
|
case DTA_DestWidth:
|
|
case DTA_DestHeight:
|
|
*(DWORD *)tags = TAG_IGNORE;
|
|
data = va_arg (tags, DWORD);
|
|
break;
|
|
|
|
// Translation is specified explicitly by the text.
|
|
case DTA_Translation:
|
|
*(DWORD *)tags = TAG_IGNORE;
|
|
ptrval = va_arg (tags, void*);
|
|
break;
|
|
|
|
case DTA_CleanNoMove:
|
|
boolval = va_arg (tags, INTBOOL);
|
|
if (boolval)
|
|
{
|
|
scalex = CleanXfac;
|
|
scaley = CleanYfac;
|
|
maxwidth = Width - (Width % CleanYfac);
|
|
}
|
|
break;
|
|
|
|
case DTA_Clean:
|
|
case DTA_320x200:
|
|
boolval = va_arg (tags, INTBOOL);
|
|
if (boolval)
|
|
{
|
|
scalex = scaley = 1;
|
|
maxwidth = 320;
|
|
}
|
|
break;
|
|
|
|
case DTA_VirtualWidth:
|
|
maxwidth = va_arg (tags, int);
|
|
scalex = scaley = 1;
|
|
break;
|
|
|
|
case DTA_TextLen:
|
|
maxstrlen = va_arg (tags, int);
|
|
break;
|
|
|
|
case DTA_CellX:
|
|
forcedwidth = va_arg (tags, int);
|
|
break;
|
|
|
|
case DTA_CellY:
|
|
height = va_arg (tags, int);
|
|
break;
|
|
}
|
|
tag = va_arg (tags, DWORD);
|
|
}
|
|
|
|
height *= scaley;
|
|
|
|
while ((const char *)ch - string < maxstrlen)
|
|
{
|
|
c = *ch++;
|
|
if (!c)
|
|
break;
|
|
|
|
if (c == TEXTCOLOR_ESCAPE)
|
|
{
|
|
EColorRange newcolor = V_ParseFontColor (ch, normalcolor, boldcolor);
|
|
if (newcolor != CR_UNDEFINED)
|
|
{
|
|
range = font->GetColorTranslation (newcolor);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (c == '\n')
|
|
{
|
|
cx = x;
|
|
cy += height;
|
|
continue;
|
|
}
|
|
|
|
if (NULL != (pic = font->GetChar (c, &w)))
|
|
{
|
|
va_list taglist;
|
|
va_start (taglist, string);
|
|
if (forcedwidth)
|
|
{
|
|
w = forcedwidth;
|
|
DrawTexture (pic, cx, cy,
|
|
DTA_Translation, range,
|
|
DTA_DestWidth, forcedwidth,
|
|
DTA_DestHeight, height,
|
|
TAG_MORE, &taglist);
|
|
}
|
|
else
|
|
{
|
|
DrawTexture (pic, cx, cy,
|
|
DTA_Translation, range,
|
|
TAG_MORE, &taglist);
|
|
}
|
|
va_end (taglist);
|
|
}
|
|
cx += (w + kerning) * scalex;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Find string width using this font
|
|
//
|
|
int FFont::StringWidth (const BYTE *string) const
|
|
{
|
|
int w = 0;
|
|
int maxw = 0;
|
|
|
|
while (*string)
|
|
{
|
|
if (*string == TEXTCOLOR_ESCAPE)
|
|
{
|
|
++string;
|
|
if (*string == '[')
|
|
{
|
|
while (*string != '\0' && *string != ']')
|
|
{
|
|
++string;
|
|
}
|
|
}
|
|
else if (*string != '\0')
|
|
{
|
|
++string;
|
|
}
|
|
continue;
|
|
}
|
|
else if (*string == '\n')
|
|
{
|
|
if (w > maxw)
|
|
maxw = w;
|
|
w = 0;
|
|
++string;
|
|
}
|
|
else
|
|
{
|
|
w += GetCharWidth (*string++) + GlobalKerning;
|
|
}
|
|
}
|
|
|
|
return MAX (maxw, w);
|
|
}
|
|
|
|
//
|
|
// Break long lines of text into multiple lines no longer than maxwidth pixels
|
|
//
|
|
static void breakit (FBrokenLines *line, FFont *font, const BYTE *start, const BYTE *stop, FString &linecolor)
|
|
{
|
|
if (!linecolor.IsEmpty())
|
|
{
|
|
line->Text = TEXTCOLOR_ESCAPE;
|
|
line->Text += linecolor;
|
|
}
|
|
line->Text.AppendCStrPart ((const char *)start, stop - start);
|
|
line->Width = font->StringWidth (line->Text);
|
|
}
|
|
|
|
FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string)
|
|
{
|
|
FBrokenLines lines[128]; // Support up to 128 lines (should be plenty)
|
|
|
|
const BYTE *space = NULL, *start = string;
|
|
int i, c, w, nw;
|
|
FString lastcolor, linecolor;
|
|
bool lastWasSpace = false;
|
|
int kerning = font->GetDefaultKerning ();
|
|
|
|
i = w = 0;
|
|
|
|
while ( (c = *string++) && i < 128 )
|
|
{
|
|
if (c == TEXTCOLOR_ESCAPE)
|
|
{
|
|
if (*string)
|
|
{
|
|
if (*string == '[')
|
|
{
|
|
const BYTE *start = string;
|
|
while (*string != ']' && *string != '\0')
|
|
{
|
|
string++;
|
|
}
|
|
if (*string != '\0')
|
|
{
|
|
string++;
|
|
}
|
|
lastcolor = FString((const char *)start, string - start);
|
|
}
|
|
else
|
|
{
|
|
lastcolor = *string++;
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (isspace(c))
|
|
{
|
|
if (!lastWasSpace)
|
|
{
|
|
space = string - 1;
|
|
lastWasSpace = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lastWasSpace = false;
|
|
}
|
|
|
|
nw = font->GetCharWidth (c);
|
|
|
|
if ((w > 0 && w + nw > maxwidth) || c == '\n')
|
|
{ // Time to break the line
|
|
if (!space)
|
|
space = string - 1;
|
|
|
|
breakit (&lines[i], font, start, space, linecolor);
|
|
if (c == '\n')
|
|
{
|
|
lastcolor = ""; // Why, oh why, did I do it like this?
|
|
}
|
|
linecolor = lastcolor;
|
|
|
|
i++;
|
|
w = 0;
|
|
lastWasSpace = false;
|
|
start = space;
|
|
space = NULL;
|
|
|
|
while (*start && isspace (*start) && *start != '\n')
|
|
start++;
|
|
if (*start == '\n')
|
|
start++;
|
|
else
|
|
while (*start && isspace (*start))
|
|
start++;
|
|
string = start;
|
|
}
|
|
else
|
|
{
|
|
w += nw + kerning;
|
|
}
|
|
}
|
|
|
|
// String here is pointing one character after the '\0'
|
|
if (i < 128 && --string - start >= 1)
|
|
{
|
|
const BYTE *s = start;
|
|
|
|
while (s < string)
|
|
{
|
|
// If there is any non-white space in the remainder of the string, add it.
|
|
if (!isspace (*s++))
|
|
{
|
|
breakit (&lines[i++], font, start, string, linecolor);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Make a copy of the broken lines and return them
|
|
FBrokenLines *broken = new FBrokenLines[i+1];
|
|
|
|
for (c = 0; c < i; ++c)
|
|
{
|
|
broken[c] = lines[c];
|
|
}
|
|
broken[c].Width = -1;
|
|
|
|
return broken;
|
|
}
|
|
|
|
void V_FreeBrokenLines (FBrokenLines *lines)
|
|
{
|
|
if (lines)
|
|
{
|
|
delete[] lines;
|
|
}
|
|
}
|