Yes, of course. The reason is: 480 / 16 = 30 (rows).lizard wrote:The numbers 1  25 span only a part of the screen here.
Does anyone know what algo XP > full screen DOS?
Re: Does anyone know what algo XP > full screen DOS?
Re: Does anyone know what algo XP > full screen DOS?
But 480 / 25 = 19.2 ?
Re: Does anyone know what algo XP > full screen DOS?
You don't seem to understand. The Font's height is 16 (pixels), it's width is 8.
See paul doe's code:This then gives: 80 columns, 30 rows
(screen is: graphics, not console)
See paul doe's code:
Code: Select all
width sWidth / 8, sHeight / 16
(screen is: graphics, not console)
Re: Does anyone know what algo XP > full screen DOS?
lizard wrote:But 480 / 25 = 19.2 ?
MrSwiss wrote:(screen is: graphics, not console)
Of course, lizard. But, as MrSwiss points, it's just a graphical window, not real console mode. Old VGA displays were actually 640x400, not 640x480. If you change it in the code, you'll see that it effectively gives you an 80x25 'text' mode. The 'width' call tells the FBGFX library to use the 8x16 internal font size.
Re: Does anyone know what algo XP > full screen DOS?
counting_pine wrote:As best I recall, natural LCD scaling tends to look something like this:It preserves the basic "rectangular" nature of the pixels, like with nearest neighbour scaling, but with blurrier edges between the original pixels.Code: Select all
function avg(col1 as long, col2 as long, w1 as single, w2 as single) as long
dim as ubyte r1 = col1 shr 16, r2 = col2 shr 16
dim as ubyte g1 = col1 shr 8, g2 = col2 shr 8
dim as ubyte b1 = col1 , b2 = col2
var r = r1 + (r2  r1) * w2 / (w1 + w2)
var g = g1 + (g2  g1) * w2 / (w1 + w2)
var b = b1 + (b2  b1) * w2 / (w1 + w2)
return rgb(r, g, b)
end function
function spoint(x1 as single, y1 as single, x2 as single, y2 as single) as long
dim as long col1, col2
dim as single w1, w2
if int(x1) = int(x2) then
if int(y1) = int(y2) then
return point(x1, y1)
else
col1 = point(x1, y1)
col2 = point(x1, y1+1)
w1 = int(y1 + 1)  y1
w2 = y2  int(y2)
return avg(col1, col2, w1, w2)
end if
else
col1 = spoint(x1, y1, x1, y2)
col2 = spoint(x2, y1, x2, y2)
w1 = int(x1 + 1)  x1
w2 = x2  int(x2)
return avg(col1, col2, w1, w2)
end if
end function
screenres 1024, 768, 24
dim as integer w = 320, h = 240
dim as single dx = 320 / 1024, dy = 240 / 768
circle (160, 120), 100, &h00ff00
paint (160, 120), &h0000ff, &h00ff00
line (140, 100)(180,140), &hff0000, b
sleep
for y as integer = 768 to 0 step 1
for x as integer = 1024 to 0 step 1
pset (x, y), spoint(x * dx, y * dy, (x + 1) * dx, (y + 1) * dy)
next x
next y
sleep
It can be nicer than nearestneighbour, because it doesn't give the horrible "jagged" effect that happens when one pixel is enlarged to a pixel wider than its neighbour.
The way I picture it is like laying a set of smaller mosaic tiles (say 1 square cm) over a set of larger mosaic tiles (say 1 square inch).
If the smaller mosaic tile lands entirely within a larger tile, it gets the colour of that tile.
Otherwise, if it straddles two tiles (or four tiles), its colour is the average of the tiles it covers, weighted by how much of the smaller tile covers it.
I don't know what this method is called. But it's pretty much what you'd get if you converted some pixel art to an SVG and zoomed in
Thanks, this was exactly what I was looking for. Nearest neighbor upscaling but without the jagged edges.
Re: Does anyone know what algo XP > full screen DOS?
@paul doe,
AFAIR, you are mixing up the old, graphics Standards:
AFAIR, you are mixing up the old, graphics Standards:
 CGA = 320 x 200
