Recent

Author Topic: SDL vs OpenGL  (Read 56193 times)

Graeme

  • Hero Member
  • *****
  • Posts: 1428
    • Graeme on the web
Re: SDL vs OpenGL
« Reply #30 on: January 31, 2017, 12:23:47 pm »
See the "EDIT" comment now added to my previous post - regarding a Java version I just wrote.
--
fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal
http://fpgui.sourceforge.net/

Graeme

  • Hero Member
  • *****
  • Posts: 1428
    • Graeme on the web
Re: SDL vs OpenGL
« Reply #31 on: January 31, 2017, 12:35:24 pm »
The code has simply been translated from C, and is typical C style. C compilers are probably better to optimize poorly written code,
The original code was written for JavaScript, simply as a test to see the performance of HTML5's Canvas. The author, Notch the creator of Minecraft, explicitly said the code was terrible because he also wanted it as small (few lines) as possible.

To compare like-to-like I guess you have to stick to the "poorly written code" even in the ports. That gives you a good comparison of each language compilers optimisation and the resulting executable's performance.

Quote
for instance the repeated comparison "if d = 1 then", "if d =2 then" which does not even use the most obvious manual optimization, using an else statement (which gives me a 30% performance gain straightaway).
Interestingly, I made that one change and don't see such an improvement here. I still see the C version running between 15-30 fps. 15 fps if it looks sideways at the tunnel and 30 fps if it looks forwards.

Out of interest, I made the same small optimisation change in the Java port I created.  I do see a slight improvement there.  34-36 fps looking sideways (same as before) and now 40-50 fps looking forwards.


 I guess that disentangling the C-style loop further could improve performance significantly.
Another bad thing is the use of floor(); the math unit is per default compiled for extended precision, so each call will involve two conversions from single to extended and back.
[/quote]
--
fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal
http://fpgui.sourceforge.net/

Graeme

  • Hero Member
  • *****
  • Posts: 1428
    • Graeme on the web
Re: SDL vs OpenGL
« Reply #32 on: January 31, 2017, 12:43:25 pm »
Read my earlier post, first remove random from all tight loops, it is known slow on FPC
And like I said, the Random() call is only used in the initilazation of the textures and map (voxels). Moving through the tunnel (game loop and raycasting code) doesn't use the Random() call at all, and the world is never regenerated - it's on a infinite loop. So the use of Random in this example has nothing to do with the poor performance of the executable.
--
fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal
http://fpgui.sourceforge.net/

Nitorami

  • Sr. Member
  • ****
  • Posts: 491
Re: SDL vs OpenGL
« Reply #33 on: February 01, 2017, 10:47:06 am »
I get a performance gain from ~10 to 20fps by small optimizations as inserting else-statements as Graeme proposed, and replacing ox = ox-floor(ox) by ox = frac(ox) etc. to avoid the single->extended conversion, but mainly by using directive {$FPUTYPE SSE3}.

Form what I have read I understand that the benefit of SSE3 is mainly that the truncation of floats is slow when using x87 FPU instructions because the rounding mode in the FPU control word needs to be changed to round-to-zero and back, while when using SSE the truncation is available without control word changes.

I have not used the disassembler to check whether this is actually the case in FPC but is seems plausible, given that truncation is required quite a lot in the inner loop. The remaining performance difference to Java/C is presumably mainly to the lack of vectorization.

An exception may occur after a while because the division ll := 1/dimlength does not check for underflow or zero. I only get exceptions with SSE, I guess that the FPU exception handling flag is just set differently than for the x87. The easiest way to avoid this is obviously to check dimlength before the division. As this is not in the innermost loop, it does not impact on performance.





airpas

  • Full Member
  • ***
  • Posts: 179
Re: SDL vs OpenGL
« Reply #34 on: February 01, 2017, 11:27:26 am »
i think the bottleneck is in the while block at line 233 , which is the deepest loop

jonas already answered to this : http://www.mail-archive.com/fpc-pascal@lists.freepascal.org/msg43601.html

Nitorami

  • Sr. Member
  • ****
  • Posts: 491
Re: SDL vs OpenGL
« Reply #35 on: February 01, 2017, 11:52:48 am »
Yes, and that is where the map and texmap access is done and where float truncation is needed.

I am now at 22 - 24 fps, having replaced the linear arrays map and texmap by structured arrays such as var map: array [0..63, 0..63, 0..63], and find it 10% faster than the linear array. In general my observation is that using the language as it is meant to be is usually the fastest option. The array access by indices z,x,y is probably better optimized than manual calculation of a linear address space.

airpas

  • Full Member
  • ***
  • Posts: 179
Re: SDL vs OpenGL
« Reply #36 on: February 01, 2017, 12:11:52 pm »
interesting  , can you post the code ?

Graeme

  • Hero Member
  • *****
  • Posts: 1428
    • Graeme on the web
Re: SDL vs OpenGL
« Reply #37 on: February 01, 2017, 12:13:53 pm »
I get a performance gain from ~10 to 20fps by small optimizations as inserting else-statements as Graeme proposed, and replacing ox = ox-floor(ox) by ox = frac(ox) etc.
According to how the Java language works, many of the floor() calls can be replaced with trunc() - not sure if that is faster or not.

Tested with the following Java code.

