forked from Mirrors/openclonk
Shader landscape rendering, first simple version (scaler, shading)
parent
c84458f451
commit
a02ccafc4d
|
@ -196,6 +196,9 @@ set(OC_CLONK_SOURCES
|
||||||
src/game/C4Physics.h
|
src/game/C4Physics.h
|
||||||
src/game/landscape/C4Landscape.cpp
|
src/game/landscape/C4Landscape.cpp
|
||||||
src/game/landscape/C4Landscape.h
|
src/game/landscape/C4Landscape.h
|
||||||
|
src/game/landscape/C4LandscapeRender.cpp
|
||||||
|
src/game/landscape/C4LandscapeRenderClassic.cpp
|
||||||
|
src/game/landscape/C4LandscapeRender.h
|
||||||
src/game/landscape/C4Map.cpp
|
src/game/landscape/C4Map.cpp
|
||||||
src/game/landscape/C4MapCreatorS2.cpp
|
src/game/landscape/C4MapCreatorS2.cpp
|
||||||
src/game/landscape/C4MapCreatorS2.h
|
src/game/landscape/C4MapCreatorS2.h
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
|
||||||
|
#version 130
|
||||||
|
|
||||||
|
// Input textures
|
||||||
|
uniform sampler2D landscapeTex[1];
|
||||||
|
uniform sampler2D scalerTex;
|
||||||
|
uniform sampler3D materialTex;
|
||||||
|
|
||||||
|
// Resolution of the landscape texture
|
||||||
|
uniform vec2 resolution;
|
||||||
|
|
||||||
|
// Texture map
|
||||||
|
uniform float matTexMap[256];
|
||||||
|
|
||||||
|
// Expected parameters for the scaler
|
||||||
|
const vec2 scalerStepX = vec2(1.0 / 8.0, 0.0);
|
||||||
|
const vec2 scalerStepY = vec2(0.0, 1.0 / 32.0);
|
||||||
|
const vec2 scalerOffset = vec2(0.0, 0.0) + scalerStepX / 3.0 + scalerStepY / 3.0;
|
||||||
|
const vec2 scalerPixel = vec2(scalerStepX.x, scalerStepY.y) / 3.0;
|
||||||
|
|
||||||
|
out vec4 gl_FragColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// full pixel steps in the landscape texture (depends on landscape resolution)
|
||||||
|
vec2 fullStep = vec2(1.0, 1.0) / resolution;
|
||||||
|
vec2 fullStepX = vec2(fullStep.x, 0.0);
|
||||||
|
vec2 fullStepY = vec2(0.0, fullStep.y);
|
||||||
|
|
||||||
|
// calculate pixel position in landscape, find center of current pixel
|
||||||
|
vec2 pixelCoo = gl_TexCoord[0].st * resolution;
|
||||||
|
vec2 centerCoo = (floor(pixelCoo) + vec2(0.5, 0.5)) / resolution;
|
||||||
|
|
||||||
|
// our pixel color (with and without interpolation)
|
||||||
|
vec4 lpx = texture2D(landscapeTex[0], centerCoo);
|
||||||
|
vec4 rlpx = texture2D(landscapeTex[0], gl_TexCoord[0].st);
|
||||||
|
|
||||||
|
// gen2 other coordinate calculation (TODO: scaler map)
|
||||||
|
vec2 otherCoo = centerCoo + fullStep * round(normalize(mod(pixelCoo, vec2(1.0, 1.0)) - vec2(0.5, 0.5)));
|
||||||
|
vec4 lopx = texture2D(landscapeTex[0], otherCoo);
|
||||||
|
|
||||||
|
// find scaler coordinate
|
||||||
|
vec2 scalerCoo = scalerOffset + mod(pixelCoo, vec2(1.0, 1.0)) * scalerPixel;
|
||||||
|
|
||||||
|
if(texture2D(landscapeTex[0], centerCoo - fullStepX - fullStepY).r == lpx.r)
|
||||||
|
scalerCoo += scalerStepX;
|
||||||
|
if(texture2D(landscapeTex[0], centerCoo - fullStepY).r == lpx.r)
|
||||||
|
scalerCoo += 2.0 * scalerStepX;
|
||||||
|
if(texture2D(landscapeTex[0], centerCoo + fullStepX - fullStepY).r == lpx.r)
|
||||||
|
scalerCoo += 4.0 * scalerStepX;
|
||||||
|
|
||||||
|
if(texture2D(landscapeTex[0], centerCoo - fullStepX ).r == lpx.r)
|
||||||
|
scalerCoo += scalerStepY;
|
||||||
|
if(texture2D(landscapeTex[0], centerCoo + fullStepX ).r == lpx.r)
|
||||||
|
scalerCoo += 2.0 * scalerStepY;
|
||||||
|
|
||||||
|
if(texture2D(landscapeTex[0], centerCoo - fullStepX + fullStepY).r == lpx.r)
|
||||||
|
scalerCoo += 4.0 * scalerStepY;
|
||||||
|
if(texture2D(landscapeTex[0], centerCoo + fullStepY).r == lpx.r)
|
||||||
|
scalerCoo += 8.0 * scalerStepY;
|
||||||
|
if(texture2D(landscapeTex[0], centerCoo + fullStepX + fullStepY).r == lpx.r)
|
||||||
|
scalerCoo += 16.0 * scalerStepY;
|
||||||
|
|
||||||
|
vec4 spx = texture2DLod(scalerTex, scalerCoo, 0.0);
|
||||||
|
|
||||||
|
// Material pixel
|
||||||
|
float mix = matTexMap[int(lpx.r * 255.0)];
|
||||||
|
vec4 mpx = texture3D(materialTex, vec3(gl_TexCoord[0].st * resolution / vec2(512.0, 512.0) * vec2(3.0, 3.0), mix));
|
||||||
|
float omix = matTexMap[int(lopx.r * 255.0)];
|
||||||
|
vec4 ompx = texture3D(materialTex, vec3(gl_TexCoord[0].st * resolution / vec2(512.0, 512.0) * vec2(3.0, 3.0), omix));
|
||||||
|
|
||||||
|
// Brightness
|
||||||
|
vec2 normal = (1.5 * rlpx.yz - vec2(1.0, 1.0));
|
||||||
|
float ambientBright = 1.0;
|
||||||
|
float bright = ambientBright * (1.0 + dot(normal, vec2(0.0, -1.0)));
|
||||||
|
float bright2 = ambientBright; // * length(onormal + lightDir); // - bla.z;
|
||||||
|
|
||||||
|
gl_FragColor = vec4(
|
||||||
|
bright * spx.r * mpx.rgb + bright2 * (1.0-spx.r) * ompx.rgb,
|
||||||
|
spx.r * mpx.a + (1.0-spx.r) * ompx.a);
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 6.2 KiB |
|
@ -117,6 +117,8 @@
|
||||||
#define C4CFN_Parameters "Parameters.txt"
|
#define C4CFN_Parameters "Parameters.txt"
|
||||||
#define C4CFN_RoundResults "RoundResults.txt"
|
#define C4CFN_RoundResults "RoundResults.txt"
|
||||||
#define C4CFN_PlayerControls "PlayerControls.txt"
|
#define C4CFN_PlayerControls "PlayerControls.txt"
|
||||||
|
#define C4CFN_LandscapeShader "LandscapeShader.c"
|
||||||
|
#define C4CFN_LandscapeScaler "Scaler.png"
|
||||||
|
|
||||||
#define C4CFN_MapFolderData "FolderMap.txt"
|
#define C4CFN_MapFolderData "FolderMap.txt"
|
||||||
#define C4CFN_MapFolderBG "FolderMap"
|
#define C4CFN_MapFolderBG "FolderMap"
|
||||||
|
|
|
@ -56,9 +56,6 @@
|
||||||
#include <StdSurface8.h>
|
#include <StdSurface8.h>
|
||||||
#include <StdPNG.h>
|
#include <StdPNG.h>
|
||||||
|
|
||||||
const int C4LS_MaxLightDistY = 8;
|
|
||||||
const int C4LS_MaxLightDistX = 1;
|
|
||||||
|
|
||||||
C4Landscape::C4Landscape()
|
C4Landscape::C4Landscape()
|
||||||
{
|
{
|
||||||
Default();
|
Default();
|
||||||
|
@ -285,7 +282,7 @@ void C4Landscape::Clear(bool fClearMapCreator, bool fClearSky)
|
||||||
// clear sky
|
// clear sky
|
||||||
if (fClearSky) Sky.Clear();
|
if (fClearSky) Sky.Clear();
|
||||||
// clear surfaces, if assigned
|
// clear surfaces, if assigned
|
||||||
delete Surface32; Surface32=NULL;
|
delete pLandscapeRender; pLandscapeRender=NULL;
|
||||||
delete Surface8; Surface8=NULL;
|
delete Surface8; Surface8=NULL;
|
||||||
delete Map; Map=NULL;
|
delete Map; Map=NULL;
|
||||||
// clear initial landscape
|
// clear initial landscape
|
||||||
|
@ -307,20 +304,13 @@ void C4Landscape::Clear(bool fClearMapCreator, bool fClearSky)
|
||||||
void C4Landscape::Draw(C4TargetFacet &cgo, int32_t iPlayer)
|
void C4Landscape::Draw(C4TargetFacet &cgo, int32_t iPlayer)
|
||||||
{
|
{
|
||||||
if (Modulation) lpDDraw->ActivateBlitModulation(Modulation);
|
if (Modulation) lpDDraw->ActivateBlitModulation(Modulation);
|
||||||
// do relights
|
|
||||||
DoRelights();
|
|
||||||
// blit landscape
|
// blit landscape
|
||||||
if (::GraphicsSystem.ShowSolidMask)
|
if (::GraphicsSystem.ShowSolidMask)
|
||||||
lpDDraw->Blit8Fast(Surface8, cgo.TargetX, cgo.TargetY, cgo.Surface, cgo.X,cgo.Y,cgo.Wdt,cgo.Hgt);
|
lpDDraw->Blit8Fast(Surface8, cgo.TargetX, cgo.TargetY, cgo.Surface, cgo.X,cgo.Y,cgo.Wdt,cgo.Hgt);
|
||||||
else
|
else if(pLandscapeRender)
|
||||||
{
|
{
|
||||||
const CSurface * Surfaces[C4M_MaxTexIndex];
|
DoRelights();
|
||||||
if (Config.Graphics.HighResLandscape)
|
pLandscapeRender->Draw(cgo);
|
||||||
for (int i = 0; i < C4M_MaxTexIndex; ++i)
|
|
||||||
Surfaces[i] = ::TextureMap.GetEntry(i)->GetPattern().getSurface();
|
|
||||||
lpDDraw->BlitLandscape(Surface32, cgo.TargetX, cgo.TargetY, cgo.Surface,
|
|
||||||
cgo.X, cgo.Y, cgo.Wdt, cgo.Hgt,
|
|
||||||
Config.Graphics.HighResLandscape ? Surfaces : 0);
|
|
||||||
}
|
}
|
||||||
if (Modulation) lpDDraw->DeactivateBlitModulation();
|
if (Modulation) lpDDraw->DeactivateBlitModulation();
|
||||||
}
|
}
|
||||||
|
@ -401,7 +391,6 @@ void C4Landscape::ChunkOZoom(CSurface8 * sfcMap, int32_t iMapX, int32_t iMapY, i
|
||||||
iMapWdt=BoundBy<int32_t>(iMapWdt,0,iMapWidth-iMapX); iMapHgt=BoundBy<int32_t>(iMapHgt,0,iMapHeight-iMapY);
|
iMapWdt=BoundBy<int32_t>(iMapWdt,0,iMapWidth-iMapX); iMapHgt=BoundBy<int32_t>(iMapHgt,0,iMapHeight-iMapY);
|
||||||
// get chunk size
|
// get chunk size
|
||||||
iChunkWidth=MapZoom; iChunkHeight=MapZoom;
|
iChunkWidth=MapZoom; iChunkHeight=MapZoom;
|
||||||
Surface32->Lock();
|
|
||||||
// Scan map lines
|
// Scan map lines
|
||||||
for (iY=iMapY; iY<iMapY+iMapHgt; iY++)
|
for (iY=iMapY; iY<iMapY+iMapHgt; iY++)
|
||||||
{
|
{
|
||||||
|
@ -448,7 +437,6 @@ void C4Landscape::ChunkOZoom(CSurface8 * sfcMap, int32_t iMapX, int32_t iMapY, i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Surface32->Unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool C4Landscape::GetTexUsage(CSurface8 * sfcMap, int32_t iMapX, int32_t iMapY, int32_t iMapWdt, int32_t iMapHgt, DWORD *dwpTextureUsage)
|
bool C4Landscape::GetTexUsage(CSurface8 * sfcMap, int32_t iMapX, int32_t iMapY, int32_t iMapWdt, int32_t iMapHgt, DWORD *dwpTextureUsage)
|
||||||
|
@ -486,27 +474,14 @@ bool C4Landscape::TexOZoom(CSurface8 * sfcMap, int32_t iMapX, int32_t iMapY, int
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool C4Landscape::SkyToLandscape(int32_t iToX, int32_t iToY, int32_t iToWdt, int32_t iToHgt, int32_t iOffX, int32_t iOffY)
|
|
||||||
{
|
|
||||||
if (!Surface32->Lock()) return false;
|
|
||||||
// newgfx: simply blit the sky in realtime...
|
|
||||||
Surface32->ClearBoxDw(iToX, iToY, iToWdt, iToHgt);
|
|
||||||
Surface8->ClearBox8Only(iToX, iToY, iToWdt, iToHgt);
|
|
||||||
// unlock
|
|
||||||
Surface32->Unlock();
|
|
||||||
// Done
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool C4Landscape::MapToSurface(CSurface8 * sfcMap, int32_t iMapX, int32_t iMapY, int32_t iMapWdt, int32_t iMapHgt, int32_t iToX, int32_t iToY, int32_t iToWdt, int32_t iToHgt, int32_t iOffX, int32_t iOffY)
|
bool C4Landscape::MapToSurface(CSurface8 * sfcMap, int32_t iMapX, int32_t iMapY, int32_t iMapWdt, int32_t iMapHgt, int32_t iToX, int32_t iToY, int32_t iToWdt, int32_t iToHgt, int32_t iOffX, int32_t iOffY)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Sky background segment
|
// Clear surface
|
||||||
SkyToLandscape(iToX, iToY, iToWdt, iToHgt, iOffX, iOffY);
|
Surface8->ClearBox8Only(iToX, iToY, iToWdt, iToHgt);
|
||||||
|
|
||||||
// assign clipper
|
// assign clipper
|
||||||
Surface8->Clip(iToX,iToY,iToX+iToWdt-1,iToY+iToHgt-1);
|
Surface8->Clip(iToX,iToY,iToX+iToWdt-1,iToY+iToHgt-1);
|
||||||
Surface32->Clip(iToX,iToY,iToX+iToWdt-1,iToY+iToHgt-1);
|
|
||||||
lpDDraw->NoPrimaryClipper();
|
lpDDraw->NoPrimaryClipper();
|
||||||
|
|
||||||
// Enlarge map segment for chunky rim
|
// Enlarge map segment for chunky rim
|
||||||
|
@ -520,7 +495,6 @@ bool C4Landscape::MapToSurface(CSurface8 * sfcMap, int32_t iMapX, int32_t iMapY,
|
||||||
|
|
||||||
// remove clipper
|
// remove clipper
|
||||||
Surface8->NoClip();
|
Surface8->NoClip();
|
||||||
Surface32->NoClip();
|
|
||||||
|
|
||||||
// success
|
// success
|
||||||
return true;
|
return true;
|
||||||
|
@ -528,7 +502,7 @@ bool C4Landscape::MapToSurface(CSurface8 * sfcMap, int32_t iMapX, int32_t iMapY,
|
||||||
|
|
||||||
bool C4Landscape::MapToLandscape(CSurface8 * sfcMap, int32_t iMapX, int32_t iMapY, int32_t iMapWdt, int32_t iMapHgt, int32_t iOffsX, int32_t iOffsY)
|
bool C4Landscape::MapToLandscape(CSurface8 * sfcMap, int32_t iMapX, int32_t iMapY, int32_t iMapWdt, int32_t iMapHgt, int32_t iOffsX, int32_t iOffsY)
|
||||||
{
|
{
|
||||||
assert(Surface8); assert(Surface32);
|
assert(Surface8);
|
||||||
// Clip to map/landscape segment
|
// Clip to map/landscape segment
|
||||||
int iMapWidth,iMapHeight,iLandscapeWidth,iLandscapeHeight;
|
int iMapWidth,iMapHeight,iLandscapeWidth,iLandscapeHeight;
|
||||||
// Get map & landscape size
|
// Get map & landscape size
|
||||||
|
@ -547,11 +521,9 @@ bool C4Landscape::MapToLandscape(CSurface8 * sfcMap, int32_t iMapX, int32_t iMap
|
||||||
To.Wdt = iMapWdt*MapZoom;
|
To.Wdt = iMapWdt*MapZoom;
|
||||||
To.Hgt = iMapHgt*MapZoom;
|
To.Hgt = iMapHgt*MapZoom;
|
||||||
|
|
||||||
Surface32->Lock();
|
|
||||||
PrepareChange(To);
|
PrepareChange(To);
|
||||||
MapToSurface(sfcMap, iMapX, iMapY, iMapWdt, iMapHgt, To.x, To.y, To.Wdt, To.Hgt, iOffsX, iOffsY);
|
MapToSurface(sfcMap, iMapX, iMapY, iMapWdt, iMapHgt, To.x, To.y, To.Wdt, To.Hgt, iOffsX, iOffsY);
|
||||||
FinishChange(To);
|
FinishChange(To);
|
||||||
Surface32->Unlock();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -746,27 +718,41 @@ bool C4Landscape::Init(C4Group &hGroup, bool fOverloadCurrent, bool fLoadSky, bo
|
||||||
// Scan settings
|
// Scan settings
|
||||||
ScanSpeed=BoundBy(Width/500,2,15);
|
ScanSpeed=BoundBy(Width/500,2,15);
|
||||||
|
|
||||||
// create it
|
// map to big surface and sectionize it
|
||||||
if (!Game.C4S.Landscape.ExactLandscape)
|
// (not for shaders though - they require continous textures)
|
||||||
|
// Create landscape surface
|
||||||
|
Surface8 = new CSurface8();
|
||||||
|
if (!Surface8->Create(Width, Height) || !Mat2Pal())
|
||||||
{
|
{
|
||||||
// map to big surface and sectionize it
|
delete Surface8; Surface8 = 0;
|
||||||
// Create landscape surface
|
return false;
|
||||||
Surface32 = new CSurface();
|
|
||||||
Surface8 = new CSurface8();
|
|
||||||
if (!Surface32->Create(Width, Height, true, false, lpDDraw->IsShaderific() ? 0 : 64)
|
|
||||||
|| !Surface8->Create(Width, Height)
|
|
||||||
|| !Mat2Pal())
|
|
||||||
{
|
|
||||||
delete Surface8; delete Surface32;
|
|
||||||
Surface8 = 0; Surface32 = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map to landscape
|
|
||||||
if (!MapToLandscape()) return false;
|
|
||||||
}
|
}
|
||||||
Game.SetInitProgress(87);
|
|
||||||
|
|
||||||
|
// Map to landscape
|
||||||
|
if (!MapToLandscape()) return false;
|
||||||
|
Game.SetInitProgress(84);
|
||||||
|
|
||||||
|
// Create renderer
|
||||||
|
pLandscapeRender = NULL;
|
||||||
|
#ifdef USE_GL
|
||||||
|
if (!pLandscapeRender && ::Config.Graphics.HighResLandscape)
|
||||||
|
pLandscapeRender = new C4LandscapeRenderGL();
|
||||||
|
#endif
|
||||||
|
#ifndef USE_CONSOLE
|
||||||
|
if (!pLandscapeRender)
|
||||||
|
pLandscapeRender = new C4LandscapeRenderClassic();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(pLandscapeRender)
|
||||||
|
{
|
||||||
|
// Initialize renderer
|
||||||
|
if(!pLandscapeRender->Init(Width, Height, &::TextureMap, &::GraphicsResource.Files))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Write landscape data
|
||||||
|
pLandscapeRender->Update(C4Rect(0, 0, Width, Height), this);
|
||||||
|
Game.SetInitProgress(87);
|
||||||
|
}
|
||||||
#ifdef DEBUGREC
|
#ifdef DEBUGREC
|
||||||
AddDbgRec(RCT_Block, "|---LS---|", 11);
|
AddDbgRec(RCT_Block, "|---LS---|", 11);
|
||||||
AddDbgRec(RCT_Ls, Surface8->Bits, Surface8->Pitch*Surface8->Hgt);
|
AddDbgRec(RCT_Ls, Surface8->Bits, Surface8->Pitch*Surface8->Hgt);
|
||||||
|
@ -793,6 +779,7 @@ bool C4Landscape::Init(C4Group &hGroup, bool fOverloadCurrent, bool fLoadSky, bo
|
||||||
// and not creating the map
|
// and not creating the map
|
||||||
Game.FixRandom(Game.RandomSeed);
|
Game.FixRandom(Game.RandomSeed);
|
||||||
|
|
||||||
|
|
||||||
// Success
|
// Success
|
||||||
rfLoaded=true;
|
rfLoaded=true;
|
||||||
return true;
|
return true;
|
||||||
|
@ -812,23 +799,20 @@ bool C4Landscape::SetPix(int32_t x, int32_t y, BYTE npix)
|
||||||
if (npix == _GetPix(x, y))
|
if (npix == _GetPix(x, y))
|
||||||
return true;
|
return true;
|
||||||
// note for relight
|
// note for relight
|
||||||
C4Rect CheckRect(x - 2 * C4LS_MaxLightDistX, y - 2 * C4LS_MaxLightDistY, 4 * C4LS_MaxLightDistX + 1, 4 * C4LS_MaxLightDistY + 1);
|
if(pLandscapeRender)
|
||||||
for (int32_t i = 0; i < C4LS_MaxRelights; i++)
|
{
|
||||||
if (!Relights[i].Wdt || Relights[i].Overlap(CheckRect) || i + 1 >= C4LS_MaxRelights)
|
C4Rect CheckRect = pLandscapeRender->GetAffectedRect(C4Rect(x, y, 1, 1));
|
||||||
{
|
for (int32_t i = 0; i < C4LS_MaxRelights; i++)
|
||||||
Relights[i].Add(C4Rect(x,y,1,1));
|
if (!Relights[i].Wdt || Relights[i].Overlap(CheckRect) || i + 1 >= C4LS_MaxRelights)
|
||||||
break;
|
{
|
||||||
}
|
Relights[i].Add(CheckRect);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
// set pixel
|
// set pixel
|
||||||
return _SetPix(x, y, npix);
|
return _SetPix(x, y, npix);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool C4Landscape::SetPixDw(int32_t x, int32_t y, DWORD dwPix)
|
|
||||||
{
|
|
||||||
// set in surface
|
|
||||||
return Surface32->SetPixDw(x, y, dwPix);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool C4Landscape::_SetPix(int32_t x, int32_t y, BYTE npix)
|
bool C4Landscape::_SetPix(int32_t x, int32_t y, BYTE npix)
|
||||||
{
|
{
|
||||||
#ifdef DEBUGREC
|
#ifdef DEBUGREC
|
||||||
|
@ -1514,13 +1498,7 @@ bool C4Landscape::SaveInternal(C4Group &hGroup)
|
||||||
if (!hGroup.Move( szTempLandscape, C4CFN_Landscape ))
|
if (!hGroup.Move( szTempLandscape, C4CFN_Landscape ))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
SCopy(Config.AtTempPath(C4CFN_TempLandscapePNG), szTempLandscape);
|
// Save map
|
||||||
MakeTempFilename(szTempLandscape);
|
|
||||||
if (!Surface32->SavePNG(szTempLandscape, true, false, false))
|
|
||||||
return false;
|
|
||||||
if (!hGroup.Move( szTempLandscape, C4CFN_LandscapePNG ))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (fMapChanged && Map)
|
if (fMapChanged && Map)
|
||||||
if (!SaveMap(hGroup))
|
if (!SaveMap(hGroup))
|
||||||
return false;
|
return false;
|
||||||
|
@ -1608,29 +1586,10 @@ bool C4Landscape::Load(C4Group &hGroup, bool fLoadSky, bool fSavegame)
|
||||||
int iWidth, iHeight;
|
int iWidth, iHeight;
|
||||||
Surface8->GetSurfaceSize(iWidth,iHeight);
|
Surface8->GetSurfaceSize(iWidth,iHeight);
|
||||||
Width = iWidth; Height = iHeight;
|
Width = iWidth; Height = iHeight;
|
||||||
Surface32 = new CSurface(Width, Height);
|
|
||||||
// adjust pal
|
// adjust pal
|
||||||
if (!Mat2Pal()) return false;
|
if (!Mat2Pal()) return false;
|
||||||
// load the 32bit-surface, too
|
|
||||||
size_t iSize;
|
|
||||||
if (hGroup.AccessEntry(C4CFN_LandscapePNG, &iSize))
|
|
||||||
{
|
|
||||||
CPNGFile png;
|
|
||||||
BYTE *pPNG = new BYTE [iSize];
|
|
||||||
hGroup.Read(pPNG, iSize);
|
|
||||||
bool fSuccess = png.Load(pPNG, iSize);
|
|
||||||
delete [] pPNG;
|
|
||||||
if (fSuccess)
|
|
||||||
fSuccess = !!Surface32->Lock();
|
|
||||||
if (fSuccess)
|
|
||||||
{
|
|
||||||
for (int32_t y=0; y<Height; ++y) for (int32_t x=0; x<Width; ++x)
|
|
||||||
Surface32->SetPixDw(x, y, png.GetPix(x, y));
|
|
||||||
Surface32->Unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// no PNG: convert old-style landscapes
|
// no PNG: convert old-style landscapes
|
||||||
else if (!Game.C4S.Landscape.NewStyleLandscape)
|
if (!Game.C4S.Landscape.NewStyleLandscape)
|
||||||
{
|
{
|
||||||
// convert all pixels
|
// convert all pixels
|
||||||
for (int32_t y=0; y<Height; ++y) for (int32_t x=0; x<Width; ++x)
|
for (int32_t y=0; y<Height; ++y) for (int32_t x=0; x<Width; ++x)
|
||||||
|
@ -1705,7 +1664,7 @@ void C4Landscape::Default()
|
||||||
{
|
{
|
||||||
Mode=C4LSC_Undefined;
|
Mode=C4LSC_Undefined;
|
||||||
Surface8=NULL;
|
Surface8=NULL;
|
||||||
Surface32=NULL;
|
pLandscapeRender=NULL;
|
||||||
Map=NULL;
|
Map=NULL;
|
||||||
Width=Height=0;
|
Width=Height=0;
|
||||||
MapWidth=MapHeight=MapZoom=0;
|
MapWidth=MapHeight=MapZoom=0;
|
||||||
|
@ -2576,118 +2535,28 @@ inline DWORD DarkenClr1_4(DWORD &dwDst) // make it 3/4 as bright, slightly viole
|
||||||
|
|
||||||
bool C4Landscape::DoRelights()
|
bool C4Landscape::DoRelights()
|
||||||
{
|
{
|
||||||
|
if (!pLandscapeRender) return true;
|
||||||
for (int32_t i = 0; i < C4LS_MaxRelights; i++)
|
for (int32_t i = 0; i < C4LS_MaxRelights; i++)
|
||||||
{
|
{
|
||||||
if (!Relights[i].Wdt)
|
if (!Relights[i].Wdt)
|
||||||
break;
|
break;
|
||||||
C4Rect SolidMaskRect = Relights[i];
|
// Remove all solid masks in the (twice!) extended region around the change
|
||||||
SolidMaskRect.x -= 2 * C4LS_MaxLightDistX; SolidMaskRect.y -= 2 * C4LS_MaxLightDistY;
|
C4Rect SolidMaskRect = pLandscapeRender->GetAffectedRect(Relights[i]);
|
||||||
SolidMaskRect.Wdt += 4 * C4LS_MaxLightDistX; SolidMaskRect.Hgt += 4 * C4LS_MaxLightDistY;
|
|
||||||
C4SolidMask * pSolid;
|
C4SolidMask * pSolid;
|
||||||
for (pSolid = C4SolidMask::Last; pSolid; pSolid = pSolid->Prev)
|
for (pSolid = C4SolidMask::Last; pSolid; pSolid = pSolid->Prev)
|
||||||
{
|
|
||||||
pSolid->RemoveTemporary(SolidMaskRect);
|
pSolid->RemoveTemporary(SolidMaskRect);
|
||||||
}
|
// Perform the update
|
||||||
Relight(Relights[i]);
|
pLandscapeRender->Update(Relights[i], this);
|
||||||
// Restore Solidmasks
|
// Restore Solidmasks
|
||||||
for (pSolid = C4SolidMask::First; pSolid; pSolid = pSolid->Next)
|
for (pSolid = C4SolidMask::First; pSolid; pSolid = pSolid->Next)
|
||||||
{
|
|
||||||
pSolid->PutTemporary(SolidMaskRect);
|
pSolid->PutTemporary(SolidMaskRect);
|
||||||
}
|
|
||||||
Relights[i].Default();
|
|
||||||
C4SolidMask::CheckConsistency();
|
C4SolidMask::CheckConsistency();
|
||||||
|
// Clear slot
|
||||||
|
Relights[i].Default();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool C4Landscape::Relight(C4Rect To)
|
|
||||||
{
|
|
||||||
// Enlarge to relight pixels surrounding a changed one
|
|
||||||
To.x -= C4LS_MaxLightDistX; To.y -= C4LS_MaxLightDistY;
|
|
||||||
To.Wdt += 2 * C4LS_MaxLightDistX; To.Hgt += 2 * C4LS_MaxLightDistY;
|
|
||||||
// Apply lighting
|
|
||||||
return ApplyLighting(To);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool C4Landscape::ApplyLighting(C4Rect To)
|
|
||||||
{
|
|
||||||
// clip to landscape size
|
|
||||||
To.Intersect(C4Rect(0,0,GBackWdt,GBackHgt));
|
|
||||||
// everything clipped?
|
|
||||||
if (To.Wdt<=0 || To.Hgt<=0) return true;
|
|
||||||
if (!Surface32->Lock()) return false;
|
|
||||||
|
|
||||||
// We clear the affected region here because ClearBoxDw allocates the
|
|
||||||
// main memory buffer for the box, so that only that box needs to be
|
|
||||||
// sent to the gpu, and not the whole texture, or every pixel
|
|
||||||
// separately. It's an important optimization.
|
|
||||||
Surface32->ClearBoxDw(To.x, To.y, To.Wdt, To.Hgt);
|
|
||||||
|
|
||||||
if (lpDDraw->IsShaderific() && Config.Graphics.HighResLandscape)
|
|
||||||
{
|
|
||||||
for (int32_t iX=To.x; iX<To.x+To.Wdt; ++iX)
|
|
||||||
for (int32_t iY=To.y; iY<To.y+To.Hgt; ++iY)
|
|
||||||
Surface32->SetPixDw(iX, iY, _GetPix(iX, iY));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
// do lightning
|
|
||||||
for (int32_t iX=To.x; iX<To.x+To.Wdt; ++iX)
|
|
||||||
{
|
|
||||||
int AboveDensity = 0, BelowDensity = 0;
|
|
||||||
for (int i = 1; i <= 8; ++i)
|
|
||||||
{
|
|
||||||
AboveDensity += GetPlacement(iX, To.y - i - 1);
|
|
||||||
BelowDensity += GetPlacement(iX, To.y + i - 1);
|
|
||||||
}
|
|
||||||
for (int32_t iY=To.y; iY<To.y+To.Hgt; ++iY)
|
|
||||||
{
|
|
||||||
AboveDensity -= GetPlacement(iX, iY - 9);
|
|
||||||
AboveDensity += GetPlacement(iX, iY - 1);
|
|
||||||
BelowDensity -= GetPlacement(iX, iY);
|
|
||||||
BelowDensity += GetPlacement(iX, iY + 8);
|
|
||||||
BYTE pix = _GetPix(iX, iY);
|
|
||||||
// Sky
|
|
||||||
if (!pix)
|
|
||||||
{
|
|
||||||
Surface32->SetPixDw(iX, iY, 0x00ffffff);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// get density
|
|
||||||
int iOwnDens = Pix2Place[pix];
|
|
||||||
if (!iOwnDens) continue;
|
|
||||||
iOwnDens *= 2;
|
|
||||||
iOwnDens += GetPlacement(iX + 1, iY) + GetPlacement(iX - 1, iY);
|
|
||||||
iOwnDens /= 4;
|
|
||||||
// get texture map entry for pixel
|
|
||||||
const C4TexMapEntry *pTex = ::TextureMap.GetEntry(PixCol2Tex(pix));
|
|
||||||
assert(pTex);
|
|
||||||
// get texture contents
|
|
||||||
DWORD dwBackClr;
|
|
||||||
if (pTex) dwBackClr = pTex->GetPattern().PatternClr(iX, iY);
|
|
||||||
// get density of surrounding materials
|
|
||||||
int iCompareDens = AboveDensity / 8;
|
|
||||||
if (iOwnDens > iCompareDens)
|
|
||||||
{
|
|
||||||
// apply light
|
|
||||||
LightenClrBy(dwBackClr, Min(30, 2 * (iOwnDens - iCompareDens)));
|
|
||||||
}
|
|
||||||
else if (iOwnDens < iCompareDens && iOwnDens < 30)
|
|
||||||
{
|
|
||||||
DarkenClrBy(dwBackClr, Min(30, 2 * (iCompareDens - iOwnDens)));
|
|
||||||
}
|
|
||||||
iCompareDens = BelowDensity / 8;
|
|
||||||
if (iOwnDens > iCompareDens)
|
|
||||||
{
|
|
||||||
DarkenClrBy(dwBackClr, Min(30, 2 * (iOwnDens - iCompareDens)));
|
|
||||||
}
|
|
||||||
Surface32->SetPixDw(iX, iY, dwBackClr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Surface32->Unlock();
|
|
||||||
// done
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool C4Landscape::DrawMap(int32_t iX, int32_t iY, int32_t iWdt, int32_t iHgt, const char *szMapDef)
|
bool C4Landscape::DrawMap(int32_t iX, int32_t iY, int32_t iWdt, int32_t iHgt, const char *szMapDef)
|
||||||
{
|
{
|
||||||
// safety
|
// safety
|
||||||
|
@ -2911,8 +2780,8 @@ void C4Landscape::PrepareChange(C4Rect BoundingBox)
|
||||||
{
|
{
|
||||||
// move solidmasks out of the way
|
// move solidmasks out of the way
|
||||||
C4Rect SolidMaskRect = BoundingBox;
|
C4Rect SolidMaskRect = BoundingBox;
|
||||||
SolidMaskRect.x -= 2 * C4LS_MaxLightDistX; SolidMaskRect.y -= 2 * C4LS_MaxLightDistY;
|
if (pLandscapeRender)
|
||||||
SolidMaskRect.Wdt += 4 * C4LS_MaxLightDistX; SolidMaskRect.Hgt += 4 * C4LS_MaxLightDistY;
|
SolidMaskRect = pLandscapeRender->GetAffectedRect(pLandscapeRender->GetAffectedRect(SolidMaskRect));
|
||||||
for (C4SolidMask * pSolid = C4SolidMask::Last; pSolid; pSolid = pSolid->Prev)
|
for (C4SolidMask * pSolid = C4SolidMask::Last; pSolid; pSolid = pSolid->Prev)
|
||||||
{
|
{
|
||||||
pSolid->RemoveTemporary(SolidMaskRect);
|
pSolid->RemoveTemporary(SolidMaskRect);
|
||||||
|
@ -2922,19 +2791,20 @@ void C4Landscape::PrepareChange(C4Rect BoundingBox)
|
||||||
|
|
||||||
void C4Landscape::FinishChange(C4Rect BoundingBox)
|
void C4Landscape::FinishChange(C4Rect BoundingBox)
|
||||||
{
|
{
|
||||||
// relight
|
// update render
|
||||||
Relight(BoundingBox);
|
if(pLandscapeRender)
|
||||||
|
pLandscapeRender->Update(BoundingBox, this);
|
||||||
UpdateMatCnt(BoundingBox, true);
|
UpdateMatCnt(BoundingBox, true);
|
||||||
// Restore Solidmasks
|
// Restore Solidmasks
|
||||||
C4Rect SolidMaskRect = BoundingBox;
|
C4Rect SolidMaskRect = BoundingBox;
|
||||||
SolidMaskRect.x -= 2 * C4LS_MaxLightDistX; SolidMaskRect.y -= 2 * C4LS_MaxLightDistY;
|
if (pLandscapeRender)
|
||||||
SolidMaskRect.Wdt += 4 * C4LS_MaxLightDistX; SolidMaskRect.Hgt += 4 * C4LS_MaxLightDistY;
|
SolidMaskRect = pLandscapeRender->GetAffectedRect(pLandscapeRender->GetAffectedRect(SolidMaskRect));
|
||||||
for (C4SolidMask * pSolid = C4SolidMask::First; pSolid; pSolid = pSolid->Next)
|
for (C4SolidMask * pSolid = C4SolidMask::First; pSolid; pSolid = pSolid->Next)
|
||||||
{
|
{
|
||||||
pSolid->Repair(SolidMaskRect);
|
pSolid->Repair(SolidMaskRect);
|
||||||
}
|
}
|
||||||
UpdatePixCnt(BoundingBox);
|
|
||||||
C4SolidMask::CheckConsistency();
|
C4SolidMask::CheckConsistency();
|
||||||
|
UpdatePixCnt(BoundingBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
void C4Landscape::UpdatePixCnt(const C4Rect &Rect, bool fCheck)
|
void C4Landscape::UpdatePixCnt(const C4Rect &Rect, bool fCheck)
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
#include "C4Sky.h"
|
#include "C4Sky.h"
|
||||||
#include "C4Shape.h"
|
#include "C4Shape.h"
|
||||||
|
#include "C4LandscapeRender.h"
|
||||||
|
|
||||||
#include <StdSurface8.h>
|
#include <StdSurface8.h>
|
||||||
#include <C4Material.h>
|
#include <C4Material.h>
|
||||||
|
@ -76,8 +77,8 @@ public:
|
||||||
bool fMapChanged;
|
bool fMapChanged;
|
||||||
BYTE *pInitial; // Initial landscape after creation - used for diff
|
BYTE *pInitial; // Initial landscape after creation - used for diff
|
||||||
protected:
|
protected:
|
||||||
CSurface * Surface32;
|
|
||||||
CSurface8 * Surface8;
|
CSurface8 * Surface8;
|
||||||
|
C4LandscapeRender *pLandscapeRender;
|
||||||
int32_t Pix2Mat[256], Pix2Dens[256], Pix2Place[256];
|
int32_t Pix2Mat[256], Pix2Dens[256], Pix2Place[256];
|
||||||
int32_t PixCntPitch;
|
int32_t PixCntPitch;
|
||||||
uint8_t *PixCnt;
|
uint8_t *PixCnt;
|
||||||
|
@ -115,7 +116,6 @@ public:
|
||||||
bool ApplyDiff(C4Group &hGroup);
|
bool ApplyDiff(C4Group &hGroup);
|
||||||
bool SetMode(int32_t iMode);
|
bool SetMode(int32_t iMode);
|
||||||
bool SetPix(int32_t x, int32_t y, BYTE npix); // set landscape pixel (bounds checked)
|
bool SetPix(int32_t x, int32_t y, BYTE npix); // set landscape pixel (bounds checked)
|
||||||
bool SetPixDw(int32_t x, int32_t y, DWORD dwPix); // set pixel how it is visible only
|
|
||||||
bool _SetPix(int32_t x, int32_t y, BYTE npix); // set landsape pixel (bounds not checked)
|
bool _SetPix(int32_t x, int32_t y, BYTE npix); // set landsape pixel (bounds not checked)
|
||||||
bool _SetPixIfMask(int32_t x, int32_t y, BYTE npix, BYTE nMask) ; // set landscape pixel, if it matches nMask color (no bound-checks)
|
bool _SetPixIfMask(int32_t x, int32_t y, BYTE npix, BYTE nMask) ; // set landscape pixel, if it matches nMask color (no bound-checks)
|
||||||
bool CheckInstability(int32_t tx, int32_t ty);
|
bool CheckInstability(int32_t tx, int32_t ty);
|
||||||
|
@ -136,10 +136,6 @@ public:
|
||||||
{
|
{
|
||||||
return Surface8->_GetPix(x,y);
|
return Surface8->_GetPix(x,y);
|
||||||
}
|
}
|
||||||
inline DWORD _GetPixDw(int32_t x, int32_t y, bool fApplyModulation) // get landscape pixel (bounds not checked)
|
|
||||||
{
|
|
||||||
return Surface32->GetPixDw(x, y, fApplyModulation);
|
|
||||||
}
|
|
||||||
inline BYTE GetPix(int32_t x, int32_t y) // get landscape pixel (bounds checked)
|
inline BYTE GetPix(int32_t x, int32_t y) // get landscape pixel (bounds checked)
|
||||||
{
|
{
|
||||||
extern BYTE MCVehic;
|
extern BYTE MCVehic;
|
||||||
|
|
|
@ -0,0 +1,589 @@
|
||||||
|
|
||||||
|
#include "C4Include.h"
|
||||||
|
#include "C4LandscapeRender.h"
|
||||||
|
|
||||||
|
#include "C4Landscape.h"
|
||||||
|
#include "C4Texture.h"
|
||||||
|
|
||||||
|
#include "C4GroupSet.h"
|
||||||
|
#include "C4Components.h"
|
||||||
|
|
||||||
|
#include "StdGL.h"
|
||||||
|
#include "StdColors.h"
|
||||||
|
|
||||||
|
#ifdef USE_GL
|
||||||
|
|
||||||
|
// Automatically reload shaders when changed at runtime?
|
||||||
|
#define AUTO_RELOAD_SHADERS
|
||||||
|
|
||||||
|
// How much to look into each direction for bias
|
||||||
|
const int C4LR_BiasDistanceX = 8;
|
||||||
|
const int C4LR_BiasDistanceY = 8;
|
||||||
|
|
||||||
|
C4LandscapeRenderGL::C4LandscapeRenderGL()
|
||||||
|
: iLandscapeShaderTime(0),
|
||||||
|
hVert(0), hFrag(0), hProg(0),
|
||||||
|
hLandscapeUnit(0), hScalerUnit(0), hMaterialUnit(0),
|
||||||
|
hResolutionUniform(0), hMatTexMapUniform(0),
|
||||||
|
iTexCount(0),
|
||||||
|
hMaterialTexture(0)
|
||||||
|
{
|
||||||
|
ZeroMem(MatTexMap, sizeof(MatTexMap));
|
||||||
|
ZeroMem(Surfaces, sizeof(Surfaces));
|
||||||
|
}
|
||||||
|
|
||||||
|
C4LandscapeRenderGL::~C4LandscapeRenderGL()
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool C4LandscapeRenderGL::Init(int32_t iWidth, int32_t iHeight, C4TextureMap *pTexs, C4GroupSet *pGraphics)
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
|
||||||
|
// Create our surfaces
|
||||||
|
for(int i = 0; i < C4LR_SurfaceCount; i++)
|
||||||
|
{
|
||||||
|
Surfaces[i] = new CSurface();
|
||||||
|
if(!Surfaces[i]->Create(iWidth, iHeight))
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safe info
|
||||||
|
this->iWidth = iWidth;
|
||||||
|
this->iHeight = iHeight;
|
||||||
|
|
||||||
|
// Count the textures
|
||||||
|
iTexCount = 0;
|
||||||
|
while(pTexs->GetTexture(iTexCount))
|
||||||
|
iTexCount++;
|
||||||
|
|
||||||
|
// Build material-texture map (depth parameter where to find appropriate texture)
|
||||||
|
for(int pix = 0; pix < 256; pix++)
|
||||||
|
{
|
||||||
|
// Look up indexed entry
|
||||||
|
const C4TexMapEntry *pEntry = pTexs->GetEntry(PixCol2Tex(BYTE(pix)));
|
||||||
|
if(!pEntry->GetTextureName())
|
||||||
|
{
|
||||||
|
MatTexMap[pix] = 0.5 / (iTexCount - 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Assign texture
|
||||||
|
int32_t iTexIndex = pTexs->GetTextureIndex(pEntry->GetTextureName());
|
||||||
|
if(iTexIndex < 0) iTexIndex = 0;
|
||||||
|
MatTexMap[pix] = (float(iTexIndex) + 0.5) / (iTexCount - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build texture, er, texture
|
||||||
|
if (!InitMaterialTexture(pTexs))
|
||||||
|
{
|
||||||
|
LogFatal("[!] Could not initialize landscape textures for rendering!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load sclaer
|
||||||
|
if (!LoadScaler(pGraphics))
|
||||||
|
{
|
||||||
|
LogFatal("[!] Could not load scaler!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load shader
|
||||||
|
if (!LoadShaders(pGraphics))
|
||||||
|
{
|
||||||
|
LogFatal("[!] Could not initialize landscape shader!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void C4LandscapeRenderGL::Clear()
|
||||||
|
{
|
||||||
|
ClearShaders();
|
||||||
|
|
||||||
|
// free textures
|
||||||
|
for (int i = 0; i < C4LR_SurfaceCount; i++)
|
||||||
|
{
|
||||||
|
delete Surfaces[i];
|
||||||
|
Surfaces[i] = NULL;
|
||||||
|
}
|
||||||
|
glDeleteObjectARB(hMaterialTexture);
|
||||||
|
hMaterialTexture = 0;
|
||||||
|
|
||||||
|
LandscapeShader.Clear();
|
||||||
|
LandscapeShaderPath.Clear();
|
||||||
|
iLandscapeShaderTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool C4LandscapeRenderGL::InitMaterialTexture(C4TextureMap *pTexs)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Find first (actual) texture
|
||||||
|
int iRefTexIx = 0; C4Texture *pRefTex; CSurface *pRefSfc = NULL;
|
||||||
|
for(; pRefTex = pTexs->GetTexture(pTexs->GetTexture(iRefTexIx)); iRefTexIx++)
|
||||||
|
if(pRefSfc = pRefTex->Surface32)
|
||||||
|
break;
|
||||||
|
if(!pRefSfc)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Compose together data of all textures
|
||||||
|
const int iTexWdt = pRefSfc->Wdt, iTexHgt = pRefSfc->Hgt;
|
||||||
|
const int iBytesPP = pRefSfc->byBytesPP;
|
||||||
|
const int iTexSize = iTexWdt * iTexHgt * iBytesPP;
|
||||||
|
const int iSize = iTexSize * iTexCount;
|
||||||
|
char *pData = new char [iSize];
|
||||||
|
for(int i = 0; i < iTexCount; i++)
|
||||||
|
{
|
||||||
|
char *p = pData + i * iTexSize;
|
||||||
|
C4Texture *pTex; CSurface *pSurface;
|
||||||
|
if(!(pTex = pTexs->GetTexture(pTexs->GetTexture(i))))
|
||||||
|
{}
|
||||||
|
if(!(pSurface = pTex->Surface32))
|
||||||
|
{}
|
||||||
|
else if(pSurface->Wdt != iTexWdt || pSurface->Hgt != iTexHgt)
|
||||||
|
LogF(" gl: texture %s size mismatch (%dx%d vs %dx%d)!", pTexs->GetTexture(i), pSurface->Wdt, pSurface->Hgt, iTexWdt, iTexHgt);
|
||||||
|
else if(pSurface->iTexX != 1 || pSurface->iTexY != 1)
|
||||||
|
Log(" gl: Halp! Material texture is fragmented!");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(p, pSurface->ppTex[0]->texLock.pBits, iTexSize);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
memset(p, 0, iTexSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear error error(s?)
|
||||||
|
while(glGetError()) {}
|
||||||
|
|
||||||
|
// Alloc a 3D texture
|
||||||
|
glEnable(GL_TEXTURE_3D);
|
||||||
|
glGenTextures(1, &hMaterialTexture);
|
||||||
|
glBindTexture(GL_TEXTURE_3D, hMaterialTexture);
|
||||||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
|
|
||||||
|
// We fully expect to tile these
|
||||||
|
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
|
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
|
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
// Make it happen!
|
||||||
|
glTexImage3D(GL_TEXTURE_3D, 0, 4, iTexWdt, iTexHgt, iTexCount, 0, GL_BGRA,
|
||||||
|
iBytesPP == 2 ? GL_UNSIGNED_SHORT_4_4_4_4_REV : GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||||
|
pData);
|
||||||
|
glDisable(GL_TEXTURE_3D);
|
||||||
|
|
||||||
|
// Dispose of data
|
||||||
|
delete [] pData;
|
||||||
|
|
||||||
|
// Check whether we were successful
|
||||||
|
if(int err = glGetError())
|
||||||
|
{
|
||||||
|
LogF(" gl: Could not load textures (error %d)", err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
C4Rect C4LandscapeRenderGL::GetAffectedRect(C4Rect Rect)
|
||||||
|
{
|
||||||
|
Rect.Enlarge(C4LR_BiasDistanceX, C4LR_BiasDistanceY);
|
||||||
|
return Rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
void C4LandscapeRenderGL::Update(C4Rect To, C4Landscape *pSource)
|
||||||
|
{
|
||||||
|
// clip to landscape size
|
||||||
|
To.Intersect(C4Rect(0,0,iWidth,iHeight));
|
||||||
|
// everything clipped?
|
||||||
|
if (To.Wdt<=0 || To.Hgt<=0) return;
|
||||||
|
|
||||||
|
// Lock surfaces
|
||||||
|
// We clear the affected region here because ClearBoxDw allocates the
|
||||||
|
// main memory buffer for the box, so that only that box needs to be
|
||||||
|
// sent to the gpu, and not the whole texture, or every pixel
|
||||||
|
// separately. It's an important optimization.
|
||||||
|
for (int i = 0; i < C4LR_SurfaceCount; i++) {
|
||||||
|
if (!Surfaces[i]->Lock()) return;
|
||||||
|
Surfaces[i]->ClearBoxDw(To.x, To.y, To.Wdt, To.Hgt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize up & down arrays
|
||||||
|
int x, y;
|
||||||
|
int *pUp = new int [To.Wdt * 2];
|
||||||
|
int *pDown = pUp + To.Wdt;
|
||||||
|
for(x = 0; x < To.Wdt; x++) {
|
||||||
|
int iSum = 0;
|
||||||
|
for(y = 1; y < Min(C4LR_BiasDistanceY, To.y+1); y++)
|
||||||
|
iSum += pSource->_GetPlacement(To.x+x, To.y-y);
|
||||||
|
pUp[x] = iSum;
|
||||||
|
iSum = 0;
|
||||||
|
for(y = 1; y < Min(C4LR_BiasDistanceY, iHeight - To.y); y++)
|
||||||
|
iSum += pSource->_GetPlacement(To.x+x, To.y+y);
|
||||||
|
pDown[x] = iSum;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get tex refs (shortcut, we will use them quite heavily)
|
||||||
|
CTexRef *TexRefs[C4LR_SurfaceCount];
|
||||||
|
x = y = 0;
|
||||||
|
for(int i = 0; i < C4LR_SurfaceCount; i++)
|
||||||
|
Surfaces[i]->GetTexAt(&TexRefs[i], x, y);
|
||||||
|
|
||||||
|
// Go through it from top to bottom
|
||||||
|
for(y = 0; y < To.Hgt; y++) {
|
||||||
|
|
||||||
|
// Initialize left & right
|
||||||
|
int iLeft = 0;
|
||||||
|
int iRight = 0;
|
||||||
|
for(x = 1; x < Min(C4LR_BiasDistanceX, To.x+1); x++)
|
||||||
|
iLeft += pSource->_GetPlacement(To.x-x,To.y+y);
|
||||||
|
for(x = 1; x < Min(C4LR_BiasDistanceX, iWidth - To.x); x++)
|
||||||
|
iRight += pSource->_GetPlacement(To.x+x,To.y+y);
|
||||||
|
|
||||||
|
for(x = 0; x < To.Wdt; x++) {
|
||||||
|
|
||||||
|
// Biases
|
||||||
|
int iPlac = pSource->_GetPlacement(To.x+x, To.y+y);
|
||||||
|
int iHBias = Max(0, iPlac * (C4LR_BiasDistanceY-1) - iRight) -
|
||||||
|
Max(0, iPlac * (C4LR_BiasDistanceY-1) - iLeft);
|
||||||
|
int iVBias = Max(0, iPlac * (C4LR_BiasDistanceY-1) - pDown[x]) -
|
||||||
|
Max(0, iPlac * (C4LR_BiasDistanceY-1) - pUp[x]);
|
||||||
|
|
||||||
|
// Maximum placement differences that make a difference in the result,
|
||||||
|
// after which we are at the limits of what can be packed into a byte
|
||||||
|
const int iMaxPlacDiff = 40;
|
||||||
|
int iHBiasScaled = BoundBy(iHBias * 127 / iMaxPlacDiff / C4LR_BiasDistanceX + 128, 0, 255);
|
||||||
|
int iVBiasScaled = BoundBy(iVBias * 127 / iMaxPlacDiff / C4LR_BiasDistanceY + 128, 0, 255);
|
||||||
|
|
||||||
|
// Collect data to save per pixel
|
||||||
|
unsigned char data[C4LR_SurfaceCount * 4];
|
||||||
|
memset(data, 0, sizeof(data));
|
||||||
|
|
||||||
|
data[C4LR_Material] = pSource->_GetPix(To.x+x, To.y+y);
|
||||||
|
data[C4LR_BiasX] = iHBiasScaled;
|
||||||
|
data[C4LR_BiasY] = iVBiasScaled;
|
||||||
|
|
||||||
|
for(int i = 0; i < C4LR_SurfaceCount; i++)
|
||||||
|
TexRefs[i]->SetPix4(To.x+x, To.y+y,
|
||||||
|
RGBA(data[i*4+0], data[i*4+1], data[i*4+2], data[i*4+3]));
|
||||||
|
|
||||||
|
// Update left & right
|
||||||
|
if(To.x+x + 1 < iWidth)
|
||||||
|
iRight -= pSource->_GetPlacement(To.x+x + 1, To.y+y);
|
||||||
|
if(To.x+x + C4LR_BiasDistanceX < iWidth)
|
||||||
|
iRight += pSource->_GetPlacement(To.x+x + C4LR_BiasDistanceX, To.y+y);
|
||||||
|
iLeft += pSource->_GetPlacement(To.x+x, To.y+y);
|
||||||
|
if(To.x+x - C4LR_BiasDistanceX - 1 >= 0)
|
||||||
|
iLeft -= pSource->_GetPlacement(To.x+x - C4LR_BiasDistanceX - 1, To.y+y);
|
||||||
|
|
||||||
|
// Update up & down arrays
|
||||||
|
if(To.y+y + 1 < iHeight)
|
||||||
|
pDown[x] -= pSource->_GetPlacement(To.x+x, To.y+y + 1);
|
||||||
|
if(To.y+y + C4LR_BiasDistanceY < iHeight)
|
||||||
|
pDown[x] += pSource->_GetPlacement(To.x+x, To.y+y + C4LR_BiasDistanceY);
|
||||||
|
pUp[x] += pSource->_GetPlacement(To.x+x, To.y+y);
|
||||||
|
if(To.y+y - C4LR_BiasDistanceY + 1 >= 0) {
|
||||||
|
pUp[x] -= pSource->_GetPlacement(To.x+x, To.y+y - C4LR_BiasDistanceY + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// done
|
||||||
|
delete[] pUp;
|
||||||
|
for (int i = 0; i < C4LR_SurfaceCount; i++)
|
||||||
|
Surfaces[i]->Unlock();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void C4LandscapeRenderGL::DumpInfoLog(const char *szWhat, GLhandleARB hShader)
|
||||||
|
{
|
||||||
|
// Get length of info line
|
||||||
|
int iLength = 0;
|
||||||
|
glGetObjectParameterivARB(hShader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &iLength);
|
||||||
|
if(iLength <= 1) return;
|
||||||
|
|
||||||
|
// Allocate buffer, get data
|
||||||
|
char *pBuf = new char [iLength + 1];
|
||||||
|
int iActualLength = 0;
|
||||||
|
glGetInfoLogARB(hShader, iLength, &iActualLength, pBuf);
|
||||||
|
if(iActualLength > iLength || iActualLength <= 0) return;
|
||||||
|
|
||||||
|
// Terminate, log
|
||||||
|
pBuf[iActualLength + 1] = '\0';
|
||||||
|
Log(pBuf);
|
||||||
|
delete[] pBuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int C4LandscapeRenderGL::GetObjectStatus(GLhandleARB hObj, GLenum type)
|
||||||
|
{
|
||||||
|
int iStatus = 0;
|
||||||
|
glGetObjectParameterivARB(hObj, type, &iStatus);
|
||||||
|
return iStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLhandleARB C4LandscapeRenderGL::CreateShader(GLenum iShaderType, const char *szWhat, const char *szCode)
|
||||||
|
{
|
||||||
|
const char *szCodes[1] = { szCode };
|
||||||
|
GLhandleARB hShader = glCreateShaderObjectARB(iShaderType);
|
||||||
|
glShaderSourceARB(hShader, 1, szCodes, 0);
|
||||||
|
glCompileShaderARB(hShader);
|
||||||
|
|
||||||
|
// Dump any information to log
|
||||||
|
DumpInfoLog(szWhat, hShader);
|
||||||
|
|
||||||
|
// Success?
|
||||||
|
if(GetObjectStatus(hShader, GL_OBJECT_COMPILE_STATUS_ARB) != 1)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return hShader;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool C4LandscapeRenderGL::InitShaders()
|
||||||
|
{
|
||||||
|
// Already initialized or no shader load?
|
||||||
|
if(hProg || LandscapeShader.getLength() <= 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// No support?
|
||||||
|
if(!GLEW_ARB_fragment_program)
|
||||||
|
{
|
||||||
|
Log(" gl: no shader support!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create trivial fragment shader
|
||||||
|
const char *szVert = "void main() { gl_TexCoord[0] = gl_MultiTexCoord0; gl_Position = ftransform(); } ";
|
||||||
|
hVert = CreateShader(GL_VERTEX_SHADER_ARB, "Vertex shader", szVert);
|
||||||
|
hFrag = CreateShader(GL_FRAGMENT_SHADER_ARB, "Fragment shader", LandscapeShader.getData());
|
||||||
|
if(!hFrag || !hVert) return false;
|
||||||
|
|
||||||
|
// Link program
|
||||||
|
hProg = glCreateProgramObjectARB();
|
||||||
|
glAttachObjectARB(hProg, hVert);
|
||||||
|
glAttachObjectARB(hProg, hFrag);
|
||||||
|
glLinkProgramARB(hProg);
|
||||||
|
|
||||||
|
// Link successful?
|
||||||
|
DumpInfoLog("Shader program", hProg);
|
||||||
|
if(GetObjectStatus(hProg, GL_OBJECT_LINK_STATUS_ARB) != 1)
|
||||||
|
{
|
||||||
|
ClearShaders();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get variable locations
|
||||||
|
hLandscapeUnit = glGetUniformLocationARB(hProg, "landscapeTex");
|
||||||
|
hScalerUnit = glGetUniformLocationARB(hProg, "scalerTex");
|
||||||
|
hMaterialUnit = glGetUniformLocationARB(hProg, "materialTex");
|
||||||
|
hResolutionUniform = glGetUniformLocationARB(hProg, "resolution");
|
||||||
|
hMatTexMapUniform = glGetUniformLocationARB(hProg, "matTexMap");
|
||||||
|
|
||||||
|
// Success?
|
||||||
|
if(int err = glGetError())
|
||||||
|
{
|
||||||
|
LogF(" gl: error code %d", err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void C4LandscapeRenderGL::ClearShaders()
|
||||||
|
{
|
||||||
|
if (!hProg) return;
|
||||||
|
|
||||||
|
// Need to be detached, then deleted
|
||||||
|
glDetachShader(hProg, hFrag);
|
||||||
|
glDetachShader(hProg, hVert);
|
||||||
|
glDeleteObjectARB(hFrag);
|
||||||
|
glDeleteObjectARB(hVert);
|
||||||
|
glDeleteObjectARB(hProg);
|
||||||
|
hFrag = hVert = hProg = 0;
|
||||||
|
|
||||||
|
hLandscapeUnit = hScalerUnit = hMaterialUnit = 0;
|
||||||
|
hResolutionUniform = hMatTexMapUniform = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool C4LandscapeRenderGL::LoadShaders(C4GroupSet *pGroups)
|
||||||
|
{
|
||||||
|
// First, clear out all existing shaders
|
||||||
|
ClearShaders();
|
||||||
|
// Search for our shaders
|
||||||
|
C4Group *pGroup = pGroups->FindEntry(C4CFN_LandscapeShader);
|
||||||
|
if(!pGroup) return false;
|
||||||
|
// Load it, save the path for later reloading
|
||||||
|
if(!pGroup->LoadEntryString(C4CFN_LandscapeShader, &LandscapeShader))
|
||||||
|
return false;
|
||||||
|
// If it physically exists, save back file name
|
||||||
|
if(FileExists(pGroup->GetFullName().getData()))
|
||||||
|
{
|
||||||
|
LandscapeShaderPath.Format("%s" DirSep C4CFN_LandscapeShader, pGroup->GetFullName().getData());
|
||||||
|
iLandscapeShaderTime = FileTime(LandscapeShaderPath.getData());
|
||||||
|
}
|
||||||
|
// Initialize
|
||||||
|
return InitShaders();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool C4LandscapeRenderGL::LoadScaler(C4GroupSet *pGroups)
|
||||||
|
{
|
||||||
|
// Search for scaler
|
||||||
|
C4Group *pGroup = pGroups->FindEntry(C4CFN_LandscapeScaler);
|
||||||
|
if(!pGroup) return false;
|
||||||
|
// Load scaler from group
|
||||||
|
return fctScaler.Load(*pGroup, C4CFN_LandscapeScaler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void C4LandscapeRenderGL::Draw(const C4TargetFacet &cgo)
|
||||||
|
{
|
||||||
|
// Must have GL and be initialized
|
||||||
|
if(!pGL && !hProg) return;
|
||||||
|
|
||||||
|
// prepare rendering to surface
|
||||||
|
CSurface *sfcTarget = cgo.Surface;
|
||||||
|
if (!pGL->PrepareRendering(sfcTarget)) return;
|
||||||
|
|
||||||
|
#ifdef AUTO_RELOAD_SHADERS
|
||||||
|
// File changed?
|
||||||
|
if(!LandscapeShaderPath.isNull() &&
|
||||||
|
FileTime(LandscapeShaderPath.getData()) != iLandscapeShaderTime)
|
||||||
|
{
|
||||||
|
ClearShaders();
|
||||||
|
// Load new shader
|
||||||
|
char szParentPath[_MAX_PATH+1]; C4Group Group;
|
||||||
|
GetParentPath(LandscapeShaderPath.getData(),szParentPath);
|
||||||
|
if(!Group.Open(szParentPath) ||
|
||||||
|
!Group.LoadEntryString(GetFilename(LandscapeShaderPath.getData()),&LandscapeShader) ||
|
||||||
|
!Group.Close())
|
||||||
|
return;
|
||||||
|
// Reinitialize
|
||||||
|
InitShaders();
|
||||||
|
iLandscapeShaderTime = FileTime(LandscapeShaderPath.getData());
|
||||||
|
}
|
||||||
|
#endif // AUTO_RELOAD_SHADERS
|
||||||
|
|
||||||
|
// Clear error(s?)
|
||||||
|
while(glGetError()) {}
|
||||||
|
|
||||||
|
// Activate shader
|
||||||
|
glUseProgramObjectARB(hProg);
|
||||||
|
|
||||||
|
// Bind data
|
||||||
|
glUniform1fvARB(hMatTexMapUniform, 256, MatTexMap);
|
||||||
|
glUniform2fARB(hResolutionUniform, iWidth, iHeight);
|
||||||
|
|
||||||
|
// Bind textures
|
||||||
|
int iUnit = 0; int iMaterialUnit = -1;
|
||||||
|
if(hScalerUnit >= 0)
|
||||||
|
{
|
||||||
|
glUniform1iARB(hScalerUnit, iUnit);
|
||||||
|
glActiveTexture(GL_TEXTURE0 + iUnit);
|
||||||
|
iUnit++;
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, fctScaler.Surface->ppTex[0]->texName);
|
||||||
|
}
|
||||||
|
if(hMaterialUnit >= 0)
|
||||||
|
{
|
||||||
|
iMaterialUnit = iUnit;
|
||||||
|
glUniform1iARB(hMaterialUnit, iUnit);
|
||||||
|
glActiveTexture(GL_TEXTURE0 + iUnit);
|
||||||
|
iUnit++;
|
||||||
|
glEnable(GL_TEXTURE_3D);
|
||||||
|
glBindTexture(GL_TEXTURE_3D, hMaterialTexture);
|
||||||
|
}
|
||||||
|
if(hLandscapeUnit >= 0)
|
||||||
|
{
|
||||||
|
GLint iLandscapeUnits[C4LR_SurfaceCount];
|
||||||
|
for(int i = 0; i < C4LR_SurfaceCount; i++)
|
||||||
|
{
|
||||||
|
iLandscapeUnits[i] = iUnit;
|
||||||
|
glActiveTexture(GL_TEXTURE0 + iUnit);
|
||||||
|
iUnit++;
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, Surfaces[i]->ppTex[0]->texName);
|
||||||
|
if (pGL->Zoom != 1.0)
|
||||||
|
{
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glUniform1ivARB(hLandscapeUnit, C4LR_SurfaceCount, iLandscapeUnits);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get current blitting offset in texture
|
||||||
|
int iBlitX=0;
|
||||||
|
int iBlitY=0;
|
||||||
|
|
||||||
|
// set up blit data as rect
|
||||||
|
FLOAT_RECT fTexBlt, tTexBlt;
|
||||||
|
float fx = float(cgo.TargetX), fy = float(cgo.TargetY);
|
||||||
|
fTexBlt.left = fx;
|
||||||
|
fTexBlt.top = fy;
|
||||||
|
fTexBlt.right = fx + float(cgo.Wdt);
|
||||||
|
fTexBlt.bottom= fy + float(cgo.Hgt);
|
||||||
|
|
||||||
|
// apply Zoom
|
||||||
|
float tx = float(cgo.X), ty = float(cgo.Y);
|
||||||
|
pGL->ApplyZoom(tx, ty);
|
||||||
|
tTexBlt.left = tx;
|
||||||
|
tTexBlt.top = ty;
|
||||||
|
tTexBlt.right = tx + float(cgo.Wdt) * pGL->Zoom;
|
||||||
|
tTexBlt.bottom= ty + float(cgo.Hgt) * pGL->Zoom;
|
||||||
|
|
||||||
|
// blit positions
|
||||||
|
CBltVertex Vtx[4];
|
||||||
|
Vtx[0].ftx = tTexBlt.left; Vtx[0].fty = tTexBlt.top;
|
||||||
|
Vtx[1].ftx = tTexBlt.right; Vtx[1].fty = tTexBlt.top;
|
||||||
|
Vtx[2].ftx = tTexBlt.right; Vtx[2].fty = tTexBlt.bottom;
|
||||||
|
Vtx[3].ftx = tTexBlt.left; Vtx[3].fty = tTexBlt.bottom;
|
||||||
|
Vtx[0].tx = fTexBlt.left; Vtx[0].ty = fTexBlt.top;
|
||||||
|
Vtx[1].tx = fTexBlt.right; Vtx[1].ty = fTexBlt.top;
|
||||||
|
Vtx[2].tx = fTexBlt.right; Vtx[2].ty = fTexBlt.bottom;
|
||||||
|
Vtx[3].tx = fTexBlt.left; Vtx[3].ty = fTexBlt.bottom;
|
||||||
|
for (int i=0; i<4; ++i)
|
||||||
|
{
|
||||||
|
Vtx[i].tx /= float(iWidth);
|
||||||
|
Vtx[i].ty /= float(iHeight);
|
||||||
|
Vtx[i].ftz = 0;
|
||||||
|
Vtx[i].color[0] = 255;
|
||||||
|
Vtx[i].color[1] = 255;
|
||||||
|
Vtx[i].color[2] = 255;
|
||||||
|
Vtx[i].color[3] = 255;
|
||||||
|
//DwTo4UB(RGBA(255, 255, 255, 255), Vtx[i].color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// color modulation?
|
||||||
|
//DWORD dwModClr = BlitModulated ? BlitModulateClr : 0xffffffff;
|
||||||
|
//for (int i=0; i<4; ++i)
|
||||||
|
// DwTo4UB(dwModClr | dwModMask, Vtx[i].color);
|
||||||
|
|
||||||
|
// Blit
|
||||||
|
glInterleavedArrays(GL_T2F_C4UB_V3F, sizeof(CBltVertex), Vtx);
|
||||||
|
glDrawArrays(GL_QUADS, 0, 4);
|
||||||
|
|
||||||
|
// Remove shader
|
||||||
|
glUseProgramObjectARB(0);
|
||||||
|
|
||||||
|
// Unbind textures
|
||||||
|
while(iUnit > 0)
|
||||||
|
{
|
||||||
|
iUnit--;
|
||||||
|
glActiveTexture(GL_TEXTURE0 + iUnit);
|
||||||
|
glDisable(iUnit == iMaterialUnit ? GL_TEXTURE_3D : GL_TEXTURE_2D);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Got an error?
|
||||||
|
if(int err = glGetError())
|
||||||
|
{
|
||||||
|
LogF("GL error: %d", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // USE_GL
|
|
@ -0,0 +1,127 @@
|
||||||
|
|
||||||
|
#ifndef C4LANDSCAPE_RENDER_H
|
||||||
|
#define C4LANDSCAPE_RENDER_H
|
||||||
|
|
||||||
|
#include "StdSurface2.h"
|
||||||
|
#include "C4FacetEx.h"
|
||||||
|
|
||||||
|
// Data we want to store per landscape pixel
|
||||||
|
enum C4LR_Byte {
|
||||||
|
C4LR_Material,
|
||||||
|
C4LR_BiasX,
|
||||||
|
C4LR_BiasY,
|
||||||
|
|
||||||
|
C4LR_ByteCount
|
||||||
|
};
|
||||||
|
|
||||||
|
// How much data we want to store per landscape pixel
|
||||||
|
const int C4LR_BytesPerPx = 3;
|
||||||
|
|
||||||
|
// How much data we can hold per surface, how much surfaces we therefore need.
|
||||||
|
const int C4LR_BytesPerSurface = 4;
|
||||||
|
const int C4LR_SurfaceCount = (C4LR_ByteCount + C4LR_BytesPerSurface - 1) / C4LR_BytesPerSurface;
|
||||||
|
|
||||||
|
class C4Landscape; class C4TextureMap;
|
||||||
|
|
||||||
|
class C4LandscapeRender
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
C4LandscapeRender()
|
||||||
|
: iWidth(0), iHeight(0), pTexs(NULL) { }
|
||||||
|
virtual ~C4LandscapeRender()
|
||||||
|
{}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int32_t iWidth, iHeight;
|
||||||
|
C4TextureMap *pTexs;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual bool Init(int32_t iWidth, int32_t iHeight, C4TextureMap *pTexs, C4GroupSet *pGraphics) = 0;
|
||||||
|
virtual void Clear() = 0;
|
||||||
|
|
||||||
|
// Returns the rectangle of pixels that must be updated on changes in the given rect
|
||||||
|
virtual C4Rect GetAffectedRect(C4Rect Rect) = 0;
|
||||||
|
|
||||||
|
// Updates the landscape rendering to reflect the landscape contents in
|
||||||
|
// the given rectangle
|
||||||
|
virtual void Update(C4Rect Rect, C4Landscape *pSource) = 0;
|
||||||
|
|
||||||
|
virtual void Draw(const C4TargetFacet &cgo) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef USE_GL
|
||||||
|
class C4LandscapeRenderGL : public C4LandscapeRender
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
C4LandscapeRenderGL();
|
||||||
|
~C4LandscapeRenderGL();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// surfaces
|
||||||
|
CSurface *Surfaces[C4LR_SurfaceCount];
|
||||||
|
|
||||||
|
// shader sources
|
||||||
|
StdStrBuf LandscapeShader;
|
||||||
|
StdStrBuf LandscapeShaderPath;
|
||||||
|
int iLandscapeShaderTime;
|
||||||
|
// shaders
|
||||||
|
GLhandleARB hVert, hFrag, hProg;
|
||||||
|
// shader variables
|
||||||
|
GLhandleARB hLandscapeUnit, hScalerUnit, hMaterialUnit;
|
||||||
|
GLhandleARB hResolutionUniform, hMatTexMapUniform;
|
||||||
|
|
||||||
|
// Texture count
|
||||||
|
int32_t iTexCount;
|
||||||
|
// 3D material textures
|
||||||
|
GLuint hMaterialTexture;
|
||||||
|
// material map
|
||||||
|
GLfloat MatTexMap[256];
|
||||||
|
|
||||||
|
// scaler image
|
||||||
|
C4FacetSurface fctScaler;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual bool Init(int32_t iWidth, int32_t iHeight, C4TextureMap *pMap, C4GroupSet *pGraphics);
|
||||||
|
virtual void Clear();
|
||||||
|
|
||||||
|
virtual C4Rect GetAffectedRect(C4Rect Rect);
|
||||||
|
virtual void Update(C4Rect Rect, C4Landscape *pSource);
|
||||||
|
|
||||||
|
virtual void Draw(const C4TargetFacet &cgo);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool InitMaterialTexture(C4TextureMap *pMap);
|
||||||
|
bool LoadShaders(C4GroupSet *pGraphics);
|
||||||
|
bool LoadScaler(C4GroupSet *pGraphics);
|
||||||
|
|
||||||
|
void DumpInfoLog(const char *szWhat, GLhandleARB hShader);
|
||||||
|
int GetObjectStatus(GLhandleARB hObj, GLenum type);
|
||||||
|
GLhandleARB CreateShader(GLenum iShaderType, const char *szWhat, const char *szCode);
|
||||||
|
|
||||||
|
bool InitShaders();
|
||||||
|
void ClearShaders();
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class C4LandscapeRenderClassic : public C4LandscapeRender
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
C4LandscapeRenderClassic();
|
||||||
|
~C4LandscapeRenderClassic();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CSurface *Surface32;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual bool Init(int32_t iWidth, int32_t iHeight, C4TextureMap *pMap, C4GroupSet *pGraphics);
|
||||||
|
virtual void Clear();
|
||||||
|
|
||||||
|
virtual C4Rect GetAffectedRect(C4Rect Rect);
|
||||||
|
virtual void Update(C4Rect Rect, C4Landscape *pSource);
|
||||||
|
|
||||||
|
virtual void Draw(const C4TargetFacet &cgo);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // C4LANDSCAPE_RENDER_H
|
|
@ -0,0 +1,120 @@
|
||||||
|
|
||||||
|
#include "C4Include.h"
|
||||||
|
#include "C4LandscapeRender.h"
|
||||||
|
#include "C4Landscape.h"
|
||||||
|
#include "C4Texture.h"
|
||||||
|
|
||||||
|
const int C4LS_MaxLightDistY = 8;
|
||||||
|
const int C4LS_MaxLightDistX = 1;
|
||||||
|
|
||||||
|
C4LandscapeRenderClassic::C4LandscapeRenderClassic()
|
||||||
|
: Surface32(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
C4LandscapeRenderClassic::~C4LandscapeRenderClassic()
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool C4LandscapeRenderClassic::Init(int32_t iWidth, int32_t iHeight, C4TextureMap *pTexs, C4GroupSet *pGraphics)
|
||||||
|
{
|
||||||
|
// Create surface
|
||||||
|
Surface32 = new CSurface();
|
||||||
|
if(!Surface32->Create(iWidth, iHeight, false, false, 256))
|
||||||
|
return false;
|
||||||
|
// Safe back info
|
||||||
|
this->iWidth = iWidth;
|
||||||
|
this->iHeight = iHeight;
|
||||||
|
this->pTexs = pTexs;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void C4LandscapeRenderClassic::Clear()
|
||||||
|
{
|
||||||
|
delete Surface32; Surface32 = 0;
|
||||||
|
iWidth = iHeight = 0;
|
||||||
|
pTexs = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
C4Rect C4LandscapeRenderClassic::GetAffectedRect(C4Rect Rect)
|
||||||
|
{
|
||||||
|
Rect.Enlarge(C4LS_MaxLightDistX, C4LS_MaxLightDistY);
|
||||||
|
return Rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
void C4LandscapeRenderClassic::Update(C4Rect To, C4Landscape *pSource)
|
||||||
|
{
|
||||||
|
// clip to landscape size
|
||||||
|
To.Intersect(C4Rect(0,0,iWidth,iHeight));
|
||||||
|
// everything clipped?
|
||||||
|
if (To.Wdt<=0 || To.Hgt<=0) return;
|
||||||
|
if (!Surface32->Lock()) return;
|
||||||
|
|
||||||
|
// We clear the affected region here because ClearBoxDw allocates the
|
||||||
|
// main memory buffer for the box, so that only that box needs to be
|
||||||
|
// sent to the gpu, and not the whole texture, or every pixel
|
||||||
|
// separately. It's an important optimization.
|
||||||
|
Surface32->ClearBoxDw(To.x, To.y, To.Wdt, To.Hgt);
|
||||||
|
|
||||||
|
// do lightning
|
||||||
|
for (int32_t iX=To.x; iX<To.x+To.Wdt; ++iX)
|
||||||
|
{
|
||||||
|
int AboveDensity = 0, BelowDensity = 0;
|
||||||
|
for (int i = 1; i <= 8; ++i)
|
||||||
|
{
|
||||||
|
AboveDensity += pSource->GetPlacement(iX, To.y - i - 1);
|
||||||
|
BelowDensity += pSource->GetPlacement(iX, To.y + i - 1);
|
||||||
|
}
|
||||||
|
for (int32_t iY=To.y; iY<To.y+To.Hgt; ++iY)
|
||||||
|
{
|
||||||
|
AboveDensity -= pSource->GetPlacement(iX, iY - 9);
|
||||||
|
AboveDensity += pSource->GetPlacement(iX, iY - 1);
|
||||||
|
BelowDensity -= pSource->GetPlacement(iX, iY);
|
||||||
|
BelowDensity += pSource->GetPlacement(iX, iY + 8);
|
||||||
|
BYTE pix = pSource->_GetPix(iX, iY);
|
||||||
|
// Sky
|
||||||
|
if (!pix)
|
||||||
|
{
|
||||||
|
Surface32->SetPixDw(iX, iY, 0x00ffffff);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// get density
|
||||||
|
int iOwnDens = pSource->_GetPlacement(iX, iY);
|
||||||
|
if (!iOwnDens) continue;
|
||||||
|
iOwnDens *= 2;
|
||||||
|
iOwnDens += pSource->GetPlacement(iX + 1, iY) + pSource->GetPlacement(iX - 1, iY);
|
||||||
|
iOwnDens /= 4;
|
||||||
|
// get texture map entry for pixel
|
||||||
|
const C4TexMapEntry *pTex = pTexs->GetEntry(PixCol2Tex(pix));
|
||||||
|
assert(pTex);
|
||||||
|
// get texture contents
|
||||||
|
DWORD dwBackClr;
|
||||||
|
if (pTex) dwBackClr = pTex->GetPattern().PatternClr(iX, iY);
|
||||||
|
// get density of surrounding materials
|
||||||
|
int iCompareDens = AboveDensity / 8;
|
||||||
|
if (iOwnDens > iCompareDens)
|
||||||
|
{
|
||||||
|
// apply light
|
||||||
|
LightenClrBy(dwBackClr, Min(30, 2 * (iOwnDens - iCompareDens)));
|
||||||
|
}
|
||||||
|
else if (iOwnDens < iCompareDens && iOwnDens < 30)
|
||||||
|
{
|
||||||
|
DarkenClrBy(dwBackClr, Min(30, 2 * (iCompareDens - iOwnDens)));
|
||||||
|
}
|
||||||
|
iCompareDens = BelowDensity / 8;
|
||||||
|
if (iOwnDens > iCompareDens)
|
||||||
|
{
|
||||||
|
DarkenClrBy(dwBackClr, Min(30, 2 * (iOwnDens - iCompareDens)));
|
||||||
|
}
|
||||||
|
Surface32->SetPixDw(iX, iY, dwBackClr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Surface32->Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void C4LandscapeRenderClassic::Draw(const C4TargetFacet &cgo)
|
||||||
|
{
|
||||||
|
lpDDraw->BlitLandscape(Surface32, cgo.TargetX, cgo.TargetY, cgo.Surface,
|
||||||
|
cgo.X, cgo.Y, cgo.Wdt, cgo.Hgt, 0);
|
||||||
|
}
|
|
@ -287,7 +287,7 @@ int32_t C4TextureMap::LoadTextures(C4Group &hGroup, C4Group* OverloadFile)
|
||||||
char texname[256+1];
|
char texname[256+1];
|
||||||
C4Surface *ctex;
|
C4Surface *ctex;
|
||||||
size_t binlen;
|
size_t binlen;
|
||||||
// newgfx: load PNG-textures first
|
|
||||||
hGroup.ResetSearch();
|
hGroup.ResetSearch();
|
||||||
while (hGroup.AccessNextEntry("*",&binlen,texname))
|
while (hGroup.AccessNextEntry("*",&binlen,texname))
|
||||||
{
|
{
|
||||||
|
@ -306,6 +306,7 @@ int32_t C4TextureMap::LoadTextures(C4Group &hGroup, C4Group* OverloadFile)
|
||||||
delete ctex;
|
delete ctex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return texnum;
|
return texnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,6 +382,16 @@ C4Texture * C4TextureMap::GetTexture(const char *szTexture)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t C4TextureMap::GetTextureIndex(const char *szName)
|
||||||
|
{
|
||||||
|
C4Texture *pTexture;
|
||||||
|
int32_t i=0;
|
||||||
|
for (pTexture=FirstTexture; pTexture; pTexture=pTexture->Next, i++)
|
||||||
|
if (SEqualNoCase(pTexture->Name,szName))
|
||||||
|
return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
bool C4TextureMap::CheckTexture(const char *szTexture)
|
bool C4TextureMap::CheckTexture(const char *szTexture)
|
||||||
{
|
{
|
||||||
C4Texture *pTexture;
|
C4Texture *pTexture;
|
||||||
|
|
|
@ -97,6 +97,7 @@ public:
|
||||||
C4Texture * GetTexture(const char *szTexture);
|
C4Texture * GetTexture(const char *szTexture);
|
||||||
bool CheckTexture(const char *szTexture); // return whether texture exists
|
bool CheckTexture(const char *szTexture); // return whether texture exists
|
||||||
bool AddEntry(BYTE byIndex, const char *szMaterial, const char *szTexture);
|
bool AddEntry(BYTE byIndex, const char *szMaterial, const char *szTexture);
|
||||||
|
int32_t GetTextureIndex(const char *pTexName);
|
||||||
protected:
|
protected:
|
||||||
bool AddTexture(const char *szTexture, CSurface * sfcSurface);
|
bool AddTexture(const char *szTexture, CSurface * sfcSurface);
|
||||||
};
|
};
|
||||||
|
|
|
@ -57,8 +57,10 @@ public:
|
||||||
void Normalize()
|
void Normalize()
|
||||||
{ if (Wdt < 0) { x+=Wdt+1; Wdt=-Wdt; } if (Hgt < 0) { y+=Hgt+1; Hgt=-Hgt; } }
|
{ if (Wdt < 0) { x+=Wdt+1; Wdt=-Wdt; } if (Hgt < 0) { y+=Hgt+1; Hgt=-Hgt; } }
|
||||||
|
|
||||||
|
void Enlarge(int32_t iByX, int32_t iByY)
|
||||||
|
{ x -= iByX; y -= iByY; Wdt += 2*iByX; Hgt += 2*iByY; }
|
||||||
void Enlarge(int32_t iBy)
|
void Enlarge(int32_t iBy)
|
||||||
{ x -= iBy; y -= iBy; Wdt += 2*iBy; Hgt += 2*iBy; }
|
{ Enlarge(iBy, iBy); }
|
||||||
|
|
||||||
int32_t GetMiddleX() { return x+Wdt/2; }
|
int32_t GetMiddleX() { return x+Wdt/2; }
|
||||||
int32_t GetMiddleY() { return y+Hgt/2; }
|
int32_t GetMiddleY() { return y+Hgt/2; }
|
||||||
|
|
Loading…
Reference in New Issue