EGA = 640 x 400
VGA = 640 x 480
Re: Does anyone know what algo XP > full screen DOS?
Depends on whether you mean graphics mode or text mode. Vga text mode is actually 640x400. And actually sometimes it's 720x400 and the graphics card would duplicate the last column of the character cell's pixels, which made those special fill characters look funny.
Btw, Ega graphics mode was 640x350. And yes you are right that vga graphics mode is indeed 640x480. Ega used 8x14 cells for text and vga used 8x16. 30 rows.
Btw, Ega graphics mode was 640x350. And yes you are right that vga graphics mode is indeed 640x480. Ega used 8x14 cells for text and vga used 8x16. 30 rows.
Re: Does anyone know what algo XP > full screen DOS?
counting_pine wrote:As best I recall, natural LCD scaling tends to look something like this:It preserves the basic "rectangular" nature of the pixels, like with nearest neighbour scaling, but with blurrier edges between the original pixels.Code: Select all
function avg(col1 as long, col2 as long, w1 as single, w2 as single) as long
dim as ubyte r1 = col1 shr 16, r2 = col2 shr 16
dim as ubyte g1 = col1 shr 8, g2 = col2 shr 8
dim as ubyte b1 = col1 , b2 = col2
var r = r1 + (r2  r1) * w2 / (w1 + w2)
var g = g1 + (g2  g1) * w2 / (w1 + w2)
var b = b1 + (b2  b1) * w2 / (w1 + w2)
return rgb(r, g, b)
end function
function spoint(x1 as single, y1 as single, x2 as single, y2 as single) as long
dim as long col1, col2
dim as single w1, w2
if int(x1) = int(x2) then
if int(y1) = int(y2) then
return point(x1, y1)
else
col1 = point(x1, y1)
col2 = point(x1, y1+1)
w1 = int(y1 + 1)  y1
w2 = y2  int(y2)
return avg(col1, col2, w1, w2)
end if
else
col1 = spoint(x1, y1, x1, y2)
col2 = spoint(x2, y1, x2, y2)
w1 = int(x1 + 1)  x1
w2 = x2  int(x2)
return avg(col1, col2, w1, w2)
end if
end function
screenres 1024, 768, 24
dim as integer w = 320, h = 240
dim as single dx = 320 / 1024, dy = 240 / 768
circle (160, 120), 100, &h00ff00
paint (160, 120), &h0000ff, &h00ff00
line (140, 100)(180,140), &hff0000, b
sleep
for y as integer = 768 to 0 step 1
for x as integer = 1024 to 0 step 1
pset (x, y), spoint(x * dx, y * dy, (x + 1) * dx, (y + 1) * dy)
next x
next y
sleep
It can be nicer than nearestneighbour, because it doesn't give the horrible "jagged" effect that happens when one pixel is enlarged to a pixel wider than its neighbour.
The way I picture it is like laying a set of smaller mosaic tiles (say 1 square cm) over a set of larger mosaic tiles (say 1 square inch).
If the smaller mosaic tile lands entirely within a larger tile, it gets the colour of that tile.
Otherwise, if it straddles two tiles (or four tiles), its colour is the average of the tiles it covers, weighted by how much of the smaller tile covers it.
I don't know what this method is called. But it's pretty much what you'd get if you converted some pixel art to an SVG and zoomed in
I tried this code in FreeBasic. Works great! So, I tried to adapt this into C# and ran into a few problems.
Am I correct to assume int(6.7) = 6 in FreeBasic, whereas Convert.ToInt32(6.7) in C# might yield 7?
Update: I got the code to work in C#. Just have to use Convert.ToInt32(Math.Floor()) where int() is found. It's really slow, so now I have to learn about parallel processing...
Re: Does anyone know what algo XP > full screen DOS?
You can't make a silk purse out of a sow's ear, so they say.
Here is my effort
some functions are unused
Here is my effort
Code: Select all
#include "file.bi"
Function grey(c As Ulong) As Ulong
dim as ubyte v=.299*((c Shr 16)And 255)+.587*((c Shr 8)And 255)+.114*(c And 255)
Return Rgb(v,v,v)
End Function
function resize(picture As String,_x As long=0,_y As long=0,greyflag as long=0) as any ptr
if fileexists (picture)=0 then print picture;" not found":sleep:end
#define map(a,b,x,c,d) ((d)(c))*((x)(a))/((b)(a))+(c)
dim as long dimensionx,dimensiony
Open picture For Binary access read As #1
Get #1, 19, dimensionx
Get #1, 23, dimensiony
' get #1, 29, b
Close #1
if _x* _y=0 then _x=dimensionx:_y=dimensiony
dim as single dx=_x/dimensionx,dy=_y/dimensiony
dx=dx/2:dy=dy/2
dim as any ptr im=Imagecreate(dimensionx,dimensiony)
dim as any ptr tim=Imagecreate(_x,_y)
Bload picture,im
Dim As Ulong col
For y As long=0 To (dimensiony1)
For x As long=0 To (dimensionx1)
Dim As long xx=map(0,(dimensionx1),x,0,_x)
Dim As long yy=map(0,(dimensiony1),y,0,_y)
if greyflag then
Line tim,(xxdx,yydy)(xx+dx,yy+dy),grey(point(x,y,im)),bf
else
Line tim,(xxdx,yydy)(xx+dx,yy+dy),point(x,y,im),bf
end if
Next x
Next y
return tim
End function
Function Filter(Byref tim As Ulong Pointer,_
byval rad As Single,_
byval destroy As long=1,_
byval fade As long=0) As Ulong Pointer
#define map(a,b,_x_,c,d) ((d)(c))*((_x_)(a))/((b)(a))+(c)
If fade<0 Then fade=0:If fade>100 Then fade=100
Type p2
As long x,y
As Ulong col
End Type
#macro ppoint(_x,_y,colour)
pixel=row+pitch*(_y)+(_x)*4
(colour)=*pixel
#endmacro
#macro ppset(_x,_y,colour)
pixel=row+pitch*(_y)+(_x)*4
*pixel=(colour)
#endmacro
#macro average()
ar=0:ag=0:ab=0:inc=0
xmin=x:If xmin>rad Then xmin=rad
xmax=rad:If x>=(_x1rad) Then xmax=_x1x
ymin=y:If ymin>rad Then ymin=rad
ymax=rad:If y>=(_y1rad) Then ymax=_y1y
For y1 As long=ymin To ymax
For x1 As long=xmin To xmax
inc=inc+1
ar=ar+(NewPoints(x+x1,y+y1).col Shr 16 And 255)
ag=ag+(NewPoints(x+x1,y+y1).col Shr 8 And 255)
ab=ab+(NewPoints(x+x1,y+y1).col And 255)
Next x1
Next y1
If fade=0 Then
averagecolour=Rgb(ar/(inc),ag/(inc),ab/(inc))
Else
averagecolour=Rgb(fd*ar/(inc),fd*ag/(inc),fd*ab/(inc))
End If
#endmacro
Dim As Single fd=map(0,100,fade,1,0)
Dim As integer _x,_y
Imageinfo tim,_x,_y
Dim As Ulong Pointer im=Imagecreate(_x,_y)
Dim As integer pitch
Dim As Any Pointer row
Dim As Ulong Pointer pixel
Dim As Ulong col
Imageinfo tim,,,,pitch,row
Dim As p2 NewPoints(_x1,_y1)
For y As long=0 To (_y)1
For x As long=0 To (_x)1
ppoint(x,y,col)
NewPoints(x,y)=Type<p2>(x,y,col)
Next x
Next y
Dim As Ulong averagecolour
Dim As long ar,ag,ab
Dim As long xmin,xmax,ymin,ymax,inc
Imageinfo im,,,,pitch,row
For y As long=0 To _y1
For x As long=0 To _x1
average()
ppset((NewPoints(x,y).x),(NewPoints(x,y).y),averagecolour)
Next x
Next y
If destroy Then Imagedestroy tim: tim = 0
Function= im
End Function
Function sharpen(Byref im As Any Ptr) As Any Ptr
'point and pset speeded up
#macro _point(_x,_y,colour)
pixel=row+pitch*(_y)+4*(_x)
(colour)=*pixel
#endmacro
#macro _pset(_x,_y,colour)
pixel=row+pitch*(_y)+4*(_x)
*pixel=(colour)
#endmacro
Dim As Long Sieve(2,2)={ {1,1,1}, _
{1,12,1}, _
{1,1,1}}
Dim As integer szx,szy
Dim As integer pitch
Dim As Any Pointer row
Dim As Ulong Pointer pixel
Dim As Ulong col
Imageinfo im,szx,szy,,pitch,row
Dim _out(szx2, szy2, 2) As Long
Dim As Long f,r,g,b
Dim As Ulong c
For Y As Long = 1 To szy2
For X As Long = 1 To szx2
R = 0 : G = 0 : B = 0
For I As Long = 1 To 1
For J As Long = 1 To 1
_point((x+i),(y+j),c)
f = Sieve(I+1,J+1)
r += f * ( ( c ) Shr 16 And 255 )
g += f * ( ( c ) Shr 8 And 255 )
b += f * ( ( c ) And 255 )
Next
Next
If r < 0 Then r = 0 :End If:If r > 1020 Then r = 1020
If g < 0 Then g = 0 :End If:If g > 1020 Then g = 1020
If b < 0 Then b = 0 :End If:If b > 1020 Then b = 1020
_out(x,y,0) = r \ 4
_out(x,y,1) = g \ 4 '
_out(x,y,2) = b \ 4
Next
Next
For y As Long = 1 To szy2
For x As Long = 1 To szx2
_pset(x,y,Rgb(_out(x,y,0),_out(x,y,1),_out(x,y,2)))
Next x
Next y
Return im
End Function
screenres 1024, 768, 24
circle (160, 120), 100, &h00ff00
paint (160, 120), &h0000ff, &h00ff00
draw string(140,70),"Hello"
line (140, 100)(180,140), &hff0000, b
dim as any ptr i=imagecreate(211,211)
line(60,20)(260,220),rgb(0,100,200),b
get (605,205)(260+5,220+5),i
bsave "Temporary.bmp",i
dim as any ptr i2=resize("Temporary.bmp",700,700)
i2=filter(i2,2)' try 1 2 3 ...
'i2=sharpen(i2)'try
put(260,40),i2
sleep
imagedestroy i
imagedestroy i2
kill "Temporary.bmp"
some functions are unused

 Site Admin
 Posts: 5941
 Joined: Jul 05, 2005 17:32
 Location: Manchester, Lancs
