mirror of
https://github.com/ZDoom/Raze.git
synced 2024-11-15 00:42:08 +00:00
- added GZDoom's 2D drawer to the project.
So that for anything new I don't have to bother with the awful 2D interface Build provides.
This commit is contained in:
parent
20df360778
commit
2fa5e339fc
10 changed files with 2516 additions and 0 deletions
|
@ -636,6 +636,7 @@ file( GLOB HEADER_FILES
|
|||
mact/include/*.h
|
||||
mact/src/*.h
|
||||
common/*.h
|
||||
common/2d/*.h
|
||||
common/utility/*.h
|
||||
common/console/*.h
|
||||
|
||||
|
@ -789,6 +790,11 @@ set (PCH_SOURCES
|
|||
common/gameconfigfile.cpp
|
||||
common/gamecvars.cpp
|
||||
|
||||
common/2d/v_2ddrawer.cpp
|
||||
common/2d/v_draw.cpp
|
||||
common/2d/v_drawtext.cpp
|
||||
common/2d/renderstyle.cpp
|
||||
|
||||
common/console/c_cvars.cpp
|
||||
|
||||
common/utility/cmdlib.cpp
|
||||
|
|
196
source/common/2d/drawparms.h
Normal file
196
source/common/2d/drawparms.h
Normal file
|
@ -0,0 +1,196 @@
|
|||
#pragma once
|
||||
/*
|
||||
** v_video.h
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 1998-2008 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 "palentry.h"
|
||||
#include "renderstyle.h"
|
||||
#include "c_cvars.h"
|
||||
#include "v_2ddrawer.h"
|
||||
|
||||
#define TAG_DONE (0) /* Used to indicate the end of the Tag list */
|
||||
#define TAG_END (0) /* Ditto */
|
||||
/* list pointed to in ti_Data */
|
||||
|
||||
enum
|
||||
{
|
||||
DTA_Base = 1,
|
||||
DTA_DestWidth, // width of area to draw to
|
||||
DTA_DestHeight, // height of area to draw to
|
||||
DTA_Alpha, // alpha value for translucency
|
||||
DTA_FillColor, // color to stencil onto the destination
|
||||
DTA_TranslationIndex, // translation table to recolor the source
|
||||
DTA_AlphaChannel, // bool: the source is an alpha channel; used with DTA_FillColor
|
||||
DTA_Clean, // bool: scale texture size and position by CleanXfac and CleanYfac
|
||||
DTA_320x200, // bool: scale texture size and position to fit on a virtual 320x200 screen
|
||||
DTA_Bottom320x200, // bool: same as DTA_320x200 but centers virtual screen on bottom for 1280x1024 targets
|
||||
DTA_CleanNoMove, // bool: like DTA_Clean but does not reposition output position
|
||||
DTA_CleanNoMove_1, // bool: like DTA_CleanNoMove, but uses Clean[XY]fac_1 instead
|
||||
DTA_FlipX, // bool: flip image horizontally //FIXME: Does not work with DTA_Window(Left|Right)
|
||||
DTA_ShadowColor, // color of shadow
|
||||
DTA_ShadowAlpha, // alpha of shadow
|
||||
DTA_Shadow, // set shadow color and alphas to defaults
|
||||
DTA_VirtualWidth, // pretend the canvas is this wide
|
||||
DTA_VirtualHeight, // pretend the canvas is this tall
|
||||
DTA_TopOffset, // override texture's top offset
|
||||
DTA_LeftOffset, // override texture's left offset
|
||||
DTA_CenterOffset, // bool: override texture's left and top offsets and set them for the texture's middle
|
||||
DTA_CenterBottomOffset,// bool: override texture's left and top offsets and set them for the texture's bottom middle
|
||||
DTA_WindowLeft, // don't draw anything left of this column (on source, not dest)
|
||||
DTA_WindowRight, // don't draw anything at or to the right of this column (on source, not dest)
|
||||
DTA_ClipTop, // don't draw anything above this row (on dest, not source)
|
||||
DTA_ClipBottom, // don't draw anything at or below this row (on dest, not source)
|
||||
DTA_ClipLeft, // don't draw anything to the left of this column (on dest, not source)
|
||||
DTA_ClipRight, // don't draw anything at or to the right of this column (on dest, not source)
|
||||
DTA_Masked, // true(default)=use masks from texture, false=ignore masks
|
||||
DTA_HUDRules, // use fullscreen HUD rules to position and size textures
|
||||
DTA_HUDRulesC, // only used internally for marking HUD_HorizCenter
|
||||
DTA_KeepRatio, // doesn't adjust screen size for DTA_Virtual* if the aspect ratio is not 4:3
|
||||
DTA_RenderStyle, // same as render style for actors
|
||||
DTA_ColorOverlay, // uint32_t: ARGB to overlay on top of image; limited to black for software
|
||||
DTA_BilinearFilter, // bool: apply bilinear filtering to the image
|
||||
DTA_SpecialColormap,// pointer to FSpecialColormapParameters
|
||||
DTA_Desaturate, // explicit desaturation factor (does not do anything in Legacy OpenGL)
|
||||
DTA_Fullscreen, // Draw image fullscreen (same as DTA_VirtualWidth/Height with graphics size.)
|
||||
|
||||
// floating point duplicates of some of the above:
|
||||
DTA_DestWidthF,
|
||||
DTA_DestHeightF,
|
||||
DTA_TopOffsetF,
|
||||
DTA_LeftOffsetF,
|
||||
DTA_VirtualWidthF,
|
||||
DTA_VirtualHeightF,
|
||||
DTA_WindowLeftF,
|
||||
DTA_WindowRightF,
|
||||
|
||||
// For DrawText calls:
|
||||
DTA_TextLen, // stop after this many characters, even if \0 not hit
|
||||
DTA_CellX, // horizontal size of character cell
|
||||
DTA_CellY, // vertical size of character cell
|
||||
|
||||
// New additions.
|
||||
DTA_Color,
|
||||
DTA_FlipY, // bool: flip image vertically
|
||||
DTA_SrcX, // specify a source rectangle (this supersedes the poorly implemented DTA_WindowLeft/Right
|
||||
DTA_SrcY,
|
||||
DTA_SrcWidth,
|
||||
DTA_SrcHeight,
|
||||
DTA_LegacyRenderStyle, // takes an old-style STYLE_* constant instead of an FRenderStyle
|
||||
DTA_Burn, // activates the burn shader for this element
|
||||
DTA_Spacing, // Strings only: Additional spacing between characters
|
||||
DTA_Monospace, // Fonts only: Use a fixed distance between characters.
|
||||
};
|
||||
|
||||
enum EMonospacing : int
|
||||
{
|
||||
Off = 0,
|
||||
CellLeft = 1,
|
||||
CellCenter = 2,
|
||||
CellRight = 3
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
HUD_Normal,
|
||||
HUD_HorizCenter
|
||||
};
|
||||
|
||||
|
||||
class FFont;
|
||||
|
||||
struct DrawParms
|
||||
{
|
||||
double x, y;
|
||||
double texwidth;
|
||||
double texheight;
|
||||
double destwidth;
|
||||
double destheight;
|
||||
double virtWidth;
|
||||
double virtHeight;
|
||||
double windowleft;
|
||||
double windowright;
|
||||
int cleanmode;
|
||||
int dclip;
|
||||
int uclip;
|
||||
int lclip;
|
||||
int rclip;
|
||||
double top;
|
||||
double left;
|
||||
float Alpha;
|
||||
int remap;
|
||||
PalEntry fillcolor;
|
||||
PalEntry colorOverlay;
|
||||
PalEntry color;
|
||||
int alphaChannel;
|
||||
int flipX;
|
||||
int flipY;
|
||||
//float shadowAlpha;
|
||||
int shadowColor;
|
||||
int keepratio;
|
||||
int masked;
|
||||
int bilinear;
|
||||
FRenderStyle style;
|
||||
int desaturate;
|
||||
int scalex, scaley;
|
||||
int cellx, celly;
|
||||
int monospace;
|
||||
int spacing;
|
||||
int maxstrlen;
|
||||
bool fortext;
|
||||
bool virtBottom;
|
||||
double srcx, srcy;
|
||||
double srcwidth, srcheight;
|
||||
bool burn;
|
||||
};
|
||||
|
||||
struct Va_List
|
||||
{
|
||||
va_list list;
|
||||
};
|
||||
|
||||
int CheckRatio (int width, int height, int *trueratio=NULL);
|
||||
static inline int CheckRatio (double width, double height) { return CheckRatio(int(width), int(height)); }
|
||||
inline bool IsRatioWidescreen(int ratio) { return (ratio & 3) != 0; }
|
||||
|
||||
float ActiveRatio (int width, int height, float *trueratio = NULL);
|
||||
static inline double ActiveRatio (double width, double height) { return ActiveRatio(int(width), int(height)); }
|
||||
|
||||
int AspectBaseWidth(float aspect);
|
||||
int AspectBaseHeight(float aspect);
|
||||
double AspectPspriteOffset(float aspect);
|
||||
int AspectMultiplier(float aspect);
|
||||
bool AspectTallerThanWide(float aspect);
|
||||
void ScaleWithAspect(int &w, int &h, int Width, int Height);
|
||||
|
||||
int GetUIScale(int altval);
|
||||
int GetConScale(int altval);
|
158
source/common/2d/renderstyle.cpp
Normal file
158
source/common/2d/renderstyle.cpp
Normal file
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
** r_data.cpp
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2008-2011 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 "templates.h"
|
||||
#include "renderstyle.h"
|
||||
#include "c_cvars.h"
|
||||
|
||||
CVAR (Bool, r_drawtrans, true, 0)
|
||||
CVAR (Int, r_drawfuzz, 1, CVAR_ARCHIVE)
|
||||
|
||||
// Convert legacy render styles to flexible render styles.
|
||||
|
||||
FRenderStyle LegacyRenderStyles[STYLE_Count] =
|
||||
{
|
||||
{ { STYLEOP_None, STYLEALPHA_Zero, STYLEALPHA_Zero, 0 } }, /* STYLE_None */
|
||||
{ { STYLEOP_Add, STYLEALPHA_Src, STYLEALPHA_InvSrc, STYLEF_Alpha1 } }, /* STYLE_Normal */
|
||||
{ { STYLEOP_Fuzz, STYLEALPHA_Src, STYLEALPHA_InvSrc, 0 } }, /* STYLE_Fuzzy */
|
||||
{ { STYLEOP_FuzzOrAdd, STYLEALPHA_Src, STYLEALPHA_InvSrc, 0 } }, /* STYLE_OptFuzzy */
|
||||
{ { STYLEOP_Add, STYLEALPHA_Src, STYLEALPHA_InvSrc, STYLEF_Alpha1 | STYLEF_ColorIsFixed } }, /* STYLE_Stencil */
|
||||
{ { STYLEOP_Add, STYLEALPHA_Src, STYLEALPHA_InvSrc, 0 } }, /* STYLE_Translucent */
|
||||
{ { STYLEOP_Add, STYLEALPHA_Src, STYLEALPHA_One, 0 } }, /* STYLE_Add */
|
||||
{ { STYLEOP_Add, STYLEALPHA_Src, STYLEALPHA_InvSrc, STYLEF_RedIsAlpha | STYLEF_ColorIsFixed } }, /* STYLE_Shaded */
|
||||
{ { STYLEOP_Add, STYLEALPHA_Src, STYLEALPHA_InvSrc, STYLEF_ColorIsFixed } }, /* STYLE_TranslucentStencil */
|
||||
{ { STYLEOP_Shadow, 0, 0, 0 } }, /* STYLE_Shadow */
|
||||
{ { STYLEOP_RevSub, STYLEALPHA_Src, STYLEALPHA_One, 0 } }, /* STYLE_Subtract*/
|
||||
{ { STYLEOP_Add, STYLEALPHA_Src, STYLEALPHA_One, STYLEF_ColorIsFixed } }, /* STYLE_AddStencil */
|
||||
{ { STYLEOP_Add, STYLEALPHA_Src, STYLEALPHA_One, STYLEF_RedIsAlpha | STYLEF_ColorIsFixed } }, /* STYLE_AddShaded */
|
||||
{ { STYLEOP_Add, STYLEALPHA_DstCol, STYLEALPHA_Zero, 0 } }, /* STYLE_Multiply */
|
||||
{ { STYLEOP_Add, STYLEALPHA_InvDstCol, STYLEALPHA_Zero, 0 } }, /* STYLE_InverseMultiply */
|
||||
{ { STYLEOP_Add, STYLEALPHA_SrcCol, STYLEALPHA_InvSrcCol, 0 } }, /* STYLE_ColorBlend */
|
||||
{ { STYLEOP_Add, STYLEALPHA_One, STYLEALPHA_Zero, 0 } }, /* STYLE_Source */
|
||||
{ { STYLEOP_Add, STYLEALPHA_SrcCol, STYLEALPHA_One, 0 } }, /* STYLE_ColorAdd */
|
||||
};
|
||||
|
||||
double GetAlpha(int type, double alpha)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case STYLEALPHA_Zero: return 0;
|
||||
case STYLEALPHA_One: return 1.;
|
||||
case STYLEALPHA_Src: return alpha;
|
||||
case STYLEALPHA_InvSrc: return 1. - alpha;
|
||||
default: return 0.5; // undeterminable
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FRenderStyle :: IsVisible
|
||||
//
|
||||
// Coupled with the given alpha, will this render style produce something
|
||||
// visible on-screen?
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FRenderStyle::IsVisible(double alpha) const throw()
|
||||
{
|
||||
if (BlendOp == STYLEOP_None)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (BlendOp == STYLEOP_Add || BlendOp == STYLEOP_RevSub)
|
||||
{
|
||||
if (Flags & STYLEF_Alpha1)
|
||||
{
|
||||
alpha = 1.;
|
||||
}
|
||||
else
|
||||
{
|
||||
alpha = clamp(alpha, 0., 1.);
|
||||
}
|
||||
return GetAlpha(SrcAlpha, alpha) != 0 || GetAlpha(DestAlpha, alpha) != 1;
|
||||
}
|
||||
// Treat anything else as visible.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FRenderStyle :: CheckFuzz
|
||||
//
|
||||
// Adjusts settings based on r_drawfuzz CVAR
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FRenderStyle::CheckFuzz()
|
||||
{
|
||||
switch (BlendOp)
|
||||
{
|
||||
default:
|
||||
return;
|
||||
|
||||
case STYLEOP_FuzzOrAdd:
|
||||
if (r_drawtrans && r_drawfuzz == 0)
|
||||
{
|
||||
BlendOp = STYLEOP_Add;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case STYLEOP_FuzzOrSub:
|
||||
if (r_drawtrans && r_drawfuzz == 0)
|
||||
{
|
||||
BlendOp = STYLEOP_Sub;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case STYLEOP_FuzzOrRevSub:
|
||||
if (r_drawtrans && r_drawfuzz == 0)
|
||||
{
|
||||
BlendOp = STYLEOP_RevSub;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (r_drawfuzz == 2)
|
||||
{
|
||||
BlendOp = STYLEOP_Shadow;
|
||||
}
|
||||
else
|
||||
{
|
||||
BlendOp = STYLEOP_Fuzz;
|
||||
}
|
||||
}
|
182
source/common/2d/renderstyle.h
Normal file
182
source/common/2d/renderstyle.h
Normal file
|
@ -0,0 +1,182 @@
|
|||
#pragma once
|
||||
/*
|
||||
** r_blend.h
|
||||
** Constants and types for specifying texture blending.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2008 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 <stdint.h>
|
||||
|
||||
// <wingdi.h> also #defines OPAQUE
|
||||
#ifdef OPAQUE
|
||||
#undef OPAQUE
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
OPAQUE = 65536,
|
||||
};
|
||||
|
||||
enum ETexMode
|
||||
{
|
||||
TM_NORMAL = 0, // (r, g, b, a)
|
||||
TM_STENCIL, // (1, 1, 1, a)
|
||||
TM_OPAQUE, // (r, g, b, 1)
|
||||
TM_INVERSE, // (1-r, 1-g, 1-b, a)
|
||||
TM_ALPHATEXTURE, // (1, 1, 1, r)
|
||||
TM_CLAMPY, // (r, g, b, (t >= 0.0 && t <= 1.0)? a:0)
|
||||
TM_INVERTOPAQUE, // (1-r, 1-g, 1-b, 1)
|
||||
TM_FOGLAYER, // (renders a fog layer in the shape of the active texture)
|
||||
TM_FIXEDCOLORMAP = TM_FOGLAYER, // repurposes the objectcolor uniforms to render a fixed colormap range. (Same constant because they cannot be used in the same context.
|
||||
};
|
||||
|
||||
// Legacy render styles
|
||||
enum ERenderStyle
|
||||
{
|
||||
STYLE_None, // Do not draw
|
||||
STYLE_Normal, // Normal; just copy the image to the screen
|
||||
STYLE_Fuzzy, // Draw silhouette using "fuzz" effect
|
||||
STYLE_OptFuzzy, // Draw as fuzzy or translucent, based on user preference
|
||||
STYLE_Stencil, // Fill image interior with alphacolor
|
||||
STYLE_Translucent, // Draw translucent
|
||||
STYLE_Add, // Draw additive
|
||||
STYLE_Shaded, // Treat patch data as alpha values for alphacolor
|
||||
STYLE_TranslucentStencil,
|
||||
STYLE_Shadow,
|
||||
STYLE_Subtract, // Actually this is 'reverse subtract' but this is what normal people would expect by 'subtract'.
|
||||
STYLE_AddStencil, // Fill image interior with alphacolor
|
||||
STYLE_AddShaded, // Treat patch data as alpha values for alphacolor
|
||||
STYLE_Multiply, // Multiply source with destination (HW renderer only.)
|
||||
STYLE_InverseMultiply, // Multiply source with inverse of destination (HW renderer only.)
|
||||
STYLE_ColorBlend, // Use color intensity as transparency factor
|
||||
STYLE_Source, // No blending (only used internally)
|
||||
STYLE_ColorAdd, // Use color intensity as transparency factor and blend additively.
|
||||
|
||||
STYLE_Count
|
||||
};
|
||||
|
||||
// Flexible render styles (most possible combinations are supported in software)
|
||||
enum ERenderOp
|
||||
{
|
||||
STYLEOP_None, // Do not draw
|
||||
STYLEOP_Add, // Add source to destination
|
||||
STYLEOP_Sub, // Subtract source from destination
|
||||
STYLEOP_RevSub, // Subtract destination from source
|
||||
STYLEOP_Fuzz, // Draw fuzzy on top of destination - ignores alpha and color
|
||||
STYLEOP_FuzzOrAdd, // Draw fuzzy or add, based on user preference
|
||||
STYLEOP_FuzzOrSub, // Draw fuzzy or subtract, based on user preference
|
||||
STYLEOP_FuzzOrRevSub, // Draw fuzzy or reverse subtract, based on user preference
|
||||
|
||||
// special styles
|
||||
STYLEOP_Shadow,
|
||||
};
|
||||
|
||||
enum ERenderAlpha
|
||||
{
|
||||
STYLEALPHA_Zero, // Blend factor is 0.0
|
||||
STYLEALPHA_One, // Blend factor is 1.0
|
||||
STYLEALPHA_Src, // Blend factor is alpha
|
||||
STYLEALPHA_InvSrc, // Blend factor is 1.0 - alpha
|
||||
STYLEALPHA_SrcCol, // Blend factor is color (HWR only)
|
||||
STYLEALPHA_InvSrcCol, // Blend factor is 1.0 - color (HWR only)
|
||||
STYLEALPHA_DstCol, // Blend factor is dest. color (HWR only)
|
||||
STYLEALPHA_InvDstCol, // Blend factor is 1.0 - dest. color (HWR only)
|
||||
STYLEALPHA_MAX
|
||||
};
|
||||
|
||||
enum ERenderFlags
|
||||
{
|
||||
// Force alpha to 1. Not the same as STYLEALPHA_One, since that also
|
||||
// ignores alpha from the texture.
|
||||
STYLEF_Alpha1 = 2,
|
||||
|
||||
// Use red component from grayscale/RGB texture as alpha. If the texture
|
||||
// is paletted, the palette is ignored and it is treated as grayscale.
|
||||
// This should generally be combined with STYLEF_ColorIsFixed, since that's
|
||||
// all the software renderer supports, but hardware acceleration can do
|
||||
// them separately should you want to do that for some reason.
|
||||
STYLEF_RedIsAlpha = 4,
|
||||
|
||||
// Ignore texture for RGB output. Color comes from fillcolor for actors
|
||||
// or DTA_FillColor for DrawTexture().
|
||||
STYLEF_ColorIsFixed = 8,
|
||||
|
||||
// Invert source color, either the texture color or the fixed color.
|
||||
STYLEF_InvertSource = 16,
|
||||
|
||||
// Invert overlay color. This is the fade for actors and DTA_ColorOverlay
|
||||
// for DrawTexture().
|
||||
STYLEF_InvertOverlay = 32,
|
||||
|
||||
// Actors only: Ignore sector fade and fade to black. To fade to white,
|
||||
// combine this with STYLEF_InvertOverlay.
|
||||
STYLEF_FadeToBlack = 64,
|
||||
};
|
||||
|
||||
union FRenderStyle
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t BlendOp; // Of ERenderOp type
|
||||
uint8_t SrcAlpha; // Of ERenderAlpha type
|
||||
uint8_t DestAlpha; // Of ERenderAlpha type
|
||||
uint8_t Flags;
|
||||
};
|
||||
uint32_t AsDWORD;
|
||||
|
||||
inline FRenderStyle &operator= (ERenderStyle legacy);
|
||||
bool operator==(const FRenderStyle &o) const { return AsDWORD == o.AsDWORD; }
|
||||
bool operator!=(const FRenderStyle &o) const { return AsDWORD != o.AsDWORD; }
|
||||
void CheckFuzz();
|
||||
bool IsVisible(double alpha) const throw();
|
||||
private:
|
||||
// Code that compares an actor's render style with a legacy render
|
||||
// style value should be updated.
|
||||
operator ERenderStyle() = delete;
|
||||
operator int() const = delete;
|
||||
};
|
||||
|
||||
extern FRenderStyle LegacyRenderStyles[STYLE_Count];
|
||||
|
||||
inline FRenderStyle DefaultRenderStyle()
|
||||
{
|
||||
return LegacyRenderStyles[STYLE_Normal];
|
||||
}
|
||||
|
||||
inline FRenderStyle &FRenderStyle::operator= (ERenderStyle legacy)
|
||||
{
|
||||
if (legacy < STYLE_None || legacy >= STYLE_Count)
|
||||
{
|
||||
legacy = STYLE_None;
|
||||
}
|
||||
*this = LegacyRenderStyles[legacy];
|
||||
return *this;
|
||||
}
|
||||
|
554
source/common/2d/v_2ddrawer.cpp
Normal file
554
source/common/2d/v_2ddrawer.cpp
Normal file
|
@ -0,0 +1,554 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2016-2018 Christoph Oelckers
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** v_2ddrawer.h
|
||||
** Device independent 2D draw list
|
||||
**
|
||||
**/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "c_cvars.h"
|
||||
#include "v_2ddrawer.h"
|
||||
#include "renderstyle.h"
|
||||
#include "drawparms.h"
|
||||
#include "vectors.h"
|
||||
//#include "doomtype.h"
|
||||
#include "templates.h"
|
||||
//#include "r_utility.h"
|
||||
//#include "v_video.h"
|
||||
//#include "g_levellocals.h"
|
||||
//#include "vm.h"
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int F2DDrawer::AddCommand(const RenderCommand *data)
|
||||
{
|
||||
if (mData.Size() > 0 && data->isCompatible(mData.Last()))
|
||||
{
|
||||
// Merge with the last command.
|
||||
mData.Last().mIndexCount += data->mIndexCount;
|
||||
mData.Last().mVertCount += data->mVertCount;
|
||||
return mData.Size();
|
||||
}
|
||||
else
|
||||
{
|
||||
return mData.Push(*data);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void F2DDrawer::AddIndices(int firstvert, int count, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, count);
|
||||
int addr = mIndices.Reserve(count);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
mIndices[addr + i] = firstvert + va_arg(ap, int);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// SetStyle
|
||||
//
|
||||
// Patterned after R_SetPatchStyle.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool F2DDrawer::SetStyle(FTexture *tex, DrawParms &parms, PalEntry &vertexcolor, RenderCommand &quad)
|
||||
{
|
||||
FRenderStyle style = parms.style;
|
||||
float alpha;
|
||||
bool stencilling;
|
||||
|
||||
if (style.Flags & STYLEF_Alpha1)
|
||||
{
|
||||
alpha = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
alpha = clamp(parms.Alpha, 0.f, 1.f);
|
||||
}
|
||||
|
||||
style.CheckFuzz();
|
||||
if (style.BlendOp == STYLEOP_Shadow || style.BlendOp == STYLEOP_Fuzz)
|
||||
{
|
||||
style = LegacyRenderStyles[STYLE_TranslucentStencil];
|
||||
alpha = 0.3f;
|
||||
parms.fillcolor = 0;
|
||||
}
|
||||
else if (style.BlendOp == STYLEOP_FuzzOrAdd)
|
||||
{
|
||||
style.BlendOp = STYLEOP_Add;
|
||||
}
|
||||
else if (style.BlendOp == STYLEOP_FuzzOrSub)
|
||||
{
|
||||
style.BlendOp = STYLEOP_Sub;
|
||||
}
|
||||
else if (style.BlendOp == STYLEOP_FuzzOrRevSub)
|
||||
{
|
||||
style.BlendOp = STYLEOP_RevSub;
|
||||
}
|
||||
|
||||
stencilling = false;
|
||||
|
||||
if (style.Flags & STYLEF_InvertOverlay)
|
||||
{
|
||||
// Only the overlay color is inverted, not the overlay alpha.
|
||||
parms.colorOverlay.r = 255 - parms.colorOverlay.r;
|
||||
parms.colorOverlay.g = 255 - parms.colorOverlay.g;
|
||||
parms.colorOverlay.b = 255 - parms.colorOverlay.b;
|
||||
}
|
||||
|
||||
SetColorOverlay(parms.colorOverlay, alpha, vertexcolor, quad.mColor1);
|
||||
|
||||
if (style.Flags & STYLEF_ColorIsFixed)
|
||||
{
|
||||
if (style.Flags & STYLEF_InvertSource)
|
||||
{ // Since the source color is a constant, we can invert it now
|
||||
// without spending time doing it in the shader.
|
||||
parms.fillcolor.r = 255 - parms.fillcolor.r;
|
||||
parms.fillcolor.g = 255 - parms.fillcolor.g;
|
||||
parms.fillcolor.b = 255 - parms.fillcolor.b;
|
||||
style.Flags &= ~STYLEF_InvertSource;
|
||||
}
|
||||
if (parms.desaturate > 0)
|
||||
{
|
||||
// Desaturation can also be computed here without having to do it in the shader.
|
||||
auto gray = parms.fillcolor.Luminance();
|
||||
auto notgray = 255 - gray;
|
||||
parms.fillcolor.r = uint8_t((parms.fillcolor.r * notgray + gray * 255) / 255);
|
||||
parms.fillcolor.g = uint8_t((parms.fillcolor.g * notgray + gray * 255) / 255);
|
||||
parms.fillcolor.b = uint8_t((parms.fillcolor.b * notgray + gray * 255) / 255);
|
||||
parms.desaturate = 0;
|
||||
}
|
||||
|
||||
// Set up the color mod to replace the color from the image data.
|
||||
vertexcolor.r = parms.fillcolor.r;
|
||||
vertexcolor.g = parms.fillcolor.g;
|
||||
vertexcolor.b = parms.fillcolor.b;
|
||||
|
||||
if (style.Flags & STYLEF_RedIsAlpha)
|
||||
{
|
||||
quad.mDrawMode = TM_ALPHATEXTURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
quad.mDrawMode = TM_STENCIL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (style.Flags & STYLEF_RedIsAlpha)
|
||||
{
|
||||
quad.mDrawMode = TM_ALPHATEXTURE;
|
||||
}
|
||||
else if (style.Flags & STYLEF_InvertSource)
|
||||
{
|
||||
quad.mDrawMode = TM_INVERSE;
|
||||
}
|
||||
quad.mDesaturate = parms.desaturate;
|
||||
}
|
||||
// apply the element's own color. This is being blended with anything that came before.
|
||||
vertexcolor = PalEntry((vertexcolor.a * parms.color.a) / 255, (vertexcolor.r * parms.color.r) / 255, (vertexcolor.g * parms.color.g) / 255, (vertexcolor.b * parms.color.b) / 255);
|
||||
|
||||
if (!parms.masked)
|
||||
{
|
||||
// For TM_ALPHATEXTURE and TM_STENCIL the mask cannot be turned off because it would not yield a usable result.
|
||||
if (quad.mDrawMode == TM_NORMAL) quad.mDrawMode = TM_OPAQUE;
|
||||
else if (quad.mDrawMode == TM_INVERSE) quad.mDrawMode = TM_INVERTOPAQUE;
|
||||
}
|
||||
quad.mRenderStyle = parms.style; // this contains the blend mode and blend equation settings.
|
||||
if (parms.burn) quad.mFlags |= DTF_Burn;
|
||||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Draws a texture
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void F2DDrawer::SetColorOverlay(PalEntry color, float alpha, PalEntry &vertexcolor, PalEntry &overlaycolor)
|
||||
{
|
||||
if (color.a != 0 && (color & 0xffffff) != 0)
|
||||
{
|
||||
// overlay color uses premultiplied alpha.
|
||||
int a = color.a * 256 / 255;
|
||||
overlaycolor.r = (color.r * a) >> 8;
|
||||
overlaycolor.g = (color.g * a) >> 8;
|
||||
overlaycolor.b = (color.b * a) >> 8;
|
||||
overlaycolor.a = 0; // The overlay gets added on top of the texture data so to preserve the pixel's alpha this must be 0.
|
||||
}
|
||||
else
|
||||
{
|
||||
overlaycolor = 0;
|
||||
}
|
||||
// Vertex intensity is the inverse of the overlay so that the shader can do a simple addition to combine them.
|
||||
uint8_t light = 255 - color.a;
|
||||
vertexcolor = PalEntry(int(alpha * 255), light, light, light);
|
||||
|
||||
// The real color gets multiplied into vertexcolor later.
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Draws a texture
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void F2DDrawer::AddTexture(FTexture *img, DrawParms &parms)
|
||||
{
|
||||
if (parms.style.BlendOp == STYLEOP_None) return; // not supposed to be drawn.
|
||||
|
||||
double xscale = parms.destwidth / parms.texwidth;
|
||||
double yscale = parms.destheight / parms.texheight;
|
||||
double x = parms.x - parms.left * xscale;
|
||||
double y = parms.y - parms.top * yscale;
|
||||
double w = parms.destwidth;
|
||||
double h = parms.destheight;
|
||||
double u1, v1, u2, v2;
|
||||
PalEntry vertexcolor;
|
||||
|
||||
RenderCommand dg;
|
||||
|
||||
dg.mType = DrawTypeTriangles;
|
||||
dg.mVertCount = 4;
|
||||
dg.mTexture = img;
|
||||
|
||||
dg.mTranslation = 0;
|
||||
SetStyle(img, parms, vertexcolor, dg);
|
||||
|
||||
u1 = parms.srcx;
|
||||
v1 = parms.srcy;
|
||||
u2 = parms.srcx + parms.srcwidth;
|
||||
v2 = parms.srcy + parms.srcheight;
|
||||
|
||||
if (parms.flipX)
|
||||
std::swap(u1, u2);
|
||||
|
||||
if (parms.flipY)
|
||||
std::swap(v1, v2);
|
||||
|
||||
// This is crap. Only kept for backwards compatibility with scripts that may have used it.
|
||||
// Note that this only works for unflipped full textures.
|
||||
if (parms.windowleft > 0 || parms.windowright < parms.texwidth)
|
||||
{
|
||||
double wi = std::min(parms.windowright, parms.texwidth);
|
||||
x += parms.windowleft * xscale;
|
||||
w -= (parms.texwidth - wi + parms.windowleft) * xscale;
|
||||
|
||||
u1 = float(u1 + parms.windowleft / parms.texwidth);
|
||||
u2 = float(u2 - (parms.texwidth - wi) / parms.texwidth);
|
||||
}
|
||||
|
||||
if (x < (double)parms.lclip || y < (double)parms.uclip || x + w >(double)parms.rclip || y + h >(double)parms.dclip)
|
||||
{
|
||||
dg.mScissor[0] = parms.lclip;
|
||||
dg.mScissor[1] = parms.uclip;
|
||||
dg.mScissor[2] = parms.rclip;
|
||||
dg.mScissor[3] = parms.dclip;
|
||||
dg.mFlags |= DTF_Scissor;
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(dg.mScissor, 0, sizeof(dg.mScissor));
|
||||
}
|
||||
|
||||
dg.mVertCount = 4;
|
||||
dg.mVertIndex = (int)mVertices.Reserve(4);
|
||||
TwoDVertex *ptr = &mVertices[dg.mVertIndex];
|
||||
ptr->Set(x, y, 0, u1, v1, vertexcolor); ptr++;
|
||||
ptr->Set(x, y + h, 0, u1, v2, vertexcolor); ptr++;
|
||||
ptr->Set(x + w, y, 0, u2, v1, vertexcolor); ptr++;
|
||||
ptr->Set(x + w, y + h, 0, u2, v2, vertexcolor); ptr++;
|
||||
dg.mIndexIndex = mIndices.Size();
|
||||
dg.mIndexCount += 6;
|
||||
AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2);
|
||||
AddCommand(&dg);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void F2DDrawer::AddPoly(FTexture *texture, FVector2 *points, int npoints,
|
||||
double originx, double originy, double scalex, double scaley,
|
||||
DAngle rotation, int colormap, PalEntry flatcolor, int lightlevel,
|
||||
uint32_t *indices, size_t indexcount)
|
||||
{
|
||||
// Use an equation similar to player sprites to determine shade
|
||||
|
||||
// Convert a light level into an unbounded colormap index (shade).
|
||||
// Why the +12? I wish I knew, but experimentation indicates it
|
||||
// is necessary in order to best reproduce Doom's original lighting.
|
||||
double fadelevel;
|
||||
|
||||
// The hardware renderer's light modes 0, 1 and 4 use a linear light scale which must be used here as well. Otherwise the automap gets too dark.
|
||||
fadelevel = 1. - clamp(lightlevel, 0, 255) / 255.f;
|
||||
|
||||
RenderCommand poly;
|
||||
|
||||
poly.mType = DrawTypeTriangles;
|
||||
poly.mTexture = texture;
|
||||
poly.mRenderStyle = DefaultRenderStyle();
|
||||
poly.mFlags |= DTF_Wrap;
|
||||
poly.mDesaturate = 0;
|
||||
|
||||
PalEntry color0;
|
||||
double invfade = 1. - fadelevel;
|
||||
|
||||
color0.r = uint8_t(flatcolor.r * invfade);
|
||||
color0.g = uint8_t(flatcolor.g * invfade);
|
||||
color0.b = uint8_t(flatcolor.b * invfade);
|
||||
color0.a = 255;
|
||||
|
||||
poly.mColor1 = 0;
|
||||
|
||||
bool dorotate = rotation != 0;
|
||||
|
||||
float cosrot = (float)cos(rotation.Radians());
|
||||
float sinrot = (float)sin(rotation.Radians());
|
||||
|
||||
float uscale = float(1.f / (texture->GetWidth() * scalex));
|
||||
float vscale = float(1.f / (texture->GetHeight() * scaley));
|
||||
float ox = float(originx);
|
||||
float oy = float(originy);
|
||||
|
||||
poly.mVertCount = npoints;
|
||||
poly.mVertIndex = (int)mVertices.Reserve(npoints);
|
||||
for (int i = 0; i < npoints; ++i)
|
||||
{
|
||||
float u = points[i].X - 0.5f - ox;
|
||||
float v = points[i].Y - 0.5f - oy;
|
||||
if (dorotate)
|
||||
{
|
||||
float t = u;
|
||||
u = t * cosrot - v * sinrot;
|
||||
v = v * cosrot + t * sinrot;
|
||||
}
|
||||
mVertices[poly.mVertIndex+i].Set(points[i].X, points[i].Y, 0, u*uscale, v*vscale, color0);
|
||||
}
|
||||
poly.mIndexIndex = mIndices.Size();
|
||||
|
||||
if (indices == nullptr || indexcount == 0)
|
||||
{
|
||||
poly.mIndexCount += (npoints - 2) * 3;
|
||||
for (int i = 2; i < npoints; ++i)
|
||||
{
|
||||
AddIndices(poly.mVertIndex, 3, 0, i - 1, i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
poly.mIndexCount += (int)indexcount;
|
||||
int addr = mIndices.Reserve(indexcount);
|
||||
for (size_t i = 0; i < indexcount; i++)
|
||||
{
|
||||
mIndices[addr + i] = poly.mVertIndex + indices[i];
|
||||
}
|
||||
}
|
||||
|
||||
AddCommand(&poly);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void F2DDrawer::AddFlatFill(int left, int top, int right, int bottom, FTexture *src, bool local_origin)
|
||||
{
|
||||
float fU1, fU2, fV1, fV2;
|
||||
|
||||
RenderCommand dg;
|
||||
|
||||
dg.mType = DrawTypeTriangles;
|
||||
dg.mRenderStyle = DefaultRenderStyle();
|
||||
dg.mTexture = src;
|
||||
dg.mVertCount = 4;
|
||||
dg.mTexture = src;
|
||||
dg.mFlags = DTF_Wrap;
|
||||
|
||||
// scaling is not used here.
|
||||
if (!local_origin)
|
||||
{
|
||||
fU1 = float(left) / src->GetWidth();
|
||||
fV1 = float(top) / src->GetHeight();
|
||||
fU2 = float(right) / src->GetWidth();
|
||||
fV2 = float(bottom) / src->GetHeight();
|
||||
}
|
||||
else
|
||||
{
|
||||
fU1 = 0;
|
||||
fV1 = 0;
|
||||
fU2 = float(right - left) / src->GetWidth();
|
||||
fV2 = float(bottom - top) / src->GetHeight();
|
||||
}
|
||||
dg.mVertIndex = (int)mVertices.Reserve(4);
|
||||
auto ptr = &mVertices[dg.mVertIndex];
|
||||
|
||||
ptr->Set(left, top, 0, fU1, fV1, 0xffffffff); ptr++;
|
||||
ptr->Set(left, bottom, 0, fU1, fV2, 0xffffffff); ptr++;
|
||||
ptr->Set(right, top, 0, fU2, fV1, 0xffffffff); ptr++;
|
||||
ptr->Set(right, bottom, 0, fU2, fV2, 0xffffffff); ptr++;
|
||||
dg.mIndexIndex = mIndices.Size();
|
||||
dg.mIndexCount += 6;
|
||||
AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2);
|
||||
AddCommand(&dg);
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void F2DDrawer::AddColorOnlyQuad(int x1, int y1, int w, int h, PalEntry color, FRenderStyle *style)
|
||||
{
|
||||
RenderCommand dg;
|
||||
|
||||
dg.mType = DrawTypeTriangles;
|
||||
dg.mVertCount = 4;
|
||||
dg.mVertIndex = (int)mVertices.Reserve(4);
|
||||
dg.mRenderStyle = style? *style : LegacyRenderStyles[STYLE_Translucent];
|
||||
auto ptr = &mVertices[dg.mVertIndex];
|
||||
ptr->Set(x1, y1, 0, 0, 0, color); ptr++;
|
||||
ptr->Set(x1, y1 + h, 0, 0, 0, color); ptr++;
|
||||
ptr->Set(x1 + w, y1, 0, 0, 0, color); ptr++;
|
||||
ptr->Set(x1 + w, y1 + h, 0, 0, 0, color); ptr++;
|
||||
dg.mIndexIndex = mIndices.Size();
|
||||
dg.mIndexCount += 6;
|
||||
AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2);
|
||||
AddCommand(&dg);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void F2DDrawer::AddLine(int x1, int y1, int x2, int y2, uint32_t color, uint8_t alpha)
|
||||
{
|
||||
PalEntry p = (PalEntry)color;
|
||||
p.a = alpha;
|
||||
|
||||
RenderCommand dg;
|
||||
|
||||
dg.mType = DrawTypeLines;
|
||||
dg.mRenderStyle = LegacyRenderStyles[STYLE_Translucent];
|
||||
dg.mVertCount = 2;
|
||||
dg.mVertIndex = (int)mVertices.Reserve(2);
|
||||
mVertices[dg.mVertIndex].Set(x1, y1, 0, 0, 0, p);
|
||||
mVertices[dg.mVertIndex+1].Set(x2, y2, 0, 0, 0, p);
|
||||
AddCommand(&dg);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void F2DDrawer::AddThickLine(int x1, int y1, int x2, int y2, double thickness, uint32_t color, uint8_t alpha)
|
||||
{
|
||||
PalEntry p = (PalEntry)color;
|
||||
p.a = alpha;
|
||||
|
||||
DVector2 point0(x1, y1);
|
||||
DVector2 point1(x2, y2);
|
||||
|
||||
DVector2 delta = point1 - point0;
|
||||
DVector2 perp(-delta.Y, delta.X);
|
||||
perp.MakeUnit();
|
||||
perp *= thickness / 2;
|
||||
|
||||
DVector2 corner0 = point0 + perp;
|
||||
DVector2 corner1 = point0 - perp;
|
||||
DVector2 corner2 = point1 + perp;
|
||||
DVector2 corner3 = point1 - perp;
|
||||
|
||||
RenderCommand dg;
|
||||
|
||||
dg.mType = DrawTypeTriangles;
|
||||
dg.mVertCount = 4;
|
||||
dg.mVertIndex = (int)mVertices.Reserve(4);
|
||||
dg.mRenderStyle = LegacyRenderStyles[STYLE_Translucent];
|
||||
auto ptr = &mVertices[dg.mVertIndex];
|
||||
ptr->Set(corner0.X, corner0.Y, 0, 0, 0, p); ptr++;
|
||||
ptr->Set(corner1.X, corner1.Y, 0, 0, 0, p); ptr++;
|
||||
ptr->Set(corner2.X, corner2.Y, 0, 0, 0, p); ptr++;
|
||||
ptr->Set(corner3.X, corner3.Y, 0, 0, 0, p); ptr++;
|
||||
dg.mIndexIndex = mIndices.Size();
|
||||
dg.mIndexCount += 6;
|
||||
AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2);
|
||||
AddCommand(&dg);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void F2DDrawer::AddPixel(int x1, int y1, uint32_t color)
|
||||
{
|
||||
PalEntry p = (PalEntry)color;
|
||||
p.a = 255;
|
||||
|
||||
RenderCommand dg;
|
||||
|
||||
dg.mType = DrawTypePoints;
|
||||
dg.mRenderStyle = LegacyRenderStyles[STYLE_Translucent];
|
||||
dg.mVertCount = 1;
|
||||
dg.mVertIndex = (int)mVertices.Reserve(1);
|
||||
mVertices[dg.mVertIndex].Set(x1, y1, 0, 0, 0, p);
|
||||
AddCommand(&dg);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void F2DDrawer::Clear()
|
||||
{
|
||||
mVertices.Clear();
|
||||
mIndices.Clear();
|
||||
mData.Clear();
|
||||
mIsFirstPass = true;
|
||||
}
|
134
source/common/2d/v_2ddrawer.h
Normal file
134
source/common/2d/v_2ddrawer.h
Normal file
|
@ -0,0 +1,134 @@
|
|||
#ifndef __2DDRAWER_H
|
||||
#define __2DDRAWER_H
|
||||
|
||||
#include "tarray.h"
|
||||
#include "vectors.h"
|
||||
#include "textures.h"
|
||||
#include "renderstyle.h"
|
||||
|
||||
struct DrawParms;
|
||||
|
||||
|
||||
|
||||
class F2DDrawer
|
||||
{
|
||||
public:
|
||||
|
||||
enum EDrawType : uint8_t
|
||||
{
|
||||
DrawTypeTriangles,
|
||||
DrawTypeLines,
|
||||
DrawTypePoints,
|
||||
};
|
||||
|
||||
enum ETextureFlags : uint8_t
|
||||
{
|
||||
DTF_Wrap = 1,
|
||||
DTF_Scissor = 2,
|
||||
DTF_Burn = 4,
|
||||
};
|
||||
|
||||
|
||||
// This vertex type is hardware independent and needs conversion when put into a buffer.
|
||||
struct TwoDVertex
|
||||
{
|
||||
float x, y, z;
|
||||
float u, v;
|
||||
PalEntry color0;
|
||||
|
||||
void Set(float xx, float yy, float zz)
|
||||
{
|
||||
x = xx;
|
||||
z = zz;
|
||||
y = yy;
|
||||
u = 0;
|
||||
v = 0;
|
||||
color0 = 0;
|
||||
}
|
||||
|
||||
void Set(double xx, double yy, double zz, double uu, double vv, PalEntry col)
|
||||
{
|
||||
x = (float)xx;
|
||||
z = (float)zz;
|
||||
y = (float)yy;
|
||||
u = (float)uu;
|
||||
v = (float)vv;
|
||||
color0 = col;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct RenderCommand
|
||||
{
|
||||
EDrawType mType;
|
||||
int mVertIndex;
|
||||
int mVertCount;
|
||||
int mIndexIndex;
|
||||
int mIndexCount;
|
||||
|
||||
FTexture *mTexture;
|
||||
FRemapTable *mTranslation;
|
||||
PalEntry mSpecialColormap[2];
|
||||
int mScissor[4];
|
||||
int mDesaturate;
|
||||
FRenderStyle mRenderStyle;
|
||||
PalEntry mColor1; // Overlay color
|
||||
ETexMode mDrawMode;
|
||||
uint8_t mFlags;
|
||||
|
||||
RenderCommand()
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
|
||||
// If these fields match, two draw commands can be batched.
|
||||
bool isCompatible(const RenderCommand &other) const
|
||||
{
|
||||
return mTexture == other.mTexture &&
|
||||
mType == other.mType &&
|
||||
mTranslation == other.mTranslation &&
|
||||
mSpecialColormap[0].d == other.mSpecialColormap[0].d &&
|
||||
mSpecialColormap[1].d == other.mSpecialColormap[1].d &&
|
||||
!memcmp(mScissor, other.mScissor, sizeof(mScissor)) &&
|
||||
mDesaturate == other.mDesaturate &&
|
||||
mRenderStyle == other.mRenderStyle &&
|
||||
mDrawMode == other.mDrawMode &&
|
||||
mFlags == other.mFlags &&
|
||||
mColor1.d == other.mColor1.d;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
TArray<int> mIndices;
|
||||
TArray<TwoDVertex> mVertices;
|
||||
TArray<RenderCommand> mData;
|
||||
|
||||
int AddCommand(const RenderCommand *data);
|
||||
void AddIndices(int firstvert, int count, ...);
|
||||
bool SetStyle(FTexture *tex, DrawParms &parms, PalEntry &color0, RenderCommand &quad);
|
||||
void SetColorOverlay(PalEntry color, float alpha, PalEntry &vertexcolor, PalEntry &overlaycolor);
|
||||
|
||||
public:
|
||||
void AddTexture(FTexture *img, DrawParms &parms);
|
||||
void AddPoly(FTexture *texture, FVector2 *points, int npoints,
|
||||
double originx, double originy, double scalex, double scaley,
|
||||
DAngle rotation, int colormap, PalEntry flatcolor, int lightlevel, uint32_t *indices, size_t indexcount);
|
||||
void AddFlatFill(int left, int top, int right, int bottom, FTexture *src, bool local_origin);
|
||||
|
||||
void AddColorOnlyQuad(int left, int top, int width, int height, PalEntry color, FRenderStyle *style);
|
||||
|
||||
void AddDim(PalEntry color, float damount, int x1, int y1, int w, int h);
|
||||
void AddClear(int left, int top, int right, int bottom, int palcolor, uint32_t color);
|
||||
|
||||
|
||||
void AddLine(int x1, int y1, int x2, int y2, uint32_t color, uint8_t alpha = 255);
|
||||
void AddThickLine(int x1, int y1, int x2, int y2, double thickness, uint32_t color, uint8_t alpha = 255);
|
||||
void AddPixel(int x1, int y1, uint32_t color);
|
||||
|
||||
void Clear();
|
||||
|
||||
bool mIsFirstPass = true;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
873
source/common/2d/v_draw.cpp
Normal file
873
source/common/2d/v_draw.cpp
Normal file
|
@ -0,0 +1,873 @@
|
|||
/*
|
||||
** v_draw.cpp
|
||||
** Draw patches and blocks to a canvas
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 1998-2008 Randy Heit
|
||||
** Copyright 2005-2019 Christoph Oelckers
|
||||
** 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 <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include "c_cvars.h"
|
||||
#include "drawparms.h"
|
||||
#include "templates.h"
|
||||
#include "v_draw.h"
|
||||
|
||||
ScreenDummy* screen;
|
||||
|
||||
CUSTOM_CVAR(Int, uiscale, 0, CVAR_ARCHIVE | CVAR_NOINITCALL)
|
||||
{
|
||||
if (self < 0)
|
||||
{
|
||||
self = 0;
|
||||
return;
|
||||
}
|
||||
//setsizeneeded = true;
|
||||
}
|
||||
|
||||
CVAR(Int, vid_aspect, 0, 0)
|
||||
|
||||
int GetUIScale(int altval)
|
||||
{
|
||||
int scaleval;
|
||||
if (altval > 0) scaleval = altval;
|
||||
else if (uiscale == 0)
|
||||
{
|
||||
// Default should try to scale to 640x400
|
||||
int vscale = screen->GetHeight() / 400;
|
||||
int hscale = screen->GetWidth() / 640;
|
||||
scaleval = clamp(vscale, 1, hscale);
|
||||
}
|
||||
else scaleval = uiscale;
|
||||
|
||||
// block scales that result in something larger than the current screen.
|
||||
int vmax = screen->GetHeight() / 200;
|
||||
int hmax = screen->GetWidth() / 320;
|
||||
int max = std::max(vmax, hmax);
|
||||
return std::max(1,std::min(scaleval, max));
|
||||
}
|
||||
|
||||
// The new console font is twice as high, so the scaling calculation must factor that in.
|
||||
int GetConScale(int altval)
|
||||
{
|
||||
int scaleval;
|
||||
if (altval > 0) scaleval = (altval+1) / 2;
|
||||
else if (uiscale == 0)
|
||||
{
|
||||
// Default should try to scale to 640x400
|
||||
int vscale = screen->GetHeight() / 800;
|
||||
int hscale = screen->GetWidth() / 1280;
|
||||
scaleval = clamp(vscale, 1, hscale);
|
||||
}
|
||||
else scaleval = (uiscale+1) / 2;
|
||||
|
||||
// block scales that result in something larger than the current screen.
|
||||
int vmax = screen->GetHeight() / 400;
|
||||
int hmax = screen->GetWidth() / 640;
|
||||
int max = std::max(vmax, hmax);
|
||||
return std::max(1, std::min(scaleval, max));
|
||||
}
|
||||
|
||||
|
||||
// [RH] Stretch values to make a 320x200 image best fit the screen
|
||||
// without using fractional steppings
|
||||
int CleanXfac, CleanYfac;
|
||||
|
||||
// [RH] Effective screen sizes that the above scale values give you
|
||||
int CleanWidth, CleanHeight;
|
||||
|
||||
// Above minus 1 (or 1, if they are already 1)
|
||||
int CleanXfac_1, CleanYfac_1, CleanWidth_1, CleanHeight_1;
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Draw parameter parsing
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool SetTextureParms(DrawParms *parms, FTexture *img, double xx, double yy)
|
||||
{
|
||||
if (img != NULL)
|
||||
{
|
||||
parms->x = xx;
|
||||
parms->y = yy;
|
||||
parms->texwidth = img->GetWidth();
|
||||
parms->texheight = img->GetHeight();
|
||||
if (parms->top == INT_MAX || parms->fortext)
|
||||
{
|
||||
parms->top = img->GetTopOffset();
|
||||
}
|
||||
if (parms->left == INT_MAX || parms->fortext)
|
||||
{
|
||||
parms->left = img->GetLeftOffset();
|
||||
}
|
||||
if (parms->destwidth == INT_MAX || parms->fortext)
|
||||
{
|
||||
parms->destwidth = img->GetWidth();
|
||||
}
|
||||
if (parms->destheight == INT_MAX || parms->fortext)
|
||||
{
|
||||
parms->destheight = img->GetHeight();
|
||||
}
|
||||
|
||||
switch (parms->cleanmode)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
|
||||
case DTA_Clean:
|
||||
parms->x = (parms->x - 160.0) * CleanXfac + (screen->GetWidth() * 0.5);
|
||||
parms->y = (parms->y - 100.0) * CleanYfac + (screen->GetHeight() * 0.5);
|
||||
parms->destwidth = parms->texwidth * CleanXfac;
|
||||
parms->destheight = parms->texheight * CleanYfac;
|
||||
break;
|
||||
|
||||
case DTA_CleanNoMove:
|
||||
parms->destwidth = parms->texwidth * CleanXfac;
|
||||
parms->destheight = parms->texheight * CleanYfac;
|
||||
break;
|
||||
|
||||
case DTA_CleanNoMove_1:
|
||||
parms->destwidth = parms->texwidth * CleanXfac_1;
|
||||
parms->destheight = parms->texheight * CleanYfac_1;
|
||||
break;
|
||||
|
||||
case DTA_Fullscreen:
|
||||
parms->x = parms->y = 0;
|
||||
break;
|
||||
|
||||
}
|
||||
if (parms->virtWidth != screen->GetWidth() || parms->virtHeight != screen->GetHeight())
|
||||
{
|
||||
VirtualToRealCoords(parms->x, parms->y, parms->destwidth, parms->destheight,
|
||||
parms->virtWidth, parms->virtHeight, parms->virtBottom, !parms->keepratio);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// template helpers
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void ListEnd(Va_List &tags)
|
||||
{
|
||||
va_end(tags.list);
|
||||
}
|
||||
|
||||
static int ListGetInt(Va_List &tags)
|
||||
{
|
||||
return va_arg(tags.list, int);
|
||||
}
|
||||
|
||||
static inline double ListGetDouble(Va_List &tags)
|
||||
{
|
||||
return va_arg(tags.list, double);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Main taglist parsing
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool ParseDrawTextureTags(FTexture *img, double x, double y, uint32_t tag, Va_List& tags, DrawParms *parms, bool fortext)
|
||||
{
|
||||
int boolval;
|
||||
int intval;
|
||||
bool translationset = false;
|
||||
bool fillcolorset = false;
|
||||
|
||||
if (!fortext)
|
||||
{
|
||||
if (img == NULL)
|
||||
{
|
||||
ListEnd(tags);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Do some sanity checks on the coordinates.
|
||||
if (x < -16383 || x > 16383 || y < -16383 || y > 16383)
|
||||
{
|
||||
ListEnd(tags);
|
||||
return false;
|
||||
}
|
||||
|
||||
parms->fortext = fortext;
|
||||
parms->windowleft = 0;
|
||||
parms->windowright = INT_MAX;
|
||||
parms->dclip = screen->GetHeight();
|
||||
parms->uclip = 0;
|
||||
parms->lclip = 0;
|
||||
parms->rclip = screen->GetWidth();
|
||||
parms->left = INT_MAX;
|
||||
parms->top = INT_MAX;
|
||||
parms->destwidth = INT_MAX;
|
||||
parms->destheight = INT_MAX;
|
||||
parms->Alpha = 1.f;
|
||||
parms->fillcolor = -1;
|
||||
parms->colorOverlay = 0;
|
||||
parms->alphaChannel = false;
|
||||
parms->flipX = false;
|
||||
parms->flipY = false;
|
||||
parms->color = 0xffffffff;
|
||||
//parms->shadowAlpha = 0;
|
||||
parms->shadowColor = 0;
|
||||
parms->virtWidth = screen->GetWidth();
|
||||
parms->virtHeight = screen->GetHeight();
|
||||
parms->keepratio = false;
|
||||
parms->style.BlendOp = 255; // Dummy "not set" value
|
||||
parms->masked = true;
|
||||
parms->bilinear = false;
|
||||
parms->desaturate = 0;
|
||||
parms->cleanmode = DTA_Base;
|
||||
parms->scalex = parms->scaley = 1;
|
||||
parms->cellx = parms->celly = 0;
|
||||
parms->maxstrlen = INT_MAX;
|
||||
parms->virtBottom = false;
|
||||
parms->srcx = 0.;
|
||||
parms->srcy = 0.;
|
||||
parms->srcwidth = 1.;
|
||||
parms->srcheight = 1.;
|
||||
parms->burn = false;
|
||||
parms->monospace = EMonospacing::Off;
|
||||
parms->spacing = 0;
|
||||
parms->remap = 0;
|
||||
|
||||
// Parse the tag list for attributes. (For floating point attributes,
|
||||
// consider that the C ABI dictates that all floats be promoted to
|
||||
// doubles when passed as function arguments.)
|
||||
while (tag != TAG_DONE)
|
||||
{
|
||||
switch (tag)
|
||||
{
|
||||
default:
|
||||
ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_DestWidth:
|
||||
assert(fortext == false);
|
||||
if (fortext) return false;
|
||||
parms->cleanmode = DTA_Base;
|
||||
parms->destwidth = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_DestWidthF:
|
||||
assert(fortext == false);
|
||||
if (fortext) return false;
|
||||
parms->cleanmode = DTA_Base;
|
||||
parms->destwidth = ListGetDouble(tags);
|
||||
break;
|
||||
|
||||
case DTA_DestHeight:
|
||||
assert(fortext == false);
|
||||
if (fortext) return false;
|
||||
parms->cleanmode = DTA_Base;
|
||||
parms->destheight = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_DestHeightF:
|
||||
assert(fortext == false);
|
||||
if (fortext) return false;
|
||||
parms->cleanmode = DTA_Base;
|
||||
parms->destheight = ListGetDouble(tags);
|
||||
break;
|
||||
|
||||
case DTA_Clean:
|
||||
boolval = ListGetInt(tags);
|
||||
if (boolval)
|
||||
{
|
||||
parms->scalex = 1;
|
||||
parms->scaley = 1;
|
||||
parms->cleanmode = tag;
|
||||
}
|
||||
break;
|
||||
|
||||
case DTA_CleanNoMove:
|
||||
boolval = ListGetInt(tags);
|
||||
if (boolval)
|
||||
{
|
||||
parms->scalex = CleanXfac;
|
||||
parms->scaley = CleanYfac;
|
||||
parms->cleanmode = tag;
|
||||
}
|
||||
break;
|
||||
|
||||
case DTA_CleanNoMove_1:
|
||||
boolval = ListGetInt(tags);
|
||||
if (boolval)
|
||||
{
|
||||
parms->scalex = CleanXfac_1;
|
||||
parms->scaley = CleanYfac_1;
|
||||
parms->cleanmode = tag;
|
||||
}
|
||||
break;
|
||||
|
||||
case DTA_320x200:
|
||||
boolval = ListGetInt(tags);
|
||||
if (boolval)
|
||||
{
|
||||
parms->cleanmode = DTA_Base;
|
||||
parms->scalex = 1;
|
||||
parms->scaley = 1;
|
||||
parms->virtWidth = 320;
|
||||
parms->virtHeight = 200;
|
||||
}
|
||||
break;
|
||||
|
||||
case DTA_Bottom320x200:
|
||||
boolval = ListGetInt(tags);
|
||||
if (boolval)
|
||||
{
|
||||
parms->cleanmode = DTA_Base;
|
||||
parms->scalex = 1;
|
||||
parms->scaley = 1;
|
||||
parms->virtWidth = 320;
|
||||
parms->virtHeight = 200;
|
||||
}
|
||||
parms->virtBottom = true;
|
||||
break;
|
||||
|
||||
case DTA_HUDRules:
|
||||
intval = ListGetInt(tags);
|
||||
parms->cleanmode = intval == HUD_HorizCenter ? DTA_HUDRulesC : DTA_HUDRules;
|
||||
break;
|
||||
|
||||
case DTA_VirtualWidth:
|
||||
parms->cleanmode = DTA_Base;
|
||||
parms->virtWidth = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_VirtualWidthF:
|
||||
parms->cleanmode = DTA_Base;
|
||||
parms->virtWidth = ListGetDouble(tags);
|
||||
break;
|
||||
|
||||
case DTA_VirtualHeight:
|
||||
parms->cleanmode = DTA_Base;
|
||||
parms->virtHeight = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_VirtualHeightF:
|
||||
parms->cleanmode = DTA_Base;
|
||||
parms->virtHeight = ListGetDouble(tags);
|
||||
break;
|
||||
|
||||
case DTA_Fullscreen:
|
||||
boolval = ListGetInt(tags);
|
||||
if (boolval)
|
||||
{
|
||||
assert(fortext == false);
|
||||
if (img == NULL) return false;
|
||||
parms->cleanmode = DTA_Fullscreen;
|
||||
parms->virtWidth = img->GetWidth();
|
||||
parms->virtHeight = img->GetHeight();
|
||||
}
|
||||
break;
|
||||
|
||||
case DTA_Alpha:
|
||||
parms->Alpha = (float)(std::min<double>(1., ListGetDouble(tags)));
|
||||
break;
|
||||
|
||||
case DTA_AlphaChannel:
|
||||
parms->alphaChannel = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_FillColor:
|
||||
parms->fillcolor = ListGetInt(tags);
|
||||
if (parms->fillcolor != ~0u)
|
||||
{
|
||||
fillcolorset = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case DTA_TranslationIndex:
|
||||
parms->remap = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_ColorOverlay:
|
||||
parms->colorOverlay = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_Color:
|
||||
parms->color = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_FlipX:
|
||||
parms->flipX = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_FlipY:
|
||||
parms->flipY = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_SrcX:
|
||||
parms->srcx = ListGetDouble(tags) / img->GetWidth();
|
||||
break;
|
||||
|
||||
case DTA_SrcY:
|
||||
parms->srcy = ListGetDouble(tags) / img->GetHeight();
|
||||
break;
|
||||
|
||||
case DTA_SrcWidth:
|
||||
parms->srcwidth = ListGetDouble(tags) / img->GetWidth();
|
||||
break;
|
||||
|
||||
case DTA_SrcHeight:
|
||||
parms->srcheight = ListGetDouble(tags) / img->GetHeight();
|
||||
break;
|
||||
|
||||
case DTA_TopOffset:
|
||||
assert(fortext == false);
|
||||
if (fortext) return false;
|
||||
parms->top = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_TopOffsetF:
|
||||
assert(fortext == false);
|
||||
if (fortext) return false;
|
||||
parms->top = ListGetDouble(tags);
|
||||
break;
|
||||
|
||||
case DTA_LeftOffset:
|
||||
assert(fortext == false);
|
||||
if (fortext) return false;
|
||||
parms->left = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_LeftOffsetF:
|
||||
assert(fortext == false);
|
||||
if (fortext) return false;
|
||||
parms->left = ListGetDouble(tags);
|
||||
break;
|
||||
|
||||
case DTA_CenterOffset:
|
||||
assert(fortext == false);
|
||||
if (fortext) return false;
|
||||
if (ListGetInt(tags))
|
||||
{
|
||||
parms->left = img->GetWidth() * 0.5;
|
||||
parms->top = img->GetHeight() * 0.5;
|
||||
}
|
||||
break;
|
||||
|
||||
case DTA_CenterBottomOffset:
|
||||
assert(fortext == false);
|
||||
if (fortext) return false;
|
||||
if (ListGetInt(tags))
|
||||
{
|
||||
parms->left = img->GetWidth() * 0.5;
|
||||
parms->top = img->GetHeight();
|
||||
}
|
||||
break;
|
||||
|
||||
case DTA_WindowLeft:
|
||||
assert(fortext == false);
|
||||
if (fortext) return false;
|
||||
parms->windowleft = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_WindowLeftF:
|
||||
assert(fortext == false);
|
||||
if (fortext) return false;
|
||||
parms->windowleft = ListGetDouble(tags);
|
||||
break;
|
||||
|
||||
case DTA_WindowRight:
|
||||
assert(fortext == false);
|
||||
if (fortext) return false;
|
||||
parms->windowright = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_WindowRightF:
|
||||
assert(fortext == false);
|
||||
if (fortext) return false;
|
||||
parms->windowright = ListGetDouble(tags);
|
||||
break;
|
||||
|
||||
case DTA_ClipTop:
|
||||
parms->uclip = ListGetInt(tags);
|
||||
if (parms->uclip < 0)
|
||||
{
|
||||
parms->uclip = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case DTA_ClipBottom:
|
||||
parms->dclip = ListGetInt(tags);
|
||||
if (parms->dclip > screen->GetHeight())
|
||||
{
|
||||
parms->dclip = screen->GetHeight();
|
||||
}
|
||||
break;
|
||||
|
||||
case DTA_ClipLeft:
|
||||
parms->lclip = ListGetInt(tags);
|
||||
if (parms->lclip < 0)
|
||||
{
|
||||
parms->lclip = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case DTA_ClipRight:
|
||||
parms->rclip = ListGetInt(tags);
|
||||
if (parms->rclip > screen->GetWidth())
|
||||
{
|
||||
parms->rclip = screen->GetWidth();
|
||||
}
|
||||
break;
|
||||
|
||||
case DTA_ShadowAlpha:
|
||||
//parms->shadowAlpha = (float)std::min(1., ListGetDouble(tags));
|
||||
break;
|
||||
|
||||
case DTA_ShadowColor:
|
||||
parms->shadowColor = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_Shadow:
|
||||
boolval = ListGetInt(tags);
|
||||
if (boolval)
|
||||
{
|
||||
//parms->shadowAlpha = 0.5;
|
||||
parms->shadowColor = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
//parms->shadowAlpha = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case DTA_Masked:
|
||||
parms->masked = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_BilinearFilter:
|
||||
parms->bilinear = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_KeepRatio:
|
||||
// I think this is a terribly misleading name, since it actually turns
|
||||
// *off* aspect ratio correction.
|
||||
parms->keepratio = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_RenderStyle:
|
||||
parms->style.AsDWORD = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_LegacyRenderStyle: // mainly for ZScript which does not handle FRenderStyle that well.
|
||||
parms->style = (ERenderStyle)ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_Desaturate:
|
||||
parms->desaturate = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_TextLen:
|
||||
parms->maxstrlen = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_CellX:
|
||||
parms->cellx = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_CellY:
|
||||
parms->celly = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_Monospace:
|
||||
parms->monospace = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_Spacing:
|
||||
parms->spacing = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_Burn:
|
||||
parms->burn = true;
|
||||
break;
|
||||
|
||||
}
|
||||
tag = ListGetInt(tags);
|
||||
}
|
||||
ListEnd(tags);
|
||||
|
||||
if (parms->uclip >= parms->dclip || parms->lclip >= parms->rclip)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (img != NULL)
|
||||
{
|
||||
SetTextureParms(parms, img, x, y);
|
||||
|
||||
if (parms->destwidth <= 0 || parms->destheight <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (parms->style.BlendOp == 255)
|
||||
{
|
||||
if (fillcolorset)
|
||||
{
|
||||
if (parms->alphaChannel)
|
||||
{
|
||||
parms->style = STYLE_Shaded;
|
||||
}
|
||||
else if (parms->Alpha < 1.f)
|
||||
{
|
||||
parms->style = STYLE_TranslucentStencil;
|
||||
}
|
||||
else
|
||||
{
|
||||
parms->style = STYLE_Stencil;
|
||||
}
|
||||
}
|
||||
else if (parms->Alpha < 1.f)
|
||||
{
|
||||
parms->style = STYLE_Translucent;
|
||||
}
|
||||
else
|
||||
{
|
||||
parms->style = STYLE_Normal;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Coordinate conversion
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void VirtualToRealCoords(double &x, double &y, double &w, double &h,
|
||||
double vwidth, double vheight, bool vbottom, bool handleaspect)
|
||||
{
|
||||
float myratio = handleaspect ? ActiveRatio (screen->GetWidth(), screen->GetHeight()) : (4.0f / 3.0f);
|
||||
|
||||
// if 21:9 AR, map to 16:9 for all callers.
|
||||
// this allows for black bars and stops the stretching of fullscreen images
|
||||
if (myratio > 1.7f) {
|
||||
myratio = 16.0f / 9.0f;
|
||||
}
|
||||
|
||||
double right = x + w;
|
||||
double bottom = y + h;
|
||||
|
||||
if (myratio > 1.334f)
|
||||
{ // The target surface is either 16:9 or 16:10, so expand the
|
||||
// specified virtual size to avoid undesired stretching of the
|
||||
// image. Does not handle non-4:3 virtual sizes. I'll worry about
|
||||
// those if somebody expresses a desire to use them.
|
||||
x = (x - vwidth * 0.5) * screen->GetWidth() * 960 / (vwidth * AspectBaseWidth(myratio)) + screen->GetWidth() * 0.5;
|
||||
w = (right - vwidth * 0.5) * screen->GetWidth() * 960 / (vwidth * AspectBaseWidth(myratio)) + screen->GetWidth() * 0.5 - x;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = x * screen->GetWidth() / vwidth;
|
||||
w = right * screen->GetWidth() / vwidth - x;
|
||||
}
|
||||
if (AspectTallerThanWide(myratio))
|
||||
{ // The target surface is 5:4
|
||||
y = (y - vheight * 0.5) * screen->GetHeight() * 600 / (vheight * AspectBaseHeight(myratio)) + screen->GetHeight() * 0.5;
|
||||
h = (bottom - vheight * 0.5) * screen->GetHeight() * 600 / (vheight * AspectBaseHeight(myratio)) + screen->GetHeight() * 0.5 - y;
|
||||
if (vbottom)
|
||||
{
|
||||
y += (screen->GetHeight() - screen->GetHeight() * AspectMultiplier(myratio) / 48.0) * 0.5;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
y = y * screen->GetHeight() / vheight;
|
||||
h = bottom * screen->GetHeight() / vheight - y;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Helper for ActiveRatio and CheckRatio. Returns the forced ratio type, or -1 if none.
|
||||
int ActiveFakeRatio(int width, int height)
|
||||
{
|
||||
int fakeratio = -1;
|
||||
if ((vid_aspect >= 1) && (vid_aspect <= 6))
|
||||
{
|
||||
// [SP] User wants to force aspect ratio; let them.
|
||||
fakeratio = int(vid_aspect);
|
||||
if (fakeratio == 3)
|
||||
{
|
||||
fakeratio = 0;
|
||||
}
|
||||
else if (fakeratio == 5)
|
||||
{
|
||||
fakeratio = 3;
|
||||
}
|
||||
}
|
||||
else if (vid_aspect == 0)// && ViewportIsScaled43())
|
||||
{
|
||||
fakeratio = 0;
|
||||
}
|
||||
return fakeratio;
|
||||
}
|
||||
|
||||
// Active screen ratio based on cvars and size
|
||||
float ActiveRatio(int width, int height, float* trueratio)
|
||||
{
|
||||
static float forcedRatioTypes[] =
|
||||
{
|
||||
4 / 3.0f,
|
||||
16 / 9.0f,
|
||||
16 / 10.0f,
|
||||
17 / 10.0f,
|
||||
5 / 4.0f,
|
||||
17 / 10.0f,
|
||||
21 / 9.0f
|
||||
};
|
||||
|
||||
float ratio = width / (float)height;
|
||||
int fakeratio = ActiveFakeRatio(width, height);
|
||||
|
||||
if (trueratio)
|
||||
*trueratio = ratio;
|
||||
return (fakeratio != -1) ? forcedRatioTypes[fakeratio] : ratio;
|
||||
}
|
||||
|
||||
// Tries to guess the physical dimensions of the screen based on the
|
||||
// screen's pixel dimensions. Can return:
|
||||
// 0: 4:3
|
||||
// 1: 16:9
|
||||
// 2: 16:10
|
||||
// 3: 17:10
|
||||
// 4: 5:4
|
||||
// 5: 17:10 (redundant, never returned)
|
||||
// 6: 21:9
|
||||
int CheckRatio(int width, int height, int* trueratio)
|
||||
{
|
||||
float aspect = width / (float)height;
|
||||
|
||||
static std::pair<float, int> ratioTypes[] =
|
||||
{
|
||||
{ 21 / 9.0f , 6 },
|
||||
{ 16 / 9.0f , 1 },
|
||||
{ 17 / 10.0f , 3 },
|
||||
{ 16 / 10.0f , 2 },
|
||||
{ 4 / 3.0f , 0 },
|
||||
{ 5 / 4.0f , 4 },
|
||||
{ 0.0f, 0 }
|
||||
};
|
||||
|
||||
int ratio = ratioTypes[0].second;
|
||||
float distance = fabs(ratioTypes[0].first - aspect);
|
||||
for (int i = 1; ratioTypes[i].first != 0.0f; i++)
|
||||
{
|
||||
float d = fabs(ratioTypes[i].first - aspect);
|
||||
if (d < distance)
|
||||
{
|
||||
ratio = ratioTypes[i].second;
|
||||
distance = d;
|
||||
}
|
||||
}
|
||||
|
||||
int fakeratio = ActiveFakeRatio(width, height);
|
||||
if (fakeratio == -1)
|
||||
fakeratio = ratio;
|
||||
|
||||
if (trueratio)
|
||||
*trueratio = ratio;
|
||||
return fakeratio;
|
||||
}
|
||||
|
||||
int AspectBaseWidth(float aspect)
|
||||
{
|
||||
return (int)round(240.0f * aspect * 3.0f);
|
||||
}
|
||||
|
||||
int AspectBaseHeight(float aspect)
|
||||
{
|
||||
if (!AspectTallerThanWide(aspect))
|
||||
return (int)round(200.0f * (320.0f / (AspectBaseWidth(aspect) / 3.0f)) * 3.0f);
|
||||
else
|
||||
return (int)round((200.0f * (4.0f / 3.0f)) / aspect * 3.0f);
|
||||
}
|
||||
|
||||
double AspectPspriteOffset(float aspect)
|
||||
{
|
||||
if (!AspectTallerThanWide(aspect))
|
||||
return 0.0;
|
||||
else
|
||||
return ((4.0 / 3.0) / aspect - 1.0) * 97.5;
|
||||
}
|
||||
|
||||
int AspectMultiplier(float aspect)
|
||||
{
|
||||
if (!AspectTallerThanWide(aspect))
|
||||
return (int)round(320.0f / (AspectBaseWidth(aspect) / 3.0f) * 48.0f);
|
||||
else
|
||||
return (int)round(200.0f / (AspectBaseHeight(aspect) / 3.0f) * 48.0f);
|
||||
}
|
||||
|
||||
bool AspectTallerThanWide(float aspect)
|
||||
{
|
||||
return aspect < 1.333f;
|
||||
}
|
||||
|
||||
void ScaleWithAspect(int& w, int& h, int Width, int Height)
|
||||
{
|
||||
int resRatio = CheckRatio(Width, Height);
|
||||
int screenRatio;
|
||||
CheckRatio(w, h, &screenRatio);
|
||||
if (resRatio == screenRatio)
|
||||
return;
|
||||
|
||||
double yratio;
|
||||
switch (resRatio)
|
||||
{
|
||||
case 0: yratio = 4. / 3.; break;
|
||||
case 1: yratio = 16. / 9.; break;
|
||||
case 2: yratio = 16. / 10.; break;
|
||||
case 3: yratio = 17. / 10.; break;
|
||||
case 4: yratio = 5. / 4.; break;
|
||||
case 6: yratio = 21. / 9.; break;
|
||||
default: return;
|
||||
}
|
||||
double y = w / yratio;
|
||||
if (y > h)
|
||||
w = static_cast<int>(h * yratio);
|
||||
else
|
||||
h = static_cast<int>(y);
|
||||
}
|
||||
|
35
source/common/2d/v_draw.h
Normal file
35
source/common/2d/v_draw.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
|
||||
struct ScreenDummy
|
||||
{
|
||||
static int GetWidth() { return 1360; }
|
||||
static int GetHeight() { return 768; }
|
||||
};
|
||||
extern ScreenDummy* screen;
|
||||
|
||||
int GetUIScale(int altval);
|
||||
int GetConScale(int altval);
|
||||
|
||||
// [RH] Stretch values to make a 320x200 image best fit the screen
|
||||
// without using fractional steppings
|
||||
extern int CleanXfac, CleanYfac;
|
||||
|
||||
// [RH] Effective screen sizes that the above scale values give you
|
||||
extern int CleanWidth, CleanHeight;
|
||||
|
||||
// Above minus 1 (or 1, if they are already 1)
|
||||
extern int CleanXfac_1, CleanYfac_1, CleanWidth_1, CleanHeight_1;
|
||||
|
||||
|
||||
bool SetTextureParms(DrawParms *parms, FTexture *img, double xx, double yy);
|
||||
bool ParseDrawTextureTags(FTexture *img, double x, double y, uint32_t tag, Va_List& tags, DrawParms *parms, bool fortext);
|
||||
void VirtualToRealCoords(double &x, double &y, double &w, double &h, double vwidth, double vheight, bool vbottom, bool handleaspect);
|
||||
int ActiveFakeRatio(int width, int height);
|
||||
float ActiveRatio(int width, int height, float* trueratio);
|
||||
int CheckRatio(int width, int height, int* trueratio);
|
||||
int AspectBaseWidth(float aspect);;
|
||||
int AspectBaseHeight(float aspect);
|
||||
double AspectPspriteOffset(float aspect);
|
||||
int AspectMultiplier(float aspect);
|
||||
bool AspectTallerThanWide(float aspect);
|
||||
void ScaleWithAspect(int& w, int& h, int Width, int Height);
|
254
source/common/2d/v_drawtext.cpp
Normal file
254
source/common/2d/v_drawtext.cpp
Normal file
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
** 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 <wctype.h>
|
||||
|
||||
#include "utf8.h"
|
||||
#include "v_text.h"
|
||||
|
||||
#include "drawparms.h"
|
||||
#include "v_draw.h"
|
||||
#include "image.h"
|
||||
#include "v_2ddrawer.h"
|
||||
|
||||
class FFont;
|
||||
int NumTextColors;
|
||||
//==========================================================================
|
||||
//
|
||||
// Internal texture drawing function
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DrawTexture(F2DDrawer *drawer, FTexture* img, double x, double y, int tags_first, ...)
|
||||
{
|
||||
Va_List tags;
|
||||
va_start(tags.list, tags_first);
|
||||
DrawParms parms;
|
||||
|
||||
bool res = ParseDrawTextureTags(img, x, y, tags_first, tags, &parms, false);
|
||||
va_end(tags.list);
|
||||
if (!res)
|
||||
{
|
||||
return;
|
||||
}
|
||||
drawer->AddTexture(img, parms);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DrawChar
|
||||
//
|
||||
// Write a single character using the given font
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DrawChar (F2DDrawer* drawer, FFont *font, int normalcolor, double x, double y, int character, int tag_first, ...)
|
||||
{
|
||||
if (font == NULL)
|
||||
return;
|
||||
|
||||
if (normalcolor >= NumTextColors)
|
||||
normalcolor = CR_UNTRANSLATED;
|
||||
|
||||
FTexture *pic;
|
||||
int dummy;
|
||||
bool redirected;
|
||||
|
||||
#if 0
|
||||
if (NULL != (pic = font->GetChar (character, normalcolor, &dummy, &redirected)))
|
||||
{
|
||||
DrawParms parms;
|
||||
Va_List tags;
|
||||
va_start(tags.list, tag_first);
|
||||
bool res = ParseDrawTextureTags(pic, x, y, tag_first, tags, &parms, false);
|
||||
va_end(tags.list);
|
||||
if (!res)
|
||||
{
|
||||
return;
|
||||
}
|
||||
PalEntry color = 0xffffffff;
|
||||
parms.remap = redirected? nullptr : font->GetColorTranslation((EColorRange)normalcolor, &color);
|
||||
parms.color = PalEntry((color.a * parms.color.a) / 255, (color.r * parms.color.r) / 255, (color.g * parms.color.g) / 255, (color.b * parms.color.b) / 255);
|
||||
drawer->AddTexture(pic, parms);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DrawText
|
||||
//
|
||||
// Write a string using the given font
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
// This is only needed as a dummy. The code using wide strings does not need color control.
|
||||
EColorRange V_ParseFontColor(const char32_t *&color_value, int normalcolor, int boldcolor) { return CR_UNTRANSLATED; }
|
||||
|
||||
template<class chartype>
|
||||
void DrawTextCommon(F2DDrawer* drawer, FFont *font, int normalcolor, double x, double y, const chartype *string, DrawParms &parms)
|
||||
{
|
||||
#if 0
|
||||
int w;
|
||||
const chartype *ch;
|
||||
int c;
|
||||
double cx;
|
||||
double cy;
|
||||
int boldcolor;
|
||||
FRemapTable *range;
|
||||
int kerning;
|
||||
FTexture *pic;
|
||||
|
||||
if (parms.celly == 0) parms.celly = font->GetHeight() + 1;
|
||||
parms.celly *= parms.scaley;
|
||||
|
||||
if (normalcolor >= NumTextColors)
|
||||
normalcolor = CR_UNTRANSLATED;
|
||||
boldcolor = normalcolor ? normalcolor - 1 : NumTextColors - 1;
|
||||
|
||||
PalEntry colorparm = parms.color;
|
||||
PalEntry color = 0xffffffff;
|
||||
range = font->GetColorTranslation((EColorRange)normalcolor, &color);
|
||||
parms.color = PalEntry(colorparm.a, (color.r * colorparm.r) / 255, (color.g * colorparm.g) / 255, (color.b * colorparm.b) / 255);
|
||||
|
||||
kerning = font->GetDefaultKerning();
|
||||
|
||||
ch = string;
|
||||
cx = x;
|
||||
cy = y;
|
||||
|
||||
if (parms.monospace == EMonospacing::CellCenter)
|
||||
cx += parms.spacing / 2;
|
||||
else if (parms.monospace == EMonospacing::CellRight)
|
||||
cx += parms.spacing;
|
||||
|
||||
|
||||
auto currentcolor = normalcolor;
|
||||
while (ch - string < parms.maxstrlen)
|
||||
{
|
||||
c = GetCharFromString(ch);
|
||||
if (!c)
|
||||
break;
|
||||
|
||||
if (c == TEXTCOLOR_ESCAPE)
|
||||
{
|
||||
EColorRange newcolor = V_ParseFontColor(ch, normalcolor, boldcolor);
|
||||
if (newcolor != CR_UNDEFINED)
|
||||
{
|
||||
range = font->GetColorTranslation(newcolor, &color);
|
||||
parms.color = PalEntry(colorparm.a, (color.r * colorparm.r) / 255, (color.g * colorparm.g) / 255, (color.b * colorparm.b) / 255);
|
||||
currentcolor = newcolor;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
cx = x;
|
||||
cy += parms.celly;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool redirected = false;
|
||||
if (NULL != (pic = font->GetChar(c, currentcolor, &w, &redirected)))
|
||||
{
|
||||
parms.remap = redirected? nullptr : range;
|
||||
SetTextureParms(&parms, pic, cx, cy);
|
||||
if (parms.cellx)
|
||||
{
|
||||
w = parms.cellx;
|
||||
parms.destwidth = parms.cellx;
|
||||
parms.destheight = parms.celly;
|
||||
}
|
||||
if (parms.monospace == EMonospacing::CellLeft)
|
||||
parms.left = 0;
|
||||
else if (parms.monospace == EMonospacing::CellCenter)
|
||||
parms.left = w / 2.;
|
||||
else if (parms.monospace == EMonospacing::CellRight)
|
||||
parms.left = w;
|
||||
|
||||
drawer->AddTexture(pic, parms);
|
||||
}
|
||||
if (parms.monospace == EMonospacing::Off)
|
||||
{
|
||||
cx += (w + kerning + parms.spacing) * parms.scalex;
|
||||
}
|
||||
else
|
||||
{
|
||||
cx += (parms.spacing) * parms.scalex;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void DrawText(F2DDrawer* drawer, FFont *font, int normalcolor, double x, double y, const char *string, int tag_first, ...)
|
||||
{
|
||||
Va_List tags;
|
||||
DrawParms parms;
|
||||
|
||||
if (font == NULL || string == NULL)
|
||||
return;
|
||||
|
||||
va_start(tags.list, tag_first);
|
||||
bool res = ParseDrawTextureTags(nullptr, 0, 0, tag_first, tags, &parms, true);
|
||||
va_end(tags.list);
|
||||
if (!res)
|
||||
{
|
||||
return;
|
||||
}
|
||||
DrawTextCommon(drawer, font, normalcolor, x, y, (const uint8_t*)string, parms);
|
||||
}
|
||||
|
||||
void DrawText(F2DDrawer* drawer, FFont *font, int normalcolor, double x, double y, const char32_t *string, int tag_first, ...)
|
||||
{
|
||||
Va_List tags;
|
||||
DrawParms parms;
|
||||
|
||||
if (font == NULL || string == NULL)
|
||||
return;
|
||||
|
||||
va_start(tags.list, tag_first);
|
||||
bool res = ParseDrawTextureTags(nullptr, 0, 0, tag_first, tags, &parms, true);
|
||||
va_end(tags.list);
|
||||
if (!res)
|
||||
{
|
||||
return;
|
||||
}
|
||||
DrawTextCommon(drawer, font, normalcolor, x, y, string, parms);
|
||||
}
|
||||
|
124
source/common/2d/v_text.h
Normal file
124
source/common/2d/v_text.h
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
** v_text.h
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** 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.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __V_TEXT_H__
|
||||
#define __V_TEXT_H__
|
||||
|
||||
#include "zstring.h"
|
||||
class FFont;
|
||||
|
||||
struct FBrokenLines
|
||||
{
|
||||
unsigned Width;
|
||||
FString Text;
|
||||
};
|
||||
|
||||
#define TEXTCOLOR_ESCAPE '\034'
|
||||
#define TEXTCOLOR_ESCAPESTR "\034"
|
||||
|
||||
#define TEXTCOLOR_BRICK "\034A"
|
||||
#define TEXTCOLOR_TAN "\034B"
|
||||
#define TEXTCOLOR_GRAY "\034C"
|
||||
#define TEXTCOLOR_GREY "\034C"
|
||||
#define TEXTCOLOR_GREEN "\034D"
|
||||
#define TEXTCOLOR_BROWN "\034E"
|
||||
#define TEXTCOLOR_GOLD "\034F"
|
||||
#define TEXTCOLOR_RED "\034G"
|
||||
#define TEXTCOLOR_BLUE "\034H"
|
||||
#define TEXTCOLOR_ORANGE "\034I"
|
||||
#define TEXTCOLOR_WHITE "\034J"
|
||||
#define TEXTCOLOR_YELLOW "\034K"
|
||||
#define TEXTCOLOR_UNTRANSLATED "\034L"
|
||||
#define TEXTCOLOR_BLACK "\034M"
|
||||
#define TEXTCOLOR_LIGHTBLUE "\034N"
|
||||
#define TEXTCOLOR_CREAM "\034O"
|
||||
#define TEXTCOLOR_OLIVE "\034P"
|
||||
#define TEXTCOLOR_DARKGREEN "\034Q"
|
||||
#define TEXTCOLOR_DARKRED "\034R"
|
||||
#define TEXTCOLOR_DARKBROWN "\034S"
|
||||
#define TEXTCOLOR_PURPLE "\034T"
|
||||
#define TEXTCOLOR_DARKGRAY "\034U"
|
||||
#define TEXTCOLOR_CYAN "\034V"
|
||||
#define TEXTCOLOR_ICE "\034W"
|
||||
#define TEXTCOLOR_FIRE "\034X"
|
||||
#define TEXTCOLOR_SAPPHIRE "\034Y"
|
||||
#define TEXTCOLOR_TEAL "\034Z"
|
||||
|
||||
#define TEXTCOLOR_NORMAL "\034-"
|
||||
#define TEXTCOLOR_BOLD "\034+"
|
||||
|
||||
#define TEXTCOLOR_CHAT "\034*"
|
||||
#define TEXTCOLOR_TEAMCHAT "\034!"
|
||||
|
||||
enum EColorRange : int
|
||||
{
|
||||
CR_UNDEFINED = -1,
|
||||
CR_BRICK,
|
||||
CR_TAN,
|
||||
CR_GRAY,
|
||||
CR_GREY = CR_GRAY,
|
||||
CR_GREEN,
|
||||
CR_BROWN,
|
||||
CR_GOLD,
|
||||
CR_RED,
|
||||
CR_BLUE,
|
||||
CR_ORANGE,
|
||||
CR_WHITE,
|
||||
CR_YELLOW,
|
||||
CR_UNTRANSLATED,
|
||||
CR_BLACK,
|
||||
CR_LIGHTBLUE,
|
||||
CR_CREAM,
|
||||
CR_OLIVE,
|
||||
CR_DARKGREEN,
|
||||
CR_DARKRED,
|
||||
CR_DARKBROWN,
|
||||
CR_PURPLE,
|
||||
CR_DARKGRAY,
|
||||
CR_CYAN,
|
||||
CR_ICE,
|
||||
CR_FIRE,
|
||||
CR_SAPPHIRE,
|
||||
CR_TEAL,
|
||||
NUM_TEXT_COLORS,
|
||||
};
|
||||
|
||||
extern int NumTextColors;
|
||||
|
||||
TArray<FBrokenLines> V_BreakLines (FFont *font, int maxwidth, const uint8_t *str, bool preservecolor = false);
|
||||
inline TArray<FBrokenLines> V_BreakLines (FFont *font, int maxwidth, const char *str, bool preservecolor = false)
|
||||
{ return V_BreakLines (font, maxwidth, (const uint8_t *)str, preservecolor); }
|
||||
inline TArray<FBrokenLines> V_BreakLines (FFont *font, int maxwidth, const FString &str, bool preservecolor = false)
|
||||
{ return V_BreakLines (font, maxwidth, (const uint8_t *)str.GetChars(), preservecolor); }
|
||||
|
||||
#endif //__V_TEXT_H__
|
Loading…
Reference in a new issue