Author Topic: Learning from examples of O2 and expanding them  (Read 2261 times)

0 Members and 1 Guest are viewing this topic.

Arnold

  • Hero Member
  • *****
  • Posts: 977
Learning from examples of O2 and expanding them
« on: October 28, 2019, 07:36:51 am »
Hello,

in my opinion there are many interesting examples provided with Oxygenbasic which can be used to learn more about the WinApi. For instance, \WinGui\GraphWin.o2bas is a nice sample for this purpose. These are my modifications:

instead of function WinMain() I applied MainWindow() (of winutil.inc)
filled the shapes with color
Space bar can be used to change the size of the Red Square
Left Mouse Button can be used to move the Red Square
Arrow keys can be used to move the Blue Ball (these routines are already provided)
added a Green Ball which happily moves across the window

For me this little demo was very instructive and the routines can probably be applied in more extended apps too.

Roland

This is GraphWin2.o2bas
Code: OxygenBasic
  1. 'Derived from examples\WinGui\GraphWin.o2bas
  2.  
  3. $ filename "GraphWin2.exe"
  4. 'uses rtl32
  5. 'uses rtl64
  6.  
  7. uses winutil
  8.  
  9. % GCLP_HBRBACKGROUND = -10
  10. % COLOR_3DSHADOW=16
  11. % MK_LBUTTON = 1
  12.  
  13. #lookahead ' for procedures
  14.  
  15. 'GLOBAL DEFINITIONS
  16.  
  17. % ID_Timer1  3000
  18. % ID_Timer2  3001
  19.  
  20. sys hdc
  21.  
  22. int r =15, idx =5, idy=5, xball=200, yball=100 'Blue ball
  23. int ix=0 'Green ball interval move
  24. int sLen=50
  25. int sL=50, sT=200
  26. RECT square = {sL, sT, sL+sLen, sT+sLen} 'Red square
  27.  
  28. sys brush_blue = CreateSolidBrush BLUE
  29. sys brush_green = CreateSolidBrush GREEN
  30. sys brush_red = CreateSolidBrush RED
  31.  
  32. dim as RECT crect 'for WndProc and TimerProc
  33.  
  34. string crlf = chr(13,10)
  35.  
  36. -------------------------------------------------------------
  37. MainWindow(800,600, WS_OVERLAPPEDWINDOW)
  38. -------------------------------------------------------------
  39.  
  40. function WndProc (sys hWnd, uint uMsg, sys wParam, lParam) as sys callback
  41.     static as sys count=0, hdc, htimer1, htimer2
  42.     static as String txt
  43.     static as PaintStruct Paintst
  44.     POINT pt
  45.     static bool mayDrag
  46.    
  47.  
  48.     select uMsg
  49.  
  50.     case WM_CREATE
  51.         SetWindowText(hwnd, "OxygenBasic Demo - F1 for Help")
  52.         'Adjust color of MainWindow
  53.        SetClassLongPtr(hwnd,GCLP_HBRBACKGROUND, GetSysColorBrush(COLOR_3DSHADOW))
  54.  
  55.         htimer1 = SetTimer (hWnd, ID_Timer1, 50, &TimerProc)
  56.         htimer2 = SetTimer (hWnd, ID_Timer2, 10, &TimerProc)
  57.         GetClientRect  hWnd,&cRect
  58.  
  59.     case WM_LBUTTONDOWN
  60.         ' Check if square is in the client area.
  61.        GetClientRect(hwnd, &crect)
  62.         pt.x = LOWORD(lParam)
  63.         pt.y = HIWORD(lParam)
  64.  
  65.         if pt.x >= square.left and pt.x <= square.right and
  66.            pt.y >= square.top  and pt.y <= crect.bottom then          
  67.              mayDrag = true              
  68.              SetCapture(hWnd)
  69.         end if
  70.  
  71.      case WM_MOUSEMOVE
  72.         if mayDrag and (MK_LBUTTON & wParam) then
  73.            'Move Red square        
  74.           square.left = LOWORD(lParam)
  75.            square.top  = HIWORD(lParam)
  76.            square.right = square.left + sLen
  77.            square.bottom = square.top + sLen
  78.            Rectangle hdc, square.left, square.top, square.right, square.bottom  
  79.         end if
  80.  
  81.     case WM_LBUTTONUP
  82.         ReleaseCapture()
  83.         mayDrag = false
  84.            
  85.     case WM_PAINT
  86.         'TEXT
  87.        'http://msdn.microsoft.com/en-us/library/dd144821(v=VS.85).aspx
  88.  
  89.         'DRAWING AND PAINTING
  90.        'http://msdn.microsoft.com/en-us/library/dd162760(v=VS.85).aspx
  91.  
  92.         hDC=BeginPaint hWnd,&Paintst
  93.         GetClientRect  hWnd,&cRect
  94.         'style
  95.        '0x20 DT_SINGLELINE
  96.        '0x04 DT_VCENTER
  97.        '0x01 DT_CENTER
  98.        '0x25
  99.  
  100.         SetBkColor   hdc,yellow
  101.         SetTextColor hdc,red
  102.         txt="Blue Ball - x y pos: " str(xball) " , " str(yball)
  103.         DrawText hDC, txt,-1, &cRect, 0x25
  104.         SelectObject(hDC, brush_blue);
  105.         Ellipse hdc, xball-r, yball-r, xball+r, yball+r      'Blue ball
  106.        SelectObject(hDC, brush_green)
  107.         Ellipse hdc, ix, 300, ix+50, 350  'Green Ball
  108.        SelectObject(hDC, brush_red)        
  109.         Rectangle hdc, square.left, square.top, square.right, square.bottom  'Red square
  110.  
  111.         EndPaint hWnd,&Paintst
  112.         ValidateRect hwnd,&crect
  113.  
  114.     case WM_KEYDOWN
  115.         select wParam
  116.  
  117.         case VK_LEFT   : xball -= idx   'LEFT
  118.        case VK_RIGHT  : xball += idx   'RIGHT
  119.        case VK_UP     : yball -= idy   'UP
  120.        case VK_DOWN   : yball += idy   'DOWN
  121.        case VK_SPACE  : sLen += 10 : square.right += 10 : square.bottom += 10   'SPACE
  122.                         if square.right = square.left + 200 then
  123.                            sLen = 50
  124.                            square.right = square.left + sLen
  125.                            square.bottom = square.top + sLen
  126.                          end if  
  127.         case VK_ESCAPE : SendMessage hwnd, WM_CLOSE, 0, 0           'ESCAPE
  128.        case VK_F1 : mbox "Arrow Keys to move Blue Ball" + crlf +
  129.                           "Space bar to change size of Red Square" + crlf +
  130.                           "Press Left MouseButton to move Red Square" + crlf +
  131.                           "Escape to quit"
  132.                  
  133.         end select
  134.  
  135.         'InvalidateRect hwnd, &cRect, 1 'FULL SCREEN REFRESH
  136.  
  137.     case WM_CLOSE
  138.         SendMessage(hWnd, WM_DESTROY, 0,0)
  139.                
  140.     case WM_DESTROY
  141.         KillTimer(hWnd,ID_Timer1)
  142.         KillTimer(hWnd,ID_Timer2)
  143.         DeleteObject(brush_blue)
  144.         DeleteObject(brush_green)
  145.         DeleteObject(brush_red)
  146.         PostQuitMessage 0
  147.  
  148.     case else
  149.         function=DefWindowProc hWnd,uMsg,wParam,lParam
  150.  
  151.     end select
  152. end function ' WndProc
  153.  
  154.  
  155. function TimerProc(sys hWnd, uint uMsg, nIDEvent, dword dwTime) as sys callback
  156.     static sys d=1
  157.  
  158.     select uMsg
  159.  
  160.     case WM_TIMER
  161.         if nIDEvent=ID_Timer1 then        'Blue ball
  162.            InvalidateRect hwnd,&crect,1
  163.             if r=100 then d=-1
  164.             if r=10 then d=1
  165.             r+=d
  166.         end if
  167.         if nIDEvent=ID_Timer2 then        'Green ball
  168.            ix+=2
  169.             if ix>crect.right then ix=-100
  170.         end if
  171.        
  172.         function = 0        
  173.     end select
  174. end function ' TimerProc
  175.  

