mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-13 03:28:19 +00:00
49bed71932
5696: Add option for parallax-aware zoom r=def- a=Fireball-Teeworlds ## How this works Currently we have parallax X and Y parameters that control how far away a layer feels. Currently it's only taken into account for camera moving sideways. This pull request makes zoom behave as if the camera was moving closer or further away, taking into account the distance to the layer. In order to provide flexibility, this behaviour is using a separate parallax value, similar to how we have separate values for X and Y. Para Zoom will default to the minimum of parallax X, Y, clamped to be between 0 and 100. This seems to look well on most maps. This pull request also introduces two new features to the Editor: * Controls for configuring per-group Para Zoom value. If Custom Zoom is set to No, Para Zoom will automatically keep following to the default value described above, so that people new to the feature don't have to figure out how it works. * Zoom button that previews the zoom behavior (next to Proof at the top). ## Editor Screenshots ### Para Zoom controls ![screenshot_2022-08-22_21-38-04](https://user-images.githubusercontent.com/68162181/186014490-f7b91245-460f-405f-8d5c-3f91db2a1b9a.png) ![screenshot_2022-08-22_21-37-58](https://user-images.githubusercontent.com/68162181/186014522-03b6e814-4dd9-4d07-9af9-7db5fb434a56.png) ### Zoom Button ![screenshot_2022-08-22_21-40-46](https://user-images.githubusercontent.com/68162181/186014856-2d1d499d-9011-439c-b217-536957e0c1e3.png) ![screenshot_2022-08-22_21-40-50](https://user-images.githubusercontent.com/68162181/186014874-6d2939d3-00ff-4327-a790-414b5151ba31.png) ## In-Game Screenshots Video: https://youtu.be/W7eXQN0gRFI This is an older version of the pull request that had an option to disable the new behaviour. The current version can only be disabled in map editor for a particular map. ### Springlobe 3 With new feature: ![screenshot_2022-08-02_04-28-19](https://user-images.githubusercontent.com/68162181/182286371-b67cee1c-73d8-4a24-a9c3-1b28340a3b42.png) Without: ![screenshot_2022-08-02_04-28-25](https://user-images.githubusercontent.com/68162181/182286367-24555381-1700-4ff1-80c7-39e5dce63820.png) ### Beyond Dreams With new feature: ![screenshot_2022-08-02_04-28-59](https://user-images.githubusercontent.com/68162181/182286322-114ecb90-0860-462c-9012-bb2f3ff848fb.png) Without: ![screenshot_2022-08-02_04-28-55](https://user-images.githubusercontent.com/68162181/182286654-f34da72b-7991-4f42-89ad-679279fcb83e.png) ## Checklist - [X] Tested the change ingame - [X] Provided screenshots if it is a visual change - [X] Tested in combination with possibly related configuration options - [ ] Written a unit test (especially base/) or added coverage to integration test - [X] Considered possible null pointers and out of bounds array indexing - [ ] Changed no physics that affect existing maps - [X] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional) Co-authored-by: Fireball <fireball.teeworlds@gmail.com>
426 lines
14 KiB
C++
426 lines
14 KiB
C++
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
|
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
|
#include <cmath>
|
|
|
|
#include <base/math.h>
|
|
|
|
#include "animstate.h"
|
|
#include "render.h"
|
|
|
|
#include <engine/graphics.h>
|
|
#include <engine/shared/config.h>
|
|
|
|
#include <game/generated/client_data.h>
|
|
#include <game/generated/client_data7.h>
|
|
#include <game/generated/protocol.h>
|
|
|
|
#include <game/mapitems.h>
|
|
#include <game/mapitems_ex.h>
|
|
|
|
static float gs_SpriteWScale;
|
|
static float gs_SpriteHScale;
|
|
|
|
void CRenderTools::Init(IGraphics *pGraphics, ITextRender *pTextRender)
|
|
{
|
|
m_pGraphics = pGraphics;
|
|
m_pTextRender = pTextRender;
|
|
m_TeeQuadContainerIndex = Graphics()->CreateQuadContainer(false);
|
|
Graphics()->SetColor(1.f, 1.f, 1.f, 1.f);
|
|
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
|
QuadContainerAddSprite(m_TeeQuadContainerIndex, 64.f);
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
|
QuadContainerAddSprite(m_TeeQuadContainerIndex, 64.f);
|
|
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
|
QuadContainerAddSprite(m_TeeQuadContainerIndex, 64.f * 0.4f);
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
|
QuadContainerAddSprite(m_TeeQuadContainerIndex, 64.f * 0.4f);
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
|
QuadContainerAddSprite(m_TeeQuadContainerIndex, 64.f * 0.4f);
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
|
QuadContainerAddSprite(m_TeeQuadContainerIndex, 64.f * 0.4f);
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
|
QuadContainerAddSprite(m_TeeQuadContainerIndex, 64.f * 0.4f);
|
|
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
|
QuadContainerAddSprite(m_TeeQuadContainerIndex, -32.f, -16.f, 64.f, 32.f);
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
|
QuadContainerAddSprite(m_TeeQuadContainerIndex, -32.f, -16.f, 64.f, 32.f);
|
|
Graphics()->QuadContainerUpload(m_TeeQuadContainerIndex);
|
|
}
|
|
|
|
void CRenderTools::SelectSprite(CDataSprite *pSpr, int Flags, int sx, int sy)
|
|
{
|
|
int x = pSpr->m_X + sx;
|
|
int y = pSpr->m_Y + sy;
|
|
int w = pSpr->m_W;
|
|
int h = pSpr->m_H;
|
|
int cx = pSpr->m_pSet->m_Gridx;
|
|
int cy = pSpr->m_pSet->m_Gridy;
|
|
|
|
GetSpriteScaleImpl(w, h, gs_SpriteWScale, gs_SpriteHScale);
|
|
|
|
float x1 = x / (float)cx + 0.5f / (float)(cx * 32);
|
|
float x2 = (x + w) / (float)cx - 0.5f / (float)(cx * 32);
|
|
float y1 = y / (float)cy + 0.5f / (float)(cy * 32);
|
|
float y2 = (y + h) / (float)cy - 0.5f / (float)(cy * 32);
|
|
|
|
if(Flags & SPRITE_FLAG_FLIP_Y)
|
|
std::swap(y1, y2);
|
|
|
|
if(Flags & SPRITE_FLAG_FLIP_X)
|
|
std::swap(x1, x2);
|
|
|
|
Graphics()->QuadsSetSubset(x1, y1, x2, y2);
|
|
}
|
|
|
|
void CRenderTools::SelectSprite(int Id, int Flags, int sx, int sy)
|
|
{
|
|
if(Id < 0 || Id >= g_pData->m_NumSprites)
|
|
return;
|
|
SelectSprite(&g_pData->m_aSprites[Id], Flags, sx, sy);
|
|
}
|
|
|
|
void CRenderTools::GetSpriteScale(client_data7::CDataSprite *pSprite, float &ScaleX, float &ScaleY)
|
|
{
|
|
int w = pSprite->m_W;
|
|
int h = pSprite->m_H;
|
|
GetSpriteScaleImpl(w, h, ScaleX, ScaleY);
|
|
}
|
|
|
|
void CRenderTools::GetSpriteScale(struct CDataSprite *pSprite, float &ScaleX, float &ScaleY)
|
|
{
|
|
int w = pSprite->m_W;
|
|
int h = pSprite->m_H;
|
|
GetSpriteScaleImpl(w, h, ScaleX, ScaleY);
|
|
}
|
|
|
|
void CRenderTools::GetSpriteScale(int Id, float &ScaleX, float &ScaleY)
|
|
{
|
|
GetSpriteScale(&g_pData->m_aSprites[Id], ScaleX, ScaleY);
|
|
}
|
|
|
|
void CRenderTools::GetSpriteScaleImpl(int Width, int Height, float &ScaleX, float &ScaleY)
|
|
{
|
|
float f = sqrtf(Height * Height + Width * Width);
|
|
ScaleX = Width / f;
|
|
ScaleY = Height / f;
|
|
}
|
|
|
|
void CRenderTools::DrawSprite(float x, float y, float Size)
|
|
{
|
|
IGraphics::CQuadItem QuadItem(x, y, Size * gs_SpriteWScale, Size * gs_SpriteHScale);
|
|
Graphics()->QuadsDraw(&QuadItem, 1);
|
|
}
|
|
|
|
void CRenderTools::DrawSprite(float x, float y, float ScaledWidth, float ScaledHeight)
|
|
{
|
|
IGraphics::CQuadItem QuadItem(x, y, ScaledWidth, ScaledHeight);
|
|
Graphics()->QuadsDraw(&QuadItem, 1);
|
|
}
|
|
|
|
void CRenderTools::RenderCursor(vec2 Center, float Size)
|
|
{
|
|
Graphics()->WrapClamp();
|
|
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_CURSOR].m_Id);
|
|
Graphics()->QuadsBegin();
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
|
IGraphics::CQuadItem QuadItem(Center.x, Center.y, Size, Size);
|
|
Graphics()->QuadsDrawTL(&QuadItem, 1);
|
|
Graphics()->QuadsEnd();
|
|
Graphics()->WrapNormal();
|
|
}
|
|
|
|
void CRenderTools::RenderIcon(int ImageId, int SpriteId, const CUIRect *pRect, const ColorRGBA *pColor)
|
|
{
|
|
Graphics()->TextureSet(g_pData->m_aImages[ImageId].m_Id);
|
|
Graphics()->QuadsBegin();
|
|
SelectSprite(SpriteId);
|
|
if(pColor)
|
|
Graphics()->SetColor(pColor->r * pColor->a, pColor->g * pColor->a, pColor->b * pColor->a, pColor->a);
|
|
IGraphics::CQuadItem QuadItem(pRect->x, pRect->y, pRect->w, pRect->h);
|
|
Graphics()->QuadsDrawTL(&QuadItem, 1);
|
|
Graphics()->QuadsEnd();
|
|
}
|
|
|
|
int CRenderTools::QuadContainerAddSprite(int QuadContainerIndex, float x, float y, float Size)
|
|
{
|
|
IGraphics::CQuadItem QuadItem(x, y, Size, Size);
|
|
return Graphics()->QuadContainerAddQuads(QuadContainerIndex, &QuadItem, 1);
|
|
}
|
|
|
|
int CRenderTools::QuadContainerAddSprite(int QuadContainerIndex, float Size)
|
|
{
|
|
IGraphics::CQuadItem QuadItem(-(Size) / 2.f, -(Size) / 2.f, (Size), (Size));
|
|
return Graphics()->QuadContainerAddQuads(QuadContainerIndex, &QuadItem, 1);
|
|
}
|
|
|
|
int CRenderTools::QuadContainerAddSprite(int QuadContainerIndex, float Width, float Height)
|
|
{
|
|
IGraphics::CQuadItem QuadItem(-(Width) / 2.f, -(Height) / 2.f, (Width), (Height));
|
|
return Graphics()->QuadContainerAddQuads(QuadContainerIndex, &QuadItem, 1);
|
|
}
|
|
|
|
int CRenderTools::QuadContainerAddSprite(int QuadContainerIndex, float X, float Y, float Width, float Height)
|
|
{
|
|
IGraphics::CQuadItem QuadItem(X, Y, Width, Height);
|
|
return Graphics()->QuadContainerAddQuads(QuadContainerIndex, &QuadItem, 1);
|
|
}
|
|
|
|
void CRenderTools::GetRenderTeeAnimScaleAndBaseSize(CAnimState *pAnim, CTeeRenderInfo *pInfo, float &AnimScale, float &BaseSize)
|
|
{
|
|
AnimScale = pInfo->m_Size * 1.0f / 64.0f;
|
|
BaseSize = pInfo->m_Size;
|
|
}
|
|
|
|
void CRenderTools::GetRenderTeeBodyScale(float BaseSize, float &BodyScale)
|
|
{
|
|
BodyScale = g_Config.m_ClFatSkins ? BaseSize * 1.3f : BaseSize;
|
|
BodyScale /= 64.0f;
|
|
}
|
|
|
|
void CRenderTools::GetRenderTeeFeetScale(float BaseSize, float &FeetScaleWidth, float &FeetScaleHeight)
|
|
{
|
|
FeetScaleWidth = BaseSize / 64.0f;
|
|
FeetScaleHeight = (BaseSize / 2) / 32.0f;
|
|
}
|
|
|
|
void CRenderTools::GetRenderTeeBodySize(CAnimState *pAnim, CTeeRenderInfo *pInfo, vec2 &BodyOffset, float &Width, float &Height)
|
|
{
|
|
float AnimScale, BaseSize;
|
|
GetRenderTeeAnimScaleAndBaseSize(pAnim, pInfo, AnimScale, BaseSize);
|
|
|
|
float BodyScale;
|
|
GetRenderTeeBodyScale(BaseSize, BodyScale);
|
|
|
|
Width = pInfo->m_SkinMetrics.m_Body.WidthNormalized() * 64.0f * BodyScale;
|
|
Height = pInfo->m_SkinMetrics.m_Body.HeightNormalized() * 64.0f * BodyScale;
|
|
BodyOffset.x = pInfo->m_SkinMetrics.m_Body.OffsetXNormalized() * 64.0f * BodyScale;
|
|
BodyOffset.y = pInfo->m_SkinMetrics.m_Body.OffsetYNormalized() * 64.0f * BodyScale;
|
|
}
|
|
|
|
void CRenderTools::GetRenderTeeFeetSize(CAnimState *pAnim, CTeeRenderInfo *pInfo, vec2 &FeetOffset, float &Width, float &Height)
|
|
{
|
|
float AnimScale, BaseSize;
|
|
GetRenderTeeAnimScaleAndBaseSize(pAnim, pInfo, AnimScale, BaseSize);
|
|
|
|
float FeetScaleWidth, FeetScaleHeight;
|
|
GetRenderTeeFeetScale(BaseSize, FeetScaleWidth, FeetScaleHeight);
|
|
|
|
Width = pInfo->m_SkinMetrics.m_Feet.WidthNormalized() * 64.0f * FeetScaleWidth;
|
|
Height = pInfo->m_SkinMetrics.m_Feet.HeightNormalized() * 32.0f * FeetScaleHeight;
|
|
FeetOffset.x = pInfo->m_SkinMetrics.m_Feet.OffsetXNormalized() * 64.0f * FeetScaleWidth;
|
|
FeetOffset.y = pInfo->m_SkinMetrics.m_Feet.OffsetYNormalized() * 32.0f * FeetScaleHeight;
|
|
}
|
|
|
|
void CRenderTools::GetRenderTeeOffsetToRenderedTee(CAnimState *pAnim, CTeeRenderInfo *pInfo, vec2 &TeeOffsetToMid)
|
|
{
|
|
float AnimScale, BaseSize;
|
|
GetRenderTeeAnimScaleAndBaseSize(pAnim, pInfo, AnimScale, BaseSize);
|
|
vec2 BodyPos = vec2(pAnim->GetBody()->m_X, pAnim->GetBody()->m_Y) * AnimScale;
|
|
|
|
float AssumedScale = BaseSize / 64.0f;
|
|
|
|
// just use the lowest feet
|
|
vec2 FeetPos;
|
|
CAnimKeyframe *pFoot = pAnim->GetFrontFoot();
|
|
FeetPos = vec2(pFoot->m_X * AnimScale, pFoot->m_Y * AnimScale);
|
|
pFoot = pAnim->GetBackFoot();
|
|
FeetPos = vec2(FeetPos.x, maximum(FeetPos.y, pFoot->m_Y * AnimScale));
|
|
|
|
vec2 BodyOffset;
|
|
float BodyWidth, BodyHeight;
|
|
GetRenderTeeBodySize(pAnim, pInfo, BodyOffset, BodyWidth, BodyHeight);
|
|
|
|
// -32 is the assumed min relative position for the quad
|
|
float MinY = -32.0f * AssumedScale;
|
|
// the body pos shifts the body away from center
|
|
MinY += BodyPos.y;
|
|
// the actual body is smaller tho, bcs it doesnt use the full skin image in most cases
|
|
MinY += BodyOffset.y;
|
|
|
|
vec2 FeetOffset;
|
|
float FeetWidth, FeetHeight;
|
|
GetRenderTeeFeetSize(pAnim, pInfo, FeetOffset, FeetWidth, FeetHeight);
|
|
|
|
// MaxY builds up from the MinY
|
|
float MaxY = MinY + BodyHeight;
|
|
// if the body is smaller than the total feet offset, use feet
|
|
// since feets are smaller in height, respect the assumed relative position
|
|
MaxY = maximum(MaxY, (-16.0f * AssumedScale + FeetPos.y) + FeetOffset.y + FeetHeight);
|
|
|
|
// now we got the full rendered size
|
|
float FullHeight = (MaxY - MinY);
|
|
|
|
// next step is to calculate the offset that was created compared to the assumed relative positon
|
|
float MidOfRendered = MinY + FullHeight / 2.0f;
|
|
|
|
// TODO: x coordinate is ignored for now, bcs it's not really used yet anyway
|
|
TeeOffsetToMid.x = 0;
|
|
// negative value, because the calculation that uses this offset should work with addition.
|
|
TeeOffsetToMid.y = -MidOfRendered;
|
|
}
|
|
|
|
void CRenderTools::RenderTee(CAnimState *pAnim, CTeeRenderInfo *pInfo, int Emote, vec2 Dir, vec2 Pos, float Alpha)
|
|
{
|
|
vec2 Direction = Dir;
|
|
vec2 Position = Pos;
|
|
|
|
const CSkin::SSkinTextures *pSkinTextures = pInfo->m_CustomColoredSkin ? &pInfo->m_ColorableRenderSkin : &pInfo->m_OriginalRenderSkin;
|
|
|
|
// first pass we draw the outline
|
|
// second pass we draw the filling
|
|
for(int p = 0; p < 2; p++)
|
|
{
|
|
int OutLine = p == 0 ? 1 : 0;
|
|
|
|
for(int f = 0; f < 2; f++)
|
|
{
|
|
float AnimScale, BaseSize;
|
|
GetRenderTeeAnimScaleAndBaseSize(pAnim, pInfo, AnimScale, BaseSize);
|
|
if(f == 1)
|
|
{
|
|
Graphics()->QuadsSetRotation(pAnim->GetBody()->m_Angle * pi * 2);
|
|
|
|
// draw body
|
|
Graphics()->SetColor(pInfo->m_ColorBody.r, pInfo->m_ColorBody.g, pInfo->m_ColorBody.b, Alpha);
|
|
vec2 BodyPos = Position + vec2(pAnim->GetBody()->m_X, pAnim->GetBody()->m_Y) * AnimScale;
|
|
float BodyScale;
|
|
GetRenderTeeBodyScale(BaseSize, BodyScale);
|
|
Graphics()->TextureSet(OutLine == 1 ? pSkinTextures->m_BodyOutline : pSkinTextures->m_Body);
|
|
Graphics()->RenderQuadContainerAsSprite(m_TeeQuadContainerIndex, OutLine, BodyPos.x, BodyPos.y, BodyScale, BodyScale);
|
|
|
|
// draw eyes
|
|
if(p == 1)
|
|
{
|
|
int QuadOffset = 2;
|
|
int EyeQuadOffset = 0;
|
|
int TeeEye = 0;
|
|
switch(Emote)
|
|
{
|
|
case EMOTE_PAIN:
|
|
EyeQuadOffset = 0;
|
|
TeeEye = SPRITE_TEE_EYE_PAIN - SPRITE_TEE_EYE_NORMAL;
|
|
break;
|
|
case EMOTE_HAPPY:
|
|
EyeQuadOffset = 1;
|
|
TeeEye = SPRITE_TEE_EYE_HAPPY - SPRITE_TEE_EYE_NORMAL;
|
|
break;
|
|
case EMOTE_SURPRISE:
|
|
EyeQuadOffset = 2;
|
|
TeeEye = SPRITE_TEE_EYE_SURPRISE - SPRITE_TEE_EYE_NORMAL;
|
|
break;
|
|
case EMOTE_ANGRY:
|
|
EyeQuadOffset = 3;
|
|
TeeEye = SPRITE_TEE_EYE_ANGRY - SPRITE_TEE_EYE_NORMAL;
|
|
break;
|
|
default:
|
|
EyeQuadOffset = 4;
|
|
break;
|
|
}
|
|
|
|
float EyeScale = BaseSize * 0.40f;
|
|
float h = Emote == EMOTE_BLINK ? BaseSize * 0.15f : EyeScale;
|
|
float EyeSeparation = (0.075f - 0.010f * absolute(Direction.x)) * BaseSize;
|
|
vec2 Offset = vec2(Direction.x * 0.125f, -0.05f + Direction.y * 0.10f) * BaseSize;
|
|
|
|
Graphics()->TextureSet(pSkinTextures->m_aEyes[TeeEye]);
|
|
Graphics()->RenderQuadContainerAsSprite(m_TeeQuadContainerIndex, QuadOffset + EyeQuadOffset, BodyPos.x - EyeSeparation + Offset.x, BodyPos.y + Offset.y, EyeScale / (64.f * 0.4f), h / (64.f * 0.4f));
|
|
Graphics()->RenderQuadContainerAsSprite(m_TeeQuadContainerIndex, QuadOffset + EyeQuadOffset, BodyPos.x + EyeSeparation + Offset.x, BodyPos.y + Offset.y, -EyeScale / (64.f * 0.4f), h / (64.f * 0.4f));
|
|
}
|
|
}
|
|
|
|
// draw feet
|
|
CAnimKeyframe *pFoot = f ? pAnim->GetFrontFoot() : pAnim->GetBackFoot();
|
|
|
|
float w = BaseSize;
|
|
float h = BaseSize / 2;
|
|
|
|
int QuadOffset = 7;
|
|
|
|
Graphics()->QuadsSetRotation(pFoot->m_Angle * pi * 2);
|
|
|
|
bool Indicate = !pInfo->m_GotAirJump && g_Config.m_ClAirjumpindicator;
|
|
float ColorScale = 1.0f;
|
|
|
|
if(!OutLine)
|
|
{
|
|
++QuadOffset;
|
|
if(Indicate)
|
|
ColorScale = 0.5f;
|
|
}
|
|
|
|
Graphics()->SetColor(pInfo->m_ColorFeet.r * ColorScale, pInfo->m_ColorFeet.g * ColorScale, pInfo->m_ColorFeet.b * ColorScale, Alpha);
|
|
|
|
Graphics()->TextureSet(OutLine == 1 ? pSkinTextures->m_FeetOutline : pSkinTextures->m_Feet);
|
|
Graphics()->RenderQuadContainerAsSprite(m_TeeQuadContainerIndex, QuadOffset, Position.x + pFoot->m_X * AnimScale, Position.y + pFoot->m_Y * AnimScale, w / 64.f, h / 32.f);
|
|
}
|
|
}
|
|
|
|
Graphics()->SetColor(1.f, 1.f, 1.f, 1.f);
|
|
Graphics()->QuadsSetRotation(0);
|
|
}
|
|
|
|
void CRenderTools::CalcScreenParams(float Aspect, float Zoom, float *pWidth, float *pHeight)
|
|
{
|
|
const float Amount = 1150 * 1000;
|
|
const float WMax = 1500;
|
|
const float HMax = 1050;
|
|
|
|
float f = sqrtf(Amount) / sqrtf(Aspect);
|
|
*pWidth = f * Aspect;
|
|
*pHeight = f;
|
|
|
|
// limit the view
|
|
if(*pWidth > WMax)
|
|
{
|
|
*pWidth = WMax;
|
|
*pHeight = *pWidth / Aspect;
|
|
}
|
|
|
|
if(*pHeight > HMax)
|
|
{
|
|
*pHeight = HMax;
|
|
*pWidth = *pHeight * Aspect;
|
|
}
|
|
|
|
*pWidth *= Zoom;
|
|
*pHeight *= Zoom;
|
|
}
|
|
|
|
void CRenderTools::MapScreenToWorld(float CenterX, float CenterY, float ParallaxX, float ParallaxY,
|
|
float ParallaxZoom, float OffsetX, float OffsetY, float Aspect, float Zoom, float *pPoints)
|
|
{
|
|
float Width, Height;
|
|
CalcScreenParams(Aspect, Zoom, &Width, &Height);
|
|
|
|
float Scale = (ParallaxZoom * (Zoom - 1.0f) + 100.0f) / 100.0f / Zoom;
|
|
Width *= Scale;
|
|
Height *= Scale;
|
|
|
|
CenterX *= ParallaxX / 100.0f;
|
|
CenterY *= ParallaxY / 100.0f;
|
|
pPoints[0] = OffsetX + CenterX - Width / 2;
|
|
pPoints[1] = OffsetY + CenterY - Height / 2;
|
|
pPoints[2] = pPoints[0] + Width;
|
|
pPoints[3] = pPoints[1] + Height;
|
|
}
|
|
|
|
void CRenderTools::MapScreenToGroup(float CenterX, float CenterY, CMapItemGroup *pGroup, CMapItemGroupEx *pGroupEx, float Zoom)
|
|
{
|
|
float ParallaxZoom = GetParallaxZoom(pGroup, pGroupEx);
|
|
float aPoints[4];
|
|
MapScreenToWorld(CenterX, CenterY, pGroup->m_ParallaxX, pGroup->m_ParallaxY, ParallaxZoom,
|
|
pGroup->m_OffsetX, pGroup->m_OffsetY, Graphics()->ScreenAspect(), Zoom, aPoints);
|
|
Graphics()->MapScreen(aPoints[0], aPoints[1], aPoints[2], aPoints[3]);
|
|
}
|
|
|
|
void CRenderTools::MapScreenToInterface(float CenterX, float CenterY)
|
|
{
|
|
float aPoints[4];
|
|
MapScreenToWorld(CenterX, CenterY, 100.0f, 100.0f, 100.0f,
|
|
0, 0, Graphics()->ScreenAspect(), 1.0f, aPoints);
|
|
Graphics()->MapScreen(aPoints[0], aPoints[1], aPoints[2], aPoints[3]);
|
|
}
|