Code: Java  [Select][+][-]
  1. public class Test {
  2.  
  3.     public static void main(String[] args) {
  4.       float f4 = 0.4f;
  5.       float f5 = 0.5f;
  6.       float f6 = 0.6f;
  7.      
  8.       int i4 = (int) f4;
  9.       int i5 = (int) f5;
  10.       int i6 = (int) f6;
  11.      
  12.       System.out.println(i4);
  13.       System.out.println(i5);
  14.       System.out.println(i6);
  15.     }
  16. }
  17.  

Quote
An exception may occur after a while because the division ll := 1/dimlength does not check for underflow or zero.
That is actually a bug in the Pascal port I believe. Airpas incorrectly interpreted what the original C code does. Here is the corrected snippet. This will also fix the bug where left and bottom sides of the blocks are not rendered in the Pascal version.

-------------------------------
         if dimLength < 0.0 then
-          dimLength := -dimLength;
-        ll := 1.0 / dimLength;
+          ll := 1.0 / -dimLength
+        else
+          ll := 1.0 / dimLength;
-------------------------------
--
fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal
http://fpgui.sourceforge.net/

Graeme

  • Hero Member
  • *****
  • Posts: 1428
    • Graeme on the web
Re: SDL vs OpenGL
« Reply #38 on: February 01, 2017, 12:24:05 pm »
I am now at 22 - 24 fps, having replaced the linear arrays map and texmap by structured arrays such as var map: array [0..63, 0..63, 0..63]
That's impressive and very interesting.

Quote
In general my observation is that using the language as it is meant to be is usually the fastest option.
No doubt about that.

The nice thing about the "original versions" is that they are written very similar, so is great for comparisons of what the compiler can do with it and how good it can optimise non-optimal code. There seems to be lots of scope for improving the performance of all versions of the demo.


On a side note:
  I did notice that the Pascal and Java versions render a more dense world around the tunnel - not many gaps. In the C version their are plenty of gaps and "floating blocks". I haven't found out what causes that difference as the map generating code looks identical. But that could (small chance) also improve the performance of the C version over the others.


For those interested, here is my Java port of the original JavaScript & C versions. Running it as a Applet is untested (to date), so simply compile with "javac Minecraft4k.java" and then run it from a console window "java Minecraft4k". FPS will be written to the console window. I also created two new textures (blocks). Mossy Red Bricks and Mossy Stone. :)