Re: Does anyone know what algo XP > full screen DOS?
CGAMan wrote:Update: I got the code to work in C#. Just have to use Convert.ToInt32(Math.Floor()) where int() is found. It's really slow, so now I have to learn about parallel processing...
Yeah.. my code isn't much more than "reference implementation", the algorithm can be rewritten in much more efficient ways.
There are lots of calculations done that only need to happen once per row, or per column, or perhaps only once ever.
I think it should be possible to do it all in integer math, with only one multiplication per pixel per colour channel.
Re: Does anyone know what algo XP > full screen DOS?
counting_pine wrote:CGAMan wrote:Update: I got the code to work in C#. Just have to use Convert.ToInt32(Math.Floor()) where int() is found. It's really slow, so now I have to learn about parallel processing...
Yeah.. my code isn't much more than "reference implementation", the algorithm can be rewritten in much more efficient ways.
There are lots of calculations done that only need to happen once per row, or per column, or perhaps only once ever.
I think it should be possible to do it all in integer math, with only one multiplication per pixel per colour channel.
I thought it was going to be a complicated ordeal to implement parallel processing in C#, since the Bitmap class doesn't do parallel processing. As I was using custom GetPixel(), SetPixel() methods found on the web to test out this algorithm, I discovered that these methods had already been made parallel processingcapable (using LockBits and Marshal.Copy on a bytes array to bypass C#'s inability to do parallel processing on bitmaps). So, it was a simple task of me rewriting for loops to Parallel.For.
I was then able to achieve near realtime upscaling of my very small bitmap!
So, the next question is, seeing how FreeBasic does this single threaded way faster than C#, can FreeBasic do parallel processing on this algorithm as well? (Coz then my image should render way faster in fbc using parallel processing than in C#...)

 Site Admin
 Posts: 5941
 Joined: Jul 05, 2005 17:32
 Location: Manchester, Lancs
