Improve the default Zoom and Zoom changes

The default Zoom should now show a piece of the landscape about the size of
one Clonk's vision.
Günther Brammer 2010-04-27 01:32:45 +02:00
parent 349e463abd
commit 0f4e88db87
11 changed files with 76 additions and 69 deletions

View File

@ -36,6 +36,8 @@ extern C4Game Game;
const float C4GFX_ZoomStep = 1.1040895f;
#define C4FOW_Def_View_RangeX 500
class C4GraphicsSystem
{
public:

View File

@ -1148,8 +1148,8 @@ bool C4PlayerControl::GetCurrentPlayerCursorPos(int32_t *x_out, int32_t *y_out)
if (!vp) return false;
int32_t game_x = cursor_obj->GetX(), game_y=cursor_obj->GetY();
// game coordinate to screen coordinates...
float screen_x = (float(game_x) - vp->last_game_draw_cgo.TargetX - vp->last_game_draw_cgo.X) * vp->Zoom;
float screen_y = (float(game_y) - vp->last_game_draw_cgo.TargetY - vp->last_game_draw_cgo.Y) * vp->Zoom;
float screen_x = (float(game_x) - vp->last_game_draw_cgo.TargetX - vp->last_game_draw_cgo.X) * vp->GetZoom();
float screen_y = (float(game_y) - vp->last_game_draw_cgo.TargetY - vp->last_game_draw_cgo.Y) * vp->GetZoom();
// ...and screen coordinates to GUI coordinates (might push this into a helper function of C4Viewport?)
float gui_x = (screen_x - vp->last_game_draw_cgo.X) / C4GUI::GetZoom() + vp->last_game_draw_cgo.X;
float gui_y = (screen_y - vp->last_game_draw_cgo.Y) / C4GUI::GetZoom() + vp->last_game_draw_cgo.Y;

View File

@ -2012,8 +2012,8 @@ bool C4Object::ActivateMenu(int32_t iMenu, int32_t iMenuSelect,
Menu->SetPermanent(true);
Menu->SetAlignment(C4MN_Align_Free);
C4Viewport *pViewport = ::GraphicsSystem.GetViewport(Controller); // Hackhackhack!!!
if (pViewport) Menu->SetLocation((pTarget->GetX() + pTarget->Shape.GetX() + pTarget->Shape.Wdt + 10 - pViewport->ViewX) * pViewport->Zoom,
(pTarget->GetY() + pTarget->Shape.GetY() - pViewport->ViewY) * pViewport->Zoom);
if (pViewport) Menu->SetLocation((pTarget->GetX() + pTarget->Shape.GetX() + pTarget->Shape.Wdt + 10 - pViewport->ViewX) * pViewport->GetZoom(),
(pTarget->GetY() + pTarget->Shape.GetY() - pViewport->ViewY) * pViewport->GetZoom());
// Add info item
fctSymbol.Create(C4PictureSize, C4PictureSize); pTarget->Def->Draw(fctSymbol, false, pTarget->Color, pTarget);
Menu->Add(pTarget->GetName(), fctSymbol, "", C4MN_Item_NoCount, NULL, pTarget->GetInfoString().getData());

View File

@ -49,8 +49,6 @@
#include <C4GameObjects.h>
#include <C4GameControl.h>
#define C4FOW_Def_View_RangeX 500
C4Player::C4Player() : C4PlayerInfoCore()
{
Default();

View File

@ -285,9 +285,12 @@ namespace C4GUI
C4Rect &rcClientRect = GetClientRect();
C4Rect &rcClipArea = (IsComponentOutsideClientArea() ? GetBounds() : GetClientRect());
// clip to window area
float clx1, cly1, clx2, cly2;
int clx1, cly1, clx2, cly2;
lpDDraw->GetPrimaryClipper(clx1, cly1, clx2, cly2);
lpDDraw->SubPrimaryClipper(cgo.TargetX+rcClipArea.x, cgo.TargetY+rcClipArea.y, cgo.TargetX+rcClipArea.x+rcClipArea.Wdt-1, cgo.TargetY+rcClipArea.y+rcClipArea.Hgt-1);
float nclx1 = cgo.TargetX+rcClipArea.x, ncly1 = cgo.TargetY+rcClipArea.y, nclx2 = cgo.TargetX+rcClipArea.x+rcClipArea.Wdt-1, ncly2 = cgo.TargetY+rcClipArea.y+rcClipArea.Hgt-1;
lpDDraw->ApplyZoom(nclx1, ncly1);
lpDDraw->ApplyZoom(nclx2, ncly2);
lpDDraw->SubPrimaryClipper(nclx1, ncly1, nclx2, ncly2);
// update target area
cgo.TargetX += rcClientRect.x; cgo.TargetY += rcClientRect.y;
// draw contents

View File

@ -605,9 +605,12 @@ namespace C4GUI
// default frame color
Draw3DFrame(cgo);
// clipping
float cx0,cy0,cx1,cy1; bool fClip, fOwnClip;
int cx0,cy0,cx1,cy1; bool fClip, fOwnClip;
fClip = lpDDraw->GetPrimaryClipper(cx0,cy0,cx1,cy1);
fOwnClip = lpDDraw->SetPrimaryClipper(rcClientRect.x+cgo.TargetX-2,rcClientRect.y+cgo.TargetY,rcClientRect.x+rcClientRect.Wdt+cgo.TargetX+1,rcClientRect.y+rcClientRect.Hgt+cgo.TargetY);
float nclx1 = rcClientRect.x+cgo.TargetX-2, ncly1 = rcClientRect.y+cgo.TargetY, nclx2 = rcClientRect.x+rcClientRect.Wdt+cgo.TargetX+1, ncly2 = rcClientRect.y+rcClientRect.Hgt+cgo.TargetY;
lpDDraw->ApplyZoom(nclx1, ncly1);
lpDDraw->ApplyZoom(nclx2, ncly2);
fOwnClip = lpDDraw->SetPrimaryClipper(nclx1, ncly1, nclx2, ncly2);
// get usable height of edit field
int32_t iHgt = pFont->GetLineHeight(), iY0;
if (rcClientRect.Hgt <= iHgt)

View File

@ -212,7 +212,7 @@ namespace C4GUI
void MultilineLabel::DrawElement(C4TargetFacet &cgo)
{
// get clipping
float iClipX, iClipY, iClipX2, iClipY2;
int iClipX, iClipY, iClipX2, iClipY2;
lpDDraw->GetPrimaryClipper(iClipX, iClipY, iClipX2, iClipY2);
// draw all lines
int32_t iIndex = 0; const char *szLine;

View File

@ -75,12 +75,6 @@ namespace
#ifdef _WIN32
double round(double x)
{
// Dunno if this matches the implementation of round()
return (x < 0.0) ? floor(x) : ceil(x);
}
#include <shellapi.h>
LRESULT APIENTRY ViewportWinProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
@ -988,7 +982,7 @@ void C4Viewport::Draw(C4TargetFacet &cgo0, bool fDrawOverlay)
cgo.TargetX += BorderLeft/Zoom; cgo.TargetY += BorderTop/Zoom;
// Apply Zoom
lpDDraw->SetZoom(GameZoom);
Application.DDraw->SetPrimaryClipper(cgo.X,cgo.Y,cgo.X+(ViewWdt-1-BorderRight-BorderLeft)/Zoom,cgo.Y+(ViewHgt-1-BorderBottom-BorderTop)/Zoom);
Application.DDraw->SetPrimaryClipper(cgo.X,cgo.Y,DrawX+ViewWdt-1-BorderRight,DrawY+ViewHgt-1-BorderBottom);
}
last_game_draw_cgo = cgo;
@ -1044,7 +1038,7 @@ void C4Viewport::Draw(C4TargetFacet &cgo0, bool fDrawOverlay)
float fGUIZoom = C4GUI::GetZoom();
// now restore complete cgo range for overlay drawing
lpDDraw->SetZoom(DrawX,DrawY, fGUIZoom);
Application.DDraw->SetPrimaryClipper(DrawX,DrawY,DrawX+(ViewWdt-1)/fGUIZoom,DrawY+(ViewHgt-1)/fGUIZoom);
Application.DDraw->SetPrimaryClipper(DrawX,DrawY,DrawX+(ViewWdt-1),DrawY+(ViewHgt-1));
cgo.Set(cgo0);
cgo.X = DrawX; cgo.Y = DrawY;
@ -1106,7 +1100,7 @@ void C4Viewport::Execute()
C4TargetFacet cgo;
CStdWindow * w = pWindow;
if (!w) w = &FullScreen;
cgo.Set(w->pSurface,DrawX,DrawY,int32_t(float(ViewWdt)/Zoom),int32_t(float(ViewHgt)/Zoom),ViewX,ViewY);
cgo.Set(w->pSurface,DrawX,DrawY,int32_t(ceilf(float(ViewWdt)/Zoom)),int32_t(ceilf(float(ViewHgt)/Zoom)),ViewX,ViewY);
lpDDraw->PrepareRendering(w->pSurface);
// Draw
Draw(cgo, true);
@ -1125,61 +1119,69 @@ void C4Viewport::ChangeZoom(float by_factor)
void C4Viewport::AdjustPosition()
{
const float ZoomAdjustFactor = 1.08f; // must be > 1.0 to have effect
const float ZoomAdjustFactor = 1.025f; // must be > 1.0 to have effect
float ViewportScrollBorder = fIsNoOwnerViewport ? 0 : float(C4ViewportScrollBorder);
C4Player *pPlr = ::Players.Get(Player);
if (ZoomTarget < 0.000001f)
{
ZoomTarget = Max(float(ViewWdt)/GBackWdt, 1.0f);
if (pPlr) ZoomTarget = Max(ViewWdt / (2.0f * C4FOW_Def_View_RangeX), ZoomTarget);
Zoom = ZoomTarget;
}
// View position
if (PlayerLock && ValidPlr(Player))
{
C4Player *pPlr = ::Players.Get(Player);
float iScrollRange = Min(ViewWdt/(10*Zoom),ViewHgt/(10*Zoom));
float iExtraBoundsX = 0, iExtraBoundsY = 0;
float PrefViewX = ViewX + ViewWdt / (Zoom * 2) - ViewOffsX;
float PrefViewY = ViewY + ViewHgt / (Zoom * 2) - ViewOffsY;
// Change Zoom
assert(Zoom>0);
if (Zoom < ZoomTarget)
Zoom *= ZoomAdjustFactor;
if (Zoom > ZoomTarget)
{
Zoom /= ZoomAdjustFactor;
if (Zoom < ZoomTarget)
Zoom = ZoomTarget;
}
float ScrollRange = Min(ViewWdt/(10*Zoom),ViewHgt/(10*Zoom));
float ExtraBoundsX = 0, ExtraBoundsY = 0;
if (pPlr->ViewMode == C4PVM_Scrolling)
{
iScrollRange=0;
iExtraBoundsX=iExtraBoundsY=ViewportScrollBorder;
ScrollRange=0;
ExtraBoundsX=ExtraBoundsY=ViewportScrollBorder;
}
else
{
// if view is close to border, allow scrolling
if (pPlr->ViewX < ViewportScrollBorder) iExtraBoundsX = Min<float>(ViewportScrollBorder - pPlr->ViewX, ViewportScrollBorder);
else if (pPlr->ViewX >= GBackWdt - ViewportScrollBorder) iExtraBoundsX = Min<float>(float(pPlr->ViewX - GBackWdt), 0) + ViewportScrollBorder;
if (pPlr->ViewY < ViewportScrollBorder) iExtraBoundsY = Min<float>(ViewportScrollBorder - pPlr->ViewY, ViewportScrollBorder);
else if (pPlr->ViewY >= GBackHgt - ViewportScrollBorder) iExtraBoundsY = Min<float>(float(pPlr->ViewY - GBackHgt), 0) + ViewportScrollBorder;
if (pPlr->ViewX < ViewportScrollBorder) ExtraBoundsX = Min<float>(ViewportScrollBorder - pPlr->ViewX, ViewportScrollBorder);
else if (pPlr->ViewX >= GBackWdt - ViewportScrollBorder) ExtraBoundsX = Min<float>(float(pPlr->ViewX - GBackWdt), 0) + ViewportScrollBorder;
if (pPlr->ViewY < ViewportScrollBorder) ExtraBoundsY = Min<float>(ViewportScrollBorder - pPlr->ViewY, ViewportScrollBorder);
else if (pPlr->ViewY >= GBackHgt - ViewportScrollBorder) ExtraBoundsY = Min<float>(float(pPlr->ViewY - GBackHgt), 0) + ViewportScrollBorder;
}
iExtraBoundsX = Max(iExtraBoundsX, (ViewWdt/Zoom - GBackWdt) / 2+1);
iExtraBoundsY = Max(iExtraBoundsY, (ViewHgt/Zoom - GBackHgt) / 2+1);
ExtraBoundsX = Max(ExtraBoundsX, (ViewWdt/Zoom - GBackWdt) / 2+1);
ExtraBoundsY = Max(ExtraBoundsY, (ViewHgt/Zoom - GBackHgt) / 2+1);
// calc target view position
float iTargetViewX = pPlr->ViewX - ViewWdt / (Zoom * 2);
float iTargetViewY = pPlr->ViewY - ViewHgt / (Zoom * 2);
float TargetViewX = pPlr->ViewX/* */;
float TargetViewY = pPlr->ViewY/* */;
// add mouse auto scroll
float iPrefViewX = ViewX - ViewOffsX, iPrefViewY = ViewY - ViewOffsY;
if (pPlr->MouseControl && ::MouseControl.InitCentered && Config.Controls.MouseAScroll)
{
iTargetViewX += (::MouseControl.VpX - ViewWdt / 2) / Zoom;
iTargetViewY += (::MouseControl.VpY - ViewHgt / 2) / Zoom;
TargetViewX += (::MouseControl.VpX - ViewWdt / 2) / Zoom;
TargetViewY += (::MouseControl.VpY - ViewHgt / 2) / Zoom;
}
// scroll range
iTargetViewX = BoundBy(iPrefViewX, iTargetViewX - iScrollRange, iTargetViewX + iScrollRange);
iTargetViewY = BoundBy(iPrefViewY, iTargetViewY - iScrollRange, iTargetViewY + iScrollRange);
TargetViewX = BoundBy(PrefViewX, TargetViewX - ScrollRange, TargetViewX + ScrollRange);
TargetViewY = BoundBy(PrefViewY, TargetViewY - ScrollRange, TargetViewY + ScrollRange);
// bounds
iTargetViewX = BoundBy(iTargetViewX, -iExtraBoundsX, GBackWdt - ViewWdt / Zoom + iExtraBoundsX);
iTargetViewY = BoundBy(iTargetViewY, -iExtraBoundsY, GBackHgt - ViewHgt / Zoom + iExtraBoundsY);
TargetViewX = BoundBy(TargetViewX, ViewWdt / (Zoom * 2) - ExtraBoundsX, GBackWdt - ViewWdt / (Zoom * 2) + ExtraBoundsX);
TargetViewY = BoundBy(TargetViewY, ViewHgt / (Zoom * 2) - ExtraBoundsY, GBackHgt - ViewHgt / (Zoom * 2) + ExtraBoundsY);
// smooth
ViewX += (iTargetViewX - ViewX) / BoundBy<int32_t>(Config.General.ScrollSmooth, 1, 50);
ViewY += (iTargetViewY - ViewY) / BoundBy<int32_t>(Config.General.ScrollSmooth, 1, 50);
// Change Zoom
ViewX += ViewWdt / (Zoom * 2);
ViewY += ViewHgt / (Zoom * 2);
assert(Zoom>0);
if (Zoom < ZoomTarget) Zoom *= ZoomAdjustFactor;
if (Zoom > ZoomTarget) Zoom /= ZoomAdjustFactor;
// snap to rounded target if it's near to avoid unsightly Zooms
if (round(ZoomTarget * 10) == round(Zoom * 10))
Zoom = round(ZoomTarget * 10) / 10;
ViewX -= ViewWdt / (Zoom * 2);
ViewY -= ViewHgt / (Zoom * 2);
ViewX = PrefViewX + (TargetViewX - PrefViewX) / BoundBy<int32_t>(Config.General.ScrollSmooth, 1, 50);
ViewY = PrefViewY + (TargetViewY - PrefViewY) / BoundBy<int32_t>(Config.General.ScrollSmooth, 1, 50);
// apply offset
ViewX += ViewOffsX; ViewY += ViewOffsY;
ViewX -= ViewWdt / (Zoom * 2) - ViewOffsX;
ViewY -= ViewHgt / (Zoom * 2) - ViewOffsY;
}
// NO_OWNER can't scroll
if (fIsNoOwnerViewport) { ViewOffsX=0; ViewOffsY=0; }
@ -1241,7 +1243,7 @@ void C4Viewport::Default()
OutX=OutY=ViewWdt=ViewHgt=0;
DrawX=DrawY=0;
Zoom = 1.0;
ZoomTarget = 1.0;
ZoomTarget = 0.0;
Next=NULL;
PlayerLock=true;
ResetMenuPositions=false;

View File

@ -91,9 +91,8 @@ public:
// facets used for last drawing operations
C4TargetFacet last_game_draw_cgo, last_gui_draw_cgo;
// factor between "landscape" and "display"
float Zoom;
float ZoomTarget;
bool fIsNoOwnerViewport; // this viewport is found for searches of NO_OWNER-viewports; even if it has a player assigned (for network obs)
float GetZoom() { return Zoom; }
void Default();
void Clear();
void Execute();
@ -114,6 +113,8 @@ public:
int32_t GetPlayer() { return Player; }
void CenterPosition();
protected:
float Zoom;
float ZoomTarget;
int32_t Player;
bool PlayerLock;
int32_t OutX,OutY;

View File

@ -426,10 +426,10 @@ bool CStdDDraw::SetPrimaryPalette(BYTE *pBuf, BYTE *pAlphaBuf)
return true;
}
bool CStdDDraw::SubPrimaryClipper(float iX1, float iY1, float iX2, float iY2)
bool CStdDDraw::SubPrimaryClipper(int iX1, int iY1, int iX2, int iY2)
{
// Set sub primary clipper
SetPrimaryClipper(Max(iX1,fClipX1),Max(iY1,fClipY1),Min(iX2,fClipX2),Min(iY2,fClipY2));
SetPrimaryClipper(Max(iX1,iClipX1),Max(iY1,iClipY1),Min(iX2,iClipX2),Min(iY2,iClipY2));
return true;
}
@ -447,13 +447,11 @@ bool CStdDDraw::RestorePrimaryClipper()
return true;
}
bool CStdDDraw::SetPrimaryClipper(float iX1, float iY1, float iX2, float iY2)
bool CStdDDraw::SetPrimaryClipper(int iX1, int iY1, int iX2, int iY2)
{
// set clipper
fClipX1=iX1; fClipY1=iY1; fClipX2=iX2; fClipY2=iY2;
float fZClipX1=fClipX1, fZClipY1=fClipY1, fZClipX2=fClipX2, fZClipY2=fClipY2;
ApplyZoom(fZClipX1, fZClipY1); ApplyZoom(fZClipX2, fZClipY2);
iClipX1=int32_t(fZClipX1); iClipY1=int32_t(fZClipY1); iClipX2=int32_t(fZClipX2); iClipY2=int32_t(fZClipY2);
iClipX1=iX1; iClipY1=iY1; iClipX2=iX2; iClipY2=iY2;
UpdateClipper();
// Done
return true;
@ -861,7 +859,7 @@ bool CStdDDraw::CreatePrimaryClipper(unsigned int iXRes, unsigned int iYRes)
// simply setup primary viewport
// assume no zoom has been set yet
assert(Zoom==1.0f);
SetPrimaryClipper(0, 0, float(iXRes - 1), float(iYRes - 1));
SetPrimaryClipper(0, 0, iXRes - 1, iYRes - 1);
StorePrimaryClipper();
return true;
}
@ -1266,7 +1264,7 @@ void CStdDDraw::Grayscale(SURFACE sfcSfc, int32_t iOffset)
sfcSfc->Unlock();
}
bool CStdDDraw::GetPrimaryClipper(float &rX1, float &rY1, float &rX2, float &rY2)
bool CStdDDraw::GetPrimaryClipper(int &rX1, int &rY1, int &rX2, int &rY2)
{
// Store drawing clip values
rX1=fClipX1; rY1=fClipY1; rX2=fClipX2; rY2=fClipY2;

View File

@ -258,9 +258,9 @@ public:
bool SetPrimaryPaletteQuad(BYTE *pBuf);
bool AttachPrimaryPalette(SURFACE sfcSurface);
// Clipper
bool GetPrimaryClipper(float &rX1, float &rY1, float &rX2, float &rY2);
bool SetPrimaryClipper(float iX1, float iY1, float iX2, float iY2);
bool SubPrimaryClipper(float iX1, float iY1, float iX2, float iY2);
bool GetPrimaryClipper(int &rX1, int &rY1, int &rX2, int &rY2);
bool SetPrimaryClipper(int iX1, int iY1, int iX2, int iY2);
bool SubPrimaryClipper(int iX1, int iY1, int iX2, int iY2);
bool StorePrimaryClipper();
bool RestorePrimaryClipper();
bool NoPrimaryClipper();