Code: Java  [Select][+][-]
  1. package com.opensoft.game;
  2.  
  3. import java.applet.Applet;
  4. import java.awt.Frame;
  5. import java.awt.image.BufferedImage;
  6. import java.awt.image.DataBufferInt;
  7. import java.util.Random;
  8.  
  9. public class Minecraft4k extends Applet implements Runnable {
  10.  
  11.         private static final long serialVersionUID = 1L;
  12.         private static final String version = "0.0.1";
  13.  
  14.         // // screen dimensions: scale x4 - low fidelity
  15.         // private static final int WIDTH = 214;
  16.         // private static final int HEIGHT = 120;
  17.         // private static final int SCALE = 4;
  18.  
  19.         // screen dimensions: scale x2 - high fidelity
  20.         // private static final int WIDTH = 428;
  21.         // private static final int HEIGHT = 240;
  22.         // private static final int SCALE = 2;
  23.  
  24.         private static final int WIDTH = 640;
  25.         private static final int HEIGHT = 400;
  26.         private static final int SCALE = 1;
  27.  
  28.         // the block world map is stored in a cube of sides 64 in length;
  29.         // each map entry determines the colour of the corresponding block
  30.         private static final int MAPDIM = 64; // map dimensions
  31.         private static final int MAPCUBE = MAPDIM * MAPDIM * MAPDIM; // value 262144
  32.         private int[] map = new int[MAPCUBE];
  33.  
  34.         Random rand = new Random();
  35.  
  36.         public static void main(String[] args) {
  37.                 Frame f = new Frame("Minecraft4k Java Demo " + version);
  38.                 f.addWindowListener(new java.awt.event.WindowAdapter() {
  39.                         @Override
  40.                         public void windowClosing(java.awt.event.WindowEvent e) {
  41.                                 System.exit(0);
  42.                         };
  43.                 });
  44.  
  45.                 Minecraft4k mc = new Minecraft4k();
  46.                 mc.setSize(WIDTH * SCALE, HEIGHT * SCALE);
  47.                 f.add(mc);
  48.                 f.pack();
  49.                 mc.start();
  50.                 f.setSize(WIDTH * SCALE, HEIGHT * SCALE);
  51.                 f.setVisible(true);
  52.         }
  53.  
  54.         @Override
  55.         public void start() {
  56.                 new Thread(this).start(); // triggers the run() method
  57.         }
  58.  
  59.         /*
  60.          * The following textures are generated
  61.          * 0 Air
  62.          * 1 Grass + Dirt
  63.          * 2 Dirt
  64.          * 3 Dirt
  65.          * 4 Stone (gray)
  66.          * 5 Brick
  67.          * 6 Dirt
  68.          * 7 Wood
  69.          * 8 Tree leaves
  70.          * 9 Water
  71.          * 10 .. 13 Dirt
  72.          * 14 Stone with moss
  73.          * 15 Red Brick with moss
  74.          */
  75.         private int[] generate_textures() {
  76.                 // Algorithmically generate textures...
  77.                 int[] texmap = new int[12288]; // 16 * 16 * 16 * 3 = 12288
  78.                 int i = 1;
  79.  
  80.                 while (i < 16) {
  81.                         int lBrightness = 255 - rand.nextInt(96);
  82.                         int y = 0;
  83.                         while (y < (16 * 3)) { // 3 texture images (top, side and bottom),
  84.                                                                         // stored one below the other
  85.                                 int x = 0;
  86.                                 while (x < 16) {
  87.                                         int lBrightness2;
  88.                                         int lColor;
  89.                                         int color = 0x966C4A; // ground
  90.                                         if (i == 4) {
  91.                                                 color = 0x7F7F7F; // stone
  92.                                         }
  93.                                         if (i != 4 || rand.nextInt(3) == 0) {
  94.                                                 lBrightness = 255 - rand.nextInt(96);
  95.                                         }
  96.                                         if (i == 1 && y < (x * x * 3 + x * 81 >> 2 & 3) + 18) {
  97.                                                 color = 0x6AAA40; // grass
  98.                                         } else if (i == 1 && y < (x * x * 3 + x * 81 >> 2 & 3) + 19) {
  99.                                                 lBrightness = lBrightness * 2 / 3;
  100.                                         }
  101.                                         if (i == 7) {
  102.                                                 color = 0x675231; // wood
  103.                                                 if (x > 0 && x < 15 && (y > 0 && y < 15 || y > 32 && y < 47)) {
  104.                                                         color = 0xBC9862; // wood
  105.                                                         // This is WRONG - see the JavaScript version for
  106.                                                         // details
  107.                                                         lBrightness2 = x - 7;
  108.                                                         lColor = (y & 15) - 7;
  109.                                                         if (lBrightness2 < 0) {
  110.                                                                 lBrightness2 = 1 - lBrightness2;
  111.                                                         }
  112.                                                         if (lColor < 0) {
  113.                                                                 lColor = 1 - lColor;
  114.                                                         }
  115.                                                         if (lColor > lBrightness2) {
  116.                                                                 lBrightness2 = lColor;
  117.                                                         }
  118.                                                         lBrightness = 196 - rand.nextInt(32) + lBrightness2 % 3 * 32;
  119.                                                 } else if (rand.nextInt(2) == 0) {
  120.                                                         lBrightness = lBrightness * (150 - (x & 1) * 100) / 100;
  121.                                                 }
  122.                                         }
  123.                                         if (i == 5) {
  124.                                                 color = 0xB53A15; // brick
  125.                                                 if ((x + y / 4 * 4) % 8 == 0 || y % 4 == 0) {
  126.                                                         color = 0xBCAFA5;
  127.                                                 }
  128.                                         }
  129.                                         if (i == 9) {
  130.                                                 color = 0x4040ff; // water
  131.                                         }
  132.                                         if (i == 14) {
  133.                                                 color = 0x7F7F7F; // stone with moss
  134.                                                 if (rand.nextInt(3) == 0) {
  135.                                                         color = 0x6AAA40;
  136.                                                 } else if ((x + y / 4 * 4) % 8 == 0 || y % 4 == 0) {
  137.                                                         color = 0x6AAA60;
  138.                                                 }
  139.                                         }
  140.                                         if (i == 15) {
  141.                                                 color = 0xB53A15; // red bricks with moss
  142.                                                 if (rand.nextInt(3) == 0) {
  143.                                                         color = 0x6AAA40;
  144.                                                 } else if ((x + y / 4 * 4) % 8 == 0 || y % 4 == 0) {
  145.                                                         color = 0x6AAA60;
  146.                                                 }
  147.                                         }
  148.  
  149.                                         lBrightness2 = lBrightness;
  150.                                         if (y >= 32) {
  151.                                                 lBrightness2 /= 2;
  152.                                         }
  153.                                         if (i == 8) {
  154.                                                 color = 0x50D937; // leaves
  155.                                                 if (rand.nextInt(2) == 0) {
  156.                                                         color = 0;
  157.                                                         lBrightness2 = 255;
  158.                                                 }
  159.                                         }
  160.                                         lColor = (color >> 16 & 0xFF) * lBrightness2 / 0xFF << 16 //
  161.                                                         | (color >> 8 & 0xFF) * lBrightness2 / 0xFF << 8 //
  162.                                                         | (color & 0xFF) * lBrightness2 / 0xFF;
  163.                                         texmap[x + y * 16 + i * 256 * 3] = lColor;
  164.                                         ++x;
  165.                                 }
  166.                                 ++y;
  167.                         }
  168.                         ++i;
  169.  
  170.                 }
  171.  
  172.                 return texmap;
  173.         }
  174.  
  175.         private void generateMap() {
  176.                 for (int x = 0; x < MAPDIM; x++) {
  177.                         for (int y = 0; y < MAPDIM; y++) {
  178.                                 for (int z = 0; z < MAPDIM; z++) {
  179.                                         int i = (z << 12) | (y << 6) | x;
  180.                                         float yd = (y - 32.5f) * 0.4f;
  181.                                         float zd = (z - 32.5f) * 0.4f;
  182.                                         map[i] = rand.nextInt(16);
  183.                                         float th = rand.nextInt(256) / 256.0f;
  184.                                         if ((th > (Math.sqrt(Math.sqrt(yd * yd + zd * zd)) - 0.8f)) || (th < 0.5f)) {
  185.                                                 map[i] = 0;
  186.                                         }
  187.                                 }
  188.                         }
  189.                 }
  190.         }
  191.  
  192.         @Override
  193.         public void run() {
  194.                 try {
  195.                         long lastTime = System.currentTimeMillis();
  196.                         int frames = 0;
  197.  
  198.                         BufferedImage localBufferedImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
  199.                         int[] imgBufferData = ((DataBufferInt) localBufferedImage.getRaster().getDataBuffer()).getData();
  200.  
  201.                         // rand.setSeed(18295169);
  202.  
  203.                         generateMap();
  204.  
  205.                         int[] texmap = generate_textures();
  206.  
  207.                         do {
  208.                                 float l = System.currentTimeMillis() % 10000 / 10000.0f;
  209.                                 // System.out.println("now = " + l);
  210.  
  211.                                 float ox = 32.5f + l * 64;
  212.                                 float oy = 32.0f;
  213.                                 float oz = 32.5f;
  214.  
  215.                                 float xRot = (float) ((float) Math.sin(l * Math.PI * 2f) * 0.4f + Math.PI / 2f);
  216.                                 float yRot = (float) Math.cos(l * Math.PI * 2f) * 0.4f;
  217.  
  218.                                 float xSin = (float) Math.sin(xRot);
  219.                                 float xCos = (float) Math.cos(xRot);
  220.                                 float ySin = (float) Math.sin(yRot);
  221.                                 float yCos = (float) Math.cos(yRot);
  222.  
  223.                                 int x = 0;
  224.                                 // raycaster: for each column
  225.                                 while (x < WIDTH) {
  226.                                         float ___xd = (x - WIDTH / 2) / (float) HEIGHT;
  227.                                         int y = 0;
  228.                                         while (y < HEIGHT) {
  229.                                                 float __yd = (y - HEIGHT / 2) / (float) HEIGHT;
  230.                                                 float __zd = 1.0f;
  231.                                                 float ___zd = __zd * yCos + __yd * ySin;
  232.                                                 float _yd = __yd * yCos - __zd * ySin;
  233.                                                 float _xd = ___xd * xCos + ___zd * xSin;
  234.                                                 float _zd = ___zd * xCos - ___xd * xSin;
  235.  
  236.                                                 int col = 0; // black sky colour
  237.                                                 int br = 255; // brightness
  238.                                                 double closest = 32.0d; // how far can we see
  239.  
  240.                                                 int d = 0;
  241.                                                 while (d < 3) {
  242.                                                         float dimLength = _xd;
  243.                                                         if (d == 1) {
  244.                                                                 dimLength = _yd;
  245.                                                         } else if (d == 2) {
  246.                                                                 dimLength = _zd;
  247.                                                         }
  248.                                                         float ll = 1.0f / (dimLength < 0.0f ? -dimLength : dimLength);
  249.                                                         float xd = _xd * ll;
  250.                                                         float yd = _yd * ll;
  251.                                                         float zd = _zd * ll;
  252.                                                         float initial = ox - ((int) ox);
  253.                                                         if (d == 1) {
  254.                                                                 initial = oy - ((int) oy);
  255.                                                         } else if (d == 2) {
  256.                                                                 initial = oz - ((int) oz);
  257.                                                         }
  258.                                                         if (dimLength > 0.0f) {
  259.                                                                 initial = 1.0f - initial;
  260.                                                         }
  261.  
  262.                                                         float dist = ll * initial;
  263.                                                         float xp = ox + xd * initial;
  264.                                                         float yp = oy + yd * initial;
  265.                                                         float zp = oz + zd * initial;
  266.  
  267.                                                         if (dimLength < 0.0f) {
  268.                                                                 if (d == 0) {
  269.                                                                         xp--;
  270.                                                                 } else if (d == 1) {
  271.                                                                         yp--;
  272.                                                                 } else if (d == 2) {
  273.                                                                         zp--;
  274.                                                                 }
  275.  
  276.                                                         }
  277.  
  278.                                                         // while we are considering a ray that is still closer then the best so far
  279.                                                         while (dist < closest) {
  280.  
  281.                                                                 // quantize to the map grid
  282.                                                                 int mapOffset = (((int) zp & 63) << 12) | (((int) yp & 63) << 6) | ((int) xp & 63);
  283.                                                                 int tex = map[mapOffset];
  284.  
  285.                                                                 // if this voxel has a texture applied
  286.                                                                 if (tex > 0) {
  287.  
  288.                                                                         // find the uv coordinates of the intersection point
  289.                                                                         int u = (int) ((xp + zp) * 16.0f) & 15;
  290.                                                                         int v = ((int) (yp * 16.0f) & 15) + 16;
  291.  
  292.                                                                         // fix uv's for alternate directions?
  293.                                                                         if (d == 1) {
  294.                                                                                 u = (int) (xp * 16.0f) & 15;
  295.                                                                                 v = (int) (zp * 16.0f) & 15;
  296.                                                                                 if (yd < 0.0f) {
  297.                                                                                         v += 32;
  298.                                                                                 }
  299.                                                                         }
  300.  
  301.                                                                         // find the colour at the intersection point
  302.                                                                         int cc = texmap[u + v * 16 + tex * 256 * 3];
  303.  
  304.                                                                         // if the colour is not transparent
  305.                                                                         if (cc > 0) {
  306.                                                                                 col = cc;
  307.                                                                                 br = 255 - (int) (dist / 32.0f * 255.0f);
  308.                                                                                 br = br * (255 - (d + 2) % 3 * 50) / 255;
  309.                                                                                 // we now have the closest hit point (also terminates this ray)
  310.                                                                                 closest = dist;
  311.                                                                         }
  312.                                                                 }
  313.                                                                 // advance the ray
  314.                                                                 xp += xd;
  315.                                                                 yp += yd;
  316.                                                                 zp += zd;
  317.                                                                 dist += ll;
  318.                                                         }
  319.                                                         ++d;
  320.                                                 }
  321.                                                 int r = (col >> 16 & 0xFF) * br / 0xFF;
  322.                                                 int g = (col >> 8 & 0xFF) * br / 0xFF;
  323.                                                 int b = (col & 0xFF) * br / 0xFF;
  324.                                                 imgBufferData[x + y * WIDTH] = r << 16 | g << 8 | b;
  325.                                                 ++y;
  326.                                         }
  327.                                         ++x;
  328.                                 }
  329.  
  330.                                 // the following code is only needed for a Java Applet -
  331.                                 // disables application when not visible
  332.                                 // if (!this.isActive()) {
  333.                                 // return;
  334.                                 // }
  335.  
  336.                                 frames++;
  337.  
  338.                                 // Graphics g = localBufferedImage.getGraphics();
  339.                                 // g.setColor(Color.WHITE);
  340.                                 // Font stringFont = g.getFont().deriveFont(7.0f);
  341.                                 // g.setFont(stringFont);
  342.                                 // g.drawString(version, 2, 6);
  343.                                 // g.drawString(prevFrames + " fps", 2, 13);
  344.  
  345.                                 this.getGraphics().drawImage(localBufferedImage, 0, 0, WIDTH * SCALE, HEIGHT * SCALE, null);
  346.  
  347.                                 // FPS counter printed every 1 second.
  348.                                 while (System.currentTimeMillis() - lastTime > 1000) {
  349.                                         System.out.println(frames + " fps");
  350.                                         lastTime += 1000;
  351.                                         frames = 0;
  352.                                 }
  353.  
  354.                         } while (true);
  355.                 } catch (Exception e) {
  356.                         e.printStackTrace();
  357.                         return;
  358.                 }
  359.         }
  360.  
  361. }
  362. [code]
  363.  