Re: Does anyone know what algo XP > full screen DOS?
Here's a reimplementation of the algorithm that takes most of the hard math out of the inner loop.
It's still slow, but I think it's because of the use of pset/point, and working with two different image buffers. (It's faster to read and write from just the screen, and I've coded the y loop to work bottomup to allow that, to prevent the destination overwriting the source.)
There are also places where pixel values are calculated multiple times for the same colours, where instead it could reuse pixel values previously set (e.g. the value just before it, horizontally or vertically).
One way to parallelise it might be to split the image into horizontal strips and create a thread for each strip. But if you optimise the code to reuse values from the previous row, you'd have to be careful not to do that on the first row of each strip.
Code: Select all
function avg(c1 as long, c2 as long, w as single) as long
dim as integer r1, g1, b1, r2, g2, b2
r1 = c1 shr 16 and 255: r2 = c2 shr 16 and 255
g1 = c1 shr 8 and 255: g2 = c2 shr 8 and 255
b1 = c1 and 255: b2 = c2 and 255
r1 += ((r2  r1) * w)
g1 += ((g2  g1) * w)': g1 = (g1 + 128) \ 2
b1 += ((b2  b1) * w)
return rgb(r1, g1, b1)
end function
sub scale_put(src as any ptr, sw as integer, sh as integer, dw as integer, dh as integer)
#define srcpoint(x, y) point(scalex(x), scaley(y), src)
#define dstpoint(x, y) point(x, y)
dim as integer scalex(0 to dw1), scaley(0 to dh1)
dim as single splitx(0 to dw1), splity(0 to dh1)
dim as long c1, c2
'' x lookups for scaled coordinates and splits
for x as integer = 0 to dw1
scalex(x) = (x * sw) \ dw
if ((x+1) * sw) \ dw = (x * sw) \ dw then
splitx(x) = 0
else
splitx(x) = frac(((x+1) * sw) / dw) * dw / sw
end if
next x
'' y lookups for scaled coordinates and splits
for y as integer = 0 to dh1
scaley(y) = (y * sh) \ dh
if ((y+1) * sh) \ dh = (y * sh) \ dh then
splity(y) = 0
else
splity(y) = frac(((y+1) * sh) / dh) * dh / sh
end if
next y
'screenlock
for y as integer = dh to 0 step 1 '0 to dh1
if splity(y) = 0 then
for x as integer = 0 to dw1
if splitx(x) = 0 then
pset (x, y), srcpoint(x, y)
else
c1 = srcpoint(x, y)
c2 = srcpoint(x+1, y)
pset (x, y), avg(c1, c2, splitx(x))
end if
next x
else
for x as integer = 0 to dw1
if splitx(x) = 0 then
c1 = srcpoint(x, y)
c2 = srcpoint(x, y+1)
pset (x, y), avg(c1, c2, splity(y))
else
c1 = avg(srcpoint(x, y ), srcpoint(x+1, y ), splitx(x))
c2 = avg(srcpoint(x, y+1), srcpoint(x+1, y+1), splitx(x))
pset (x, y), avg(c1, c2, splity(y))
end if
next x
end if
next y
'screenunlock
end sub
screenres 1024, 768, 32
dim as any ptr img = imagecreate(321, 241)
'bload "test.bmp", img
for i as integer = 0 to 321*241
pset img, (i mod 321, i \ 321), (i mod 2 = 0)
next i
scale_put(img, 321, 241, 1024, 768)
imagedestroy img
sleep
There are also places where pixel values are calculated multiple times for the same colours, where instead it could reuse pixel values previously set (e.g. the value just before it, horizontally or vertically).
One way to parallelise it might be to split the image into horizontal strips and create a thread for each strip. But if you optimise the code to reuse values from the previous row, you'd have to be careful not to do that on the first row of each strip.
Re: Does anyone know what algo XP > full screen DOS?
You guys... The algos found on these pages are the best at emulating that old CRT display look! The ones I've tried were meant to both upscale and downscale bitmaps and excelled at neither.
Anyways, thank you all for your contributions.
What worries me is I see so many projects wanting to preserve the backends of legacy languages.
IMO, the legacy frontend should be preserved as well, ie. how the output should have looked like back in 199x...
Anyways, thank you all for your contributions.
What worries me is I see so many projects wanting to preserve the backends of legacy languages.
IMO, the legacy frontend should be preserved as well, ie. how the output should have looked like back in 199x...
Re: Does anyone know what algo XP > full screen DOS?
I'm not sure if this is what you want:
https://github.com/glasyalabolas/fbimageresizedemo
The algorithm is very similar to the one by counting_pine, but without the smoothing (adding it is no problem, though). The resize procedure in question is this:
EDIT: I removed the code, as it will get outdated pretty soon.
In my box, I get ~500 FPS in 720p, but I don't know what kind of application would you want to use it for (aside from the need to be realtime). You'll get the best image quality if you keep the original image's aspect ratio, of course.
https://github.com/glasyalabolas/fbimageresizedemo
EDIT: I removed the code, as it will get outdated pretty soon.
In my box, I get ~500 FPS in 720p, but I don't know what kind of application would you want to use it for (aside from the need to be realtime). You'll get the best image quality if you keep the original image's aspect ratio, of course.
Last edited by paul doe on Dec 14, 2017 15:00, edited 1 time in total.

 Site Admin
 Posts: 5941
 Joined: Jul 05, 2005 17:32
 Location: Manchester, Lancs
Re: Does anyone know what algo XP > full screen DOS?
paul doe wrote:I'm not sure if this is what you want:
https://github.com/glasyalabolas/fbimageresizedemo
The algorithm is very similar to the one by counting_pine, but without the smoothing (adding it is no problem, though).
(Are you glasyalabolas?)
If it's no problem for you to add the smoothing, please do!
I don't much enjoy working with FB image buffers  I tend to feel the need to cover cases like using the screen buffer, or where the source/destination buffer are the same, and it makes things a lot more complicated.
There's more math involved in smoothing, so 500fps is probably too much to hope for, but a few multiplications per (smoothed) pixel shouldn't result in unplayable framerates if done well.
Who is online
Users browsing this forum: No registered users and 1 guest