Arnold

  • Hero Member
  • *****
  • Posts: 977
Re: Learning from examples of O2 and expanding them
« Reply #1 on: October 31, 2019, 04:11:06 am »
This is a nice game which should be understandable after exploring the code of GraphWin2.o2bas above and HelloWin.o2bas:
https://www.oxygenbasic.org/forum/index.php?topic=1974.msg21098#msg21098

The logic and design of this Breakout Clone is taken from vazbreak.cpp by Phil Vaz:
http://www.vazgames.com/retro/

The exe file and complete code can be found at Bitbucket. I applied this code for several reasons:

- the C-code is very well structured and very well documented
- it is easy to compare the code with the OxygenBasic code and see the differences
- this is a nice way to learn about C and about OxygenBasic
- the logic of the game is complete. I could not do it better.

These are the differences compared with the original:
- instead of using WinMain the game loop is built on MainWindow of \inc\winutil.inc
- VazBreak runs in FullScreen. OxyBricks aims to run in a normal Window with fixed size
- The keys are checked in WndProc, ommiting the GetAsyncKeyState function which is problematic anyway.
- The app is started with pressing: 1 - using Mouse (pressing a MouseButton is not necessary)
-    or pressing: 2 - using the arrow keys to move the paddle
- I also added F1 option for Help