--
fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal
http://fpgui.sourceforge.net/

airpas

  • Full Member
  • ***
  • Posts: 179
Re: SDL vs OpenGL
« Reply #39 on: February 01, 2017, 12:52:29 pm »
Quote
That is actually a bug in the Pascal port I believe. Airpas incorrectly interpreted what the original C code does. Here is the corrected snippet. This will also fix the bug where left and bottom sides of the blocks are not rendered in the Pascal version.

-------------------------------
         if dimLength < 0.0 then
-          dimLength := -dimLength;
-        ll := 1.0 / dimLength;
+          ll := 1.0 / -dimLength
+        else
+          ll := 1.0 / dimLength;
-------------------------------

thats indeed fixed the rendering , but how this can be different?
they looks the same
Code: Pascal  [Select][+][-]
  1.  
  2. if dimLength < 0.0 then                          
  3.   ll := 1.0 / -dimLength else
  4.   ll := 1.0 / dimLength;
  5.  

and

Code: Pascal  [Select][+][-]
  1.  
  2. if dimLength < 0.0 then                          
  3.   dimLength := - dimLength;
  4.   ll := 1.0 / dimLength;
  5.  



Nitorami

  • Sr. Member
  • ****
  • Posts: 491
Re: SDL vs OpenGL
« Reply #40 on: February 01, 2017, 01:33:00 pm »
Quote
  I did notice that the Pascal and Java versions render a more dense world around the tunnel - not many gaps. In the C version their are plenty of gaps and "floating blocks". I haven't found out what causes that difference as the map generating code looks identical. But that could (small chance) also improve the performance of the C version over the others.

