Oxygen Basic
		Programming => Problems & Solutions => Topic started by: helloworld on June 19, 2017, 03:47:46 AM
		
			
			- 
				This is the function I am writing about:
 https://msdn.microsoft.com/en-us/library/windows/desktop/dd183494(v=vs.85).aspx
 
 I can set up the DIB and use GDI functions with it. But I cannot write to the bitmap bits directly - then the app crashes.
 It works in C++ and the problem seems to be the transliteration of the pointer to the pointer to the bits. In C++ it works this way:
 
 HBITMAP dibm;
 int* bits;
 dibm = CreateDIBSection(dc, (const BITMAPINFO*)&bitmapinfoheader, DIB_RGB_COLORS, (void**) &bits, NULL, 0);
 // then I can write at x,y:
 bits[y*SCANLINELEN+x]=RGB(r,g,b);
 
 Now the Oxygen Basic code. When I write to x,y, app crashes. When I use GDI on the DIB, it works:
 
 sys dibm;
 int* bits;
 dibm = CreateDIBSection(dc, @bitmapinfoheader, DIB_RGB_COLORS, @@bits, NULL, 0);
 ' when I write to x,y, app crashes:
 bits[y*SCANLINELEN+x]=RGB(r,g,b);
 
 Q: How to put the right value into the pointer variable?
 
 Also:
 When I import the BOOL GDIflush(void) function like so:
 extern lib "gdi32.dll"
 ! gdiflush() as sys
 end extern
 
 and when I use it, OB just prints out "gdiflush" and exits :D
 
 also $/examples/Asm64/HelloWorld64.o2bas does not build: linker finds "unidentified names", namely messagebox. [version=A43 12:29 22/05/2017]
 
 .
- 
				helloworld,
 
 
 ! GdiFlush() as sys 'requires precise capitalisation
 
 What prototype, if any,  are you using for CreateDIBSection?
 You could try byval @@bits
 
 I see the HelloWorld64 problem and will try to rectify soonest.
- 
				What prototype, if any,  are you using for CreateDIBSection?
 You could try byval @@bits
 
 None. Anyway the compiler requires #long#long#long#long#long#long. Byval (in the call I assume) does not work.
 And thanks, GdiFlush works now.
 
- 
				helloworld
 
 do you can post whole example that we can see what is what
 also bitmap DIB require that you must know what kind of bitmap is
 4,8,16,32 ..right?  ..or not ?
- 
				You can check whether the function has returned a valid bits pointer:
 print @bits
- 
				Are you using indexbase 0 ?
 The default is indexbase 1, which would corrupt the preceding variable space when attempting to write to bits[0].