There are two minor issues, where I hope to find a solutions some day: Minimize and Restore (disabled) does not work correctly. Moving the window off the screen and back does also not work quite correctly.

The game itself runs very well in 32-bit and 64-bit mode. Maybe the path for using sound must be corrected:

Code: [Select]
...
'Perhaps must be adapted
string o2dir = "d:\Oxygenbasic\"
string sound_dir = "c:/windows/media/"

string SOUND_HIT1   = "hit1.wav"
string SOUND_HIT2   = "hit2.wav"
string SOUND_HIT3   = "hit3.wav"
string SOUND_MISS   = o2dir +"projectsB\SDL\bmp\shoot.wav"  ' "miss.wav"
string SOUND_PADDLE = sound_dir + "chord.wav"               ' "paddle.wav"
string SOUND_SERVE  = o2dir +"projectsB\SDL\bmp\explo.wav"  ' "serve.wav"
string SOUND_SIDE   = sound_dir + "chimes.wav"              ' "side.wav"
string SOUND_TOP    = sound_dir + "chimes.wav"              ' "top.wav"
...

I only used three wav files of the original, if wished the remaining wav files can be found in the BitBucket repo. BTW: there are a lot more interesting apps and info provided at vazgames.com which would be worth to apply in O2 or get ideas for new projects.

Attached is the code of OxyBricks as a zip file.

This is probably my last major project this year. Other duties will have priority. But hopefully the project will once again show other Oxygenbasic students that many applications are possible with this language.

Roland
« Last Edit: October 31, 2019, 07:49:53 am by Arnold »

Aurel

  • Guest
Re: Learning from examples of O2 and expanding them
« Reply #2 on: October 31, 2019, 10:44:12 am »
Very well Roland / Arnold  :D
and what about Vaz-asteroids ?  or
Move and Rotate small ship (GDI)...yes it is in cpp
but logic of game should be same ?

Aurel

Arnold

  • Hero Member
  • *****
  • Posts: 977
Re: Learning from examples of O2 and expanding them
« Reply #3 on: November 01, 2019, 03:07:30 am »
Hi Zlatko,

probably many of the games could be ported to O2 in some way. Personally I was especially interested in this article:

Intro to Game Programming:
http://www.vazgames.com/retro/IntroGameProg.htm

For me as a hobbyist, the text and the examples are very instructive. My attempt at the moment is to create a general game loop template in O2 using the function WinMain or MainWindow, similar to GameLoop1.cpp and GameFullScreen.cpp (can be downloaded from: Demos / Source - C/C++ Win32 Game Loop at vazgames/retro). In OxyBricks I almost managed to adapt the logic loop for a normal sized window, but I think it is not yet complete. Charles has already implemented many of the essential routines in WinUtil.inc, OpenglSceneFrame.inc, GraphUtil.inc and other include files; the goal will be to use these files in a project.