Oh yes. Missing walls improve performance dramatically, because the "if tex > 0" block can be skipped.

@airpas: The difference between the two "dimlength" versions is for instance, that the first one leaves dimlength untouched.

But I guess a numeric exception can also arise if dimlength < 1e-38, not only for zero. This is a negligence in the original code, maybe the author did not need to bother because he set the FPU exception flag accordingly.

BTW "if x < 0 then x := -x" can be replaced by x := abs (x);  ::)

In Pascal, trunc and floor are different for negative numbers.
x - trunc(x) provides the same result as frac(x). I do not know however what x-trunk(x) is in C.

Here is my code version so far:

Code: Pascal  [Select][+][-]
  1. {$ifdef FPC}{$mode objfpc}{$h+}{$endif}
  2. {$ifdef mswindows}{$apptype gui}{$endif}
  3.  
  4. {$OPTIMIZATION FASTMATH}
  5. {$OPTIMIZATION USEEBP}
  6. {$FPUTYPE SSE3}
  7. //{$OPTIMIZATION REGVAR}
  8. //{$SAFEFPUEXCEPTIONS OFF}
  9.  
  10.  
  11. //{$IMPLICITEXCEPTIONS OFF}
  12. //{$OPTIMIZATION LOOPUNROLL}
  13. {$OPTIMIZATION CSE}
  14. //{$CODEALIGN VARMIN=4}
  15. //{$CODEALIGN LOOP=4}//
  16. //{$CODEALIGN JUMP=4}
  17.  
  18.  
  19. uses  sdl;
  20.  
  21. type
  22.       p32Array = ^u32Array;
  23.       u32Array = array[0..0] of longint;
  24.  
  25. const
  26.        s_w = 640;
  27.        s_h = 400;
  28.  
  29. var
  30.   event : TSDL_Event;
  31.   done : boolean = false;
  32.   screen : PSDL_Surface;
  33.   texmap : array [0..15,0..3*16-1,0..15] of longint;
  34.   map    : array [0..63,0..63,0..63] of smallint;
  35.  
  36.  
  37. procedure  plot(x,y,c : longint);
  38. begin
  39.   p32Array(screen^.pixels)^[y*s_w+x] := c;
  40. end;
  41.  
  42.  
  43. function inttostr(v : integer): string;
  44. begin
  45.   str(v,result);
  46. end;
  47.  
  48.  
  49. procedure makeTextures();
  50. var
  51.    j,m,k,i1,i2,i3,n : longint;
  52. begin
  53.  
  54.     // each texture
  55.  
  56.     for j:=0 to 15 do begin
  57.         k := 255 - random(96);
  58.         // each pixel in the texture
  59.         for m:=0  to (16 * 3)-1 do
  60.             for n :=0 to 15 do begin
  61.                 i1 := $966C4A;
  62.                 i2 := 0;
  63.                 i3 := 0;
  64.                 if (j = 4) then
  65.                     i1 := $7F7F7F;
  66.                 if ((j <> 4) or (random(3) = 0)) then
  67.                     k := 255 - random(96);
  68.                 if ( j = 1 ) then
  69.                 begin
  70.                     if (m < (((n * n * 3 + n * 81) >> 2) and $3) + 18) then
  71.                         i1 := $6AAA40
  72.                     else if (m < (((n * n * 3 + n * 81) >> 2) and $3) + 19) then
  73.                         k := k * 2 div 3;
  74.                 end;
  75.                 if (j = 7) then
  76.                 begin
  77.                     i1 := $675231;
  78.                     if ((n > 0) and (n < 15) and (((m > 0) and (m < 15)) or ((m > 32) and (m < 47)))) then
  79.                     begin
  80.                         i1 := $BC9862;
  81.                         i2 := n - 7;
  82.                         i3 := (m and $F) - 7;
  83.                         if (i2 < 0.0) then
  84.                             i2 := 1 - i2;
  85.  
  86.                         if (i3 < 0.0) then
  87.                             i3 := 1 - i3;
  88.  
  89.                         if (i3 > i2) then
  90.                             i2 := i3;
  91.  
  92.                         k := 196 - random(32) + i2 mod 3 * 32;
  93.                     end
  94.                     else if (random(2) = 0) then
  95.                         k := k * (150 - (n and $1) * 100) div 100;
  96.                 end;
  97.  
  98.                 if (j = 5) then
  99.                 begin
  100.                     i1 := $B53A15;
  101.                     if (((n + m div 4 * 4) mod 8 = 0) or (m mod 4 = 0)) then
  102.                         i1 := $BCAFA5;
  103.                 end;
  104.                 i2 := k;
  105.                 if (m >= 32) then
  106.                     i2 := i2 div 2;
  107.                 if (j = 8) then
  108.                 begin
  109.                     i1 := 5298487;
  110.                     if (random(2) = 0) then
  111.                     begin
  112.                         i1 := 0;
  113.                         i2 := 255;
  114.                     end;
  115.                 end;
  116.  
  117.                 // fixed point colour multiply between i1 and i2
  118.                 i3 :=
  119.                     ((((i1 >> 16) and $FF) * i2 div 255) << 16) or
  120.                     ((((i1 >>  8) and $FF) * i2 div 255) <<  8) or
  121.                       ((i1        and $FF) * i2 div 255);
  122.  
  123.                 // pack the colour away
  124.                 texmap[ n,m,j] := i3;
  125.             end;
  126.     end;
  127. end;
  128.  
  129.  
  130. procedure makeMap( ) ;
  131. var x,y,z,i : longword;
  132.     yd,zd,th : single;
  133.     begin
  134.     // add random blocks to the map
  135.     for x := 0 to 63 do begin
  136.         for y := 0 to 63 do begin
  137.              for z := 0 to 63 do begin
  138.                yd := (y - 32.5) * 0.4;
  139.                zd := (z - 32.5) * 0.4;
  140.                map[z,y,x] := random( 16 );
  141.                th := random;
  142.               if th > sqrt( sqrt( yd * yd + zd * zd ) ) - 0.8 then
  143.                  map[z,y,x] := 0;
  144.               end;
  145.         end;
  146.     end;
  147. end;
  148.  
  149. procedure init( );
  150. begin
  151.     makeTextures( );
  152.     makeMap( );
  153. end;
  154.  
  155.  
  156. // fixed point byte byte multiply
  157.  
  158. function fxmul( a,b : longint ):longint ;
  159. begin
  160.     result := (a*b) shr 8;
  161. end;
  162.  
  163.  
  164. // fixed point 8bit packed colour multiply
  165. function  rgbmul(a,b : longint ):longint;
  166. var _r,_g,_b : longint;
  167.  
  168.  
  169. begin
  170.     _r := (((a>>16) and $ff) * b) >> 8;
  171.     _g := (((a>> 8) and $ff) * b) >> 8;
  172.     _b := (((a    ) and $ff) * b) >> 8;
  173.     result := (_r<<16) or (_g<<8) or _b;
  174. end;
  175.  
  176.  
  177.  
  178. procedure render(  );
  179. var
  180.    now,xRot,yRot,yCos,
  181.    ySin,xCos,xSin,___xd,
  182.    __yd,__zd,___zd,_yd,
  183.     _xd,_zd,ddist,closest,
  184.     ox,oy,oz,dimLength,ll,
  185.     xd,yd,zd,initial,dist,
  186.     xp,yp,zp: single;
  187.     d,x,y ,col,br,tex,u,v,cc: longint;
  188. begin
  189.   now := (SDL_GetTicks( ) mod 10000) / 10000;
  190.   xRot := sin(now * pi * 2) * 0.4 + pi / 2;
  191.   yRot := cos(now * pi * 2) * 0.4;
  192.   yCos := cos(yRot);
  193.   ySin := sin(yRot);
  194.   xCos := cos(xRot);
  195.   xSin := sin(xRot);
  196.   ox := 32.5 + now * 64.0;
  197.   oy := 32.5;
  198.   oz := 32.5;
  199.  
  200.   // for each column
  201.   for x :=0 to s_w -1 do begin
  202.       // get the x axis delta
  203.       ___xd := (x - s_w / 2) / s_h;
  204.  
  205.       // for each row
  206.       for y :=0 to s_h-1 do begin
  207.        // get the y axis delta
  208.  
  209.        __yd := (y - s_h / 2) / s_h;
  210.        __zd := 1;
  211.        ___zd :=  __zd * yCos +  __yd * ySin;
  212.        _yd :=  __yd * yCos -  __zd * ySin;
  213.        _xd := ___xd * xCos + ___zd * xSin;
  214.        _zd := ___zd * xCos - ___xd * xSin;
  215.  
  216.        col := 0;
  217.        br := 255;
  218.        ddist := 0;
  219.        closest := 32.0;
  220.  
  221.      // for each principle axis  x,y,z
  222.  
  223.        for d :=0 to 2 do begin
  224.          if (d = 0) then dimLength := _xd
  225.          else if (d = 1) then dimLength := _yd
  226.          else dimLength := _zd;
  227.  
  228.          if dimlength <> 0 then ll := 1.0 / abs(dimLength) else ll := 1;
  229.          xd := _xd * ll;
  230.          yd := _yd * ll;
  231.          zd := _zd * ll;
  232.  
  233. //{$DEFINE FRAC}
  234. {$IFDEF FRAC}
  235.          if (d = 0) then initial := frac(ox)
  236.          else if (d = 1) then initial := frac(oy)
  237.          else initial := frac(oz);
  238. {$ELSE}
  239.          if (d = 0) then initial := ox-trunc(ox)
  240.          else if (d = 1) then initial := oy-trunc(oy)
  241.          else initial := oz-trunc(oz);
  242. {$ENDIF}
  243.  
  244.          if (dimLength > 0.0) then initial := 1 - initial;
  245.          dist := ll * initial;
  246.          xp := ox + xd * initial;
  247.          yp := oy + yd * initial;
  248.          zp := oz + zd * initial;
  249.  
  250.          if (dimLength < 0.0) then begin
  251.           if (d = 0) then xp-=1
  252.           else if (d = 1)then yp-=1
  253.           else if (d = 2)then zp-=1;
  254.          end;
  255.  
  256.  
  257.          // while we are concidering a ray that is still closer then the best so far
  258.          while (dist < closest) do begin
  259.          // quantize to the map grid
  260.            tex := map[ (trunc(zp) and 63),(trunc(yp) and 63),trunc(xp) and 63];
  261.  
  262.            // if this voxel has a texture applied
  263.            if (tex > 0) then begin
  264.            // find the uv coordinates of the intersection point
  265.              u := (round((xp + zp) * 16)) and 15;
  266.              v := (round(yp        * 16)  and 15) + 16;
  267.            // fix uvs for alternate directions?
  268.  
  269.            if d=1 then begin
  270.              u :=  (round(xp * 16)) and 15;
  271.              v := ((round(zp * 16)) and 15);
  272.              if (yd < 0.0) then
  273.                v += 32;
  274.            end;
  275.  
  276.            //find the colour at the intersection point
  277.            cc := texmap[u, v, tex];
  278.            // if the colour is not transparent
  279.            if (cc > 0) then begin
  280.              col := cc;
  281.              ddist := 255 - ((dist / 32 * 255));
  282.              br :=  255 - ((d + 2) mod 3) * 50;
  283.              //we now have the closest hit point (also terminates this ray)
  284.              closest := dist;
  285.            end;
  286.          end;
  287.         // advance the ray
  288.  
  289.          xp += xd;
  290.          yp += yd;
  291.          zp += zd;
  292.          dist += ll;
  293.        end;
  294.      end;
  295.      plot( x, y, rgbmul( cc, fxmul( br, round(ddist) ) ) );
  296.    end;
  297.  end;
  298. end;
  299.  
  300.  
  301.  
  302. var
  303.     tickf,tickl,fps : longword;
  304.     dif : single;
  305.     count : longword = 0;
  306.  
  307. begin
  308.     SDL_putenv('SDL_VIDEO_CENTERED=1');
  309.     SDL_Init(SDL_INIT_VIDEO);
  310.  
  311.  
  312.     screen := SDL_SetVideoMode( s_w, s_h, 32 , SDL_SWSURFACE );
  313.     init();
  314.  
  315.     tickf := SDL_GetTicks();
  316.  
  317.     while not done  do
  318.     begin
  319.  
  320.      dif := (tickl-tickf) / 1000;
  321.  
  322.      if dif >= 1.0  then begin
  323.           tickf := tickl;
  324.           fps := count;
  325.           count := 0;
  326.           SDL_WM_SetCaption(pchar('fps='+inttostr(fps)),nil);
  327.  
  328.      end else begin
  329.  
  330.           inc(count);
  331.  
  332.          end;
  333.  
  334.  
  335.          while  SDL_PollEvent( @event ) > 0  do
  336.             case event.type_  of
  337.             SDL_KEYDOWN:
  338.                 if ( event.key.keysym.sym = SDLK_ESCAPE ) then
  339.                 begin
  340.                   done := true;
  341.                 end;
  342.                 SDL_QUITEV:
  343.                 begin
  344.                   done := true;
  345.                 end;
  346.              end;
  347.            render( );
  348.            SDL_Flip(screen);
  349.            tickl := SDL_GetTicks();
  350.      end;
  351. end.
  352.  
  353.  
  354.  


