📜 ⬆️ ⬇️

Create a UWP application in SPL

At the moment there are not many programming languages ​​that are suitable for writing UWP applications (UWP - Universal Windows Platform, or "Universal Windows Platform"), equally suitable for running on desktops, tablets, smartphones and other devices running Windows 10 .

Now the SPL programming language that I am developing can also be used to create UWP applications due to the presence of the SPL SDK. I'll tell you more about this.

In this article, I will demonstrate the process of creating a standalone UWP application using a simple example — the Mandelbrot fractal browser. First I will give the text of the program, then I will explain it, then I will tell you about how this will become a UWP application.

One could, of course, limit the example of the program to just one line:
')
#.output("Hello, world!") 

but it would be too easy :)

The program below is a simple browser of the Mandelbrot fractal, which is navigated using standard multi-touch gestures of movement and scaling. Also in this example, the ability to perform tasks in parallel streams, the work of the offscreen buffer for graphic functions and the use of multi-touch gestures for the operation of the program interface are shown. This example is not specifically overloaded with additional functionality to focus on the main thing - to demonstrate how a SPL program can become an independent UWP application, which can then be downloaded to the Microsoft Store.

Fractal browser program text:

 w,h = #.scrsize() sfx = -2.5; sfy = -2*h/w; sfs = 4 #.aaoff() :again end,redo,update = 0 -> draw() '     > moved = 0 > #.pan() '  moved = 1 x,y,s = #.pan(3) x -= (s-1)/2*w y -= (s-1)/2*h #.drawoff(x,y,s) < ? moved '   sfs /= s sfx -= x*sfs/w sfy -= y*sfs/w again -> end redo = 1 . ? update & !redo '  update = 0 #.drawoff(0,0) . wn,hn = #.scrsize() ? wn!=w | hn!=h '   w = wn; h = hn again -> end redo = 1 . < draw()= :loop #.offon() '    #.scrclear(0,0,0) .redo = 0 sfx = .sfx; sfy = .sfy; fs = .sfs/.w > y, 1...h > x, 1...w fx = sfx + x*fs fy = sfy + y*fs #.drawpoint(x,y,color(fx,fy):3) < loop -> .redo .update = 1 < .end = 1 . color(x,y)= zr = x; zi = y; n = 0 maxn = #.int(200*(1-#.log10(.sfs/4))) > zr*zr+zi*zi<4 & n<maxn zrn = zr*zr-zi*zi+x; zin = 2*zr*zi+y zr = zrn; zi = zin; n += 1 < ? n=maxn; <= 0,0,0; . <= #.hsv2rgb(n/maxn*360,1,1):3 . 

image

Now let's take a closer look at this example.

 w,h = #.scrsize() sfx = -2.5; sfy = -2*h/w; sfs = 4 #.aaoff() :again end,redo,update = 0 -> draw() '     

In the first two lines we get the size of the screen, which is needed to draw a fractal in full screen, and also set the initial position and scale of the fractal. In the third line, turn off antialiasing graphics (which is enabled by default). In the last line, run the function for calculating the fractal draw in a parallel stream.

In this example, the main stream is occupied by navigation, managing the calculation of the fractal and its display on the screen, and the calculation itself is carried out in another stream into the voice-over buffer. The main stream takes the image that is currently calculated, and either simply displays it on the screen in the form of a progressively drawn fractal, or displays it displaced and scaled if the user moves and scales it with multi-touch gestures.

The main body of the program is an infinite loop, decorated with the commands> and <without any conditions, because we just need to continuously loop while waiting for user actions, while displaying the drawn picture of the fractal.

 moved = 0 > #.pan() '  moved = 1 x,y,s = #.pan(3) x -= (s-1)/2*w y -= (s-1)/2*h #.drawoff(x,y,s) < 

This cycle turns on and works if the user makes a multi-touch gesture. In the second line, the condition of the cycle operation is the multitouch operation indicator. In the fourth line, we get the parameters of the multi-touch gesture — the offset coordinates and the scale. Then the # .drawoff function displays the offscreen buffer with the fractal drawn in it so that the picture corresponds to the current offset and multitouch scale. In this way, we obtain interactive fractal navigation.

 ? moved '   sfs /= s sfx -= x*sfs/w sfy -= y*sfs/w again -> end redo = 1 . 