Roland

Aurel

  • Guest
Re: Learning from examples of O2 and expanding them
« Reply #4 on: November 01, 2019, 05:57:56 am »
Quote
the goal will be to use these files in a project
yeah that would be good , most of them are too general ,i am not interested in GL  and i prefer
only GDI, direct X is somehow abandoned from o2 even is main part of any popular windows games.

Arnold

  • Hero Member
  • *****
  • Posts: 977
Re: Learning from examples of O2 and expanding them
« Reply #5 on: March 03, 2020, 07:50:20 am »
Hello,

this is another nice demo derived from other examples. I used it to look for some issues, especially memory leaks.

The app creates drawings that can be adapted to your own patterns, e.g. samples for wallpaper, T-shirts, wrapping paper etc. or for a kind of Rorschach test. Each drawing is unique and will never come back. Some drawings are really interesting. I have only used one of the many GDI functions provided. I assume that something like a Mondrian or Picasso style would be possible with a little more effort and a little more functions.

Roland

tinyart.o2bas
Code: [Select]
$ filename "TinyArt.exe"
'uses rtl32
'uses rtl64

uses dialogs

indexbase 0

% PS_NULL 5
'% ALTERNATE 1
'% WINDING 2

macro RGB(r,g,b) {r+(g<<8)+(b<<16)}

function rand(int max) as int
   uint number
   int err = rand_s(&number) : : if err != 0 then mbox "rand_s function failed"
   return mod(number, max+1)
end function

% IDM_EXIT 1120

enum idm_colors(IDM_WHITE=1141, IDM_BLACK, IDM_BLUE, IDM_RED, IDM_GREEN, IDM_YELLOW,
IDM_MAGENTA, IDM_CYAN, IDM_GRAY)
def CSB CreateSolidBrush
sys bk_colors = {CSB WHITE, CSB BLACK, CSB BLUE, CSB RED, CSB GREEN, CSB YELLOW,
                 CSB MAGENTA, CSB CYAN, CSB LTGRAY}

enum idm_polygons(IDM_POLY1=1161, IDM_POLY2, IDM_POLY3, IDM_POLY4, IDM_POLY5)

% IDM_PLAY  1200
% IDM_HELP  1260
% IDM_ABOUT 1270
% ID_TIMER  3000

sys hMenu
sys hAccel

int maxPolygons=3
int toggle_play

int vMin=4, vMax=20  'vertices
POINT points[24], points1[24], points2[24], points3[24], points4[24]

declare sub initMenu(sys hDlg)
declare sub drawPattern(sys hDlg, int max)
declare sub showHelp()

string cr=chr(13,10)

==============================================
'MAIN CODE
=============================================
 