lainz

  • Hero Member
  • *****
  • Posts: 4468
    • https://lainz.github.io/
Re: SDL vs OpenGL
« Reply #41 on: February 01, 2017, 01:36:00 pm »
For those interested, here is my Java port of the original JavaScript & C versions. Running it as a Applet is untested (to date), so simply compile with "javac Minecraft4k.java" and then run it from a console window "java Minecraft4k". FPS will be written to the console window. I also created two new textures (blocks). Mossy Red Bricks and Mossy Stone. :)

On my PC it run between 26-30 fps.

I run it from the Netbeans IDE, when I run it from the command line it doesn't display the FPS, at least on Windows 10.

Graeme

  • Hero Member
  • *****
  • Posts: 1428
    • Graeme on the web
Re: SDL vs OpenGL
« Reply #42 on: February 01, 2017, 04:07:24 pm »
Quote
         if dimLength < 0.0 then
-          dimLength := -dimLength;
-        ll := 1.0 / dimLength;
+          ll := 1.0 / -dimLength
+        else
+          ll := 1.0 / dimLength;

thats indeed fixed the rendering , but how this can be different?
they looks the same
:) The change does look similar to the original, but it is different. In your code you immediately changed the value of dimLength, thus changing what the result is for ll. If you look at the C or Java code you will see the calculation for ll is done with dimLength yes, but not actually changing the value of the dimLength variable itself.
--
fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal
http://fpgui.sourceforge.net/

