Author Topic: Simple demo of 3 different way to make graphic in QB64  (Read 3907 times)

0 Members and 1 Guest are viewing this topic.

This topic contains a post which is marked as Best Answer. Press here if you would like to see it.

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Simple demo of 3 different way to make graphic in QB64
« on: December 06, 2020, 03:25:07 pm »
Hi
thanks to Bplus for sharing his Tangram 1.
thanks to Galleon to leave QB64 to QB64 community
thanks to QB64 team developers to maintain QB64

here I post a simple demo that shows 3 different ways to do graphic using QB64.
If you find of interest here you can see an array with 3 dimensions.

Code: QB64: [Select]
  1.  
  2. SCREEN _NEWIMAGE(1280, 740, 32)
  3.  
  4. _TITLE "Tangram 1 by Bplus" 'b+ 2020-11-09 & 10
  5. _SCREENMOVE 70, 5 'sorry this works for my screen, yours is likely different
  6.  
  7. ' ============================= Instructions ==================================================
  8. '
  9. ' The little dot on the pieces are handles for dragging pieces or rotating them with mousewheel.
  10. ' Don't drag a handle near another or the pieces will stick together, press r if they do.
  11. '
  12. '=================================================================================================
  13.  
  14. CONST sqr2d2 = SQR(2) / 2 ' for converting lengths with 45/90 triangles.
  15.  
  16. CONST True = -1, False = 0, X = 1, Y = 2, Escape = 27, Space = 32, Rmax = 114, Rmin = 82
  17. CONST Normal = 1, MapTriangle = 2, Opengl = 3, White = _RGB32(255), Up = 18432, Down = 20480
  18.  
  19.  
  20. TYPE objType
  21.     cx AS SINGLE
  22.     cy AS SINGLE
  23.     lenBase AS SINGLE
  24.     rotDegrees AS SINGLE
  25.     colr AS _UNSIGNED LONG
  26.     typ AS LONG
  27.  
  28.  
  29. DIM SHARED GlInit AS INTEGER, GrActive AS INTEGER
  30. DIM SHARED VertObj(1 TO 7, 1 TO 2, 1 TO 5) AS SINGLE
  31. ' vo(number of object, cohordinate, value of vertex with 5  as center cohordinate) ' TdB
  32.  
  33. REDIM SHARED obj(1 TO 7) AS objType
  34. REDIM SHARED copy(1 TO 7) AS objType
  35.  
  36.  
  37.  
  38. Initialize
  39.  
  40. info
  41. message "Tangram 1 Normal mode: press space to change graphic", 0, 0
  42.  
  43.     CLS
  44.     Kb = _KEYHIT
  45.     IF Kb = Escape THEN TheEND
  46.     IF Kb = Space THEN
  47.         IF GrActive < Opengl THEN GrActive = GrActive + 1 ELSE GrActive = Normal ' TdB
  48.         IF GrActive = 1 THEN
  49.             mode = "Tangram 1 Normal mode: press space to change graphic"
  50.         ELSEIF GrActive = MapTriangle THEN
  51.             mode = "Tangram 1 MapTriangle mode: press space to change graphic"
  52.         ELSEIF GrActive = 3 THEN
  53.             mode = "Tangram 1 OpenGl mode: press space to change graphic"
  54.             GrActive = 5
  55.         END IF
  56.         '    infoscreen
  57.         CLS
  58.         message mode, 0, 0
  59.         _DISPLAY
  60.         _DELAY 2
  61.         IF GrActive = 5 THEN GrActive = 3
  62.     END IF
  63.     IF Kb = Rmax OR Kb = Rmin THEN 'reset or fix
  64.         FOR i = 1 TO 7
  65.             obj(i) = copy(i)
  66.         NEXT
  67.     END IF
  68.         mx = _MOUSEX: my = _MOUSEY: mb = _MOUSEBUTTON(1): mw = _MOUSEWHEEL
  69.         FOR i = 1 TO 7
  70.             IF _HYPOT(obj(i).cx - mx, obj(i).cy - my) < 20 THEN ' mouse is down near a piece center
  71.                 IF mb THEN obj(i).cx = mx: obj(i).cy = my
  72.                 IF mw THEN obj(i).rotDegrees = obj(i).rotDegrees + mw
  73.             END IF
  74.         NEXT
  75.     WEND
  76.  
  77.     FOR i = 1 TO 7
  78.         drawObj i
  79.     NEXT i
  80.  
  81.     _DISPLAY
  82.     _LIMIT 10 'peharps we must change this fps to 30
  83.  
  84. '-------------SUBs/Functions area-------------------
  85. SUB TheEND
  86.     DIM k AS STRING
  87.     CLS
  88.     message "Do you really quit? Y/N", 0, 0
  89.     _DISPLAY
  90.     WHILE k <> "Y" AND k <> "N": k = UCASE$(INKEY$): WEND
  91.     IF k = "Y" THEN END ELSE CLS
  92.  
  93. SUB info
  94.     message "TANGRAM 1   by Bplus", 0, 5
  95.     message " Usage: press r or R reset, press spacebar to change graphic mode", -1, 11
  96.     message "        use Left Mouse Button to drag and drop the pieces by circles", -1, 12
  97.     message "        use Mouse Wheel to rotate the pieces while mouse points to circles", -1, 13
  98.     message "Press a key to continue...", 0, 18
  99.     _DISPLAY
  100.     WHILE INKEY$ = "": WEND
  101.  
  102. SUB message (t AS STRING, Xt AS INTEGER, Yt AS INTEGER)
  103.     IF LEN(t) THEN
  104.         IF Xt = -1 THEN
  105.             Xt = 1
  106.         ELSEIF Xt = 0 THEN
  107.             Xt = INT(((_WIDTH / _FONTWIDTH(_FONT)) - LEN(t)) / 2)
  108.         ELSEIF Xt = -2 THEN
  109.             Xt = INT(_WIDTH / _FONTWIDTH(_FONT)) - LEN(t)
  110.         END IF
  111.         IF Yt = -1 THEN
  112.             Yt = 1
  113.         ELSEIF Yt = 0 THEN
  114.             Yt = INT((_HEIGHT / _FONTHEIGHT(_FONT)) / 2)
  115.         ELSEIF Yt = -2 THEN
  116.             Yt = INT(_HEIGHT / _FONTHEIGHT(_FONT))
  117.         END IF
  118.         LOCATE Yt, Xt
  119.         PRINT t;
  120.     END IF
  121.  
  122. SUB drawObj (i AS LONG)
  123.     SELECT CASE obj(i).typ
  124.         CASE 1 'tri45
  125.             tri45 i
  126.         CASE 2 ' square
  127.             square i
  128.         CASE 3 ' parallel
  129.             parallel i
  130.     END SELECT
  131.  
  132.     VertObj(i, X, 5) = obj(i).cx ' TdB
  133.     VertObj(i, Y, 5) = obj(i).cy ' TdB
  134.     CIRCLE (VertObj(i, X, 5), VertObj(i, Y, 5)), 2, &HFF000000 ' here it draws the little circle
  135.     CIRCLE (VertObj(i, X, 5), VertObj(i, Y, 5)), 3, &HFFFFFFFF ' so we can use _GL_POINTS
  136.  
  137.  
  138. SUB tri45 (i AS SINGLE)
  139.     DIM rotRad AS SINGLE, bx AS SINGLE, by AS SINGLE
  140.  
  141.     rotRad = _D2R(obj(i).rotDegrees)
  142.     bx = obj(i).cx + .25 * obj(i).lenBase * COS(_PI(.5) + rotRad)
  143.     by = obj(i).cy + .25 * obj(i).lenBase * SIN(_PI(.5) + rotRad)
  144.     VertObj(i, X, 1) = bx + .5 * obj(i).lenBase * COS(_PI + rotRad)
  145.     VertObj(i, Y, 1) = by + .5 * obj(i).lenBase * SIN(_PI + rotRad)
  146.     VertObj(i, X, 2) = bx + .5 * obj(i).lenBase * COS(rotRad)
  147.     VertObj(i, Y, 2) = by + .5 * obj(i).lenBase * SIN(rotRad)
  148.     VertObj(i, X, 3) = obj(i).cx + .25 * obj(i).lenBase * COS(_PI(1.5) + rotRad)
  149.     VertObj(i, Y, 3) = obj(i).cy + .25 * obj(i).lenBase * SIN(_PI(1.5) + rotRad)
  150.  
  151.     IF GrActive = 1 THEN
  152.         ntri VertObj(i, X, 1), VertObj(i, Y, 1), VertObj(i, X, 2), VertObj(i, Y, 2), VertObj(i, X, 3), VertObj(i, Y, 3), obj(i).colr ' here we must use _GL_TRIANGLES
  153.     ELSEIF GrActive = 2 THEN
  154.         ftri VertObj(i, X, 1), VertObj(i, Y, 1), VertObj(i, X, 2), VertObj(i, Y, 2), VertObj(i, X, 3), VertObj(i, Y, 3), obj(i).colr ' here we must use _GL_TRIANGLES
  155.     END IF
  156.  
  157. SUB square (i AS SINGLE) ' 1 square
  158.     DIM in AS INTEGER
  159.     DIM rotRad AS SINGLE
  160.     rotRad = _D2R(obj(i).rotDegrees)
  161.     FOR in = 1 TO 4
  162.         VertObj(i, X, in) = obj(i).cx + obj(i).lenBase * sqr2d2 * COS(_PI / 2 * in + rotRad)
  163.         VertObj(i, Y, in) = obj(i).cy + obj(i).lenBase * sqr2d2 * SIN(_PI / 2 * in + rotRad)
  164.     NEXT
  165.  
  166.     ftri VertObj(i, X, 1), VertObj(i, Y, 1), VertObj(i, X, 2), VertObj(i, Y, 2), VertObj(i, X, 3), VertObj(i, Y, 3), obj(i).colr ' here we must use _GL_QUADS
  167.     ftri VertObj(i, X, 3), VertObj(i, Y, 3), VertObj(i, X, 4), VertObj(i, Y, 4), VertObj(i, X, 1), VertObj(i, Y, 1), obj(i).colr
  168.  
  169. SUB parallel (i AS SINGLE)
  170.  
  171.     DIM rotRad AS SINGLE, arm AS SINGLE
  172.  
  173.     rotRad = _D2R(obj(i).rotDegrees)
  174.     arm = .5 * obj(i).lenBase * sqr2d2
  175.     VertObj(i, X, 1) = obj(i).cx + arm * COS(_PI(1.25) + rotRad)
  176.     VertObj(i, Y, 1) = obj(i).cy + arm * SIN(_PI(1.25) + rotRad)
  177.     VertObj(i, X, 2) = VertObj(i, X, 1) + obj(i).lenBase * COS(0 + rotRad)
  178.     VertObj(i, Y, 2) = VertObj(i, Y, 1) + obj(i).lenBase * SIN(0 + rotRad)
  179.     VertObj(i, X, 3) = obj(i).cx + arm * COS(_PI(.25) + rotRad)
  180.     VertObj(i, Y, 3) = obj(i).cy + arm * SIN(_PI(.25) + rotRad)
  181.     VertObj(i, X, 4) = VertObj(i, X, 3) + obj(i).lenBase * COS(_PI + rotRad)
  182.     VertObj(i, Y, 4) = VertObj(i, Y, 3) + obj(i).lenBase * SIN(_PI + rotRad)
  183.  
  184.     ftri VertObj(i, X, 1), VertObj(i, Y, 1), VertObj(i, X, 2), VertObj(i, Y, 2), VertObj(i, X, 3), VertObj(i, Y, 3), obj(i).colr 'here we must use _GL_QUADS
  185.     ftri VertObj(i, X, 3), VertObj(i, Y, 3), VertObj(i, X, 4), VertObj(i, Y, 4), VertObj(i, X, 1), VertObj(i, Y, 1), obj(i).colr
  186.  
  187. SUB ftri (x1, y1, x2, y2, x3, y3, K AS _UNSIGNED LONG)
  188.     DIM D AS LONG
  189.     STATIC a&
  190.     D = _DEST
  191.     IF a& = 0 THEN a& = _NEWIMAGE(1, 1, 32)
  192.     _DEST a&
  193.     _DONTBLEND a& '  '<<<< new 2019-12-16 fix
  194.     PSET (0, 0), K
  195.     _BLEND a& '<<<< new 2019-12-16 fix
  196.     _DEST D
  197.     _MAPTRIANGLE _SEAMLESS(0, 0)-(0, 0)-(0, 0), a& TO(x1, y1)-(x2, y2)-(x3, y3)
  198.  
  199. SUB ntri (x1, y1, x2, y2, x3, y3, K AS _UNSIGNED LONG)
  200.     LINE (x1, y1)-(x2, y2), K
  201.     LINE (x2, y2)-(x3, y3), K
  202.     LINE (x3, y3)-(x1, y1), K
  203.     PAINT ((x1 + x2 + x3) / 3, (y1 + y2 + y3) / 3), K
  204.  
  205. SUB Initialize
  206.  
  207.     obj(1).typ = 1: obj(1).cx = _WIDTH / 2 - 125: obj(1).cy = _HEIGHT / 2: obj(1).lenBase = 500: obj(1).rotDegrees = 90: obj(1).colr = &HFFFF8800
  208.     drawObj 1
  209.  
  210.     obj(2).typ = 1: obj(2).cx = _WIDTH / 2: obj(2).cy = _HEIGHT / 2 - 125: obj(2).lenBase = 500: obj(2).rotDegrees = 180: obj(2).colr = &HFF008800
  211.     drawObj 2
  212.  
  213.     obj(3).typ = 1: obj(3).cx = _WIDTH / 2 - 2: obj(3).cy = _HEIGHT / 2 + 65: obj(3).lenBase = 250: obj(3).rotDegrees = 0: obj(3).colr = &HFF000066
  214.     drawObj 3
  215.  
  216.     obj(4).typ = 1: obj(4).cx = _WIDTH / 2 + 125 + 64: obj(4).cy = _HEIGHT / 2 - 125: obj(4).lenBase = 250: obj(4).rotDegrees = 270: obj(4).colr = &HFF00DDDD
  217.     drawObj 4
  218.  
  219.     obj(5).typ = 1: obj(5).cx = _WIDTH / 2 + 125 + 64: obj(5).cy = _HEIGHT / 2 + 125 + 62.5: obj(5).lenBase = 500 * sqr2d2: obj(5).rotDegrees = 135
  220.     obj(5).colr = &HFF880000
  221.     drawObj 5
  222.  
  223.     obj(6).typ = 2: obj(6).cx = _WIDTH / 2 + 125: obj(6).cy = _HEIGHT / 2: obj(6).lenBase = 250 * sqr2d2: obj(6).rotDegrees = 0
  224.     obj(6).colr = &HFFFFFF00
  225.     drawObj 6
  226.  
  227.     obj(7).typ = 3: obj(7).cx = _WIDTH / 2 - 62.5: obj(7).cy = _HEIGHT / 2 + 125 + 62.5: obj(7).lenBase = 250: obj(7).rotDegrees = 0
  228.     obj(7).colr = &HFF0000FF
  229.     drawObj 7
  230.  
  231.     DIM i AS INTEGER
  232.  
  233.     FOR i = 1 TO 7 'make a copy of settings in case a handle gets stuck on another
  234.         copy(i) = obj(i)
  235.     NEXT
  236.     GlInit = True ' TdB
  237.     GrActive = Normal ' TdB
  238.  
  239.  
  240.  
  241. '---------------OpenGL AREA---------------------------
  242. SUB _GL ()
  243.     DIM i AS INTEGER
  244.     IF GlInit = True THEN InitGl
  245.     IF GrActive <> Opengl THEN EXIT SUB
  246.  
  247.     _glClear _GL_COLOR_BUFFER_BIT
  248.     ' here it draws GL objects
  249.     FOR i = 1 TO 7
  250.         drawObj i
  251.         IF obj(i).typ = 1 THEN
  252.             GLTri45 i
  253.         ELSEIF obj(i).typ = 2 THEN
  254.             GLQuadr i
  255.         ELSEIF obj(i).typ = 3 THEN
  256.             GLParall i
  257.         END IF
  258.         DIM sRc AS INTEGER, sGc AS INTEGER, sBc AS INTEGER, sAc AS INTEGER
  259.         DIM glRc AS SINGLE, glGc AS SINGLE, glBc AS SINGLE, glAc AS SINGLE
  260.         sRc = _RED32(White)
  261.         sGc = _GREEN32(White)
  262.         sBc = _BLUE32(White)
  263.         sAc = _ALPHA32(White)
  264.         glRc = Proportion(0, 255, 0, 1, sRc)
  265.         glGc = Proportion(0, 255, 0, 1, sGc)
  266.         glBc = Proportion(0, 255, 0, 1, sBc)
  267.         glAc = Proportion(0, 255, 0, 1, sAc)
  268.         _glColor4f glRc, glGc, glBc, glAc
  269.  
  270.         _glPointSize 8
  271.         _glBegin _GL_POINTS
  272.         _glVertex2f Proportion(0, 1280, -1, 1, VertObj(i, X, 5)), Proportion(0, 740, 1, -1, VertObj(i, Y, 5))
  273.         _glEnd
  274.         _glPointSize 1
  275.     NEXT
  276.     _glFlush
  277.  
  278. SUB GLQuadr (i AS INTEGER)
  279.     DIM a AS INTEGER, sRc AS INTEGER, sGc AS INTEGER, sBc AS INTEGER, sAc AS INTEGER
  280.     DIM glRc AS SINGLE, glGc AS SINGLE, glBc AS SINGLE, glAc AS SINGLE
  281.     sRc = _RED32(obj(i).colr)
  282.     sGc = _GREEN32(obj(i).colr)
  283.     sBc = _BLUE32(obj(i).colr)
  284.     sAc = _ALPHA32(obj(i).colr)
  285.     glRc = Proportion(0, 255, 0, 1, sRc)
  286.     glGc = Proportion(0, 255, 0, 1, sGc)
  287.     glBc = Proportion(0, 255, 0, 1, sBc)
  288.     glAc = Proportion(0, 255, 0, 1, sAc)
  289.     _glColor4f glRc, glGc, glBc, glAc
  290.     _glBegin _GL_QUADS
  291.     FOR a = 1 TO 4 STEP 1
  292.         _glVertex2f Proportion(0, 1280, -1, 1, VertObj(i, X, a)), Proportion(0, 740, 1, -1, VertObj(i, Y, a))
  293.     NEXT a
  294.     _glEnd
  295.  
  296. SUB GLParall (i AS INTEGER)
  297.     DIM a AS INTEGER, sRc AS INTEGER, sGc AS INTEGER, sBc AS INTEGER, sAc AS INTEGER
  298.     DIM glRc AS SINGLE, glGc AS SINGLE, glBc AS SINGLE, glAc AS SINGLE
  299.     sRc = _RED32(obj(i).colr)
  300.     sGc = _GREEN32(obj(i).colr)
  301.     sBc = _BLUE32(obj(i).colr)
  302.     sAc = _ALPHA32(obj(i).colr)
  303.     glRc = Proportion(0, 255, 0, 1, sRc)
  304.     glGc = Proportion(0, 255, 0, 1, sGc)
  305.     glBc = Proportion(0, 255, 0, 1, sBc)
  306.     glAc = Proportion(0, 255, 0, 1, sAc)
  307.     _glColor4f glRc, glGc, glBc, glAc
  308.  
  309.     _glBegin _GL_QUADS
  310.     FOR a = 1 TO 4 STEP 1
  311.         _glVertex2f Proportion(0, 1280, -1, 1, VertObj(i, X, a)), Proportion(0, 740, 1, -1, VertObj(i, Y, a))
  312.     NEXT a
  313.     _glEnd
  314.  
  315. SUB GLTri45 (i AS INTEGER)
  316.     DIM a AS INTEGER, sRc AS INTEGER, sGc AS INTEGER, sBc AS INTEGER, sAc AS INTEGER
  317.     DIM glRc AS SINGLE, glGc AS SINGLE, glBc AS SINGLE, glAc AS SINGLE
  318.     sRc = _RED32(obj(i).colr)
  319.     sGc = _GREEN32(obj(i).colr)
  320.     sBc = _BLUE32(obj(i).colr)
  321.     sAc = _ALPHA32(obj(i).colr)
  322.     glRc = Proportion(0, 255, 0, 1, sRc)
  323.     glGc = Proportion(0, 255, 0, 1, sGc)
  324.     glBc = Proportion(0, 255, 0, 1, sBc)
  325.     glAc = Proportion(0, 255, 0, 1, sAc)
  326.     _glColor4f glRc, glGc, glBc, glAc
  327.  
  328.     _glBegin _GL_TRIANGLES
  329.     FOR a = 1 TO 3 STEP 1
  330.         _glVertex2f Proportion(0, 1280, -1, 1, VertObj(i, X, a)), Proportion(0, 740, 1, -1, VertObj(i, Y, a))
  331.     NEXT a
  332.     _glEnd
  333.  
  334. SUB InitGl
  335.     _glViewport 0, 0, 1280, 740
  336.     _glClearColor 0, 0, 0, 1
  337.  
  338. FUNCTION Proportion (min1, max1, min2, max2, value)
  339.     ' min1: max1 = min2:max2= value: X
  340.     ' (max1-min1): Value = (max2-min2) : X
  341.     ' X = ((max2-min2) * value)/ (max1-min1)
  342.     Proportion = (((max2 - min2) * value) / (max1 - min1)) + min2
  343.  