function DlgProc(sys hDlg, uint uMsg, sys wParam, lParam) as int callback

   static PAINTSTRUCT ps
   static sys hDlgBrush
   int x
   
   select case uMsg
 
     case WM_INITDIALOG
        initMenu(hDlg)

        //initialize the background brush
        hDlgBrush = bk_colors[0] 'WHITE       
        ShowWindow(hDlg, SW_NORMAL)

     case WM_COMMAND
     
        select case loword(wParam)
           case IDCANCEL, IDM_EXIT
              SendMessage(hDlg, WM_CLOSE, 0, 0)
           case IDM_WHITE to IDM_GRAY       
              for x = IDM_WHITE to IDM_GRAY 
                 if x = loword(wParam) then
                    CheckMenuItem(hMenu, x, MF_BYCOMMAND or MF_CHECKED)
                       int idx = x-IDM_WHITE
                       hDlgBrush = bk_colors[idx]                                               
                 else
                    CheckMenuItem(hMenu, x, MF_BYCOMMAND or MF_UNCHECKED)
                 end if
              next x
           case IDM_POLY1 to IDM_POLY5
              for x = IDM_POLY1 to IDM_POLY5
                 if x = loword(wParam) then
                    CheckMenuItem(hMenu, x, MF_CHECKED)
                    maxPolygons = x-IDM_POLY1 + 1
                 else
                    CheckMenuItem(hMenu, x, MF_UNCHECKED)
                 end if     
              next x

           case IDM_PLAY
              toggle_play = not toggle_play             
              if toggle_play then
                 ModifyMenu(hMenu, IDM_PLAY, MF_BYCOMMAND, IDM_PLAY, "Stop Tour!")
                 SetTimer(hDlg, ID_TIMER, 1000, NULL)
              else
                 ModifyMenu(hMenu, IDM_PLAY, MF_BYCOMMAND, IDM_PLAY, "Start Tour!")
                 KillTimer(hDlg, ID_TIMER)
              end if
              DrawMenuBar(hDlg)       

           case IDM_HELP
              showHelp()
           case IDM_ABOUT
              mbox "Simple Graphics Demo" + cr + "using OxygenBasic"                       
        end select
       
     case WM_LBUTTONDOWN
        InvalidateRect(hDlg, 0, true)
         
     case WM_SIZE
        InvalidateRect(hDlg, 0, true)
         
     case WM_TIMER
        InvalidateRect(hDlg, 0, true)
       
     case WM_KEYUP
        if wParam = 13 then  ' Enter
           InvalidateRect(hDlg, 0, true)
        end if   
                               
     case WM_CTLCOLORDLG     
        return hDlgBrush
                               
     case WM_PAINT             
        BeginPaint(hDlg, &ps)
        InvalidateRect(hDlg,Null, true)
        EndPaint(hDlg, &ps)
        drawPattern(hDlg, maxPolygons)
                                                                 
     case WM_CLOSE
        KillTimer(hDlg, ID_TIMER)
        for x = IDM_WHITE to IDM_GRAY
           int ix = x-IDM_WHITE
           if DeleteObject(bk_colors[ix]) = 0 then
             mbox "Cannot DeleteObject bk_color[" ix "]"
           end if
        next x             
        DestroyWindow(hDlg)

     case WM_DESTROY
        int idx
        DestroyAcceleratorTable(hAccel)
        PostQuitMessage(null)
               
   end select

   return 0
end function


sub winmain()
   sys hDlg, bRet
   MSG Msg

   Dialog( 0, 0, 300, 240, "My little Art Gallery",
           WS_OVERLAPPEDWINDOW or DS_CENTER )

   hDlg = CreateModelessDialog( null, @DlgProc, 0)

   while bRet := GetMessage(&Msg, NULL, 0, 0)
     if bRet = -1 then
       'show an error message
       mbox "Error in Message Loop"
       end
     else
       if TranslateAccelerator( hDlg, hAccel, @Msg ) = 0 then     
         if not IsDialogMessage(hDlg, &Msg) then
           TranslateMessage(&Msg)
           DispatchMessage(&Msg)
         end if
       end if
     end if
   wend

end sub

winmain()

========================================================

sub initMenu(sys hDlg)
   indexbase 1
   MENU(hMenu)

   BEGIN
     POPUP "&File"
     BEGIN
       MENUITEM "E&xit" tab "Alt+F4", IDM_EXIT
     ENDMenu
     POPUP "&Options"
     BEGIN
         POPUP "BackGround Color"
         BEGIN
           MENUITEM "White", IDM_WHITE, CHECKED
           MENUITEM "Black", IDM_BLACK
           MENUITEM "Blue", IDM_BLUE
           MENUITEM "Red", IDM_RED
           MENUITEM "Green", IDM_GREEN
           MENUITEM "Yellow", IDM_YELLOW
           MENUITEM "Magenta", IDM_MAGENTA
           MENUITEM "Cyan", IDM_CYAN
           MENUITEM "Gray", IDM_GRAY
         ENDMenu
         POPUP "Number of Polygons"
         BEGIN
           MENUITEM "1 polygon",  IDM_POLY1
           MENUITEM "2 polygons", IDM_POLY2
           MENUITEM "3 polygons", IDM_POLY3, CHECKED
           MENUITEM "4 polygons", IDM_POLY4
           MENUITEM "5 polygons", IDM_POLY5
         ENDMenu
     ENDMenu
     POPUP "&Help"
     BEGIN
       MENUITEM "Instructions" tab "F1", IDM_HELP
       MENUITEM "SEPARATOR"
       MENUITEM "Ab&out",IDM_ABOUT
     ENDMenu
     MENUITEM "&Start Tour!", IDM_PLAY
   ENDMenu

   if SetMenu(hDlg, hMenu) = 0 then
     mbox "SetMenu hMenu failed!"
   end if
   
   'Accelerators
   indexbase 0
   ACCEL accl[1] = {
   {FVIRTKEY, asc("S"), IDM_PLAY},
   {FVIRTKEY, VK_F1,    IDM_HELP}                 
   }
   hAccel = CreateAcceleratorTable(@accl, 2)