- 
				Are you using indexbase 0 ?
 The default is indexbase 1, which would corrupt the preceding variable space when attempting to write to bits[0].
 
 That has been it! Thank you.
 
 @Aurel
 Here the (working) code for reference:
 includepath "$/inc/"
 indexbase 0
 
 #include "MinWin.inc"
 
 #define SRCCOPY		0xCC0020
 #define BLACKNESS	0x42
 #define WHITENESS	0xFF0062
 #define SCANLEN		1280
 
 type BITMAPINFOHEADER
 DWORD biSize
 LONG  biWidth
 LONG  biHeight
 WORD  biPlanes
 WORD  biBitCount
 DWORD biCompression
 DWORD biSizeImage
 LONG  biXPelsPerMeter
 LONG  biYPelsPerMeter
 DWORD biClrUsed
 DWORD biClrImportant
 end type
 
 dim bmih as BITMAPINFOHEADER, dc0 as sys, dc1 as sys, bits as integer ptr
 
 extern lib "Gdi32.dll"
 ! CreateDIBSection
 ! GdiFlush
 end extern
 
 #lookahead ' for procedures
 s=error() : if s then: print s : end : end if
 
 dim cmdline as asciiz ptr, inst as sys
 &cmdline=GetCommandLine
 inst=GetModuleHandle 0
 
 WinMain inst,0,cmdline,SW_NORMAL
 end
 
 Function WinMain(sys inst, prevInst, asciiz*cmdline, sys show) as sys
 
 WndClass wc
 MSG      wm
 
 sys hwnd, wwd, wht, wtx, wty, tax
 
 wc.style = CS_HREDRAW or CS_VREDRAW
 wc.lpfnWndProc = @WndProc
 wc.cbClsExtra =0
 wc.cbWndExtra =0
 wc.hInstance =inst
 wc.hIcon=LoadIcon 0, IDI_APPLICATION
 wc.hCursor=LoadCursor 0,IDC_ARROW
 wc.hbrBackground = GetStockObject WHITE_BRUSH
 wc.lpszMenuName = null
 wc.lpszClassName = strptr "dib"
 
 RegisterClass (@wc)
 
 Wwd = 640 : Wht = 400
 Tax = GetSystemMetrics SM_CXSCREEN
 Wtx = (Tax - Wwd) /2
 Tax = GetSystemMetrics SM_CYSCREEN
 Wty = (Tax - Wht) /2
 hwnd = CreateWindowEx 0,wc.lpszClassName,"dib",WS_OVERLAPPEDWINDOW,Wtx,Wty,Wwd,Wht,0,0,inst,0
 
 ShowWindow hwnd,SW_SHOW
 UpdateWindow hwnd
 
 sys ret
 do while ret := GetMessage &wm, 0, 0, 0
 if ret = -1 then
 'show an error message
 else
 TranslateMessage &wm
 DispatchMessage &wm
 end if
 wend
 End Function
 
 function WndProc (hWnd, wMsg, wParam, lparam) as sys callback
 select wmsg
 case WM_CREATE
 dc0=GetDC(NULL)
 dc1=CreateCompatibleDC(dc0)
 bmih = {sizeof(BITMAPINFOHEADER), 1280, -1024, 1, 32, 0, 0, 0, 0, 0, 0}
 dibm=CreateDIBSection(dc1, @bmih, 0, @@bits, NULL, 0)
 if dc0==NULL or dc1==NULL or dibm==NULL then DestroyWindow(hwnd)
 SelectObject(dc1,dibm)
 ReleaseDC(hwnd,dc0)
 
 case WM_DESTROY
 deleteobject(dibm)
 deleteobject(dc1)
 PostQuitMessage 0
 
 case WM_PAINT
 paint hwnd,dc1
 
 case WM_KEYDOWN
 keydown hwnd,wparam,lparam
 
 case else
 function=DefWindowProc hWnd,wMsg,wParam,lParam
 end select
 end function
 
 function paint(hwnd,dc1)
 rect rc
 paintstruct ps
 
 getclientrect hwnd,&rc
 dc=beginpaint hwnd,&ps
 BitBlt dc1, 0,0, 640,400, NULL, 0, 0, WHITENESS
 gdiflush
 
 fillr(bits, 10,10,100,100,0xFF0000)
 
 /*
 for i=0 to 1280*10-1
 bits[i]=0xFF
 next
 */
 
 BitBlt(dc, 0,0, rc.right-rc.left,rc.bottom-rc.top, dc1, 0, 0, SRCCOPY)
 endpaint hwnd,&ps
 end function
 
 function keydown(hwnd,wparam,lparam)
 if wparam==0x1B 'escape
 sendmessage hwnd,WM_CLOSE,0,0
 end if
 end function
 
 function fillr(bm as integer ptr, x as dword,y as dword,w as dword,h as dword,col as dword)
 int* bits=@bm
 pitch=(SCANLEN-w)*4
 @bits+=(y*SCANLEN+x)*4
 for i=0 to <h
 for j=0 to <w
 bits=col : @bits+=4
 next
 @bits+=pitch
 next
 end function
 