At beginning I have tried to use the title of the window as a label for feedback to user, but I have had so many troubles that I have lost a week of free time! With the suggestion on discord I have found another way, using splashscreen message.
In this demo the 3 different modes of making graphic are used separately, but if you see in code of others you can see also how to use them together.
Programming isn't difficult, only it's  consuming time and coffee

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Simple demo of 3 different way to make graphic in QB64
« Reply #1 on: December 06, 2020, 07:17:59 pm »
For the record B+ didn't do the above, it's a mod that doesn't seem to work for me anyway.
« Last Edit: December 06, 2020, 08:18:13 pm by bplus »

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: Simple demo of 3 different way to make graphic in QB64
« Reply #2 on: December 07, 2020, 06:16:55 pm »
So  now we know that the added or modified code doesn't work on your machine!
If someoneelse have a similar result running this code we can focus on the few commands added by me to your opera to catch the mistake or the glitch!
Sorry to waste your opera, I like so much that I have thought to use it for show different ways of graphic output. Its original MapTriangle use is very explicative! The original code is linear and easy to read.
Again thanks to share it!
Programming isn't difficult, only it's  consuming time and coffee

Marked as best answer by TempodiBasic on December 08, 2020, 02:09:31 am

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Simple demo of 3 different way to make graphic in QB64
« Reply #3 on: December 07, 2020, 06:20:23 pm »
If I change the limit to 30, the program works.  A limit 10 just causes it to go unresponsive and freeze before ever starting.