end sub

sub makePolygon(sys hDlg, int m)   
   static sys brush_color, hPen, hDC
   RECT pRect
   int i
   
   int c = rand(vMax) + vMin
   
   GetClientRect(hDlg, &pRect)
   int h = pRect.bottom
   int w = pRect.right
   if m then h \= 2 : w \= 2

   c--     
   for i = 0 to c
      if m then
        points1[i].x = rand(w) : points2[i].x = points1[i].x + w : points3[i].x = points1[i].x + w : points4[i].x = points1[i].x
        points1[i].y = rand(h) : points2[i].y = points1[i].y + h : points3[i].y = points1[i].y     : points4[i].y = points1[i].y + h   
      else
        points[i].x = rand(w)
        points[i].y = rand(h)
      end if   
   next   

   brush_color=CreateSolidBrush(RGB(rand(255), rand(255), rand(255)))   
   hPen = CreatePen(PS_NULL,0,0)  'invisible
   
   hDC = GetDC(hDlg)
 
   SelectObject(hDC, brush_color)
   SelectObject(hDC,hPen)

   if m then
     SetPolyFillMode (hDC, rand(1)+1)  'ALTERNATE, WINDING
     Polygon(hDC, points1[],c)
     SetPolyFillMode (hDC, rand(1)+1)
     Polygon(hDC, points2[],c)
     SetPolyFillMode (hDC, rand(1)+1)
     Polygon(hDC, points3[],c)
     SetPolyFillMode (hDC, rand(1)+1)
     Polygon(hDC, points4[],c)
   else     
     SetPolyFillMode (hDC, rand(1)+1)  'ALTERNATE, WINDING
     Polygon(hDC, points[],c)
   end if 
   
   if ReleaseDC(hDlg, hDC) = 0 then mbox "Cannot ReleaseDC hDC"
   if DeleteObject(brush_color) = 0 then mbox "Cannot DeleteObject brush_color"
   if DeleteObject(hPen) = 0 then mbox "Cannot DeleteObject hPen"
end sub

sub drawPattern(sys hDlg, int max)
   int x
   int multiple = rand(1)

   for x = 1 to max
      makePolygon(hDlg, multiple)
   next
   ValidateRect(hDlg, NULL)
end sub

sub showHelp()
string s = quote """
Options for navigating:
=======================

File
    Exit, Alt-F4 or Escape key: ends the program

Options
    Background Color: change background color for next drawing

    Number of Polygons: 1 to 5 polygons can be selected
   
Start/Stop Tour! or "S" key:
    Creates continuous new drawings
   
Clicking with Left Mouse Button or pressing Enter:
    Creates a new drawing
   
Resizing Window:
    Creates new drawing.                   
"""
mbox s
end sub

Arnold

  • Hero Member
  • *****
  • Posts: 977
Re: Learning from examples of O2 and expanding them
« Reply #6 on: May 02, 2020, 04:56:18 pm »
By chance I found this nice website with some competing masterpieces:
https://pigcasso.myshopify.com/collections/all

This is the artist with sponsor:
http://pigcasso.org/about.html

Some ideas are really creative and they do no harm.