1. New Niel2.e
- Posted by Hayden McKay <hmck1 at dodo.com.au> Feb 05, 2005
- 447 views
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