And why the heck it's having that reaction is beyond me.  All the following code comes before the LIMIT, and shouldn't be affected by it at all:

Code: Text: [Select]
  1. Initialize
  2.  
  3. CLS
  4. info
  5. CLS
  6. message "Tangram 1 Normal mode: press space to change graphic", 0, 0
  7. _DISPLAY
  8. _DELAY 2

There's display routines in there, and pauses, and user needed keypresses....  And all these things should trigger before that LIMIT ever does anything whatsoever...

So why the heck does changing the limit from 10 to 30 allow the program to work, when it won't otherwise???
« Last Edit: December 07, 2020, 06:27:38 pm by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Simple demo of 3 different way to make graphic in QB64
« Reply #4 on: December 07, 2020, 08:54:31 pm »
Right it doesn't make sense for 30 to work better than the hanging.

Steve should get best answer for pointing to _LIMIT 30. It now works fine on my system. :)

I am sorry I missed this comment:
Code: QB64: [Select]
  1. _LIMIT 10 'peharps we must change this fps to 30
  2.  

Yes perhaps we should :)

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: Simple demo of 3 different way to make graphic in QB64
« Reply #5 on: December 08, 2020, 07:09:10 am »
@Steve, Bplus

Thanks for feedbacks

I love this community!

PS Bplus passes the laurel to Steve so I change the Green Best answer
Programming isn't difficult, only it's  consuming time and coffee