This is where the condition is triggered if the user has just finished the navigation gesture. New fractal parameters are recalculated: sfs scale and sfx, sfy coordinates. In the fifth line, the program goes to the label again to re-start the calculation of the fractal, if it has already completed, that is, the variable end is not equal to zero. If the fractal is still considered, then it is simply sent to the recalculation due to the redo variable being set to 1.

 ? update & !redo '  update = 0 #.drawoff(0,0) . 

This condition is triggered if the fractal simply continues its calculation and already has something new to display, that is, the update variable is not zero. In the third line, the contents of the offscreen buffer is displayed on the screen.

 wn,hn = #.scrsize() ? wn!=w | hn!=h '   w = wn; h = hn again -> end redo = 1 . 

The purpose of this condition is to determine whether the screen size has changed - the user can maximize the window, simply resize the window or rotate the tablet to a different orientation - then the new widths and heights of the window wn, hn will not match the old w, h.

If this happens, then, similarly to what we have done before, we either restart the flow with the fractal calculation in the fourth line, or signal this flow in the fifth line that it needs to start the calculation anew.

 draw()= :loop #.offon() '    #.scrclear(0,0,0) .redo = 0 sfx = .sfx; sfy = .sfy; fs = .sfs/.w > y, 1...h > x, 1...w fx = sfx + x*fs fy = sfy + y*fs #.drawpoint(x,y,color(fx,fy):3) < loop -> .redo .update = 1 < .end = 1 . 

This is the main cycle of drawing a fractal. In the third line, the stream of graphic commands is redirected to the voice-over buffer, so that it is then from there to display the fractal, taking into account its current offset and scale for interactive navigation. As you can see from this example, working with graphics is safe for multi-threaded calculations in SPL.

The main drawing function here is the # .drawpoint function, which takes three passed values ​​from the color function as a color argument.

Next, we see that the calculation starts anew by moving to the loop label, if the global variable .redo is not zero.

Next, by setting the value of the global variable .update to one, we indicate to the main thread what is already there, what new can be displayed in the fractal.

If the fractal calculation is completed, the value of the global variable .end is set to one. Knowing this, if it is necessary to recalculate the fractal, we will re-launch the fractal calculation flow.

 color(x,y)= zr = x; zi = y; n = 0 maxn = #.int(200*(1-#.log10(.sfs/4))) > zr*zr+zi*zi<4 & n<maxn zrn = zr*zr-zi*zi+x; zin = 2*zr*zi+y zr = zrn; zi = zin; n += 1 < ? n=maxn; <= 0,0,0; . <= #.hsv2rgb(n/maxn*360,1,1):3 . 

This is the last function in our example, it performs the most important thing - it returns the color of the fractal at each point on the screen. The function color takes the coordinates of a point in the fractal as input parameters x, y.

Next in the cycle, the Mandelbrot fractal is calculated, and in the last two lines of the function, the point color is returned depending on whether the fractal calculation is obtained or 0.0.0, if the fractal did not exceed the set maxn limit, or the color from the HSV color space in accordance with with the resulting fractal value.

Here the lyrical part of the article ends and proceed to the technical part. Let's make a separate UWP application from the SPL program.

The fact is that the SPL interpreter first generates the intermediate binary code, and then executes it. This all happens “behind the scenes” and the user may not even be aware of the existence of this intermediate code - the COD file. But, having included the corresponding option in the program, this COD file can be seen and copied from SPL. Then we take the SPL SDK, made in the form of a ready-made project Visual Studio 2017, and copy this COD file into it as a resource.



Then we indicate the name of the program in the first line. In our case, this is “fractal.txt”. You do not need to specify the .cod extension of the .cod file.



The SPL SDK itself is simply a “performer” of COD files, which will automatically launch your SPL program when it starts.

In general, that's all. Independent UWP application is ready! Now it can be compiled and run on any device on Windows 10. If desired, you can send this application to the Microsoft Store.

Now the SPL programming language is under active development. The purpose of the language SPL (Simple Programming Language) - amateur programming as a hobby. SPL is a programming language that I personally invented and developed. Also “SPL” is my Windows 10 application, which is currently in the closed beta stage. Those users who are interested in the SPL programming language and who would like to take part in its development through testing, as well as their suggestions, welcome to the SPL language site . There you will find SPL documentation and other useful information.

All success in programming!

Source: https://habr.com/ru/post/332418/


All Articles