1. New Niel2.e
I've just downloaded and tried niel2.e
Below is a couple is a few line routines that can be easily modified to
run with niel2.e or any other graphics lib by changing the call to EU's
pixel() with the pixel routine fron the desired library ie; niel2.e.
I also found a problem with the machine code to map the linear frame
buffer that was also in the origional niel.e.
(Unless it was deliberatly coded that way for EU compatablity reasons).
First here are the line routines:
-- Bressenham algorithm with no restrictions on input variables.
-- You need to supply your own abs() function.
global procedure Line(atom Color, sequence xy1, sequence xy2)
atom d, ax, ay, sx, sy, dx, dy
atom x1, x2, y1, y2
x1 = xy1[1] y1 = xy1[2] x2 = xy2[1] y2 = xy2[2]
dx = x2 - x1 ax = abs(dx) * 2 if dx < 0 then sx = -1 else sx = 1 end if
dy = y2 - y1 ay = abs(dy) * 2 if dy < 0 then sy = -1 else sy = 1 end if
pixel(Color, {x1, y1})
if ax > ay then
d = ay - (ax * 2)
while x1 != x2 do
if d >= 0 then y1 += sy d -= ax end if
x1 += sx
d += ay
pixel(Color, {x1, y1})
end while
else
d = ax - (ay * 2)
while y1 != y2 do
if d >= 0 then x1 += sx d -= ay end if
y1 += sy
d += ax
pixel(Color, {x1, y1})
end while
end if
end procedure
global procedure Cubic_Bezier_Curve(atom Color,
sequence xy1, sequence xy2, sequence xy3, sequence xy4)
atom x1, y1, x2, y2, x3, y3, x4, y4
atom tx1, tx2, tx3, ty1, ty2, ty3, mu1, mu2, mu3, muDelta
integer xStart, yStart, xEnd, yEnd
x1 = xy1[1] y1 = xy1[2]
x2 = xy2[1] y2 = xy2[2]
x3 = xy3[1] y3 = xy3[2]
x4 = xy4[1] y4 = xy4[2]
tx1 = -x1 + 3 * x2 - 3 * x3 + x4 ty1 = -y1 + 3 * y2 - 3 * y3 + y4
tx2 = 3 * x1 - 6 * x2 + 3 * x3 ty2 = 3 * y1 - 6 * y2 + 3 * y3
tx3 = -3 * x1 + 3 * x2 ty3 = -3 * y1 + 3 * y2
xStart = 1 yStart = 1
muDelta = 1 / 128 mu1 = muDelta
for n = 1 to 128 do
mu2 = mu1 * mu1 mu3 = mu2 * mu1
xEnd = floor(mu3 * tx1 + mu2 * tx2 + mu1 * tx3 + x1)
yEnd = floor(mu3 * ty1 + mu2 * ty2 + mu1 * ty3 + y1)
Line(Color, {xStart, yStart}, {xEnd, yEnd})
mu1 += muDelta
xStart = xEnd
yStart = yEnd
end for
end procedure
Mapping the linear frame buffer.
Niel2.e neglects to check that the linear frame buffer has been set up
correctly ie; When linear mode is available but the code to map the
linear frame buffer fails, for whatever reason, niel2.e should resort
to bank switching for the mode.
I found the machine code in niel2.e to map the linear frame buffer is
missing some steps needed to map the buffer correctly.
n.b. Many linear modes on various video cards I have done testing on
don't get mapped correctly wich makes screen output invalid.
(data is output to an invalid address rather than the screen address.)
after the call to int 31h func 800h (dpmi physical address mapping).
there should be;
* Allocate LTD descriptor. int 31h func 000h
* Set segmant base address. int 31h func 007h
* Set segment limit. int 31h func 008h ((maxx*maxy*bytepp)-1)
Also the size specified in si:di for int 31h 800h should be
'maxx*maxy*bytepp' not 4194304d.
To unmap the linear buffer Niel2.e should
* Get segment base address. int 31h func 006h
* Unmap physical memroy. int 31h func 801h
* Free LTD descriptor. int 31h func 001h
Below is an attempt to create an include file to map the linear buffer.
Content is untested but it may be used as a template to map the linear
frame buffer for future versions of Niel2.e.
include bits.e
include mixedlib.e
constant
--
lpALLOCLTDDESC=define_asm_func(
ENTER_PROC(0)&{
#66,#8B,#4D,#08, -- mov cx, word ptr [ebp+8]
#31,#C0, -- xor eax, eax
#CD,#31, -- int #31
#73,#02, -- jnc @F
#31,#C0 -- xor eax, eax
-- @@:
}&LEAVE_PROC(0),
{WORD}, WORD, 4)
constant
--
lpFREELTDDESC=define_asm_proc(
ENTER_PROC(0)&{
#66,#8B,#5D,#08, -- mov bx, word ptr [ebp+8]
#B8,#01,#00,#00,#00, -- mov eax, 0001
#CD,#31 -- int #31
}&LEAVE_PROC(0),
{WORD}, 4)
constant
--
lpSETSEGBASEADDR=define_asm_proc(
ENTER_PROC(0)&{
#66,#8B,#5D,#08, -- mov bx word ptr [ebp+8]
#66,#8B,#55,#0C, -- mov dx word ptr [ebp+12]
#8B,#4D,#0C, -- mov ecx [ebp+12]
#C1,#E9,#10, -- shr ecx, 16
#B8,#07,#00,#00,#00, -- mov eax, #0007
#CD,#31 -- int #31
}&LEAVE_PROC(0),
{WORD, DWORD}, 4)
constant
--
lpGETSEGBASEADDR=define_asm_func(
ENTER_PROC(0)&{
#66,#8B,#5D,#08, -- mov bx word ptr [ebp+8]
#B8,#06,#00,#00,#00, -- mov eax, #0006
#CD,#31, -- int #31
#73,#04, -- jnc @F
#31,#C0, -- xor eax, eax
#EB,#08, -- jmp leave
-- @@:
#C1,#E1,#10, -- shl ecx, 16
#66,#89,#D1, -- mov cx, dx
#89,#C8 -- mov eax, ecx
-- leave:
}&LEAVE_PROC(0),
{WORD}, DWORD, 4)
constant
--
lpSETSEGLIMIT=define_asm_proc(
ENTER_PROC(0)&{
#66,#8B,#5D,#08, -- mov bx word ptr [ebp+8]
#66,#8B,#55,#0C, -- mov dx word ptr [ebp+12]
#8B,#4D,#0C, -- mov ecx [ebp+12]
#C1,#E9,#10, -- shr ecx, 16
#B8,#08,#00,#00,#00, -- mov eax, #0008
#CD,#31 -- int #31
}&LEAVE_PROC(0),
{WORD, DWORD}, 4)
constant
--
SETDESCACCESS=define_asm_proc(
ENTER_PROC(0)&{
#66,#8B,#5D,#08, -- mov bx word ptr [ebp+8]
#8A,#6D,#0C, -- mov ch byte ptr [ebp+12]
#8A,#4D,#10, -- mov cl byte ptr [ebp+16]
#B8,#09,#00,#00,#00, -- mov eax, #0009
#CD,#31 -- int #31
}&LEAVE_PROC(0),
{WORD, BYTE, BYTE}, 4)
constant
--
lpMAPPHYSMEMORY=define_asm_func(
ENTER_PROC(0)&{
#8B,#5D,#08, -- mov ebx, [ebp+8]
#8B,#75,#10, -- mov esi, [ebp+16]
#66,#8B,#4D,#08, -- mov cx, word ptr [ebp+8]
#66,#8B,#7D,#10, -- mov di, word ptr [ebp+16]
#C1,#EB,#10, -- shr ebx, 16
#C1,#EE,#10, -- shr esi, 16
#B8,#00,#08,#00,#00, -- mov eax #0800
#CD,#31, -- int #31
#73,#04, -- jnc @F
#31,#C0, -- xor eax, eax
#EB,#08, -- jmp leave
-- @@:
#C1,#E3,#10, -- shl ebx, 16
#66,#89,#CB, -- mov bx, cx
#89,#D8 -- mov eax, ebx
-- leave:
}&LEAVE_PROC(0),
{DWORD, DWORD}, WORD, 4)
constant
--
lpFREEPHYSMEMORY=define_asm_proc(
ENTER_PROC(0)&{
#8B,#5D,#08, -- mov ebx, [ebp+8]
#66,#8B,#4D,#08, -- mov cx, word ptr [ebp+8]
#C1,#EB,#10, -- shr ebx, 16
#B8,#01,#08,#00,#00, -- mov eax #0801
#CD,#31 -- int #31
}&LEAVE_PROC(0),
{WORD}, 4)
global
function
--
Map_Linear_Framebuffer(dword phys, word maxx, word maxy, byte bytepp)
dword size word desc
desc=-1
size=maxx*maxy*bytepp
phys=c_func(lpMAPPHYSMEMORY, {phys, size})
if phys then
desc=c_func(lpALLOCLTDDESC,{1})
if desc then
-- ToDo: Theese should be functions, If SETSEGBASEADDR or SETSEGLIMIT fails then
we should
-- free the useless descriptor and unmap the physical address and resort to bank
switching.
c_proc(lpSETSEGBASEADDR, {desc, phys})
c_proc(lpSETSEGLIMIT, {desc, size-1})
else c_proc(lpFREEPHYSMEMORY, {phys})
end if
end if
return desc -- the selector to linear buffer.
end function
global
procedure
--
Unmap_Linear_Framebuffer(word sel)
atom addr
addr=c_func(lpGETSEGBASEADDR, {sel})
c_proc(lpFREEPHYSMEMORY, {addr})
c_proc(lpFREELTDDESC, {sel})
end procedure