I'm here because TASing combines three big facets of my life: video games, computer science, and obsessive compulsive behavior. Sometimes I encode videos.

TAS Ideas

NDS Layout Automater for AviSynth


####################################
### Nintendo DS Layout Automater ###
####################################
# Based on layouts by Spikestuff
# Adapted by Zinfidel

#################
### Importing ###
#################
# In the importing script, the following variables must be defined before importing:
# vid  (clip)
#   The video dump.
# resX (int)
#   Final output width.
# resY (int)
#   Final output height.
# vertGap (int)
#   Sets a gap between the screens in the Top and Bottom layout to simulate the actual screen separation,
#   and also adds borders to the top and bottom of other layouts to keep everything aligned. This value is
#   relative to the *native* size of the screens, and will be scaled to the final output resolution. Setting
#   this to either 90 or 32 pixels gets the screens pretty close to lined up exactly, depending on NDS model.
#   LEAVE THIS VALUE AT 0 IF YOU ARE NOT GOING TO USE TOP AND BOTTOM MODE! Unnecessary borders will be added
#   to the video if you don't use that mode.
# bookGap (int)
#   Sets a gap between the screens in the Book Mode layout to simulate the actual screen separation. This does
#   not add any extra borders to other layouts. Can be combined with vertGap if the game uses both Book Mode and
#   Top and Bottom mode with a gap. Setting this to 90 or 32 pixels gets the screens pretty close to lined up exactly.
#
# The dimensions must define a resolution with an aspect ratio of 2:1. Some examples of output resolutions are:
# - Native: 768x384 (256*3 x 192*2)
# - 4K    : 3840x1920
#
# Note that the final output vertical resolution will be increased by vertGap*scaleFactor if it is greater than 0.

#############
### Usage ###
#############
# There are 7 shortcut functions defined to change the layout. They are: gt, gb, st, sb, ss, tb, and bm, which are
# Gameplay (Top), Gameplay (Bottom), Single (Top), Single (Bottom), Side by Side, Top and Bottom, and Book Mode,
# respectively. These functions automatically append to the video that they build, and each takes an integer as its
# first argument: the frame number on which to change the layout.
#
# Two of the functions (tb and bm) also take an optional second argument that overrides the gap size. This value in
# pixels is not scaled or relative to the native resolution, and is used raw. This is useful for eliminating the gap
# (by setting it to 0) for scenes that need no gap. The output dimensions are fixed based on resX, resY, vertGap, and
# bookGap - setting the gap override will adjust borders to make sure the layouts work together.
#
# These functions start with the full video being set to the last variable, and then the functions are chained to
# create the video. For example:
#
# vid = AviSource("example.avi")
# resX = 768
# resY = 384
# vertGap = 0
# bookGap = 90
# Import("dslayout.avsi")
# last = vid
# ss(0)
# tb(1000)
# gt(2000).gb(3000)
# bm(4000, 0)
#
# This would create an output video that starts in Side by Side, changes to Top and Bottom at frame 1000,
# changes to Gameplay (Top) on frame 2000, then changes to Gameplay (Bottom) on frame 3000. On frame 4000,
# the layout is changed to Book Mode, but with the gap removed by setting the override to 0. It does not
# matter if there is a line break or a dot between calls, they are functionally equivalent in AviSynth.

#############
### Setup ###
#############
cr = vid.Height / 2
global top = vid.Crop(0, 0, -0, -cr)
global bot = vid.Crop(0, cr, -0, -0)

# Calculated Screen Sizes
global screenWidth = resX / 3
global screenHeight = resY / 2
global bookWidth = (resY * 2) / 3
global bookHeight = resY

# Calculated Gap Sizes
global vGap = round((screenHeight * vertGap) / 192)
global vertBorder = vGap / 2
global bGap = round((bookWidth * bookGap) / 192)
global bookBorder = (resX - (bookWidth*2) - bGap) / 2

#############################
### Pure Layout Functions ###
#############################
function GameplayTop(clip t, clip b, int trimStart, int trimEnd) {
	t = t.Trim(trimStart, trimEnd).PointResize(screenWidth*2, screenHeight*2)
	b = b.Trim(trimStart, trimEnd).PointResize(screenWidth, screenHeight).AddBorders(0, screenHeight, 0, 0)
	return StackHorizontal(t, b).AddBorders(0, vertBorder, 0, vertBorder)
}