Graeme

  • Hero Member
  • *****
  • Posts: 1428
    • Graeme on the web
Re: SDL vs OpenGL
« Reply #43 on: February 01, 2017, 04:25:51 pm »
On my PC it run between 26-30 fps.
On my system it runs faster, and consistently faster than the C version.  The sad thing is, with the Pascal version we are trying all kinds of optimisations and yet still scraping the barrel around 10-15 fps. The C and Java versions unoptimised, runs double the speed of the Pascal version. No matter how you look at it, clearly the Free Pascal compiler is a terrible compiler for game/graphic intensive work - unless you offload everything to the GPU via OpenGL and Shaders.

It would be interesting to see the FPS comparison when the same Pascal code is compiled with the Delphi compiler.
--
fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal
http://fpgui.sourceforge.net/

lainz

  • Hero Member
  • *****
  • Posts: 4468
    • https://lainz.github.io/
Re: SDL vs OpenGL
« Reply #44 on: February 01, 2017, 04:27:26 pm »
On my PC it run between 26-30 fps.
On my system it runs faster, and consistently faster than the C version.  The sad thing is, with the Pascal version we are trying all kinds of optimisations and yet still scraping the barrel around 10-15 fps. The C and Java versions unoptimised, runs double the speed of the Pascal version. No matter how you look at it, clearly the Free Pascal compiler is a terrible compiler for game/graphic intensive work - unless you offload everything to the GPU via OpenGL and Shaders.

It would be interesting to see the FPS comparison when the same Pascal code is compiled with the Delphi compiler.

You're on Linux? I have Windows 10 on i7 4790 3.6 ghz.

 

TinyPortal © 2005-2018