2019-10-20 06:07:12 +00:00
/*
* * gl_texture . cpp
* * high level GL texture interface
* *
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* * Copyright 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 .
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* *
* *
*/
2019-10-20 06:02:45 +00:00
# include "palette.h"
2013-05-15 02:17:17 +00:00
# include "build.h"
# include "hightile.h"
# include "polymost.h"
2019-10-10 21:29:13 +00:00
# include "textures.h"
# include "bitmap.h"
2019-11-05 22:35:38 +00:00
# include "v_font.h"
2019-10-10 21:29:13 +00:00
# include "../../glbackend/glbackend.h"
2019-03-01 08:51:50 +00:00
2019-10-23 19:11:37 +00:00
// Test CVARs.
2020-01-25 18:10:05 +00:00
CVAR ( Int , fixpalette , - 1 , 0 )
CVAR ( Int , fixpalswap , - 1 , 0 )
2019-10-17 22:20:27 +00:00
template < class T >
void FlipNonSquareBlock ( T * dst , const T * src , int x , int y , int srcpitch )
{
for ( int i = 0 ; i < x ; + + i )
2019-10-17 19:44:34 +00:00
{
2019-10-17 22:20:27 +00:00
for ( int j = 0 ; j < y ; + + j )
2019-10-17 19:44:34 +00:00
{
2019-10-17 22:20:27 +00:00
dst [ i * y + j ] = src [ i + j * srcpitch ] ;
}
}
}
2019-10-17 19:44:34 +00:00
2017-06-27 02:24:34 +00:00
2019-10-17 22:20:27 +00:00
//===========================================================================
//
// Create an indexed version of the requested texture
//
//===========================================================================
2019-10-17 19:44:34 +00:00
2019-10-18 09:37:07 +00:00
FHardwareTexture * GLInstance : : CreateIndexedTexture ( FTexture * tex )
2019-10-17 22:20:27 +00:00
{
auto siz = tex - > GetSize ( ) ;
2019-10-17 19:44:34 +00:00
2019-10-17 22:20:27 +00:00
const uint8_t * p = tex - > Get8BitPixels ( ) ;
TArray < uint8_t > store ( siz . x * siz . y , true ) ;
if ( ! p )
{
tex - > Create8BitPixels ( store . Data ( ) ) ;
p = store . Data ( ) ;
2019-10-17 19:44:34 +00:00
}
2019-10-17 22:20:27 +00:00
auto glpic = GLInterface . NewTexture ( ) ;
2019-10-19 21:14:36 +00:00
glpic - > CreateTexture ( siz . x , siz . y , FHardwareTexture : : Indexed , false ) ;
2019-10-17 22:20:27 +00:00
TArray < uint8_t > flipped ( siz . x * siz . y , true ) ;
FlipNonSquareBlock ( flipped . Data ( ) , p , siz . y , siz . x , siz . y ) ;
glpic - > LoadTexture ( flipped . Data ( ) ) ;
return glpic ;
}
//===========================================================================
2019-10-18 09:37:07 +00:00
//
// Create a true color version of the requested tile
2019-10-17 22:20:27 +00:00
//
//===========================================================================
2019-10-19 21:14:36 +00:00
FHardwareTexture * GLInstance : : CreateTrueColorTexture ( FTexture * tex , int palid , bool checkfulltransparency , bool rgb8bit )
2019-10-17 22:20:27 +00:00
{
2019-10-18 09:37:07 +00:00
auto palette = palid < 0 ? nullptr : palmanager . GetPaletteData ( palid ) ;
2019-12-01 20:43:54 +00:00
if ( palid > = 0 & & palette = = nullptr ) return nullptr ;
2020-02-18 19:43:16 +00:00
auto texbuffer = tex - > CreateTexBuffer ( palette , checkfulltransparency ? 0 : CTF_ProcessData ) ;
2019-10-18 09:37:07 +00:00
// Check if the texture is fully transparent. When creating a brightmap such textures can be discarded.
if ( checkfulltransparency )
2019-10-17 19:44:34 +00:00
{
2019-10-18 09:37:07 +00:00
int siz = texbuffer . mWidth * texbuffer . mHeight * 4 ;
bool found = false ;
for ( int i = 3 ; i < siz ; i + = 4 )
2019-10-17 19:44:34 +00:00
{
2019-10-18 09:37:07 +00:00
if ( texbuffer . mBuffer [ i ] > 0 )
{
found = true ;
break ;
}
2019-10-17 19:44:34 +00:00
}
2019-10-18 09:37:07 +00:00
if ( ! found ) return nullptr ;
2019-10-17 19:44:34 +00:00
}
2019-10-18 09:37:07 +00:00
auto glpic = GLInterface . NewTexture ( ) ;
2019-10-19 21:14:36 +00:00
if ( ! rgb8bit )
glpic - > CreateTexture ( texbuffer . mWidth , texbuffer . mHeight , FHardwareTexture : : TrueColor , true ) ;
else
glpic - > CreateTexture ( texbuffer . mWidth , texbuffer . mHeight , FHardwareTexture : : Brightmap , false ) ; // Use a more memory friendly format for simple brightmaps.
2019-10-18 09:37:07 +00:00
glpic - > LoadTexture ( texbuffer . mBuffer ) ;
return glpic ;
}
//===========================================================================
//
// Retrieve the texture to be used.
//
//===========================================================================
FHardwareTexture * GLInstance : : LoadTexture ( FTexture * tex , int textype , int palid )
{
if ( textype = = TT_INDEXED ) palid = - 1 ;
auto phwtex = tex - > GetHardwareTexture ( palid ) ;
if ( phwtex ) return * phwtex ;
FHardwareTexture * hwtex ;
if ( textype = = TT_INDEXED )
2019-10-18 17:06:57 +00:00
hwtex = CreateIndexedTexture ( tex ) ;
2019-10-18 09:37:07 +00:00
else
2019-10-19 21:14:36 +00:00
hwtex = CreateTrueColorTexture ( tex , textype = = TT_HICREPLACE ? - 1 : palid , textype = = TT_BRIGHTMAP , textype = = TT_BRIGHTMAP ) ;
2019-10-18 09:37:07 +00:00
2019-11-10 18:42:26 +00:00
if ( hwtex ) tex - > SetHardwareTexture ( palid , hwtex ) ;
2019-10-18 09:37:07 +00:00
return hwtex ;
2019-10-17 22:20:27 +00:00
}
2019-10-17 19:44:34 +00:00
2019-10-17 22:20:27 +00:00
//===========================================================================
//
2019-10-18 12:04:32 +00:00
// Sets a texture for rendering. This should be the ONLY place to bind in-game textures
2019-10-17 22:20:27 +00:00
//
//===========================================================================
2019-10-17 19:44:34 +00:00
2020-01-18 21:41:08 +00:00
bool GLInstance : : SetTextureInternal ( int picnum , FTexture * tex , int palette , int method , int sampleroverride , FTexture * det , float detscale , FTexture * glow )
2019-10-17 22:20:27 +00:00
{
2019-10-18 17:29:35 +00:00
if ( tex - > GetWidth ( ) < = 0 | | tex - > GetHeight ( ) < = 0 ) return false ;
2020-01-25 18:10:05 +00:00
int usepalette = fixpalette > = 0 ? fixpalette : curbasepal ;
int usepalswap = fixpalswap > = 0 ? fixpalswap : palette ;
2019-10-17 22:20:27 +00:00
GLInterface . SetPalette ( usepalette ) ;
GLInterface . SetPalswap ( usepalswap ) ;
2019-12-30 19:44:37 +00:00
bool texbound [ 3 ] = { } ;
2020-01-18 21:41:08 +00:00
int MatrixChange = 0 ;
2019-10-17 19:44:34 +00:00
2020-02-04 19:40:10 +00:00
TextureType = hw_int_useindexedcolortextures ? TT_INDEXED : TT_TRUECOLOR ;
2019-10-17 19:44:34 +00:00
2019-10-17 22:20:27 +00:00
int lookuppal = 0 ;
VSMatrix texmat ;
2019-10-17 19:44:34 +00:00
2020-02-11 19:55:47 +00:00
GLInterface . SetBasepalTint ( 0xffffff ) ;
2020-01-11 21:18:06 +00:00
auto & h = hictinting [ palette ] ;
bool applytint = false ;
auto rep = ( hw_hightile & & ! ( h . f & HICTINT_ALWAYSUSEART ) ) ? tex - > FindReplacement ( palette ) : nullptr ;
2019-10-17 22:20:27 +00:00
if ( rep )
{
2020-02-11 19:55:47 +00:00
if ( usepalette ! = 0 )
{
// This is a global setting for the entire scene, so let's do it here, right at the start. (Fixme: Store this in a static table instead of reusing the same entry for all palettes.)
auto & hh = hictinting [ MAXPALOOKUPS - 1 ] ;
// This sets a tinting color for global palettes, e.g. water or slime - only used for hires replacements (also an option for low-resource hardware where duplicating the textures may be problematic.)
GLInterface . SetBasepalTint ( hh . tint ) ;
}
2019-10-17 22:20:27 +00:00
tex = rep - > faces [ 0 ] ;
TextureType = TT_HICREPLACE ;
2020-01-11 21:18:06 +00:00
if ( rep - > palnum ! = palette | | ( h . f & HICTINT_APPLYOVERALTPAL ) ) applytint = true ;
2019-10-17 22:20:27 +00:00
}
else
{
// Only look up the palette if we really want to use it (i.e. when creating a true color texture of an ART tile.)
2019-11-10 18:42:26 +00:00
if ( TextureType = = TT_TRUECOLOR )
{
2020-01-11 21:18:06 +00:00
// Tinting is not used on indexed textures
if ( h . f & ( HICTINT_ALWAYSUSEART | HICTINT_USEONART ) )
{
applytint = true ;
if ( ! ( h . f & HICTINT_APPLYOVERPALSWAP ) ) usepalswap = 0 ;
}
2020-01-26 09:58:00 +00:00
lookuppal = palmanager . LookupPalette ( usepalette , usepalswap , false , fixpalette < 0 ? ! ! ( curpaletteflags & Pal_Fullscreen ) : 0 ) ;
2019-11-10 18:42:26 +00:00
}
2019-10-17 22:20:27 +00:00
}
2019-10-17 19:44:34 +00:00
2020-01-11 21:18:06 +00:00
// This is intentionally the same value for both parameters. The shader does not use the same uniform for modulation and overlay colors.
2020-02-05 19:02:50 +00:00
if ( applytint & & h . f )
GLInterface . SetTinting ( h . f , h . tint , h . tint ) ;
2020-01-11 21:18:06 +00:00
else GLInterface . SetTinting ( - 1 , 0xffffff , 0xffffff ) ;
2019-10-17 22:20:27 +00:00
// Load the main texture
auto mtex = LoadTexture ( tex , TextureType , lookuppal ) ;
if ( mtex )
{
2019-10-19 18:25:58 +00:00
auto sampler = ( method & DAMETH_CLAMPED ) ? ( sampleroverride ! = - 1 ? sampleroverride : SamplerClampXY ) : SamplerRepeat ;
2019-10-19 22:31:27 +00:00
if ( TextureType = = TT_INDEXED )
{
sampler = sampler + SamplerNoFilterRepeat - SamplerRepeat ;
}
2019-12-30 19:44:37 +00:00
UseDetailMapping ( false ) ;
UseGlowMapping ( false ) ;
2019-11-10 18:42:26 +00:00
UseBrightmaps ( false ) ;
2019-10-17 19:44:34 +00:00
2019-10-17 22:20:27 +00:00
BindTexture ( 0 , mtex , sampler ) ;
2020-01-18 21:41:08 +00:00
// Needs a) testing and b) verification for correctness. This doesn't look like it makes sense.
if ( rep & & ( rep - > scale . x ! = 1.0f | | rep - > scale . y ! = 1.0f ) )
2019-10-17 22:20:27 +00:00
{
2020-01-18 21:41:08 +00:00
//texmat.loadIdentity();
//texmat.scale(rep->scale.x, rep->scale.y, 1.0f);
//GLInterface.SetMatrix(Matrix_Texture, &texmat);
2019-10-17 22:20:27 +00:00
}
2019-10-17 19:44:34 +00:00
2019-10-17 22:20:27 +00:00
// Also load additional layers needed for this texture.
2019-10-23 19:11:37 +00:00
if ( hw_detailmapping & & hw_hightile )
2019-10-17 22:20:27 +00:00
{
2019-10-18 12:04:32 +00:00
float detscalex = detscale , detscaley = detscale ;
if ( ! ( method & DAMETH_MODEL ) )
2019-10-17 22:20:27 +00:00
{
2019-10-18 17:06:57 +00:00
auto drep = tex - > FindReplacement ( DETAILPAL ) ;
2019-10-18 12:04:32 +00:00
if ( drep )
{
det = drep - > faces [ 0 ] ;
detscalex = drep - > scale . x ;
detscaley = drep - > scale . y ;
}
}
if ( det )
{
auto htex = LoadTexture ( det , TT_HICREPLACE , 0 ) ;
2019-10-17 22:20:27 +00:00
UseDetailMapping ( true ) ;
BindTexture ( 3 , htex , SamplerRepeat ) ;
2019-12-30 19:44:37 +00:00
texbound [ 0 ] = true ;
2019-10-17 22:20:27 +00:00
2020-01-18 21:41:08 +00:00
/* todo: instead of a matrix, just pass a two-component uniform. Using a full matrix here is problematic.
2019-10-18 12:04:32 +00:00
if ( MatrixChange & 1 ) MatrixChange | = 2 ;
else texmat . loadIdentity ( ) ;
if ( ( detscalex ! = 1.0f ) | | ( detscaley ! = 1.0f ) )
2019-10-17 22:20:27 +00:00
{
2019-10-18 12:04:32 +00:00
texmat . scale ( detscalex , detscaley , 1.0f ) ;
2019-10-17 22:20:27 +00:00
MatrixChange | = 2 ;
}
if ( MatrixChange & 2 ) GLInterface . SetMatrix ( Matrix_Detail , & texmat ) ;
2020-01-18 21:41:08 +00:00
*/
2019-10-17 22:20:27 +00:00
}
}
2019-10-23 19:11:37 +00:00
if ( hw_glowmapping & & hw_hightile )
2019-10-17 22:20:27 +00:00
{
2019-10-18 12:04:32 +00:00
if ( ! ( method & DAMETH_MODEL ) )
2019-10-17 22:20:27 +00:00
{
2019-12-30 19:44:37 +00:00
auto drep = tex - > FindReplacement ( GLOWPAL ) ;
2019-10-18 12:04:32 +00:00
if ( drep )
{
glow = drep - > faces [ 0 ] ;
}
}
if ( glow )
{
auto htex = LoadTexture ( glow , TT_HICREPLACE , 0 ) ;
2019-10-17 22:20:27 +00:00
UseGlowMapping ( true ) ;
BindTexture ( 4 , htex , SamplerRepeat ) ;
2019-12-30 19:44:37 +00:00
texbound [ 1 ] = true ;
2019-10-17 22:20:27 +00:00
}
}
2019-11-15 19:51:02 +00:00
# if 1
2020-02-26 17:10:06 +00:00
if ( ! ( tex - > PicAnim . sf & PICANM_NOFULLBRIGHT_BIT ) & & ! ( globalflags & GLOBAL_NO_GL_FULLBRIGHT ) & & ! tex - > NoBrightmapFlag [ usepalswap ] & & ! ( curpaletteflags & ( Pal_Fullscreen | Pal_2D ) ) )
2019-10-17 22:20:27 +00:00
{
2019-10-18 09:37:07 +00:00
if ( TextureType = = TT_HICREPLACE )
{
2019-10-18 17:06:57 +00:00
auto brep = tex - > FindReplacement ( BRIGHTPAL ) ;
2019-10-18 09:37:07 +00:00
if ( brep )
{
2019-11-24 23:02:00 +00:00
LoadTexture ( brep - > faces [ 0 ] , TT_HICREPLACE , 0 ) ;
2019-11-10 18:42:26 +00:00
UseBrightmaps ( true ) ;
2019-10-18 09:37:07 +00:00
BindTexture ( 5 , mtex , sampler ) ;
2019-12-30 19:44:37 +00:00
texbound [ 2 ] = true ;
2019-10-18 09:37:07 +00:00
}
2019-11-10 18:42:26 +00:00
else
{
tex - > PicAnim . sf | = PICANM_NOFULLBRIGHT_BIT ;
}
2019-10-18 09:37:07 +00:00
}
else if ( TextureType = = TT_TRUECOLOR )
{
lookuppal = palmanager . LookupPalette ( usepalette , usepalswap , true ) ;
if ( lookuppal > = 0 )
{
auto htex = LoadTexture ( tex , TT_BRIGHTMAP , lookuppal ) ;
2019-11-10 18:42:26 +00:00
if ( htex = = nullptr )
{
// Flag the texture as not being brightmapped for the given palette
tex - > NoBrightmapFlag . Set ( usepalswap ) ;
}
else
{
UseBrightmaps ( true ) ;
2019-11-11 22:54:09 +00:00
BindTexture ( 5 , htex , sampler ) ;
2019-12-30 19:44:37 +00:00
texbound [ 2 ] = true ;
2019-11-10 18:42:26 +00:00
}
2019-10-18 09:37:07 +00:00
}
}
2019-10-17 22:20:27 +00:00
}
2019-12-30 19:44:37 +00:00
if ( ! texbound [ 0 ] ) UnbindTexture ( 3 ) ;
if ( ! texbound [ 1 ] ) UnbindTexture ( 4 ) ;
if ( ! texbound [ 2 ] ) UnbindTexture ( 5 ) ;
2019-11-15 19:51:02 +00:00
# endif
2019-10-17 22:20:27 +00:00
}
2019-10-18 17:06:57 +00:00
else return false ;
2019-10-17 19:44:34 +00:00
2019-10-19 22:31:27 +00:00
float al = 0.5f ;
2019-10-17 22:20:27 +00:00
if ( TextureType = = TT_HICREPLACE )
{
2019-10-19 08:21:07 +00:00
al = ( ( unsigned ) picnum < MAXTILES & & alphahackarray [ picnum ] ! = 0 ) ? alphahackarray [ picnum ] * ( 1.f / 255.f ) :
2019-11-10 09:01:31 +00:00
( tex - > alphaThreshold > = 0 ? tex - > alphaThreshold * ( 1.f / 255.f ) : 0.f ) ;
2019-10-17 22:20:27 +00:00
}
2019-10-17 19:44:34 +00:00
GLInterface . SetAlphaThreshold ( al ) ;
2019-10-18 17:06:57 +00:00
return true ;
2019-10-17 19:44:34 +00:00
}
2017-06-27 02:24:34 +00:00
2013-05-15 02:18:27 +00:00
2019-11-05 22:35:38 +00:00
//===========================================================================
//
// Sets a named texture for 2D rendering. In this case the palette is
// a direct index into the palette map.
//
//===========================================================================
bool GLInstance : : SetNamedTexture ( FTexture * tex , int palette , int sampler )
{
auto mtex = LoadTexture ( tex , palette > = 0 ? TT_TRUECOLOR : TT_HICREPLACE , palette ) ;
if ( ! mtex ) return false ;
BindTexture ( 0 , mtex , sampler ) ;
2019-11-10 09:01:31 +00:00
GLInterface . SetAlphaThreshold ( tex - > isTranslucent ( ) ? 0.f : 0.5f ) ;
2019-11-05 22:35:38 +00:00
return true ;
}