- 
				OB does not do even minimal optimisation. So I wonder how to use the assembler? Fragment below does not work.
 Btw, Oxide has severe issues:
 It may "eat" characters: it may do stuff like open the "save" dialogue, start code etc, when coding and typing i.e. "s" or "e".
 Do you really use it for coding?
 
 function fillr(bm as integer ptr, x as dword,y as dword,w as dword,h as dword,col as dword)
 
 int* bits
 int pitch
 
 /*
 @bits=@bm
 pitch=(SCANLEN-w)*4
 @bits+=(y*SCANLEN+x)*4
 for i=0 to <h
 for j=0 to <w
 bits=col
 @bits+=4
 next
 @bits+=pitch
 next
 */
 
 
 mov eax,bm				; @bits=@bm
 mov bits,eax
 
 mov ecx,1280				; pitch=(SCANLEN-w)*4
 sub ecx,w
 shl ecx,2
 mov pitch,ecx
 
 mov eax,1280				; @bits+=(y*SCANLEN+x)*4
 mul y
 add eax,x
 shl eax,2
 add bits,eax
 
 mov eax,col
 mov edx,bits
 ._for1					; for i=0 to <h
 dec h
 jz _exitfor1
 mov ecx,w
 ._for2				; for j=0 to <w
 dec ecx
 jz _exitfor2
 mov [edx],eax		; bits=col
 add edx,4		; @bits+=4
 jmp _for2
 ._exitfor2
 add edx,pitch			; @bits+=pitch
 jmp _for1
 ._exitfor1
 ._leave
 xor eax,eax
 
 end function
 
 
- 
				I use Oxide for most of my code testing without the 's' and 'e' problems you describe.
 
 But when the control key is held down, a second 's' or 'e' keypress will insert ascii 19 or ascii 5 into the text. Which is an occasional nuisance that needs to be fixed.
 
 
 re: assembler
 
 You can display the assembly code generated by any line of basic by inserting #show at the beginning of the line.
 
 Optimisation is a work in progress, but the gains from hand-written asm are usually small, and maintaining 32-bit and 64-bit compatibility can be tricky.
 
 To resolve the address of any variable, including pointered variables, use the pseudo-instruction addr
 
 addr eax,bm
 
 
- 
				
 HelloWorld64 fix:
 
 https://github.com/Charles-Pegge/OxygenBasic/blob/master/Oxygen.zip
 
 
 And the attached Oxide should be free of any ctrl-s and Ctrl-e problems:
 
 .
- 
				I use Oxide for most of my code testing without the 's' and 'e' problems you describe.
 
 The problem may have been due to keyboard layout..
 I.e., it arised when I type the open bracket "[" (to do so, on my keyboard I have to prefix "Alr Gr"-key a.k.a. the right-side "Alt"-key) followed by i.e. "e" (->execute) or "s" (->save).
 
 And now is fixed. :)
 
 Other issues:
 -The -a option to co2.exe is quite useless, because the listing is normally longer than the display height. Output shoud happen to file instead.
 
 -It seems that it is not possible to transfer pointers via asm (!): there is no equivalent to @pointer1=@pointer2 witout knowing the stack position of the pointers?
 
 
- 
				Glad it worked for you :)
 
 
 re co2:
 
 You can output asm to text file:
 
 co2 -a -m prog.o2bas > t.txt
 
 re: transferring pointers in asm:
 
 One crude solution is to embed the basic line into your asm.
 
 push edi
 @pointer1 = @pointer2
 pop edi
 
 but what I need to do is support @:  addr eax,@pointer1
 then this will be possible:
 
 addr edx,@pointer1
 addr eax,pointer2
 mov [ecx],eax
 
 Another solution is to go C :o
 I have not tested this in depth yet, but it certainly works for simple expressions.
 
 #cpointer on
 'pointer1=pointer2
 mov eax,pointer2
 mov pointer1,eax
 #cpointer off
 
 
 
- 
				You can output asm to text file:
 co2 -a -m prog.o2bas > t.txt
 
 
 My bad. I tried the pipe, but missed out the -m option :D
 
 re: transferring pointers in asm:
 
 
 I found this works:
 
 dim p1 as integer ptr 
 dim p2 as integer ptr
 dim a as integer
 a=99
 @p1=@a
 (
 mov eax,@p1
 mov @p2,eax
 )
 print p2
 
 But this does not:
 
 dim as integer ptr p1 
 dim as integer ptr p2
 dim a as integer
 a=99
 @p1=@a
 (
 mov eax,@p1
 mov @p2,eax
 )
 print p2
 
 This also works:
 
 int* p1 
 int* p2
 int a
 a=99
 @p1=@a
 (
 mov eax,@p1
 mov @p2,eax
 )
 print p2