function GameplayBottom(clip t, clip b, int trimStart, int trimEnd) {
	t = t.Trim(trimStart, trimEnd).PointResize(screenWidth, screenHeight).AddBorders(0, 0, 0, screenHeight)
	b = b.Trim(trimStart, trimEnd).PointResize(screenWidth*2, screenHeight*2)
	return StackHorizontal(b, t).AddBorders(0, vertBorder, 0, vertBorder)
}

function SingleTop(clip t, clip b, int trimStart, int trimEnd) {
	ret = t.Trim(trimStart, trimEnd).PointResize(screenWidth*2, screenHeight*2).AddBorders(screenWidth/2, 0, screenWidth/2, 0)
	return ret.AddBorders(0, vertBorder, 0, vertBorder)
}

function SingleBottom(clip t, clip b, int trimStart, int trimEnd) {
	ret = b.Trim(trimStart, trimEnd).PointResize(screenWidth*2, screenHeight*2).AddBorders(screenWidth/2, 0, screenWidth/2, 0)
	return ret.AddBorders(0, vertBorder, 0, vertBorder)
}

function SideBySide(clip t, clip b, int trimStart, int trimEnd) {
	t = t.Trim(trimStart, trimEnd).PointResize(screenWidth*2, screenHeight*2).LanczosResize((screenWidth*3)/2, (screenHeight*3)/2)
	b = b.Trim(trimStart, trimEnd).PointResize(screenWidth*2, screenHeight*2).LanczosResize((screenWidth*3)/2, (screenHeight*3)/2)
	return StackHorizontal(t, b).AddBorders(0, screenHeight/4, 0, screenHeight/4).AddBorders(0, vertBorder, 0, vertBorder)
}

function TopAndBottom(clip t, clip b, int trimStart, int trimEnd, int "gap") {
	gap = defined(gap) ? gap : vGap
	t = t.Trim(trimStart, trimEnd).PointResize(screenWidth, screenHeight)
	b = b.Trim(trimStart, trimEnd).PointResize(screenWidth, screenHeight).AddBorders(0, gap, 0, 0)
	return StackVertical(t, b).AddBorders(screenWidth, (vGap-gap)/2, screenWidth, (vGap-gap)/2)
}

function BookMode(clip t, clip b, int trimStart, int trimEnd, int "gap") {
	gap = defined(gap) ? gap : bGap
	t = t.Trim(trimStart, trimEnd).PointResize(screenWidth*2, screenHeight*2).LanczosResize(bookHeight, bookWidth)
	b = b.Trim(trimStart, trimEnd).PointResize(screenWidth*2, screenHeight*2).LanczosResize(bookHeight, bookWidth).AddBorders(0, gap, 0 , 0)
	return StackVertical(t, b).TurnLeft().AddBorders(bookBorder+(bGap-gap)/2, vertBorder, bookBorder+(bGap-gap)/2, vertBorder)
}

#######################################
### Auto-Appending Layout Shortcuts ###
#######################################
function AutoAppend(clip prev, int startFrame, string func, int "gap") {
	ret = Eval(func + "(top, bot, startFrame, 0" + (defined(gap) ? ", "+string(gap) : "") + ")")
	return startFrame == 0 ? ret : prev.Trim(0, startFrame - 1) + ret
}

function gt(clip prev, int startFrame) { return AutoAppend(prev, startFrame, "GameplayTop") }
function gb(clip prev, int startFrame) { return AutoAppend(prev, startFrame, "GameplayBottom") }
function st(clip prev, int startFrame) { return AutoAppend(prev, startFrame, "SingleTop") }
function sb(clip prev, int startFrame) { return AutoAppend(prev, startFrame, "SingleBottom") }
function ss(clip prev, int startFrame) { return AutoAppend(prev, startFrame, "SideBySide") }
function tb(clip prev, int startFrame, int "gap") { return AutoAppend(prev, startFrame, "TopAndBottom", gap) }
function bm(clip prev, int startFrame, int "gap") { return AutoAppend(prev, startFrame, "BookMode", gap) }

Expand/Collapse collapse-content-_9db0b4f06cf14205bce17b0dd699a264

HomePages/Zinfidel last edited by adelikat on 1/2/2022 8:14 PM
Page History Latest diff List referrers View Source