PDA

View Full Version : FBGFX Plasma acceleration using asmosphere



Petr Schreiber
28-03-2008, 20:19
Hi Charles and Misthema,

I stole a work of you both to create hi-speed version of the plasma effect,
here is the first optimization - replacing:


c= (Sin((x+y+t)/100)+Cos((x-t)/100)+Cos((y-t)/100)+Cos((x-y+t)/100))*2+Sin(t/100)*15

... with assembler.



'Plasma-like effect with FBGFX
uses "FBGFX"
uses "OXYGEN"

Dim w,h As Double
w=200
h=150

FBGFX_ScreenRes(w,h,32,2)

Dim x,y,page As single
Dim c,t As single
dim divisor, two, fifteen As single
divisor = 100
two = 2
fifteen = 15

dim EvaluateC as string="
' (
fld dword [#x] ' Sin((x+y+t)/100)
fadd dword [#y]
fadd dword [#t]
fdiv DWORD [#divisor]
fsin

fld dword [#x] ' Cos((x-t)/100)
fsub dword [#t]
fdiv DWORD [#divisor]
fcos
faddp st(1)

fld dword [#y] ' Cos((y-t)/100)
fsub dword [#t]
fdiv DWORD [#divisor]
fcos
faddp st(1)

fld dword [#x] ' Cos((x-y+t)/100)
fsub dword [#y]
fadd dword [#t]
fdiv DWORD [#divisor]
fcos
faddp st(1) ')

fmul DWORD [#two] '*2

fld dword [#t] ' Sin(t/100)*15
fdiv DWORD [#divisor]
fsin
fmul DWORD [#fifteen]
faddp st(1)

fst dword [#c] ' -> store to c

ret
"

dim codeToEvaluateC as string=O2_asm(EvaluateC)
if codeToEvaluateC=chr$(&hc3) then msgbox 0, codeToEvaluateC

while FBGFX_InKey() <> "q" 'Program runs until "q" is pressed
t=t+1
For x = 0 To w' step 3
For y = 0 To h' step 3
MC_EXEC(codeToEvaluateC)
REM c= (Sin((x+y+t)/100)+Cos((x-t)/100)+Cos((y-t)/100)+Cos((x-y+t)/100))*2+Sin(t/100)*15

FBGFX_Color(Rgb(Sin(c)*64+128,Cos(c)*64+128,Cos(-c/2)*64+128), 0)
FBGFX_Circle(x,y,3)
Next
Next

'pageflip
page=-page+1
FBGFX_Sync(1)
FBGFX_ScreenSet(page,-page+1)

wend


It works ;D, at this stage this version is ~1.5x faster than original.

Question for now - I want to use numbers in operations, not specified using variables ( currently managed as using "two", "divisor" and "fifteen" variables, which is a bit odd :) ).
How that can be done in Asmosphere ?


Thanks,
Petr

Charles Pegge
28-03-2008, 23:53
Hi Petr,

Two problems to resolve.

First you can't feed literal numbers into the FPU, nor can it read CPU registers. It can only access numbers which are already present in memory. This leads to the second problem: How do you get local workspace, to store the temporary numbers, without using thinBasic variables?

The solution to the latter is to allocate memory on the stack by subtracting the required space from the stack pointer like this:

sub esp,1000

then using another register to index from.

mov ecx,esp

Now you can store integers

mov dword [ecx+00],15
mov dword [ecx+04],42

..etc

then you can load them into the FPU as dword integers

fild dword [ecx+00]

When you have finished it is vital to disallocate the memory from the stack.
This can be done by adding the space back to the stack pointer:

add esp,1000
ret

To create local variables using macro symbols:

def aa [ecx]
def bb [ecx+04]
def workspace 1000

then

add esp, workspace$
mov ecx,esp
mov aa$,15
fild aa$
....
add esp,workspace$
ret

In the next update I am about to send, the '$' will no longer be needed and further adjustments to the syntax allow system calls to be made in the same way as a high level language.

Petr Schreiber
28-03-2008, 23:56
Thanks for the explanation,

I think I would not figure it out myself :)


Thanks,
Petr

Charles Pegge
29-03-2008, 00:43
Petr,

I think I've exposed a bug! So I have adjusted my above example to avoid it, moving the esp by 1000 instead of 100. I am just tracing through...

Also 'ret 1000' should not be used in this method of allocation.

I am delighted your program works and you have made sense of the FPU. :)

Petr Schreiber
29-03-2008, 10:42
Hi Charles,

when I optimized further, I got some black screen - it is caused by code evaluating Red color component.
As long as it is uncommented all work as it should, maybe this is side effect of some bug?

But I like the module so far, as assembler is so similar to language use on my calculator I find it very comfortable.



'Plasma-like effect with FBGFX
uses "FBGFX"
uses "OXYGEN"

Dim w,h As Double
w=200
h=150

FBGFX_ScreenRes(w,h,32,2)

Dim x,y,page As single
Dim c,t As single
dim divisor, two, fifteen As single
divisor = 100
two = 2
fifteen = 15

dim EvaluateC as string="
' (
fld dword [#x] ' Sin((x+y+t)/100)
fadd dword [#y]
fadd dword [#t]
fdiv DWORD [#divisor]
fsin

fld dword [#x] ' Cos((x-t)/100)
fsub dword [#t]
fdiv DWORD [#divisor]
fcos
faddp st(1)

fld dword [#y] ' Cos((y-t)/100)
fsub dword [#t]
fdiv DWORD [#divisor]
fcos
faddp st(1)

fld dword [#x] ' Cos((x-y+t)/100)
fsub dword [#y]
fadd dword [#t]
fdiv DWORD [#divisor]
fcos
faddp st(1) ')

fmul DWORD [#two] '*2

fld dword [#t] ' Sin(t/100)*15
fdiv DWORD [#divisor]
fsin
fmul DWORD [#fifteen]
faddp st(1)

fst dword [#c] ' -> store to c

ret
"

dim v64, v128 as single
dim Red, Green, Blue as single = 255
v64 = 64
v128 = 128
dim EvaluateR as string = _
"
fld dword [#c]
fsin
fmul DWORD [#v64]
fadd DWORD [#v128]
fst dword [#Red] ' -> store to Red

ret
"
dim EvaluateG as string = _
"
fld dword [#c]
fcos
fmul DWORD [#v64]
fadd DWORD [#v128]
fst dword [#Green] ' -> store to Green

ret
"
dim EvaluateB as string = _
"
fld dword [#c]
fchs ' change sign
fdiv DWORD [#two]
fcos
fmul DWORD [#v64]
fadd DWORD [#v128]
fst dword [#Blue] ' -> store to Blue

ret
"


dim codeToEvaluateC as string = O2_asm(EvaluateC)
dim codeToEvaluateR as string = O2_asm(EvaluateR)
dim codeToEvaluateG as string = O2_asm(EvaluateG)
dim codeToEvaluateB as string = O2_asm(EvaluateB)

if codeToEvaluateC = chr$(&hc3) then
msgbox 0, "Error in EvaluateC, program will end now"
stop
elseif codeToEvaluateR = chr$(&hc3) then
msgbox 0, "Error in EvaluateR, program will end now"
stop
elseif codeToEvaluateG = chr$(&hc3) then
msgbox 0, "Error in EvaluateG, program will end now"
stop
elseif codeToEvaluateB = chr$(&hc3) then
msgbox 0, "Error in EvaluateB, program will end now"
stop
end if


dim t1, t2 as double

while FBGFX_InKey() <> "q" 'Program runs until "q" is pressed
t1 = gettickcount
t=t+1
For x = 0 To w' step 3
For y = 0 To h' step 3
REM MC_EXEC(codeToEvaluateR) ' -- If commented out, red defaults to 255
MC_EXEC(codeToEvaluateC)
MC_EXEC(codeToEvaluateG)
MC_EXEC(codeToEvaluateB)
FBGFX_Color(Rgb(red,green, blue), 0)

FBGFX_circle(x, y, 3)
Next
Next

'pageflip
page=-page+1
FBGFX_Sync(1)
FBGFX_ScreenSet(page,-page+1)
t2 = gettickcount
wend

msgbox 0, "FrameTime:"+STR$(t2-t1)


Thanks,
Petr

Charles Pegge
29-03-2008, 12:25
Hi Petr

If you comment out any one of the colors, it does not produce a black screen. The screen is black when all three are used.

I tweaked the color code to end with FSTP insted of FST but I dont think this was causing any problems here.



dim EvaluateR as string = _
"
fld dword [#c]
fsin
fmul DWORD [#v64]
fadd DWORD [#v128]
fstp dword [#Red] ' -> store to Red

ret
"

Michael Hartlef
29-03-2008, 15:25
Wow, the assembler puts the word interpreted into a totally new contex. Amazing what is possible. I didn't try the code so far. But do I read it correctly? In the assembler code, you can interface easily with the thinBAsic variables? If yes, then it's awesome.

Petr Schreiber
29-03-2008, 15:52
Yes,

it is pretty cool :)

You just put assembler in the string, with links to thinBASIC variable, then perform kind of JIT using O2_ASM, and since then you can execute the resultant machine code using MC_EXEC.


Bye,
Petr

Petr Schreiber
14-04-2008, 18:59
Hi,

just updating the version, works ok ( no black ) with latest Oxygen.



'Plasma-like effect with FBGFX
uses "FBGFX"
uses "OXYGEN"

Dim w,h As Double
w=200
h=150

FBGFX_ScreenRes(w,h,32,2)

Dim x,y,page As single
Dim c,t As single
dim divisor, two, fifteen As single
divisor = 100
two = 2
fifteen = 15

dim EvaluateC as string="
' (
fld dword [#x] ' Sin((x+y+t)/100)
fadd dword [#y]
fadd dword [#t]
fdiv DWORD [#divisor]
fsin

fld dword [#x] ' Cos((x-t)/100)
fsub dword [#t]
fdiv DWORD [#divisor]
fcos
faddp st(1)

fld dword [#y] ' Cos((y-t)/100)
fsub dword [#t]
fdiv DWORD [#divisor]
fcos
faddp st(1)

fld dword [#x] ' Cos((x-y+t)/100)
fsub dword [#y]
fadd dword [#t]
fdiv DWORD [#divisor]
fcos
faddp st(1) ')

fmul DWORD [#two] '*2

fld dword [#t] ' Sin(t/100)*15
fdiv DWORD [#divisor]
fsin
fmul DWORD [#fifteen]
faddp st(1)

fst dword [#c] ' -> store to c

ret
"

dim v64, v128 as single
dim Red, Green, Blue as single = 255
v64 = 64
v128 = 128
dim EvaluateR as string = _
"
fld dword [#c]
fsin
fmul DWORD [#v64]
fadd DWORD [#v128]
fstp dword [#Red] ' -> store to Red

ret
"
dim EvaluateG as string = _
"
fld dword [#c]
fcos
fmul DWORD [#v64]
fadd DWORD [#v128]
fstp dword [#Green] ' -> store to Green

ret
"
dim EvaluateB as string = _
"
fld dword [#c]
fchs ' change sign
fdiv DWORD [#two]
fcos
fmul DWORD [#v64]
fadd DWORD [#v128]
fstp dword [#Blue] ' -> store to Blue

ret
"


dim codeToEvaluateC as string = O2_asm(EvaluateC)
dim codeToEvaluateR as string = O2_asm(EvaluateR)
dim codeToEvaluateG as string = O2_asm(EvaluateG)
dim codeToEvaluateB as string = O2_asm(EvaluateB)

if codeToEvaluateC = chr$(&hc3) then
msgbox 0, "Error in EvaluateC, program will end now"
stop
elseif codeToEvaluateR = chr$(&hc3) then
msgbox 0, "Error in EvaluateR, program will end now"
stop
elseif codeToEvaluateG = chr$(&hc3) then
msgbox 0, "Error in EvaluateG, program will end now"
stop
elseif codeToEvaluateB = chr$(&hc3) then
msgbox 0, "Error in EvaluateB, program will end now"
stop
end if


dim t1, t2 as double

while FBGFX_InKey() <> "q" 'Program runs until "q" is pressed
t1 = gettickcount
t=t+1
For x = 0 To w' step 3
For y = 0 To h' step 3
MC_EXEC(codeToEvaluateR) ' -- If commented out, red defaults to 255
MC_EXEC(codeToEvaluateC)
MC_EXEC(codeToEvaluateG)
MC_EXEC(codeToEvaluateB)
FBGFX_Color(Rgb(red,green, blue), 0)

FBGFX_circle(x, y, 3)
Next
Next

'pageflip
page=-page+1
FBGFX_Sync(1)
FBGFX_ScreenSet(page,-page+1)
t2 = gettickcount
wend

msgbox 0, "FrameTime:"+STR$(t2-t1)



Petr

kryton9
15-04-2008, 02:28
Petr, is the latest asmosphere in thinBasic preview the correct one to test the new script?

Charles Pegge
15-04-2008, 05:54
Hi Kent,

Yes this works with the latest asmosphere. There was an FPU operand coding bug in the first release. But I have a thorough testing system now, which I hope will make bugs a rarity.

With the plasma screen, the messagebox at the end of the program hides behind the FBGX window so you have to uncover it to close the prog.

Petr Schreiber
15-04-2008, 08:09
Hi Kent,

I use the module from this post:
http://community.thinbasic.com/index.php?topic=1637.msg11816#msg11816

I think Oxygen is not yet in official release, but could start to be with next preview.


Petr

kryton9
16-04-2008, 01:47
Oh ok thanks guys for the news. I found out I will be out of town to visit my Sister for a couple of days. So probably when I get back a new preview version will be out by then, so I will wait for that and something to look forward too!

Charles Pegge
16-04-2008, 11:03
I've had sme fun with the plasma program: this one composes the color into ARGB for FBGFX, with Petrs Subroutines combined. It runs at a fair pace. :)




'Plasma-like effect with FBGFX
uses "FBGFX"
uses "OXYGEN"

Dim w,h As long
w=400-1
h=300-1

FBGFX_ScreenRes(w,h,32,2)

Dim x,y,page As single
Dim c,t As single
dim divisor, two, fifteen As single
divisor = 100
two = 2
fifteen = 15

dim ColorCalcSrc as string="
'-----
fld dword [#x] ' Sin((x+y+t)/100)
fadd dword [#y]
fadd dword [#t]
fdiv DWORD [#divisor]
fsin

fld dword [#x] ' Cos((x-t)/100)
fsub dword [#t]
fdiv DWORD [#divisor]
fcos
faddp st(1)

fld dword [#y] ' Cos((y-t)/100)
fsub dword [#t]
fdiv DWORD [#divisor]
fcos
faddp st(1)

fld dword [#x] ' Cos((x-y+t)/100)
fsub dword [#y]
fadd dword [#t]
fdiv DWORD [#divisor]
fcos
faddp st(1) ')

fmul DWORD [#two] '*2

fld dword [#t] ' Sin(t/100)*15
fdiv DWORD [#divisor]
fsin
fmul DWORD [#fifteen]
faddp st(1)

fstp dword [#c] ' -> store to c
'-----
fld dword [#c]
fcos
fmul DWORD [#v64]
fadd DWORD [#v128]
fistp dword [#Green] ' -> store to Green


'-----
fld dword [#c]
fsin
fmul DWORD [#v64]
fadd DWORD [#v128]
fistp dword [#Red] ' -> store to Red
'-----
fld dword [#c]
fchs ' change sign
fdiv DWORD [#two]
fcos
fmul DWORD [#v64]
fadd DWORD [#v128]
fistp dword [#Blue] ' -> store to Blue

'-----
xor eax,eax
add eax,[#red]
shl eax,8
add eax,[#green]
shl eax,8
add eax,[#blue]
'or eax,0xff000000
mov [#compo],eax ' composite ARGB color

ret
"


dim v64, v128 as single
dim Red, Green, Blue, Compo as long = 255
v64 = 64
v128 = 128

dim ColorCalc as string = O2_ASM(ColorCalcSrc)
if len(O2_ERROR) then
msgbox 0, O2_ERROR+$crlf+"Program will end now"
stop
end if

dim t1, t2 as double

while FBGFX_InKey() <> "q" 'Program runs until "q" is pressed
t1 = gettickcount
t=t+1
For x = 0 To w step 3
For y = 0 To h step 3
MC_EXEC ColorCalc
FBGFX_circle x, y, 3, compo
Next
Next

'pageflip
page=-page+1
FBGFX_Sync(1)
FBGFX_ScreenSet(page,-page+1)
t2 = gettickcount
wend


'msgbox 0, ":"+hex$(fbgfx_rgb(0,0,1))
'msgbox 0, "FrameTime:"+STR$(t2-t1)

Charles Pegge
17-04-2008, 10:00
This runs faster yet by simplifying the inner loop. The Assembler script takes on the task of stepping x and y then breaking the loop at the end of each frame. x and y have also been changed to integers.

The x y stepper illustrates how to use an O2 control structure in Asmosphere. - No jump labels needed.




'Plasma-like effect with FBGFX
uses "FBGFX"
uses "OXYGEN"

Dim w,h,x,y,i,syn As long
w=400 ' x boundary
h=300 ' y boundary
i=3 ' step
syn=0 ' loop flag

FBGFX_ScreenRes(w,h,32,2)

Dim page As single
Dim c,t As single
dim divisor, two, fifteen As single
divisor = 100
two = 2
fifteen = 15

dim ColorCalcSrc as string="
'-----
fild dword [#x] ' Sin((x+y+t)/100)
fiadd dword [#y]
fadd dword [#t]
fdiv DWORD [#divisor]
fsin

fild dword [#x] ' Cos((x-t)/100)
fsub dword [#t]
fdiv DWORD [#divisor]
fcos
faddp st(1)

fild dword [#y] ' Cos((y-t)/100)
fsub dword [#t]
fdiv DWORD [#divisor]
fcos
faddp st(1)

fild dword [#x] ' Cos((x-y+t)/100)
fisub dword [#y]
fadd dword [#t]
fdiv DWORD [#divisor]
fcos
faddp st(1) ')

fmul DWORD [#two] '*2

fld dword [#t] ' Sin(t/100)*15
fdiv DWORD [#divisor]
fsin
fmul DWORD [#fifteen]
faddp st(1)

fstp dword [#c] ' -> store to c
'-----
fld dword [#c]
fcos
fmul DWORD [#v64]
fadd DWORD [#v128]
fistp dword [#Green] ' -> store to Green


'-----
fld dword [#c]
fsin
fmul DWORD [#v64]
fadd DWORD [#v128]
fistp dword [#Red] ' -> store to Red
'-----
fld dword [#c]
fchs ' change sign
fdiv DWORD [#two]
fcos
fmul DWORD [#v64]
fadd DWORD [#v128]
fistp dword [#Blue] ' -> store to Blue

'-----
'compose rgb color
xor eax,eax
add eax,255
shl eax,8 ' alpha byte optional
add eax,[#red]
shl eax,8
add eax,[#green]
shl eax,8
add eax,[#blue]
mov [#compo],eax ' composite ARGB color

'-----
' increment x y and clear syn flag afer each screen cycle
mov eax,[#x]
mov ecx,[#y]
(
add eax,[#i] ' increment x
cmp eax,[#w] '
jl exit '
xor eax,eax ' zero x
add ecx,[#i] ' increment y
cmp ecx,[#h] '
jl exit
xor ecx,ecx ' zero y
mov [#syn],ecx ' zero sync
)
mov [#x],eax
mov [#y],ecx
ret
"


dim v64, v128 as single
dim Red, Green, Blue, Compo as long = 255
v64 = 64
v128 = 128

dim ColorCalc as string = O2_ASM(ColorCalcSrc)
if len(O2_ERROR) then
msgbox 0, O2_ERROR+$crlf+"Program will end now"
stop
end if
'msgbox 0,o2_view(ColorCalcSrc) ' look at O2 translated source
'stop

dim t1, t2 as double

while FBGFX_InKey() <> "q" 'Program runs until "q" is pressed
t1 = gettickcount
t=t+1
syn=1
while syn
MC_EXEC ColorCalc
FBGFX_circle x, y, i, compo
wend
page=-page+1 ' page flip
FBGFX_Sync(1)
FBGFX_ScreenSet(page,-page+1)
't2 = gettickcount
wend

'msgbox 0, "FrameTime:"+STR$(t2-t1)

Petr Schreiber
17-04-2008, 16:25
Thanks Charles,

all-in-one version is nice :)


Petr

Charles Pegge
23-04-2008, 10:28
Well this is an all-in-two version, :) where the assembly code is in a separate asm file:
This is probably the easier way to handle larger pieces of code - and there are no restrictions on using double quotes.

In the latest release of thinBasic_Oxygen, I have tweaked the interpretation of a #variable, so that they can be 'diverted' to a local def instead of being a pointer defined by the parent program.

The reason for doing this is to make Asmosphere easier to embed in other programs, which do not have a scripting interface. They will generate their own def header to add to the main asm source script. Assembly code developed with thinBasic, can then be used without any alteration apart from this header.

The example below also demonstrates how to set up local variables on the stack and then release them before returning

I have included this with the latest thinBasic_Oxygen:

PlasmaColor2.asm




' Plasma-like effect with FBGFX
' -----------------------------


' allocatate local workspace on stack
push ebp
mov ebp,esp
sub esp,40


' variables bound to parent
' #x row pos
' #y column pos
' #i step
' #w width of window client
' #h height of window client
' #syn parent loop flag
' #compo composite color


' local variable macros
def #v128 ebp-04
def #v64 ebp-08
def #fifteen ebp-12
def #two ebp-16
def #divisor ebp-20

' these do not require an initial value
def #red ebp-24
def #green ebp-28
def #blue ebp-32

' initialise local variables
' (constants for the FPU)
mov [#v128], 128
mov [#v64], 64
mov [#fifteen], 15
mov [#two], 2
mov [#divisor], 100

'-----
fild dword [#x] ' Sin((x+y+t)/100)
fiadd dword [#y]
fadd dword [#t]
fidiv dword [#divisor]
fsin

fild dword [#x] ' Cos((x-t)/100)
fsub dword [#t]
fidiv dword [#divisor]
fcos
faddp st(1)

fild dword [#y] ' Cos((y-t)/100)
fsub dword [#t]
fidiv dword [#divisor]
fcos
faddp st(1)

fild dword [#x] ' Cos((x-y+t)/100)
fisub dword [#y]
fadd dword [#t]
fidiv dword [#divisor]
fcos
faddp st(1) ')

fimul dword [#two] '*2

fld dword [#t] ' Sin(t/100)*15
fidiv dword [#divisor]
fsin
fimul dword [#fifteen]
faddp st(1)

fstp dword [#c] ' -> store to c
'-----
fld dword [#c]
fcos
fimul dword [#v64]
fiadd dword [#v128]
fistp dword [#Green] ' -> store to Green


'-----
fld dword [#c]
fsin
fimul dword [#v64]
fiadd dword [#v128]
fistp dword [#Red] ' -> store to Red
'-----
fld dword [#c]
fchs ' change sign
fidiv dword [#two]
fcos
fimul dword [#v64]
fiadd dword [#v128]
fistp dword [#Blue] ' -> store to Blue

'-----
'compose rgb color
xor eax,eax
add eax,255
shl eax,8 ' alpha byte optional
add eax,[#red]
shl eax,8
add eax,[#green]
shl eax,8
add eax,[#blue]
mov [#compo],eax ' composite ARGB color

'-----
' increment x y and clear syn flag afer each screen cycle
mov eax,[#x]
mov ecx,[#y]
(
add eax,[#i] ' increment x
cmp eax,[#w] '
jl exit '
xor eax,eax ' zero x
add ecx,[#i] ' increment y
cmp ecx,[#h] '
jl exit
xor ecx,ecx ' zero y
mov [#syn],ecx ' zero sync
)
mov [#x],eax
mov [#y],ecx

' deallocate local workspace from stack
add esp,40
pop ebp

ret



Test_PF2.tbasic


'Plasma-like effect with FBGFX
uses "FBGFX"
uses "OXYGEN"

Dim w,h,x,y,i,syn,compo As long
w=400 ' x boundary
h=300 ' y boundary
i=3 ' step
syn=0 ' loop flag


Dim page As single
Dim c,t As single
dim ColorCalc as string = O2_ASM_FILE "PlasmaColor2.asm"
if len(O2_ERROR)>0 then
msgbox 0, O2_ERROR+$crlf+"Program will end now"
stop
end if

dim t1, t2 as double

FBGFX_ScreenRes(w,h,32,2)

while FBGFX_InKey() <> "q" 'Program runs until "q" is pressed
t1 = gettickcount
t=t+1
syn=1
while syn
MC_EXEC ColorCalc
FBGFX_circle x, y, i, compo
wend
page=-page+1 ' page flip
FBGFX_Sync(1)
FBGFX_ScreenSet(page,-page+1)
t2 = gettickcount
wend

'msgbox 0, "FrameTime:"+STR$(t2-t1)

kryton9
23-04-2008, 23:07
That is really a great idea to have the option of all in one or all in two option!!