Skip to content

Commit

Permalink
Added: Aspect correct scaling of finale animations (InFine). If the w…
Browse files Browse the repository at this point in the history
…indow aspect ratio is equal to or close to 4:3 finales will be stretched to fill the window unless new cvar "finale-nostretch" is enabled. Otherwise finales will be scaled and positioned to fit within the window whilst maintaining their original aspect ratio (e.g., using pillarbox/letterbox drawing).

Todo: "Overlay" mode animations should not treated in this way.
Todo: Implement features so that an InFine script can request a native screenspace coordinate system (won't pillarbox/letterbox).
  • Loading branch information
danij-deng committed May 8, 2010
1 parent 93342d0 commit 7a2996c
Show file tree
Hide file tree
Showing 15 changed files with 164 additions and 18 deletions.
6 changes: 4 additions & 2 deletions doomsday/plugins/common/include/f_infine.h
Expand Up @@ -3,8 +3,8 @@
* License: GPL
* Online License Link: http://www.gnu.org/licenses/gpl.html
*
*\author Copyright © 2003-2009 Jaakko Keränen <jaakko.keranen@iki.fi>
*\author Copyright © 2006-2009 Daniel Swanson <danij@dengine.net>
*\author Copyright © 2003-2010 Jaakko Keränen <jaakko.keranen@iki.fi>
*\author Copyright © 2006-2010 Daniel Swanson <danij@dengine.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -47,6 +47,8 @@ extern boolean fiActive;
extern boolean fiCmdExecuted; // Set to true after first command.
extern boolean briefDisabled;

void FI_Register(void);

void FI_Reset(void);
void FI_Start(char* finalescript, infinemode_t mode);
void FI_End(void);
Expand Down
151 changes: 135 additions & 16 deletions doomsday/plugins/common/src/f_infine.c
Expand Up @@ -67,6 +67,12 @@

// TYPES -------------------------------------------------------------------

enum {
STRETCH = 0,
PILLARBOX,
LETTERBOX,
};

typedef char handle_t[32];

typedef struct ficmd_s {
Expand Down Expand Up @@ -387,15 +393,31 @@ static fitext_t fiDummyText;

static boolean conditionPresets[NUM_FICONDS];

// Cvars for finales:
cvar_t fiCVars[] = {
{"finale-nostretch", 0, CVT_BYTE, &cfg.fiNoStretch, 0, 1},
{NULL}
};

// CODE --------------------------------------------------------------------

/**
* Called during pre-init to register cvars and ccmds for the finale system.
*/
void FI_Register(void)
{
int i;
for(i = 0; fiCVars[i].name; ++i)
Con_AddVariable(fiCVars + i);
}

/**
* Clear the InFine state to the default, blank state.
* The 'fi' pointer must be set before calling this function.
*/
void FI_ClearState(void)
{
int i, c;
int i, c;

// General game state.
G_SetGameAction(GA_NONE);
Expand Down Expand Up @@ -1695,34 +1717,123 @@ void FI_GetTurnCenter(fipic_t *pic, float *center)
center[VY] *= pic->object.scale[VY].value;
}

static int pickScalingStrategy(int winWidth, int winHeight, float* outScale)
{
float scale = (winWidth >= winHeight? (float)winHeight/SCREENHEIGHT : (float)winWidth/SCREENWIDTH);
float a = (float)winWidth/winHeight;
float b = (float)SCREENWIDTH/SCREENHEIGHT;
int displayMode = STRETCH;

if(!INRANGE_OF(a, b, .001f) && (cfg.fiNoStretch || !INRANGE_OF(a, b, .38f)))
{
if(SCREENWIDTH * scale > winWidth || SCREENHEIGHT * scale < winHeight)
{
scale *= (float)winWidth/(SCREENWIDTH*scale);
displayMode = LETTERBOX;
}
else if(SCREENWIDTH * scale < winWidth)
{
displayMode = PILLARBOX;
}
}
if(outScale)
*outScale = scale;
return displayMode;
}

/**
* Drawing is the most complex task here.
*/
void FI_Drawer(void)
{
int i, sq;
float mid[2];
fipic_t *pic;
fitext_t *tex;
int winWidth, winHeight, displayMode, scissorState[5], i, sq;
float scale, mid[2];
fipic_t* pic;
fitext_t* tex;

// Don't draw anything until we are sure the script has started.
if(!fiActive || !fiCmdExecuted)
return;

winWidth = Get(DD_WINDOW_WIDTH);
winHeight = Get(DD_WINDOW_HEIGHT);
displayMode = pickScalingStrategy(winWidth, winHeight, &scale);

DGL_MatrixMode(DGL_PROJECTION);
DGL_PushMatrix();
DGL_LoadIdentity();
switch(displayMode)
{
case PILLARBOX:
{
/**
* Use an orthographic projection in native screenspace. Then
* translate and scale the projection to produce an aspect
* corrected coordinate space at 4:3, centered horizontally
* in the window.
*/
int w = (winWidth-SCREENWIDTH*scale)/2;
DGL_Ortho(0, 0, winWidth, winHeight, -1, 1);

DGL_SetNoMaterial();
DGL_DrawRect(0, 0, w, winHeight, 0, 0, 0, 1);
DGL_DrawRect(winWidth - w, 0, w, winHeight, 0, 0, 0, 1);

DGL_GetIntegerv(DGL_SCISSOR_TEST, scissorState);
DGL_GetIntegerv(DGL_SCISSOR_BOX, scissorState + 1);
DGL_Scissor(w, 0, SCREENWIDTH*scale, winHeight);
DGL_Enable(DGL_SCISSOR_TEST);

DGL_MatrixMode(DGL_PROJECTION);
DGL_Translatef((float)winWidth/2, (float)winHeight/2, 0);
DGL_Scalef(scale, scale, 1);
DGL_Translatef(-SCREENWIDTH/2, -SCREENHEIGHT/2, 0);
break;
}
case LETTERBOX:
{
/**
* Use an orthographic projection in native screenspace. Then
* translate and scale the projection to produce an aspect
* corrected coordinate space at 4:3, centered vertically in
* the window.
*/
int h = (winHeight-SCREENHEIGHT*scale)/2;
DGL_Ortho(0, 0, winWidth, winHeight, -1, 1);

DGL_SetNoMaterial();
DGL_DrawRect(0, 0, winWidth, h, 0, 0, 0, 1);
DGL_DrawRect(0, winHeight - h, winWidth, h, 0, 0, 0, 1);

DGL_GetIntegerv(DGL_SCISSOR_TEST, scissorState);
DGL_GetIntegerv(DGL_SCISSOR_BOX, scissorState + 1);
DGL_Scissor(0, h, winWidth, SCREENHEIGHT*scale);
DGL_Enable(DGL_SCISSOR_TEST);

DGL_MatrixMode(DGL_PROJECTION);
DGL_Translatef((float)winWidth/2, (float)winHeight/2, 0);
DGL_Scalef(scale, scale, 1);
DGL_Translatef(-SCREENWIDTH/2, -SCREENHEIGHT/2, 0);
}
break;

default: // STRETCH
DGL_Ortho(0, 0, SCREENWIDTH, SCREENHEIGHT, -1, 1);
break;
}

// Draw the background.
if(fi->bgMaterial)
{
FI_UseColor(fi->bgColor, 4);
DGL_SetMaterial(fi->bgMaterial);
DGL_DrawRectTiled(0, 0, 320, 200, 64, 64);
DGL_DrawRectTiled(0, 0, SCREENWIDTH, SCREENHEIGHT, 64, 64);
}
else
{
// Just clear the screen, then.
DGL_Disable(DGL_TEXTURING);
DGL_DrawRect(0, 0, 320, 200, fi->bgColor[0].value,
fi->bgColor[1].value, fi->bgColor[2].value,
fi->bgColor[3].value);
DGL_DrawRect(0, 0, SCREENWIDTH, SCREENHEIGHT, fi->bgColor[0].value, fi->bgColor[1].value, fi->bgColor[2].value, fi->bgColor[3].value);
DGL_Enable(DGL_TEXTURING);
}

Expand All @@ -1742,14 +1853,12 @@ void FI_Drawer(void)
// Setup the transformation.
DGL_MatrixMode(DGL_MODELVIEW);
DGL_PushMatrix();
DGL_Translatef(pic->object.x.value - fi->imgOffset[0].value,
pic->object.y.value - fi->imgOffset[1].value, 0);
DGL_Translatef(pic->object.x.value - fi->imgOffset[0].value, pic->object.y.value - fi->imgOffset[1].value, 0);
DGL_Translatef(mid[VX], mid[VY], 0);
FI_Rotate(pic->object.angle.value);
// Move to origin.
DGL_Translatef(-mid[VX], -mid[VY], 0);
DGL_Scalef((pic->flip[sq] ? -1 : 1) * pic->object.scale[0].value,
pic->object.scale[1].value, 1);
DGL_Scalef((pic->flip[sq] ? -1 : 1) * pic->object.scale[0].value, pic->object.scale[1].value, 1);

// Draw it.
if(pic->flags.is_rect)
Expand Down Expand Up @@ -1838,12 +1947,22 @@ void FI_Drawer(void)
FI_UseColor(fi->filter, 4);
DGL_Begin(DGL_QUADS);
DGL_Vertex2f(0, 0);
DGL_Vertex2f(320, 0);
DGL_Vertex2f(320, 200);
DGL_Vertex2f(0, 200);
DGL_Vertex2f(SCREENWIDTH, 0);
DGL_Vertex2f(SCREENWIDTH, SCREENHEIGHT);
DGL_Vertex2f(0, SCREENHEIGHT);
DGL_End();
DGL_Enable(DGL_TEXTURING);
}

if(displayMode != STRETCH)
{
if(!scissorState[0])
DGL_Disable(DGL_SCISSOR_TEST);
DGL_Scissor(scissorState[1], scissorState[2], scissorState[3], scissorState[4]);
}

DGL_MatrixMode(DGL_PROJECTION);
DGL_PopMatrix();
}

/**
Expand Down
1 change: 1 addition & 0 deletions doomsday/plugins/common/src/g_game.c
Expand Up @@ -479,6 +479,7 @@ void G_CommonPreInit(void)
D_NetConsoleRegistration(); // For network.
G_Register(); // Read-only game status cvars (for playsim).
G_ControlRegister(); // For controls/input.
FI_Register();
AM_Register(); // For the automap.
Hu_MenuRegister(); // For the menu.
Hu_LogRegister(); // For the player message logs.
Expand Down
3 changes: 3 additions & 0 deletions doomsday/plugins/jdoom/data/conhelp.txt
Expand Up @@ -202,6 +202,9 @@ desc = 1=Disable exit buttons during map rotation.
[server-game-cheat]
desc = 1=Allow cheating in multiplayer games (god, noclip, give).

[finale-nostretch]
desc = If the window dimension aspect ratio is not equal to but close to that of the original game, fixed-aspect finale animations will be stretched 1= disabled.

[menu-flash-r]
desc = Menu selection flash color, red component.

Expand Down
2 changes: 2 additions & 0 deletions doomsday/plugins/jdoom/include/d_config.h
Expand Up @@ -174,6 +174,8 @@ typedef struct jdoom_config_s {
byte automapPanResetOnOpen;
float automapOpenSeconds;

byte fiNoStretch; // Do not stretch finales to fill the screen at near 4:3 aspect ratios.

int msgCount;
float msgScale;
float msgUptime;
Expand Down
1 change: 1 addition & 0 deletions doomsday/plugins/jdoom/src/d_main.c
Expand Up @@ -368,6 +368,7 @@ void G_PreInit(void)
cfg.dclickUse = false;
cfg.povLookAround = true;
cfg.screenBlocks = cfg.setBlocks = 10;
cfg.fiNoStretch = false;
cfg.echoMsg = true;
cfg.lookSpeed = 3;
cfg.turnSpeed = 1;
Expand Down
3 changes: 3 additions & 0 deletions doomsday/plugins/jdoom64/data/conhelp.txt
Expand Up @@ -198,6 +198,9 @@ desc = 1=Disable exit buttons during map rotation.
[server-game-cheat]
desc = 1=Allow cheating in multiplayer games (god, noclip, give).

[finale-nostretch]
desc = If the window dimension aspect ratio is not equal to but close to that of the original game, fixed-aspect finale animations will be stretched 1= disabled.

[menu-flash-r]
desc = Menu selection flash color, red component.

Expand Down
2 changes: 2 additions & 0 deletions doomsday/plugins/jdoom64/include/d_config.h
Expand Up @@ -169,6 +169,8 @@ typedef struct jdoom64_config_s {
byte automapPanResetOnOpen;
float automapOpenSeconds;

byte fiNoStretch; // Do not stretch finales to fill the screen at near 4:3 aspect ratios.

int msgCount;
float msgScale;
float msgUptime;
Expand Down
1 change: 1 addition & 0 deletions doomsday/plugins/jdoom64/src/d_main.c
Expand Up @@ -255,6 +255,7 @@ void G_PreInit(void)
cfg.dclickUse = false;
cfg.povLookAround = true;
cfg.screenBlocks = cfg.setBlocks = 10;
cfg.fiNoStretch = false;
cfg.echoMsg = true;
cfg.lookSpeed = 3;
cfg.turnSpeed = 1;
Expand Down
3 changes: 3 additions & 0 deletions doomsday/plugins/jheretic/data/conhelp.txt
Expand Up @@ -208,6 +208,9 @@ desc = 1=Disable exit buttons during map rotation.
[server-game-cheat]
desc = 1=Allow cheating in multiplayer games (god, noclip, give).

[finale-nostretch]
desc = If the window dimension aspect ratio is not equal to but close to that of the original game, fixed-aspect finale animations will be stretched 1= disabled.

[menu-flash-r]
desc = Menu selection flash color, red component.

Expand Down
2 changes: 2 additions & 0 deletions doomsday/plugins/jheretic/include/h_config.h
Expand Up @@ -171,6 +171,8 @@ typedef struct jheretic_config_s {
byte automapPanResetOnOpen;
float automapOpenSeconds;

byte fiNoStretch; // Do not stretch finales to fill the screen at near 4:3 aspect ratios.

int msgCount;
float msgScale;
float msgUptime;
Expand Down
1 change: 1 addition & 0 deletions doomsday/plugins/jheretic/src/h_main.c
Expand Up @@ -261,6 +261,7 @@ void G_PreInit(void)
cfg.povLookAround = true;
cfg.statusbarScale = 1;
cfg.screenBlocks = cfg.setBlocks = 10;
cfg.fiNoStretch = false;
cfg.echoMsg = true;
cfg.lookSpeed = 3;
cfg.turnSpeed = 1;
Expand Down
3 changes: 3 additions & 0 deletions doomsday/plugins/jhexen/data/conhelp.txt
Expand Up @@ -220,6 +220,9 @@ desc = 1=Disable exit buttons during map rotation.
[server-game-cheat]
desc = 1=Allow cheating in multiplayer games (god, noclip, give).

[finale-nostretch]
desc = If the window dimension aspect ratio is not equal to but close to that of the original game, fixed-aspect finale animations will be stretched 1= disabled.

[menu-flash-r]
desc = Menu selection flash color, red component.

Expand Down
2 changes: 2 additions & 0 deletions doomsday/plugins/jhexen/include/x_config.h
Expand Up @@ -141,6 +141,8 @@ typedef struct {
byte automapPanResetOnOpen;
float automapOpenSeconds;

byte fiNoStretch; // Do not stretch finales to fill the screen at near 4:3 aspect ratios.

int messagesOn;
char* chatMacros[10];
byte chatBeep;
Expand Down
1 change: 1 addition & 0 deletions doomsday/plugins/jhexen/src/h2_main.c
Expand Up @@ -245,6 +245,7 @@ void G_PreInit(void)
cfg.statusbarScale = 1;
cfg.dclickUse = false;
cfg.screenBlocks = cfg.setBlocks = 10;
cfg.fiNoStretch = false;
cfg.hudShown[HUD_MANA] = true;
cfg.hudShown[HUD_HEALTH] = true;
cfg.hudShown[HUD_CURRENTITEM] = true;
Expand Down

0 comments on commit 7a2996c

Please sign in to comment.