SDL vs OpenGL lazarus / 70-OpenGL ---------------------------------------------------------------------- Graeme · 2017-01-24 19:04 I’ve been reading up on 3D graphics and looking into game engine logic. This brought me to SDL. Could somebody confirm or correct my understanding of SDL+OpenGL. 1) From what I can see from SDL’s website, is that if you combine SDL with OpenGL in a application, you must run the application full- screen? Surely this is not good. 2) I thought SDL is a cross-platform wrapper framework over software rendering, OpenGL and DirectX. But from the sample code I viewed, it seems not to be the case. eg: You still need to call the OpenGL API’s directly in your SDL+OpenGL application. So why bother with SDL then? 3) What exact advantage does SDL actually give (if you decide to use OpenGL graphics acceleration)? Does it  incorporate the other parts like user input, application loop and sound. Though you get OpenAL (family member of OpenGL), so I guess if you use OpenAL with SDL, you will have to call the OpenAL API’s directly too, just like you do for OpenGL. So again, what benefit is there in actually using SDL at all? I guess going the direct route of only using OpenGL and OpenAL seems better, and cuts out one extra dependency. Did I understand this correctly, or am I simply not understanding the point of SDL at all? ---------------------------------------------------------------------- lainz · 2017-01-24 19:41 SDL helps you to code with easy to use functions, you don't need to know OpenGL to use it. But you get the benefit of a hardware accelerated 2D application. Is like you can do with BGRABitmap OpenGL units, is a set of things that helps you to make an OpenGL application, with no coding of OpenGL stuff directly. And yes, it contains input and more stuff. ---------------------------------------------------------------------- mischi · 2017-01-24 19:43 I am not really an expert on SDL and OpenGL, but let me point you to ultrastardx, which uses SDL and OpenGL. Besides that the game window can be scaled to different sizes or blown up to fullScreen I cannot tell much. Maybe you can find some answers by looking at the code. Regarding the choice for SDL, i should mention that the game was started before OpenAL was available. Therefore, it could well be worth to look into OpenAL. MiSchi ---------------------------------------------------------------------- marcov · 2017-01-24 20:15 I assume SDL also acts as a kind of GLUT for OpenGL. i.e. Opengl has very basic primitives and no helpers (e.g. loading a picture must be done by other means) But a lot of that is initial work only, and the dglopengl header has some extra supporting features for e.g. opengl profile initialization. An overview of my opengl work is in the signed distance font topic. ---------------------------------------------------------------------- skalogryz · 2017-01-24 20:27 Quote from: Graeme on January 24, 2017, 08:04:29 pm1) From what I can see from SDL’s website, is that if you combine SDL with OpenGL in a application, you must run the application full-screen? Where did you find it? Making OpenGL itself is not bound to being full-screen or windowed. Quote from: Graeme on January 24, 2017, 08:04:29 pm2) I thought SDL is a cross-platform wrapper framework over software rendering, OpenGL and DirectX. But from the sample code I viewed, it seems not to be the case. eg: You still need to call the OpenGL API’s directly in your SDL+OpenGL application. So why bother with SDL then? (btw, you want to add OpenGLES to that list too.) SDL itself provides wrappers to easily initialize the rendering. It also provides some wrappers to draw 2d graphics. None 3d graphics at all. Thus if you'd need a 3d you'll need to make GL api calls yourself. Quote from: Graeme on January 24, 2017, 08:04:29 pm3) What exact advantage does SDL actually give (if you decide to use OpenGL graphics acceleration)? Does it  incorporate the other parts like user input, application loop and sound. It does handles user input loop and sound. Though for sound I'd recommend to use SDL_Mixer. (SDL extension). Quote from: Graeme on January 24, 2017, 08:04:29 pmThough you get OpenAL (family member of OpenGL), so I guess if you use OpenAL with SDL, you will have to call the OpenAL API’s directly too, just like you do for OpenGL. No. OpenAL, is not a family member of OpenGL. Despite of the fashioned "Open" prefix. SDL as well might be using more system native APIs (i.e. DirectSound) rather than OpenAL. No direct calls to OpenAL (or underlying sound api) are needed. Quote from: Graeme on January 24, 2017, 08:04:29 pmSo again, what benefit is there in actually using SDL at all? It safes a lot of time dealing with system specific routines (loop, input, rendering,audio). SDL extensions also help you to load both different Image file formats as well as Audio file formats. Neither OpenGL nor OpenAL have any functionality to do that, they only expect raw data (scan lines of pixels or uncompressed wave forms) ---------------------------------------------------------------------- Graeme · 2017-01-24 20:35 Thanks for the info thus far. So from what I can deduce is that GLUT is a “helper library” for extra things that OpenGL doesn’t do directly. OpenGL is only graphics rendering. As for SDL. I guess I was under the wrong impression of what it does. I thought it would automatically select the best rendering option available on my system. I looked at an SDL sample that renders a 320x200 animation - a 3D looking tunnel effect. Flying though a tunnel made out of boxes. It was very smooth, and used raycasting from what I can see. I then modified the demo to run at 800x600 and it became choppy as hell. So clearly everything was done via software rendering (via the CPU) and no hardware acceleration (GPU). This is where I’m getting confused about SDL. I thought there is some switch or parameter I can pass the initialization API call to tell it to use hardware acceleration. But from the SDL+OpenGL examples I could find (not the flying box tunnel I referred to earlier), they all seem to initialize and use OpenGL via actual OpenGL APIs - not SDL API. Yet it is a sdl application. Here is a simple snippet of SDL+OpenGL I found Code: C++  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i     /* This makes our buffer swap syncronized with the monitor’s vertical refresh */    SDL_GL_SetSwapInterval(1);     /* Clear our buffer with a red background */    glClearColor ( 1.0, 0.0, 0.0, 1.0 );    glClear ( GL_COLOR_BUFFER_BIT );    /* Swap our back buffer to the front */    SDL_GL_SwapWindow(mainwindow);  The first and last API calls are clearly SDL ones. But the “what to render” code is pure OpenGL API calls. Maybe the examples I’m looking at are bad ones. I’ll keep searching the net. ---------------------------------------------------------------------- Graeme · 2017-01-24 20:43 Quote from: skalogryz on January 24, 2017, 09:27:15 pmQuote from: Graeme on January 24, 2017, 08:04:29 pm1) From what I can see from SDL’s website, is that if you combine SDL with OpenGL in a application, you must run the application full-screen? Where did you find it? Making OpenGL itself is not bound to being full-screen or windowed. I’ll try and find that information again. But I remember clearly reading that if you use SDL+OpenGL on a X11 system (Linux, FreeBSD etc) then the application needs to be fullscreen, otherwise hardware acceleration doesn’t work. I thought this weird though, because the well known glxgears demo included with many X11 systems run hardware accelerated in a window. QuoteIt safes a lot of time dealing with system specific routines (loop, input, rendering,audio). SDL extensions also help you to load both different Image file formats as well as Audio file formats. Ah, okay. Many thanks for all the very useful information. I’ll keep exploring with SDL and see how it goes. ---------------------------------------------------------------------- Graeme · 2017-01-24 20:45 By the way, is GLU (OpenGL Utilitilies) and GLUT the same thing? ---------------------------------------------------------------------- skalogryz · 2017-01-24 20:46 Quote from: Graeme on January 24, 2017, 09:35:11 pmThe first and last API calls are clearly SDL ones. But the “what to render” code is pure OpenGL API calls. Yet again, for 3d - you'll have to use OpenGL calls, since SDL doesn't provide any counterparts. For 2d, you can easily go with SDL only and achieve results like this: ---------------------------------------------------------------------- skalogryz · 2017-01-24 20:48 Quote from: Graeme on January 24, 2017, 09:45:13 pmBy the way, is GLU (OpenGL Utilitilies) and GLUT the same thing? No ---------------------------------------------------------------------- Graeme · 2017-01-24 21:08 @skalogryz: Many thanks for that link explaining all the terms. That was super useful! ---------------------------------------------------------------------- skalogryz · 2017-01-24 21:12 Quote from: Graeme on January 24, 2017, 09:35:11 pmI then modified the demo to run at 800x600 and it became choppy as hell. So clearly everything was done via software rendering (via the CPU) and no hardware acceleration (GPU).Maybe you don't have proper drivers? or it might be a conflict in Windows, where you need to have (or instead not to have) the manifest. ---------------------------------------------------------------------- jmpessoa · 2017-01-24 21:12 About: http://www.freepascal-meets-sdl.net/ ---------------------------------------------------------------------- lainz · 2017-01-24 21:24 Quote from: skalogryz on January 24, 2017, 10:12:22 pmQuote from: Graeme on January 24, 2017, 09:35:11 pmI then modified the demo to run at 800x600 and it became choppy as hell. So clearly everything was done via software rendering (via the CPU) and no hardware acceleration (GPU).Maybe you don't have proper drivers? or it might be a conflict in Windows, where you need to have (or instead not to have) the manifest. SDL has both software and hardware, maybe the demo is for software only. ---------------------------------------------------------------------- skalogryz · 2017-01-24 21:48 Quote from: lainz on January 24, 2017, 10:24:59 pmSDL has both software and hardware, maybe the demo is for software only. I seriously doubt that OpenGL functions called are declared in SDL headers. Whenever an opengl routine is called, they are executed by the system. The only issue with SDL that could be - it failed to find hardware accelerated descriptor. However, Windows itself might cause the issue, because of the manifest settings and it might prevent an application from getting the hardware accelerated interface. ---------------------------------------------------------------------- lainz · 2017-01-24 21:58 QuoteI looked at an SDL sample that renders a 320x200 animation... Who one does a so small demo window that can be hardware accelerated BTW  According to this website http://lazyfoo.net/tutorials/SDL/index.php There's as I said software and hardware in SDL. Hardware is 'new' "A big new feature in SDL 2.0 is hardware accelerated texture based 2D rendering. Here we'll be loading an image to render it using textures." Issues with the drivers can be as said, I have these kind of problems with nvidia cards in the past. ---------------------------------------------------------------------- Graeme · 2017-01-25 09:11 Quote from: skalogryz on January 24, 2017, 10:12:22 pmMaybe you don't have proper drivers? or it might be a conflict in Windows, where you need to have (or instead not to have) the manifest. No, it's not the drivers. I have OpenGL 4.5 support (via proprietary NVIDIA drivers) on my FreeBSD system, and other OpenGL applications and demos run fine. Having a better understanding of SDL+OpenGL now, after all these discussions, I realised the SDL box tunnel demo was implemented in pure software rendering. Hence it doesn't scale well to higher resolutions. Just goes to show what an amazing job GPU's do! Other complex demos run on my system at 2560x1440 resolution without skipping a beat. ---------------------------------------------------------------------- Graeme · 2017-01-25 09:13 Quote from: jmpessoa on January 24, 2017, 10:12:54 pmhttp://www.freepascal-meets-sdl.net/ Thank you for that link. ---------------------------------------------------------------------- Graeme · 2017-01-25 09:22 Quote from: skalogryz on January 24, 2017, 10:48:21 pmI seriously doubt that OpenGL functions called are declared in SDL headers. Whenever an opengl routine is called, they are executed by the system. Like I mentioned 2 or 3 replies ago... now that I know a bit more about SDL and OpenGL and how they work together, I can clearly see that the demo I was trying out, is implemented as a pure software renderer. No OpenGL is used at all. Here is the code if you wanted to see.   http://pastebin.com/jfjqAas8 ---------------------------------------------------------------------- Graeme · 2017-01-25 09:33 Quote from: lainz on January 24, 2017, 10:58:42 pmQuoteI looked at an SDL sample that renders a 320x200 animation... Who one does a so small demo window that can be hardware accelerated BTW  That's true. That should have been a dead give away. ps:   I managed to create a 3D looking first person shooter type game engine, using software raycasting and low fidelity graphics. Internally it is low res, and then scaled 4x to 856x480. Amazingly I get  about 120fps on average. But as soon as I enable higher fidelity graphics and scale 2x or no scaling at all, but still running it at 856x480, then my frame rate drops to about 20fps.  To take this project further, I guess its time I look into hardware acceleration. ---------------------------------------------------------------------- airpas · 2017-01-28 07:56 by curiosity i translated the c example to pascal just to see the difference of speed between fpc and gcc , well the difference is so big , gcc is 6x faster than fpc . or maybe my translation needs some tweaking my translation  Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program test;{$ifdef FPC}{$mode objfpc}{$h+}{$endif}{$ifdef mswindows}{$apptype gui}{$endif}uses  sdl, math;type        p32Array = ^u32Array;        u32Array = array[0..0] of int32; const  s_w = 640;  s_h = 400;  math_pi = 3.14159265359; var  event : TSDL_Event;  done : boolean = false;  screen : PSDL_Surface;  texmap : array[0..12287] of int32;  map : array[0..262143] of smallint; procedure  plot(x,y,c : int32)inline;begin  p32Array(screen^.pixels)^[y*s_w+x] := c;end; function inttostr(v : integer): ansistring;begin  str(v,result);end; procedure makeTextures();var   j,m,k,i1,i2,i3,n : int32;begin     // each texture    for j:=0 to 15 do begin         k := 255 - random(96);         // each pixel in the texture        for m:=0  to (16 * 3)-1 do            for n :=0 to 15 do begin               i1 := $966C4A;                i2 := 0;                i3 := 0;               if (j = 4) then                    i1 := $7F7F7F;              if ((j <> 4) or (random(3) = 0)) then                    k := 255 - random(96);                if ( j = 1 ) then                begin                    if (m < (((n * n * 3 + n * 81) >> 2) and $3) + 18) then                        i1 := $6AAA40                    else if (m < (((n * n * 3 + n * 81) >> 2) and $3) + 19) then                      k := k * 2 div 3;                end;                if (j = 7) then                begin                    i1 := $675231;                  if ((n > 0) and (n < 15) and (((m > 0) and (m < 15)) or ((m > 32) and (m < 47)))) then                    begin                      i1 := $BC9862;                        i2 := n - 7;                      i3 := (m and $F) - 7;                        if (i2 < 0.0) then                            i2 := 1 - i2;                       if (i3 < 0.0) then                            i3 := 1 - i3;                       if (i3 > i2) then                            i2 := i3;                         k := 196 - random(32) + i2 mod 3 * 32;                  end                    else if (random(2) = 0) then                      k := k * (150 - (n and $1) * 100) div 100;              end;                if (j = 5) then                begin                  i1 := $B53A15;                    if (((n + m div 4 * 4) mod 8 = 0) or (m mod 4 = 0)) then                        i1 := $BCAFA5;                end;                i2 := k;                if (m >= 32) then                    i2 := i2 div 2;                if (j = 8) then                begin                    i1 := 5298487;                  if (random(2) = 0) then                    begin                      i1 := 0;                        i2 := 255;                  end;                end;                 // fixed point colour multiply between i1 and i2                i3 :=                    ((((i1 >> 16) and $FF) * i2 div 255) << 16) or                    ((((i1 >>  8) and $FF) * i2 div 255) <<  8) or                      ((i1        and $FF) * i2 div 255);                // pack the colour away                texmap[ n + m * 16 + j * 256 * 3 ] := i3;          end;    end;end; procedure makeMap( ) ;var x,y,z,i : longword;    yd,zd,th : single;begin    // add random blocks to the map    for x := 0 to 63 do begin        for y := 0 to 63 do begin             for z := 0 to 63 do begin                i := (z << 12) or (y << 6) or x;             yd := (y - 32.5) * 0.4;               zd := (z - 32.5) * 0.4;               map[i] := random( 16 );               th := random( 256 ) / 256.0;               if (th > sqrt( sqrt( yd * yd + zd * zd ) ) - 0.8) then                 map[i] := 0;              end;        end;  end;end; procedure init( );begin    makeTextures( );    makeMap( );end; // fixed point byte byte multiplyfunction fxmul( a,b : int32 ):int32 ; inline;begin    result := (a*b)>>8;end; // fixed point 8bit packed colour multiplyfunction  rgbmul(a,b : int32 ):int32;var _r,_g,_b : int32;begin    _r := (((a>>16) and $ff) * b) >> 8;    _g := (((a>> 8) and $ff) * b) >> 8;    _b := (((a    ) and $ff) * b) >> 8;  result := (_r<<16) or (_g<<8) or _b;end;  procedure render(  );var   now,xRot,yRot,yCos,   ySin,xCos,xSin,___xd,   __yd,__zd,___zd,_yd,  _xd,_zd,ddist,closest,    ox,oy,oz,dimLength,ll,    xd,yd,zd,initial,dist,    xp,yp,zp: single;   x,y ,col,br,d,tex,u,v,cc: longword;begin        now := (SDL_GetTicks( ) mod 10000) / 10000;         xRot := sin(now * math_pi * 2) * 0.4 + math_pi / 2;        yRot := cos(now * math_pi * 2) * 0.4;        yCos := cos(yRot);        ySin := sin(yRot);        xCos := cos(xRot);      xSin := sin(xRot);         ox := 32.5 + now * 64.0;        oy := 32.5;        oz := 32.5;         // for each column        for x :=0 to s_w -1 do begin                // get the x axis delta              ___xd := (x - s_w / 2) / s_h;                // for each row              for y :=0 to s_h-1 do begin                        // get the y axis delta                        __yd := (y - s_h / 2) / s_h;                      __zd := 1;                        ___zd :=  __zd * yCos +  __yd * ySin;                        _yd :=  __yd * yCos -  __zd * ySin;                        _xd := ___xd * xCos + ___zd * xSin;                      _zd := ___zd * xCos - ___xd * xSin;                       col := 0;                        br := 255;                      ddist := 0;                         closest := 32.0;                       // for each principle axis  x,y,z                        for d :=0 to 2 do begin                          dimLength := _xd;                        if (d = 1) then                            dimLength := _yd;                          if (d = 2) then                          dimLength := _zd;                          if dimLength < 0.0 then                          dimLength := -dimLength;                        ll := 1.0 / dimLength;                          xd := _xd * ll;                        yd := _yd * ll;                          zd := _zd * ll;                           initial := ox - floor(ox);                        if (d = 1) then initial := oy - floor(oy);                        if (d = 2) then initial := oz - floor(oz);                         if (dimLength > 0.0) then initial := 1 - initial;                         dist := ll * initial;                           xp := ox + xd * initial;                          yp := oy + yd * initial;                        zp := oz + zd * initial;                         if (dimLength < 0.0) then begin                           if (d = 0)then xp-=1;                           if (d = 1)then yp-=1;                         if (d = 2)then zp-=1;                          end;                           // while we are concidering a ray that is still closer then the best so far                          while (dist < closest) do begin                          // quantize to the map grid                            tex := map[ ((trunc(zp) and 63) << 12) or ((trunc(yp) and 63) << 6) or (trunc(xp) and 63) ];                           // if this voxel has a texture applied                          if (tex > 0) then begin                            // find the uv coordinates of the intersection point                              u := (round((xp + zp) * 16)) and 15;                              v := (round(yp        * 16)  and 15) + 16;                             // fix uvs for alternate directions?                            if (d = 1) then begin                              u :=  (round(xp * 16)) and 15;                              v := ((round(zp * 16)) and 15);                            if (yd < 0.0) then                              v += 32;                            end;                           //find the colour at the intersection point                          cc := texmap[ u + v * 16 + tex * 256 * 3 ];                          // if the colour is not transparent                            if (cc > 0) then begin                              col := cc;                            ddist := 255 - ((dist / 32 * 255));                            br := 255 * (255 - ((d + 2) mod 3) * 50) div 255;                            //we now have the closest hit point (also terminates this ray)                              closest := dist;                          end;                          end;                         // advance the ray                        xp += xd;                      yp += yd;                        zp += zd;                      dist += ll;                    end;                end;             plot( x, y, rgbmul( col, fxmul( br, round(ddist) ) ) );        end;  end;end; var    tickf,tickl,fps : longword;    dif : single;    count : longword = 0;begin    SDL_putenv('SDL_VIDEO_CENTERED=1');    SDL_Init(SDL_INIT_VIDEO);     screen := SDL_SetVideoMode( s_w, s_h, 32 , SDL_SWSURFACE );    init();    tickf := SDL_GetTicks();    while not done  do    begin     dif := (tickl-tickf) / 1000;     if dif >= 1.0  then begin          tickf := tickl;          fps := count;          count := 0;          SDL_WM_SetCaption(pchar('fps='+inttostr(fps)),nil);     end else begin          inc(count);         end;         while  SDL_PollEvent( @event ) > 0  do            case event.type_  of            SDL_KEYDOWN:                if ( event.key.keysym.sym = SDLK_ESCAPE ) then                begin                  done := true;              end;                SDL_QUITEV:                begin                done := true;                end;             end;           render( );           SDL_Flip(screen);           tickl := SDL_GetTicks();     end;end.   c version with fps cout Code: C  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i // C++ port of Minecraft 4k JS (http://jsdo.it/notch/dB1E)// By The8BitPimp// See: the8bitpimp.wordpress.com #define _SDL_main_h#include  #include  const int w = 640;const int h = 400; SDL_Surface *screen ; const float math_pi = 3.14159265359f; static inline float math_sin( float x ) {    return sinf( x );} static inline float math_cos( float x ) {    return cosf( x );} // the texture mapint texmap[ 16 * 16 * 16 * 3 ]; // the voxel mapchar map[ 64 * 64 * 64 ]; static inline int random( int max ) {    return (rand()^(rand()<<16)) % max;} static inline void plot( int x, int y, int c ) {    int *p = (int*) screen->pixels;    p[ y * w + x ] = c;} static void makeTextures( void ) {     // each texture    for ( int j=0; j<16; j++ ) {         int k = 255 - random(96);         // each pixel in the texture        for ( int m=0; m<16 * 3; m++ )            for ( int n = 0; n<16; n++ ) {               int i1 = 0x966C4A;                int i2 = 0;              int i3 = 0;                 if (j == 4)                    i1 = 0x7F7F7F;                if ((j != 4) || (random(3) == 0))                  k = 255 - random(96);                if ( j == 1 )              {                    if (m < (((n * n * 3 + n * 81) >> 2) & 0x3) + 18)                        i1 = 0x6AAA40;                    else if (m < (((n * n * 3 + n * 81) >> 2) & 0x3) + 19)                        k = k * 2 / 3;                }                if (j == 7)              {                    i1 = 0x675231;                    if ((n > 0) && (n < 15) && (((m > 0) && (m < 15)) || ((m > 32) && (m < 47))))                  {                        i1 = 0xBC9862;                      i2 = n - 7;                        i3 = (m & 0xF) - 7;                      if (i2 < 0)                            i2 = 1 - i2;                       if (i3 < 0)                            i3 = 1 - i3;                         if (i3 > i2)                            i2 = i3;                         k = 196 - random(32) + i2 % 3 * 32;                  }                    else if (random(2) == 0)                      k = k * (150 - (n & 0x1) * 100) / 100;                }              if (j == 5)                {                    i1 = 0xB53A15;                    if (((n + m / 4 * 4) % 8 == 0) || (m % 4 == 0))                        i1 = 0xBCAFA5;                }              i2 = k;                if (m >= 32)                    i2 /= 2;                if (j == 8)                {                    i1 = 5298487;                    if (random(2) == 0)                    {                      i1 = 0;                        i2 = 255;                  }                }                 // fixed point colour multiply between i1 and i2                i3 =                    ((((i1 >> 16) & 0xFF) * i2 / 255) << 16) |                    ((((i1 >>  8) & 0xFF) * i2 / 255) <<  8) |                      ((i1        & 0xFF) * i2 / 255);                // pack the colour away              texmap[ n + m * 16 + j * 256 * 3 ] = i3;            }    }} static void makeMap( void ) {    // add random blocks to the map        for ( int x = 0; x < 64; x++) {                for ( int y = 0; y < 64; y++) {                        for ( int z = 0; z < 64; z++) {                              int i = (z << 12) | (y << 6) | x;                              float yd = (y - 32.5) * 0.4;                              float zd = (z - 32.5) * 0.4;                                map[i] = random( 16 );                 float th = random( 256 ) / 256.0f;                               if (th > sqrtf( sqrtf( yd * yd + zd * zd ) ) - 0.8f)                                        map[i] = 0;                      }                }        }} static void init( void ) {    makeTextures( );    makeMap( );} // fixed point byte byte multiplystatic inline int fxmul( int a, int b ) {    return (a*b)>>8;} // fixed point 8bit packed colour multiplystatic inline int rgbmul( int a, int b ) {    int _r = (((a>>16) & 0xff) * b) >> 8;    int _g = (((a>> 8) & 0xff) * b) >> 8;    int _b = (((a    ) & 0xff) * b) >> 8;    return (_r<<16) | (_g<<8) | _b;} static void render( void ) {      float now = (float)(SDL_GetTicks( ) % 10000) / 10000.f;       float xRot = math_sin(now * math_pi * 2) * 0.4 + math_pi / 2;      float yRot = math_cos(now * math_pi * 2) * 0.4;        float yCos = math_cos(yRot);        float ySin = math_sin(yRot);        float xCos = math_cos(xRot);        float xSin = math_sin(xRot);         float ox = 32.5 + now * 64.0;        float oy = 32.5;        float oz = 32.5;         // for each column        for ( int x = 0; x < w; x++) {              // get the x axis delta                float ___xd = ((float)x - (float)w / 2.f) / (float)h;                // for each row              for ( int y = 0; y < h; y++) {                        // get the y axis delta                        float  __yd = ((float)y - (float)h / 2.f) / (float)h;                        float  __zd = 1;                      float ___zd =  __zd * yCos +  __yd * ySin;                      float   _yd =  __yd * yCos -  __zd * ySin;                      float   _xd = ___xd * xCos + ___zd * xSin;                        float   _zd = ___zd * xCos - ___xd * xSin;                         int col = 0;                        int br = 255;                        float ddist = 0;                         float closest = 32.f;                       // for each principle axis  x,y,z                      for ( int d = 0; d < 3; d++) {                                float dimLength = _xd;                                if (d == 1)                                      dimLength = _yd;                              if (d == 2)                                        dimLength = _zd;                                 float ll = 1.0f / (dimLength < 0.f ? -dimLength : dimLength);                                float xd = (_xd) * ll;                                float yd = (_yd) * ll;                              float zd = (_zd) * ll;                               float       initial = ox - floor(ox);                              if (d == 1) initial = oy - floor(oy);                              if (d == 2) initial = oz - floor(oz);                               if (dimLength > 0) initial = 1 - initial;                               float dist = ll * initial;                                 float xp = ox + xd * initial;                                float yp = oy + yd * initial;                                float zp = oz + zd * initial;                                 if (dimLength < 0) {                                      if (d == 0)     xp--;                                      if (d == 1)     yp--;                                      if (d == 2)     zp--;                                }                               // while we are concidering a ray that is still closer then the best so far                                while (dist < closest) {                                         // quantize to the map grid                                        int tex = map[ (((int)zp & 63) << 12) | (((int)yp & 63) << 6) | ((int)xp & 63) ];                                       // if this voxel has a texture applied                                        if (tex > 0) {                                               // find the uv coordinates of the intersection point                                                int u = ((int)((xp + zp) * 16.f)) & 15;                                              int v = ((int) (yp       * 16.f)  & 15) + 16;                                               // fix uvs for alternate directions?                                                if (d == 1) {                                                        u =  ((int)(xp * 16.f)) & 15;                                                      v = (((int)(zp * 16.f)) & 15);                                                      if (yd < 0)                                                              v += 32;                                              }                                                 // find the colour at the intersection point                                              int cc = texmap[ u + v * 16 + tex * 256 * 3 ];                                               // if the colour is not transparent                                                if (cc > 0) {                                                        col = cc;                                                      ddist = 255 - ((dist / 32 * 255));                                                      br = 255 * (255 - ((d + 2) % 3) * 50) / 255;                                                       // we now have the closest hit point (also terminates this ray)                                                      closest = dist;                                              }                                        }                                       // advance the ray                                      xp += xd;                                        yp += yd;                                      zp += zd;                                      dist += ll;                                }                      }             plot( x, y, rgbmul( col, fxmul( br, ddist ) ) );        }    }} int main( void ) {    unsigned int tickf =0 ,tickl = 0,fps = 0;    float dif;    unsigned int count = 0;    char buf[32];     SDL_Init( SDL_INIT_VIDEO );    screen = SDL_SetVideoMode( w, h, 32, 0 );    if ( screen == NULL )        return -1;    init( );    bool running = true;    tickf = SDL_GetTicks();    while ( running ) {     dif = (tickl-tickf) / 1000;      if (dif >= 1.0f ){        tickf = tickl;        fps = count;        count = 0;        sprintf(buf,"fps=%d",fps);        SDL_WM_SetCaption(buf,NULL);      } else {        count++;      };        SDL_Event event;        while ( SDL_PollEvent( &event ) ) {            running &= (event.type != SDL_QUIT);        }        render( );        SDL_Flip( screen );      tickl = SDL_GetTicks();    }    return 0;} ---------------------------------------------------------------------- Thaddy · 2017-01-28 08:12 - use the cmem memory manager. (faster - in this case -) - When C uses pointer access, do the same in pascal :$pointermath on - use sincos, not sin and cos. (that also goes for the idiot that wrote the C code: he's fired as well... ) - pascal is slow with string output other than shortstring. use shortstring or use PChars. It should be possible to have about parity in speed with this code (the compiler is in THIS case certainly capable of generating similar code to a C compiler) but you rely on too many high level pascal constructs compared to C. Use low level Pascal constructs: they are all there.... So the comparison is not fair at all. ---------------------------------------------------------------------- airpas · 2017-01-28 10:12 if you mean high level pascal is the string addition in the line 293 , this code is executed every 1 second , i don't think this would slow down the fps . the speed is still the same , maybe because fpc is still weak on vectorization  ,gcc is stronger in this area . the options used is  fpc(-O4 -Cfsse2) gcc(-O3 -msse -mfpmath=sse) , compiler versions fpc trunk , gcc 6.2 ---------------------------------------------------------------------- marcov · 2017-01-28 13:21 Quote from: airpas on January 28, 2017, 08:56:45 amby curiosity i translated the c example to pascal just to see the difference of speed between fpc and gcc , well the difference is so big , gcc is 6x faster than fpc . or maybe my translation needs some tweaking Never benchmark code with "random()" in it. It is known slow (but good quality) in FPC. Fill a block of memory with random values, and use that block within the loop. ---------------------------------------------------------------------- lainz · 2017-01-28 16:38 Please if you have time try again with the suggestions given. If FPC is still slower well there's always something to improve. What I like of this is that the comparison is between two working projects (not tested but it seems). Not only testing a specific function or procedure. ---------------------------------------------------------------------- marcov · 2017-01-28 17:20 Quote from: airpas on January 28, 2017, 11:12:54 ammaybe because fpc is still weak on vectorization  Non existent is a better word. But maybe you can disable vectorization in gcc to get an idea? ---------------------------------------------------------------------- Graeme · 2017-01-31 00:45 Quote from: airpas on January 28, 2017, 08:56:45 amby curiosity i translated the c example to pascal just to see the difference of speed between fpc and gcc , well the difference is so big , gcc is 6x faster than fpc . or maybe my translation needs some tweaking On my Intel i7 I get 10 fps which is pretty sad indeed.   Then a few seconds later I get a core dump (due to floating point exception). ---------------------------------------------------------------------- Graeme · 2017-01-31 10:02 Attached are slightly tweaked versions of the code airpas posted. This gives both a better "tunnel" effect. Sad thing is, this kills the Pascal+SDL version even more. On my i7 3770K @ 3.5GHz the Pascal version gives avg 8 fps and the C version gives avg 30 fps. Using the cmem memory manager with the Pascal version, simply gained 2 fps (from 6 fps before to 8 fps afterwards). As for the comment regarding the usage of Random() and it being slow in Free Pascal. That has no bearing on the fps because Random() is only used while generating the textures and the voxel map. Random() is not used during the gameloop and the raycasting. The comment regarding string functionality being slow. Again, that has no bearing on the performance, as the only string functionality is generating the window title that contains the FPS count, and that is only executed once per second - unlike the raycasting code that is many times per second. I also tried FPC 2.6.4 ,3.0.0 and 3.0.1 and they all yielded the same result. Clearly Free Pascal is a bad choice for game development. We all know (as fact - mentioned many times is the mailing lists over the years) that FPC's goal is code maintainability and portability. Performance has always been a distant 3rd and a "nice to have" if anybody with skills has the time. Maybe Delphi will be a better fit as it is tweaking for performance too, but then you obviously loose portability. [EDIT]   On a side note: For those that still think Java is slow.... how wrong you are. The exact   same tunnel demo in Java runs at 32-36 fps on my system. That's more than double the   speed of the C+SDL version!! [EDIT #2]   Applied the if..else minor optimisation change for the d =1 and d=2 test. The code samples below   reflect that change. The Pascal version: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {  Compile with:      fpc -O3 -Cfsse3 -Xs -ominecraft4k_sdl_fpc Minecraft4k_SDL.pas}program test;  {$mode objfpc}{$h+}  {$ifdef mswindows}    {$apptype gui}  {$endif}uses  cmem,  sdl,  math;   type        p32Array = ^u32Array;        u32Array = array[0..0] of int32; const  s_w = 640;  s_h = 400;  math_pi = 3.14159265359; var  event : TSDL_Event;  done : boolean = false;  screen : PSDL_Surface;  texmap : array[0..12287] of int32;  map : array[0..262143] of smallint; procedure  plot(x,y,c : int32)inline;begin  p32Array(screen^.pixels)^[y*s_w+x] := c;end; function inttostr(v : integer): ansistring;begin  str(v,result);end; procedure makeTextures();var   j,m,k,i1,i2,i3,n : int32;begin     // each texture    for j:=0 to 15 do begin         k := 255 - random(96);       // each pixel in the texture        for m:=0  to (16 * 3)-1 do          for n :=0 to 15 do begin                 i1 := $966C4A;              i2 := 0;                i3 := 0;                 if (j = 4) then                    i1 := $7F7F7F;                if ((j <> 4) or (random(3) = 0)) then                    k := 255 - random(96);              if ( j = 1 ) then                begin                    if (m < (((n * n * 3 + n * 81) >> 2) and $3) + 18) then                      i1 := $6AAA40                    else if (m < (((n * n * 3 + n * 81) >> 2) and $3) + 19) then                        k := k * 2 div 3;                end;                if (j = 7) then                begin                    i1 := $675231;                    if ((n > 0) and (n < 15) and (((m > 0) and (m < 15)) or ((m > 32) and (m < 47)))) then                    begin                        i1 := $BC9862;                      i2 := n - 7;                        i3 := (m and $F) - 7;                        if (i2 < 0.0) then                          i2 := 1 - i2;                         if (i3 < 0.0) then                          i3 := 1 - i3;                         if (i3 > i2) then                            i2 := i3;                         k := 196 - random(32) + i2 mod 3 * 32;                    end                  else if (random(2) = 0) then                        k := k * (150 - (n and $1) * 100) div 100;                end;                if (j = 5) then                begin                    i1 := $B53A15;                  if (((n + m div 4 * 4) mod 8 = 0) or (m mod 4 = 0)) then                        i1 := $BCAFA5;                end;              i2 := k;                if (m >= 32) then                    i2 := i2 div 2;                if (j = 8) then                begin                  i1 := 5298487;                    if (random(2) = 0) then                  begin                        i1 := 0;                      i2 := 255;                    end;                end;               // fixed point colour multiply between i1 and i2                i3 :=                    ((((i1 >> 16) and $FF) * i2 div 255) << 16) or                  ((((i1 >>  8) and $FF) * i2 div 255) <<  8) or                    ((i1        and $FF) * i2 div 255);                // pack the colour away                texmap[ n + m * 16 + j * 256 * 3 ] := i3;            end;    end;end; procedure makeMap( ) ;var x,y,z,i : longword;    yd,zd,th : single;begin    // add random blocks to the map    for x := 0 to 63 do begin        for y := 0 to 63 do begin           for z := 0 to 63 do begin                i := (z << 12) or (y << 6) or x;               yd := (y - 32.5) * 0.4;               zd := (z - 32.5) * 0.4;               map[i] := random( 16 );               th := random( 256 ) / 256.0;               if (th > sqrt( sqrt( yd * yd + zd * zd ) ) - 0.8) or (th < 0.5) then                 map[i] := 0;              end;        end;    end;end; procedure init( );begin  makeTextures( );    makeMap( );end; // fixed point byte byte multiplyfunction fxmul( a,b : int32 ):int32 ; inline;begin    result := (a*b)>>8;end; // fixed point 8bit packed colour multiplyfunction  rgbmul(a,b : int32 ):int32;var _r,_g,_b : int32;begin    _r := (((a>>16) and $ff) * b) >> 8;    _g := (((a>> 8) and $ff) * b) >> 8;  _b := (((a    ) and $ff) * b) >> 8;    result := (_r<<16) or (_g<<8) or _b;end;  procedure render(  );var   now,xRot,yRot,yCos,   ySin,xCos,xSin,___xd,   __yd,__zd,___zd,_yd,    _xd,_zd,ddist,closest,    ox,oy,oz,dimLength,ll,    xd,yd,zd,initial,dist,    xp,yp,zp: single;   x,y ,col,br,d,tex,u,v,cc: longword;begin        now := (SDL_GetTicks( ) mod 10000) / 10000;         xRot := sin(now * math_pi * 2) * 0.4 + math_pi / 2;        yRot := cos(now * math_pi * 2) * 0.4;        yCos := cos(yRot);        ySin := sin(yRot);        xCos := cos(xRot);      xSin := sin(xRot);         ox := 32.5 + now * 64.0;        oy := 32.5;        oz := 32.5;         // for each column        for x :=0 to s_w -1 do begin                // get the x axis delta              ___xd := (x - s_w / 2) / s_h;                // for each row              for y :=0 to s_h-1 do begin                        // get the y axis delta                        __yd := (y - s_h / 2) / s_h;                      __zd := 1;                        ___zd :=  __zd * yCos +  __yd * ySin;                        _yd :=  __yd * yCos -  __zd * ySin;                        _xd := ___xd * xCos + ___zd * xSin;                      _zd := ___zd * xCos - ___xd * xSin;                       col := 0;                        br := 255;                      ddist := 0;                         closest := 32.0;                       // for each principle axis  x,y,z                        for d :=0 to 2 do begin                          dimLength := _xd;                        if (d = 1) then                            dimLength := _yd                          else if (d = 2) then                          dimLength := _zd;                          if dimLength < 0.0 then                            dimLength := -dimLength;                        ll := 1.0 / dimLength;                          xd := _xd * ll;                          yd := _yd * ll;                          zd := _zd * ll;                           initial := ox - floor(ox);                        if (d = 1) then initial := oy - floor(oy);                        if (d = 2) then initial := oz - floor(oz);                         if (dimLength > 0.0) then initial := 1 - initial;                         dist := ll * initial;                         xp := ox + xd * initial;                          yp := oy + yd * initial;                          zp := oz + zd * initial;                         if (dimLength < 0.0) then begin                         if (d = 0)then xp-=1;                           if (d = 1)then yp-=1;                           if (d = 2)then zp-=1;                        end;                           // while we are concidering a ray that is still closer then the best so far                        while (dist < closest) do begin                          // quantize to the map grid                            tex := map[ ((trunc(zp) and 63) << 12) or ((trunc(yp) and 63) << 6) or (trunc(xp) and 63) ];                           // if this voxel has a texture applied                          if (tex > 0) then begin                            // find the uv coordinates of the intersection point                            u := (round((xp + zp) * 16)) and 15;                            v := (round(yp        * 16)  and 15) + 16;                           // fix uvs for alternate directions?                            if (d = 1) then begin                              u :=  (round(xp * 16)) and 15;                              v := ((round(zp * 16)) and 15);                            if (yd < 0.0) then                              v += 32;                            end;                           //find the colour at the intersection point                          cc := texmap[ u + v * 16 + tex * 256 * 3 ];                          // if the colour is not transparent                            if (cc > 0) then begin                              col := cc;                            ddist := 255 - ((dist / 32 * 255));                            br := 255 * (255 - ((d + 2) mod 3) * 50) div 255;                            //we now have the closest hit point (also terminates this ray)                              closest := dist;                          end;                          end;                       // advance the ray                        xp += xd;                      yp += yd;                        zp += zd;                      dist += ll;                    end;                end;           plot( x, y, rgbmul( col, fxmul( br, round(ddist) ) ) );        end;    end;end; var    tickf,tickl,fps : longword;    dif : single;  count : longword = 0;begin    SDL_putenv('SDL_VIDEO_CENTERED=1');    SDL_Init(SDL_INIT_VIDEO);     screen := SDL_SetVideoMode( s_w, s_h, 32 , SDL_SWSURFACE );    init();    tickf := SDL_GetTicks();    while not done  do    begin     dif := (tickl-tickf) / 1000;     if dif >= 1.0  then begin          tickf := tickl;          fps := count;          count := 0;          SDL_WM_SetCaption(pchar('fps='+inttostr(fps)),nil);     end else begin          inc(count);         end;         while  SDL_PollEvent( @event ) > 0  do            case event.type_  of            SDL_KEYDOWN:                if ( event.key.keysym.sym = SDLK_ESCAPE ) then                begin                  done := true;              end;                SDL_QUITEV:                begin                done := true;                end;             end;           render( );           SDL_Flip(screen);           tickl := SDL_GetTicks();     end;end.  And the C version: Code: C  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i // C++ port of Minecraft 4k JS (http://jsdo.it/notch/dB1E)// By The8BitPimp// See: the8bitpimp.wordpress.com // Compile as follows://   $ gcc -I/usr/include -I/usr/local/include/SDL -L/usr/local/lib -L/usr/lib -lm -lSDL -O3 -msse -mfpmath=sse -o minecraft4k_sdl_with_fps Minecraft4k_SDL.cpp  #include #include #include "SDL/SDL.h" // All SDL apps need this const int w = 640;const int h = 400; SDL_Surface *screen = NULL; const float math_pi = 3.14159265359f; static inline float math_sin( float x ) {  return sinf( x );} static inline float math_cos( float x ) {  return cosf( x );} // the texture mapint texmap[ 16 * 16 * 16 * 3 ]; // the voxel mapchar map[ 64 * 64 * 64 ]; static inline int random( int max ) {  return (rand()^(rand()<<16)) % max;} static inline void plot( int x, int y, int c ) {  int *p = (int*) screen->pixels;  p[ y * w + x ] = c;} static void makeTextures( void ) {   // each texture  for ( int j=0; j<16; j++ ) {         int k = 255 - random(96);         // each pixel in the texture        for ( int m=0; m<16 * 3; m++ )            for ( int n = 0; n<16; n++ ) {                   int i1 = 0x966C4A;                int i2 = 0;                  int i3 = 0;                 if (j == 4)                        i1 = 0x7F7F7F;                  if ((j != 4) || (random(3) == 0))                        k = 255 - random(96);                  if ( j == 1 )                  {                      if (m < (((n * n * 3 + n * 81) >> 2) & 0x3) + 18)                          i1 = 0x6AAA40;                        else if (m < (((n * n * 3 + n * 81) >> 2) & 0x3) + 19)                            k = k * 2 / 3;                  }                  if (j == 7)                {                        i1 = 0x675231;                        if ((n > 0) && (n < 15) && (((m > 0) && (m < 15)) || ((m > 32) && (m < 47))))                        {                            i1 = 0xBC9862;                            i2 = n - 7;                          i3 = (m & 0xF) - 7;                            if (i2 < 0)                                i2 = 1 - i2;                             if (i3 < 0)                                  i3 = 1 - i3;                           if (i3 > i2)                                  i2 = i3;                           k = 196 - random(32) + i2 % 3 * 32;                      }                        else if (random(2) == 0)                          k = k * (150 - (n & 0x1) * 100) / 100;                }                  if (j == 5)                  {                      i1 = 0xB53A15;                        if (((n + m / 4 * 4) % 8 == 0) || (m % 4 == 0))                            i1 = 0xBCAFA5;                }                  i2 = k;                  if (m >= 32)                      i2 /= 2;                  if (j == 8)                {                        i1 = 5298487;                        if (random(2) == 0)                        {                            i1 = 0;                            i2 = 255;                        }                  }                   // fixed point colour multiply between i1 and i2                  i3 =                        ((((i1 >> 16) & 0xFF) * i2 / 255) << 16) |                        ((((i1 >>  8) & 0xFF) * i2 / 255) <<  8) |                          ((i1        & 0xFF) * i2 / 255);                  // pack the colour away                texmap[ n + m * 16 + j * 256 * 3 ] = i3;            }  }} static void makeMap( void ) {  // add random blocks to the map      for ( int x = 0; x < 64; x++) {                  for ( int y = 0; y < 64; y++) {                            for ( int z = 0; z < 64; z++) {                                        int i = (z << 12) | (y << 6) | x;                                float yd = (y - 32.5) * 0.4f;                              float zd = (z - 32.5) * 0.4f;                                      map[i] = random( 16 );                   float th = random( 256 ) / 256.0f;                                 if (th > sqrtf( sqrtf( yd * yd + zd * zd ) ) - 0.8f || th < 0.5f)                                                map[i] = 0;                          }                  }        }} static void init( void ) {  makeTextures( );  makeMap( );} // fixed point byte byte multiplystatic inline int fxmul( int a, int b ) {  return (a*b)>>8;} // fixed point 8bit packed colour multiplystatic inline int rgbmul( int a, int b ) {  int _r = (((a>>16) & 0xff) * b) >> 8;  int _g = (((a>> 8) & 0xff) * b) >> 8;  int _b = (((a    ) & 0xff) * b) >> 8;  return (_r<<16) | (_g<<8) | _b;} static void render( void ) {    float now = (float)(SDL_GetTicks( ) % 10000) / 10000.f;  //printf("now = %f", now);         float xRot = math_sin(now * math_pi * 2) * 0.4 + math_pi / 2;        float yRot = math_cos(now * math_pi * 2) * 0.4;        float yCos = math_cos(yRot);        float ySin = math_sin(yRot);      float xCos = math_cos(xRot);        float xSin = math_sin(xRot);       float ox = 32.5 + now * 64.0;        float oy = 32.5;        float oz = 32.5;         // for each column        for ( int x = 0; x < w; x++) {                  // get the x axis delta                  float ___xd = ((float)x - (float)w / 2.f) / (float)h;                  // for each row                  for ( int y = 0; y < h; y++) {                          // get the y axis delta                            float  __yd = ((float)y - (float)h / 2.f) / (float)h;                          float  __zd = 1;                            float ___zd =  __zd * yCos +  __yd * ySin;                            float   _yd =  __yd * yCos -  __zd * ySin;                            float   _xd = ___xd * xCos + ___zd * xSin;                            float   _zd = ___zd * xCos - ___xd * xSin;                             int col = 0;                            int br = 255;                            float ddist = 0;                             float closest = 32.f;                           // for each principle axis  x,y,z                          for ( int d = 0; d < 3; d++) {                                      float dimLength = _xd;                                      if (d == 1) {                                                  dimLength = _yd;                                        }                                      else if (d == 2) {                                                dimLength = _zd;                                      }                                         float ll = 1.0f / (dimLength < 0.f ? -dimLength : dimLength);                                      float xd = (_xd) * ll;                                      float yd = (_yd) * ll;                                        float zd = (_zd) * ll;                                         float       initial = ox - floor(ox);                                        if (d == 1) {                                                initial = oy - floor(oy);                                        } else if (d == 2) {                                                initial = oz - floor(oz);                                        }                                       if (dimLength > 0) initial = 1 - initial;                                       float dist = ll * initial;                                       float xp = ox + xd * initial;                                      float yp = oy + yd * initial;                                      float zp = oz + zd * initial;                                       if (dimLength < 0) {                                              if (d == 0) {                                                      xp--;                                              }                                                else if (d == 1) {                                                      yp--;                                              }                                              else if (d == 2) {                                                      zp--;                                                }                                        }                                       // while we are considering a ray that is still closer then the best so far                                        while (dist < closest) {                                                   // quantize to the map grid                                                int tex = map[ (((int)zp & 63) << 12) | (((int)yp & 63) << 6) | ((int)xp & 63) ];                                                   // if this voxel has a texture applied                                                if (tex > 0) {                                                           // find the uv coordinates of the intersection point                                                            int u = ((int)((xp + zp) * 16.f)) & 15;                                                          int v = ((int) (yp       * 16.f)  & 15) + 16;                                                           // fix uvs for alternate directions?                                                          if (d == 1) {                                                                      u =  ((int)(xp * 16.f)) & 15;                                                                      v = (((int)(zp * 16.f)) & 15);                                                                      if (yd < 0)                                                                                v += 32;                                                          }                                                           // find the colour at the intersection point                                                          int cc = texmap[ u + v * 16 + tex * 256 * 3 ];                                                           // if the colour is not transparent                                                          if (cc > 0) {                                                                      col = cc;                                                                      ddist = 255 - ((dist / 32 * 255));                                                                      br = 255 * (255 - ((d + 2) % 3) * 50) / 255;                                                                       // we now have the closest hit point (also terminates this ray)                                                                      closest = dist;                                                          }                                                }                                                   // advance the ray                                                  xp += xd;                                                  yp += yd;                                                zp += zd;                                                dist += ll;                                      }                            }             plot( x, y, rgbmul( col, fxmul( br, ddist ) ) );        }  }} int main( void ) {  unsigned int tickf =0 ,tickl = 0,fps = 0;  float dif;  unsigned int count = 0;  char buf[32];   SDL_Init( SDL_INIT_VIDEO );  screen = SDL_SetVideoMode( w, h, 32, 0 );  if ( screen == NULL )        return -1;  init( );  bool running = true;  tickf = SDL_GetTicks();  while ( running ) {   dif = (tickl-tickf) / 1000;    if (dif >= 1.0f ){      tickf = tickl;        fps = count;        count = 0;        sprintf(buf,"fps=%d",fps);        SDL_WM_SetCaption(buf,NULL);    } else {        count++;    };        SDL_Event event;        while ( SDL_PollEvent( &event ) ) {            running &= (event.type != SDL_QUIT);        }        render( );        SDL_Flip( screen );      tickl = SDL_GetTicks();  }    // Shutdown all subsystems    SDL_Quit();      return 0;} ---------------------------------------------------------------------- Nitorami · 2017-01-31 10:35 The code has simply been translated from C, and is typical C style. C compilers are probably better to optimize poorly written code, so the programmer does not need to worry a lot. But when looking at the inner loop "for d := 0 to 2...", there are a few obvious things that could be done better, 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). 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. ---------------------------------------------------------------------- marcov · 2017-01-31 10:42 Quote from: Graeme on January 31, 2017, 11:02:01 amAttached are slightly tweaked versions of the code airpas posted. This gives both a better "tunnel" effect. Sad thing is, this kills the Pascal+SDL version even more. On my i7 3770K @ 3.5GHz the Pascal version gives avg 8 fps and the C version gives avg 30 fps. Read my earlier post, first remove random from all tight loops, it is known slow on FPC, but that is not related to the current subject. ---------------------------------------------------------------------- Graeme · 2017-01-31 11:23 See the "EDIT" comment now added to my previous post - regarding a Java version I just wrote. ---------------------------------------------------------------------- Graeme · 2017-01-31 11:35 Quote from: Nitorami on January 31, 2017, 11:35:00 amThe 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] ---------------------------------------------------------------------- Graeme · 2017-01-31 11:43 Quote from: marcov on January 31, 2017, 11:42:50 amRead 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. ---------------------------------------------------------------------- Nitorami · 2017-02-01 09:47 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 · 2017-02-01 10:27 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 · 2017-02-01 10:52 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 · 2017-02-01 11:11 interesting  , can you post the code ? ---------------------------------------------------------------------- Graeme · 2017-02-01 11:13 Quote from: Nitorami on February 01, 2017, 10:47:06 amI 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i public class Test {     public static void main(String[] args) {      float f4 = 0.4f;      float f5 = 0.5f;      float f6 = 0.6f;            int i4 = (int) f4;      int i5 = (int) f5;      int i6 = (int) f6;          System.out.println(i4);      System.out.println(i5);      System.out.println(i6);    }}  QuoteAn 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; ------------------------------- ---------------------------------------------------------------------- Graeme · 2017-02-01 11:24 Quote from: Nitorami on February 01, 2017, 11:52:48 amI 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. QuoteIn 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i package com.opensoft.game; import java.applet.Applet;import java.awt.Frame;import java.awt.image.BufferedImage;import java.awt.image.DataBufferInt;import java.util.Random; public class Minecraft4k extends Applet implements Runnable {         private static final long serialVersionUID = 1L;        private static final String version = "0.0.1";         // // screen dimensions: scale x4 - low fidelity        // private static final int WIDTH = 214;        // private static final int HEIGHT = 120;        // private static final int SCALE = 4;         // screen dimensions: scale x2 - high fidelity        // private static final int WIDTH = 428;        // private static final int HEIGHT = 240;        // private static final int SCALE = 2;         private static final int WIDTH = 640;        private static final int HEIGHT = 400;        private static final int SCALE = 1;         // the block world map is stored in a cube of sides 64 in length;        // each map entry determines the colour of the corresponding block        private static final int MAPDIM = 64; // map dimensions        private static final int MAPCUBE = MAPDIM * MAPDIM * MAPDIM; // value 262144        private int[] map = new int[MAPCUBE];         Random rand = new Random();         public static void main(String[] args) {                Frame f = new Frame("Minecraft4k Java Demo " + version);                f.addWindowListener(new java.awt.event.WindowAdapter() {                      @Override                        public void windowClosing(java.awt.event.WindowEvent e) {                              System.exit(0);                        };                });               Minecraft4k mc = new Minecraft4k();                mc.setSize(WIDTH * SCALE, HEIGHT * SCALE);                f.add(mc);              f.pack();                mc.start();                f.setSize(WIDTH * SCALE, HEIGHT * SCALE);                f.setVisible(true);        }         @Override        public void start() {                new Thread(this).start(); // triggers the run() method        }         /*         * The following textures are generated         * 0 Air         * 1 Grass + Dirt         * 2 Dirt       * 3 Dirt         * 4 Stone (gray)         * 5 Brick         * 6 Dirt         * 7 Wood         * 8 Tree leaves         * 9 Water       * 10 .. 13 Dirt         * 14 Stone with moss         * 15 Red Brick with moss         */        private int[] generate_textures() {              // Algorithmically generate textures...                int[] texmap = new int[12288]; // 16 * 16 * 16 * 3 = 12288                int i = 1;                 while (i < 16) {                        int lBrightness = 255 - rand.nextInt(96);                        int y = 0;                        while (y < (16 * 3)) { // 3 texture images (top, side and bottom),                                                                      // stored one below the other                              int x = 0;                                while (x < 16) {                                        int lBrightness2;                                      int lColor;                                      int color = 0x966C4A; // ground                                      if (i == 4) {                                                color = 0x7F7F7F; // stone                                        }                                      if (i != 4 || rand.nextInt(3) == 0) {                                                lBrightness = 255 - rand.nextInt(96);                                        }                                      if (i == 1 && y < (x * x * 3 + x * 81 >> 2 & 3) + 18) {                                                color = 0x6AAA40; // grass                                        } else if (i == 1 && y < (x * x * 3 + x * 81 >> 2 & 3) + 19) {                                              lBrightness = lBrightness * 2 / 3;                                      }                                        if (i == 7) {                                                color = 0x675231; // wood                                                if (x > 0 && x < 15 && (y > 0 && y < 15 || y > 32 && y < 47)) {                                                      color = 0xBC9862; // wood                                                      // This is WRONG - see the JavaScript version for                                                      // details                                                      lBrightness2 = x - 7;                                                      lColor = (y & 15) - 7;                                                      if (lBrightness2 < 0) {                                                              lBrightness2 = 1 - lBrightness2;                                                        }                                                        if (lColor < 0) {                                                                lColor = 1 - lColor;                                                      }                                                        if (lColor > lBrightness2) {                                                              lBrightness2 = lColor;                                                      }                                                      lBrightness = 196 - rand.nextInt(32) + lBrightness2 % 3 * 32;                                                } else if (rand.nextInt(2) == 0) {                                                      lBrightness = lBrightness * (150 - (x & 1) * 100) / 100;                                              }                                      }                                        if (i == 5) {                                              color = 0xB53A15; // brick                                                if ((x + y / 4 * 4) % 8 == 0 || y % 4 == 0) {                                                      color = 0xBCAFA5;                                              }                                        }                                      if (i == 9) {                                              color = 0x4040ff; // water                                        }                                      if (i == 14) {                                              color = 0x7F7F7F; // stone with moss                                              if (rand.nextInt(3) == 0) {                                                      color = 0x6AAA40;                                                } else if ((x + y / 4 * 4) % 8 == 0 || y % 4 == 0) {                                                      color = 0x6AAA60;                                              }                                        }                                      if (i == 15) {                                              color = 0xB53A15; // red bricks with moss                                              if (rand.nextInt(3) == 0) {                                                      color = 0x6AAA40;                                              } else if ((x + y / 4 * 4) % 8 == 0 || y % 4 == 0) {                                                      color = 0x6AAA60;                                              }                                        }                                       lBrightness2 = lBrightness;                                      if (y >= 32) {                                              lBrightness2 /= 2;                                        }                                      if (i == 8) {                                              color = 0x50D937; // leaves                                              if (rand.nextInt(2) == 0) {                                                      color = 0;                                                      lBrightness2 = 255;                                              }                                        }                                        lColor = (color >> 16 & 0xFF) * lBrightness2 / 0xFF << 16 //                                                      | (color >> 8 & 0xFF) * lBrightness2 / 0xFF << 8 //                                                      | (color & 0xFF) * lBrightness2 / 0xFF;                                        texmap[x + y * 16 + i * 256 * 3] = lColor;                                      ++x;                                }                                ++y;                        }                        ++i;               }                 return texmap;        }         private void generateMap() {                for (int x = 0; x < MAPDIM; x++) {                      for (int y = 0; y < MAPDIM; y++) {                              for (int z = 0; z < MAPDIM; z++) {                                      int i = (z << 12) | (y << 6) | x;                                      float yd = (y - 32.5f) * 0.4f;                                      float zd = (z - 32.5f) * 0.4f;                                      map[i] = rand.nextInt(16);                                      float th = rand.nextInt(256) / 256.0f;                                      if ((th > (Math.sqrt(Math.sqrt(yd * yd + zd * zd)) - 0.8f)) || (th < 0.5f)) {                                              map[i] = 0;                                        }                              }                        }                }        }       @Override        public void run() {                try {                      long lastTime = System.currentTimeMillis();                      int frames = 0;                         BufferedImage localBufferedImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);                        int[] imgBufferData = ((DataBufferInt) localBufferedImage.getRaster().getDataBuffer()).getData();                       // rand.setSeed(18295169);                         generateMap();                         int[] texmap = generate_textures();                         do {                              float l = System.currentTimeMillis() % 10000 / 10000.0f;                              // System.out.println("now = " + l);                               float ox = 32.5f + l * 64;                              float oy = 32.0f;                                float oz = 32.5f;                                 float xRot = (float) ((float) Math.sin(l * Math.PI * 2f) * 0.4f + Math.PI / 2f);                              float yRot = (float) Math.cos(l * Math.PI * 2f) * 0.4f;                               float xSin = (float) Math.sin(xRot);                              float xCos = (float) Math.cos(xRot);                              float ySin = (float) Math.sin(yRot);                              float yCos = (float) Math.cos(yRot);                               int x = 0;                                // raycaster: for each column                                while (x < WIDTH) {                                        float ___xd = (x - WIDTH / 2) / (float) HEIGHT;                                        int y = 0;                                        while (y < HEIGHT) {                                                float __yd = (y - HEIGHT / 2) / (float) HEIGHT;                                              float __zd = 1.0f;                                              float ___zd = __zd * yCos + __yd * ySin;                                              float _yd = __yd * yCos - __zd * ySin;                                              float _xd = ___xd * xCos + ___zd * xSin;                                                float _zd = ___zd * xCos - ___xd * xSin;                                               int col = 0; // black sky colour                                              int br = 255; // brightness                                              double closest = 32.0d; // how far can we see                                               int d = 0;                                              while (d < 3) {                                                      float dimLength = _xd;                                                      if (d == 1) {                                                              dimLength = _yd;                                                      } else if (d == 2) {                                                              dimLength = _zd;                                                      }                                                      float ll = 1.0f / (dimLength < 0.0f ? -dimLength : dimLength);                                                      float xd = _xd * ll;                                                      float yd = _yd * ll;                                                      float zd = _zd * ll;                                                      float initial = ox - ((int) ox);                                                      if (d == 1) {                                                              initial = oy - ((int) oy);                                                        } else if (d == 2) {                                                              initial = oz - ((int) oz);                                                      }                                                      if (dimLength > 0.0f) {                                                              initial = 1.0f - initial;                                                      }                                                       float dist = ll * initial;                                                      float xp = ox + xd * initial;                                                      float yp = oy + yd * initial;                                                        float zp = oz + zd * initial;                                                       if (dimLength < 0.0f) {                                                              if (d == 0) {                                                                      xp--;                                                              } else if (d == 1) {                                                                      yp--;                                                              } else if (d == 2) {                                                                      zp--;                                                              }                                                         }                                                       // while we are considering a ray that is still closer then the best so far                                                      while (dist < closest) {                                                                 // quantize to the map grid                                                              int mapOffset = (((int) zp & 63) << 12) | (((int) yp & 63) << 6) | ((int) xp & 63);                                                              int tex = map[mapOffset];                                                               // if this voxel has a texture applied                                                              if (tex > 0) {                                                                       // find the uv coordinates of the intersection point                                                                      int u = (int) ((xp + zp) * 16.0f) & 15;                                                                      int v = ((int) (yp * 16.0f) & 15) + 16;                                                                       // fix uv's for alternate directions?                                                                      if (d == 1) {                                                                              u = (int) (xp * 16.0f) & 15;                                                                              v = (int) (zp * 16.0f) & 15;                                                                              if (yd < 0.0f) {                                                                                      v += 32;                                                                              }                                                                      }                                                                       // find the colour at the intersection point                                                                      int cc = texmap[u + v * 16 + tex * 256 * 3];                                                                       // if the colour is not transparent                                                                      if (cc > 0) {                                                                              col = cc;                                                                              br = 255 - (int) (dist / 32.0f * 255.0f);                                                                              br = br * (255 - (d + 2) % 3 * 50) / 255;                                                                              // we now have the closest hit point (also terminates this ray)                                                                              closest = dist;                                                                      }                                                              }                                                                // advance the ray                                                              xp += xd;                                                              yp += yd;                                                              zp += zd;                                                              dist += ll;                                                      }                                                        ++d;                                                }                                              int r = (col >> 16 & 0xFF) * br / 0xFF;                                                int g = (col >> 8 & 0xFF) * br / 0xFF;                                                int b = (col & 0xFF) * br / 0xFF;                                              imgBufferData[x + y * WIDTH] = r << 16 | g << 8 | b;                                              ++y;                                      }                                        ++x;                              }                                 // the following code is only needed for a Java Applet -                                // disables application when not visible                                // if (!this.isActive()) {                                // return;                              // }                                 frames++;                                 // Graphics g = localBufferedImage.getGraphics();                                // g.setColor(Color.WHITE);                                // Font stringFont = g.getFont().deriveFont(7.0f);                              // g.setFont(stringFont);                                // g.drawString(version, 2, 6);                                // g.drawString(prevFrames + " fps", 2, 13);                               this.getGraphics().drawImage(localBufferedImage, 0, 0, WIDTH * SCALE, HEIGHT * SCALE, null);                                 // FPS counter printed every 1 second.                                while (System.currentTimeMillis() - lastTime > 1000) {                                      System.out.println(frames + " fps");                                      lastTime += 1000;                                      frames = 0;                                }                       } while (true);                } catch (Exception e) {                      e.printStackTrace();                        return;              }        } }[code] ---------------------------------------------------------------------- airpas · 2017-02-01 11:52 QuoteThat 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  if dimLength < 0.0 then                            ll := 1.0 / -dimLength else  ll := 1.0 / dimLength;  and Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  if dimLength < 0.0 then                            dimLength := - dimLength;  ll := 1.0 / dimLength; ---------------------------------------------------------------------- Nitorami · 2017-02-01 12:33 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$ifdef FPC}{$mode objfpc}{$h+}{$endif}{$ifdef mswindows}{$apptype gui}{$endif} {$OPTIMIZATION FASTMATH}{$OPTIMIZATION USEEBP}{$FPUTYPE SSE3}//{$OPTIMIZATION REGVAR}//{$SAFEFPUEXCEPTIONS OFF}  //{$IMPLICITEXCEPTIONS OFF}//{$OPTIMIZATION LOOPUNROLL}{$OPTIMIZATION CSE}//{$CODEALIGN VARMIN=4}//{$CODEALIGN LOOP=4}////{$CODEALIGN JUMP=4}  uses  sdl; type      p32Array = ^u32Array;      u32Array = array[0..0] of longint; const       s_w = 640;       s_h = 400; var  event : TSDL_Event;  done : boolean = false;  screen : PSDL_Surface;  texmap : array [0..15,0..3*16-1,0..15] of longint;  map    : array [0..63,0..63,0..63] of smallint;  procedure  plot(x,y,c : longint);begin  p32Array(screen^.pixels)^[y*s_w+x] := c;end;  function inttostr(v : integer): string;begin  str(v,result);end;  procedure makeTextures();var   j,m,k,i1,i2,i3,n : longint;begin     // each texture     for j:=0 to 15 do begin        k := 255 - random(96);      // each pixel in the texture        for m:=0  to (16 * 3)-1 do          for n :=0 to 15 do begin                i1 := $966C4A;              i2 := 0;                i3 := 0;                if (j = 4) then                  i1 := $7F7F7F;                if ((j <> 4) or (random(3) = 0)) then                    k := 255 - random(96);              if ( j = 1 ) then                begin                    if (m < (((n * n * 3 + n * 81) >> 2) and $3) + 18) then                      i1 := $6AAA40                    else if (m < (((n * n * 3 + n * 81) >> 2) and $3) + 19) then                        k := k * 2 div 3;                end;                if (j = 7) then                begin                    i1 := $675231;                    if ((n > 0) and (n < 15) and (((m > 0) and (m < 15)) or ((m > 32) and (m < 47)))) then                    begin                        i1 := $BC9862;                      i2 := n - 7;                        i3 := (m and $F) - 7;                        if (i2 < 0.0) then                          i2 := 1 - i2;                         if (i3 < 0.0) then                          i3 := 1 - i3;                         if (i3 > i2) then                            i2 := i3;                         k := 196 - random(32) + i2 mod 3 * 32;                    end                  else if (random(2) = 0) then                        k := k * (150 - (n and $1) * 100) div 100;                end;                 if (j = 5) then                begin                    i1 := $B53A15;                  if (((n + m div 4 * 4) mod 8 = 0) or (m mod 4 = 0)) then                        i1 := $BCAFA5;                end;              i2 := k;                if (m >= 32) then                    i2 := i2 div 2;                if (j = 8) then                begin                  i1 := 5298487;                    if (random(2) = 0) then                  begin                        i1 := 0;                      i2 := 255;                    end;                end;               // fixed point colour multiply between i1 and i2                i3 :=                    ((((i1 >> 16) and $FF) * i2 div 255) << 16) or                  ((((i1 >>  8) and $FF) * i2 div 255) <<  8) or                    ((i1        and $FF) * i2 div 255);                 // pack the colour away                texmap[ n,m,j] := i3;            end;    end;end;  procedure makeMap( ) ;var x,y,z,i : longword;    yd,zd,th : single;    begin    // add random blocks to the map    for x := 0 to 63 do begin        for y := 0 to 63 do begin             for z := 0 to 63 do begin               yd := (y - 32.5) * 0.4;             zd := (z - 32.5) * 0.4;               map[z,y,x] := random( 16 );             th := random;              if th > sqrt( sqrt( yd * yd + zd * zd ) ) - 0.8 then                 map[z,y,x] := 0;              end;        end;    end;end; procedure init( );begin    makeTextures( );    makeMap( );end;  // fixed point byte byte multiply function fxmul( a,b : longint ):longint ;begin    result := (a*b) shr 8;end;  // fixed point 8bit packed colour multiplyfunction  rgbmul(a,b : longint ):longint;var _r,_g,_b : longint;  begin    _r := (((a>>16) and $ff) * b) >> 8;    _g := (((a>> 8) and $ff) * b) >> 8;    _b := (((a    ) and $ff) * b) >> 8;    result := (_r<<16) or (_g<<8) or _b;end;   procedure render(  );var   now,xRot,yRot,yCos,   ySin,xCos,xSin,___xd,   __yd,__zd,___zd,_yd,    _xd,_zd,ddist,closest,    ox,oy,oz,dimLength,ll,    xd,yd,zd,initial,dist,    xp,yp,zp: single;    d,x,y ,col,br,tex,u,v,cc: longint;begin  now := (SDL_GetTicks( ) mod 10000) / 10000;  xRot := sin(now * pi * 2) * 0.4 + pi / 2;  yRot := cos(now * pi * 2) * 0.4;  yCos := cos(yRot);  ySin := sin(yRot);  xCos := cos(xRot);  xSin := sin(xRot);  ox := 32.5 + now * 64.0;  oy := 32.5;  oz := 32.5;   // for each column  for x :=0 to s_w -1 do begin      // get the x axis delta      ___xd := (x - s_w / 2) / s_h;       // for each row      for y :=0 to s_h-1 do begin       // get the y axis delta        __yd := (y - s_h / 2) / s_h;       __zd := 1;       ___zd :=  __zd * yCos +  __yd * ySin;       _yd :=  __yd * yCos -  __zd * ySin;       _xd := ___xd * xCos + ___zd * xSin;       _zd := ___zd * xCos - ___xd * xSin;        col := 0;       br := 255;       ddist := 0;       closest := 32.0;      // for each principle axis  x,y,z      for d :=0 to 2 do begin         if (d = 0) then dimLength := _xd       else if (d = 1) then dimLength := _yd         else dimLength := _zd;          if dimlength <> 0 then ll := 1.0 / abs(dimLength) else ll := 1;         xd := _xd * ll;         yd := _yd * ll;         zd := _zd * ll; //{$DEFINE FRAC}{$IFDEF FRAC}         if (d = 0) then initial := frac(ox)         else if (d = 1) then initial := frac(oy)       else initial := frac(oz);{$ELSE}         if (d = 0) then initial := ox-trunc(ox)         else if (d = 1) then initial := oy-trunc(oy)       else initial := oz-trunc(oz);{$ENDIF}          if (dimLength > 0.0) then initial := 1 - initial;         dist := ll * initial;       xp := ox + xd * initial;         yp := oy + yd * initial;         zp := oz + zd * initial;          if (dimLength < 0.0) then begin        if (d = 0) then xp-=1          else if (d = 1)then yp-=1          else if (d = 2)then zp-=1;         end;           // while we are concidering a ray that is still closer then the best so far         while (dist < closest) do begin         // quantize to the map grid         tex := map[ (trunc(zp) and 63),(trunc(yp) and 63),trunc(xp) and 63];            // if this voxel has a texture applied           if (tex > 0) then begin           // find the uv coordinates of the intersection point             u := (round((xp + zp) * 16)) and 15;           v := (round(yp        * 16)  and 15) + 16;           // fix uvs for alternate directions?            if d=1 then begin             u :=  (round(xp * 16)) and 15;             v := ((round(zp * 16)) and 15);             if (yd < 0.0) then               v += 32;           end;            //find the colour at the intersection point           cc := texmap[u, v, tex];           // if the colour is not transparent           if (cc > 0) then begin             col := cc;           ddist := 255 - ((dist / 32 * 255));             br :=  255 - ((d + 2) mod 3) * 50;             //we now have the closest hit point (also terminates this ray)             closest := dist;           end;         end;        // advance the ray          xp += xd;       yp += yd;         zp += zd;         dist += ll;       end;     end;   plot( x, y, rgbmul( cc, fxmul( br, round(ddist) ) ) );   end; end;end;   var    tickf,tickl,fps : longword;    dif : single;  count : longword = 0; begin    SDL_putenv('SDL_VIDEO_CENTERED=1');  SDL_Init(SDL_INIT_VIDEO);      screen := SDL_SetVideoMode( s_w, s_h, 32 , SDL_SWSURFACE );    init();     tickf := SDL_GetTicks();     while not done  do    begin      dif := (tickl-tickf) / 1000;      if dif >= 1.0  then begin          tickf := tickl;          fps := count;          count := 0;          SDL_WM_SetCaption(pchar('fps='+inttostr(fps)),nil);      end else begin           inc(count);          end;           while  SDL_PollEvent( @event ) > 0  do            case event.type_  of          SDL_KEYDOWN:                if ( event.key.keysym.sym = SDLK_ESCAPE ) then                begin                  done := true;                end;                SDL_QUITEV:                begin                  done := true;                end;             end;           render( );           SDL_Flip(screen);           tickl := SDL_GetTicks();     end;end. ---------------------------------------------------------------------- lainz · 2017-02-01 12:36 Quote from: Graeme on February 01, 2017, 12:24:05 pmFor 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 · 2017-02-01 15:07 Quote from: airpas on February 01, 2017, 12:52:29 pmQuote         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. ---------------------------------------------------------------------- Graeme · 2017-02-01 15:25 Quote from: lainz on February 01, 2017, 01:36:00 pmOn 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. ---------------------------------------------------------------------- lainz · 2017-02-01 15:27 Quote from: Graeme on February 01, 2017, 04:25:51 pmQuote from: lainz on February 01, 2017, 01:36:00 pmOn 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. ---------------------------------------------------------------------- Graeme · 2017-02-01 15:31 Quote from: lainz on February 01, 2017, 04:27:26 pmYou're on Linux? I have Windows 10 on i7 4790 3.6 ghz. No. FreeBSD 10.3 (64-bit) on a i7-3770K CPU running at 3.5GHZ. So I actually have a slower system (less horsepower) than you. So much for Windows 10. ;-) [edit] Oh, and OpenJDK8. ---------------------------------------------------------------------- airpas · 2017-02-01 15:47 good work Nitorami , with your version i got 24fps , but only if i turn off the optimization -O- or -O1 . with O2 and O3 it crashes with  run time error 216 at line 143 . ---------------------------------------------------------------------- Nitorami · 2017-02-01 15:54 Airpas, I had the same issue with -O2. I believe this is a bug in the optimizer related to using single with SSE3. The error does not appear when you declare float variables as double. I will issue a bug report. ---------------------------------------------------------------------- airpas · 2017-02-02 08:15 this is what i get 30fps (without sse3) , which is a pretty good result compared to 40fps of gcc with see3 enabled . kudos fpc Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program test;{$ifdef FPC}{$mode objfpc}{$h+}{$endif}{$ifdef mswindows}{$apptype gui}{$endif}uses  sdl;type        p32Array = ^u32Array;        u32Array = array[0..0] of int32; const  s_w = 640;  s_h = 400;  math_pi = 3.14159265359; var  event : TSDL_Event;  done : boolean = false;  screen : PSDL_Surface;  texmap : array [0..15,0..3*16-1,0..15] of longint;  map    : array [0..63,0..63,0..63] of smallint; procedure  plot(x,y,c : int32)inline;begin  p32Array(screen^.pixels)^[y*s_w+x] := c;end; function inttostr(v : integer): ansistring;begin  str(v,result);end; procedure makeTextures();var   j,m,k,i1,i2,i3,n : int32;begin     // each texture    for j:=0 to 15 do begin         k := 255 - random(96);         // each pixel in the texture        for m:=0  to (16 * 3)-1 do            for n :=0 to 15 do begin               i1 := $966C4A;                i2 := 0;                i3 := 0;               if (j = 4) then                    i1 := $7F7F7F;              if ((j <> 4) or (random(3) = 0)) then                    k := 255 - random(96);                if ( j = 1 ) then                begin                    if (m < (((n * n * 3 + n * 81) >> 2) and $3) + 18) then                        i1 := $6AAA40                    else if (m < (((n * n * 3 + n * 81) >> 2) and $3) + 19) then                      k := k * 2 div 3;                end;                if (j = 7) then                begin                    i1 := $675231;                  if ((n > 0) and (n < 15) and (((m > 0) and (m < 15)) or ((m > 32) and (m < 47)))) then                    begin                      i1 := $BC9862;                        i2 := n - 7;                      i3 := (m and $F) - 7;                        if (i2 < 0.0) then                            i2 := 1 - i2;                       if (i3 < 0.0) then                            i3 := 1 - i3;                       if (i3 > i2) then                            i2 := i3;                         k := 196 - random(32) + i2 mod 3 * 32;                  end                    else if (random(2) = 0) then                      k := k * (150 - (n and $1) * 100) div 100;              end;                if (j = 5) then                begin                  i1 := $B53A15;                    if (((n + m div 4 * 4) mod 8 = 0) or (m mod 4 = 0)) then                        i1 := $BCAFA5;                end;                i2 := k;                if (m >= 32) then                    i2 := i2 div 2;                if (j = 8) then                begin                    i1 := 5298487;                  if (random(2) = 0) then                    begin                      i1 := 0;                        i2 := 255;                  end;                end;                 // fixed point colour multiply between i1 and i2                i3 :=                    ((((i1 >> 16) and $FF) * i2 div 255) << 16) or                    ((((i1 >>  8) and $FF) * i2 div 255) <<  8) or                      ((i1        and $FF) * i2 div 255);                // pack the colour away                texmap[ n , m , j] := i3;            end;    end;end; procedure makeMap( ) ;var x,y,z,i : integer;    yd,zd,th : double;begin    // add random blocks to the map    for x := 0 to 63 do begin        for y := 0 to 63 do begin             for z := 0 to 63 do begin               yd := (y - 32.5) * 0.4;               zd := (z - 32.5) * 0.4;               map[x,y,z] := random( 16 );               th := random( );               if (th > sqrt( sqrt( yd * yd + zd * zd ) ) - 0.8) then                 map[x,y,z] := 0;              end;      end;    end;end; procedure init( );begin    makeTextures( );    makeMap( );end; // fixed point byte byte multiplyfunction fxmul( a,b : int32 ):int32 ; inline;begin    result := (a*b)>>8;end; // fixed point 8bit packed colour multiplyfunction  rgbmul(a,b : int32 ):int32; inline;var _r,_g,_b : int32;begin    _r := (((a>>16) and $ff) * b) >> 8;    _g := (((a>> 8) and $ff) * b) >> 8;    _b := (((a    ) and $ff) * b) >> 8;    result := (_r<<16) or (_g<<8) or _b;end;  procedure render(  );var   now,xRot,yRot,yCos,   ySin,xCos,xSin,___xd,   __yd,__zd,___zd,_yd,    _xd,_zd,ddist,closest,    ox,oy,oz,dimLength,ll,    xd,yd,zd,initial,dist,    xp,yp,zp: single;   x,y ,col,br,d,tex,u,v,cc: int32;begin        now := (SDL_GetTicks( ) mod 10000) / 10000;         xRot := sin(now * math_pi * 2) * 0.4 + math_pi / 2;        yRot := cos(now * math_pi * 2) * 0.4;        yCos := cos(yRot);        ySin := sin(yRot);        xCos := cos(xRot);      xSin := sin(xRot);         ox := 32.5 + now * 16.0;        oy := 32.5;        oz := 32.5;        // for each column        for x :=0 to s_w -1 do begin                // get the x axis delta                ___xd := (x - s_w / 2) / s_h;                // for each row              for y :=0 to s_h-1 do begin                        // get the y axis delta                        __yd := (y - s_h / 2) / s_h;                      __zd := 1;                        ___zd :=  __zd * yCos +  __yd * ySin;                        _yd :=  __yd * yCos -  __zd * ySin;                        _xd := ___xd * xCos + ___zd * xSin;                      _zd := ___zd * xCos - ___xd * xSin;                       col := 0;                        br := 255;                      ddist := 0;                         closest := 20.0;                       // for each principle axis  x,y,z                        for d :=0 to 2 do begin                         if (d = 0) then dimLength := _xd                         else if (d = 1) then dimLength := _yd                       else dimLength := _zd;                          if dimLength < 0.0 then                            //dimLength := -dimLength;                          ll := 1.0 / -dimLength else                        ll := 1.0 / dimLength;                          xd := _xd * ll;                          yd := _yd * ll;                        zd := _zd * ll;                           initial := ox - round(ox);                          if (d = 1) then initial := oy - round(oy);                          if (d = 2) then initial := oz - round(oz);                           if (dimLength > 0.0) then initial := 1 - initial;                           dist := ll * initial;                         xp := ox + xd * initial;                          yp := oy + yd * initial;                          zp := oz + zd * initial;                           if (dimLength < 0.0) then begin                         if (d = 0)then xp-=1;                           if (d = 1)then yp-=1 ;                           if (d = 2)then zp-=1;                          end;                           // while we are concidering a ray that is still closer then the best so far                          while (dist < closest) do begin                        // quantize to the map grid                            tex := map[trunc(xp),trunc(yp),trunc(zp)];                           // if this voxel has a texture applied                            if (tex > 0) then begin                            // find the uv coordinates of the intersection point                              u := (round((xp + zp) * 16)) and 15;                              v := (round(yp        * 16)  and 15) + 16;                             // fix uvs for alternate directions?                             if (d = 1) then begin                              u :=  (round(xp * 16)) and 15;                              v := ((round(zp * 16)) and 15);                            if (yd < 0.0) then                              v += 32;                            end;                           //find the colour at the intersection point                          cc := texmap[ u , v , tex];                            // if the colour is not transparent                            if (cc > 0.0) then begin                              col := cc;                            ddist := 255 - ((dist / 32 * 255));                            br := 255 * (255 - ((d + 2) mod 3) * 50) div 255;                            //we now have the closest hit point (also terminates this ray)                              closest := dist;                          end;                          end;                         // advance the ray                        xp += xd;                      yp += yd;                        zp += zd;                        dist += ll;                        end;                end;          plot( x, y, rgbmul( col, fxmul( br, round(ddist) ) ) );        end;  end;end; var    tickf,tickl,fps : longword;    dif : single;    count : longword = 0;begin     SDL_putenv('SDL_VIDEO_CENTERED=1');    SDL_Init(SDL_INIT_VIDEO);     screen := SDL_SetVideoMode( s_w, s_h, 32 , SDL_SWSURFACE );    init();    tickf := SDL_GetTicks();    while not done  do    begin     dif := (tickl-tickf) / 1000;     if dif >= 1.0  then     begin          tickf := tickl;          fps := count;        count := 0;          SDL_WM_SetCaption(pchar('fps='+inttostr(fps)),nil);     end else begin          inc(count);         end;         while  SDL_PollEvent( @event ) > 0  do            case event.type_  of            SDL_KEYDOWN:                if ( event.key.keysym.sym = SDLK_ESCAPE ) then                begin                  done := true;              end;                SDL_QUITEV:                begin                done := true;                end;             end;           render( );           SDL_Flip(screen);           tickl := SDL_GetTicks();     end;end. ---------------------------------------------------------------------- Nitorami · 2017-02-02 09:20 Question - How can I copy code from the forum without getting the line numbers ? Regardless whether I use the "select" button or mark code with the mouse to copy it to the clipboard, I always get the line numbers in the way. ---------------------------------------------------------------------- airpas · 2017-02-02 09:39 i don't know , maybe your browser !! ,  i use Chrome and never get such problem ---------------------------------------------------------------------- Nitorami · 2017-02-02 09:49 Ah yes, it's the browser, alright. I can confirm 27...30 fps with your code on my machine but need to turn SSE3 on. Otherwise I get only 15fps. CPU = 1 x Intel(R) Core(TM) i5-3320M CPU @ 2.60GHz Video Adapter = Intel(R) HD Graphics 4000 [1786 MB] When comparing to Java or C, you should be absolutely sure that the tunnel looks really the same. The handling of round or trunc may be different in C than pascal and may for instance lead to missing walls, which has a great impact on performance, making the comparison unfair. ---------------------------------------------------------------------- marcov · 2017-02-02 09:55 Quote from: airpas on February 02, 2017, 10:39:26 ami don't know , maybe your browser !! ,  i use Chrome and never get such problem My current firefox is ok now, but a year back it wasn't iirc. ---------------------------------------------------------------------- Graeme · 2017-02-02 10:01 Quote from: airpas on February 02, 2017, 09:15:55 amthis is what i get 30fps (without sse3) , That is pretty good, but you did “cheat” somewhat.  closest has now changed from 32 blocks to only 20 blocks. That means in renders way less visible blockscamera speed changed. So now it is not a like-for-like comparisonin the map generation it should have more of a tunnel effect, thus making a bigger tunnel with more      block visible (like the Java, C and Javascript versions). Change line 125 to read what is shown below Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i           if (th > sqrt( sqrt( yd * yd + zd * zd ) ) - 0.8) or (th < 0.5) then I think the change that gives you the biggest FPS boost is (1) and (3) above. Either way, it is nice to see the FPS count dipping into the 30’s now. On a side note:    I get near instant core dumps on my system though. It runs for 2-3 seconds    then crashes. Also if I change closest to 32, then I get instant core dumps    (Segmentation fault) without seeing anything. So something is still not well    with the Pascal version. ---------------------------------------------------------------------- Graeme · 2017-02-02 10:04 Quote from: marcov on February 02, 2017, 10:55:13 amQuote from: airpas on February 02, 2017, 10:39:26 ami don’t know , maybe your browser !! ,  i use Chrome and never get such problem My current firefox is ok now, but a year back it wasn’t iirc. Same here, but just testing with Firefox 49 and Chromium 51 under FreeBSD. Both copy the source code from the forum without problems (no line numbers prefixed). But a year or two ago I did have that issue - just like Marco mentioned. ---------------------------------------------------------------------- Nitorami · 2017-02-02 10:06 @Graeme: What causes the violation is the division 1/dimlength which might under/overflow. We should do a check for underflow. It does not impact on performance. Yes, airpas has cheated a bit... also the "and 63" in the indices of the map lookup has gone, which might cause strange results for larger maps. On my machine, I don't get above 15fps when using the x87 FPU. Intel explains here why float to integer on the x87 is slow on certain processors: https://software.intel.com/en-us/articles/fast-floating-point-to- integer-conversions/ Browser: I am in the office and using IE.... ---------------------------------------------------------------------- airpas · 2017-02-02 10:12 QuoteI can confirm 27...30 fps with your code on my machine but need to turn SSE3 on. Otherwise I get only 15fps. oh all those options : -CfSSE3 -CpPENTIUM4 -O4 -OoCONSTPROP -OoFASTMATH -OoLOOPUNROLL -OoPEEPHOLE was enabled in the project options ->custom options , i didn't see it , you are right i also get 15fps without sse3 . if you see the disasm code , fpc round() function interpreted exactly like  (int)float_var in C . ---------------------------------------------------------------------- airpas · 2017-02-02 10:15 QuoteThat is pretty good, but you did “cheat” somewhat. no i didn't , i compared with the same value (20) for both version , and i get 30fps for fpc , and 40 for gcc ---------------------------------------------------------------------- Graeme · 2017-02-02 10:16 Quote from: Nitorami on February 02, 2017, 11:06:52 am@Graeme: What causes the violation is the division 1/dimlength which might under/overflow.  We should do a check for underflow. Yeah, I tried to change that code in all kinds of ways, but can’t get around the crash for some reason. QuoteBrowser: I am in the office and using IE.... Oh God, that explains it!!! ---------------------------------------------------------------------- Nitorami · 2017-02-02 10:24 QuoteYeah, I tried to change that code in all kinds of ways, but can’t get around the crash for some reason. What works for me:          if dimlength <> 0 then ll := 1.0 / abs(dimLength) else ll := 1; The better option would probably be to modify the SSE3 exception mask but I don't know these details. ---------------------------------------------------------------------- Graeme · 2017-02-02 10:33 Quote from: Nitorami on February 02, 2017, 11:24:36 amWhat works for me:          if dimlength <> 0 then ll := 1.0 / abs(dimLength) else ll := 1; That seems the logical option, but unfortunately (for some odd reason) that doesn’t make any difference here. I still get a crash 1-2 seconds after starting the demo. ---------------------------------------------------------------------- Nitorami · 2017-02-02 10:45 And what about if abs(dimlength) < 1e-3 then.... ? ---------------------------------------------------------------------- Graeme · 2017-02-02 10:45 So, who’s up for porting this flying tunnel demo to OpenGL 4 so we can do more FPS comparisons. ---------------------------------------------------------------------- Nitorami · 2017-02-02 14:22 Not me.... ! I try to summarise this topic for my own reference: - The performance of this code is determined mainly by the performance of the trunc() operations in the innermost loop. - Trunc may be slow on the x87, better use SSE2 if available. See Internet sources on this. - The only potential for any significant improvement would be by vectorising these trunc() calls in the inner loop, e.g. in "tex := map[trunc(z), trunc(y),trunc(x)]" using AVX/SSE. - Such vector support had been introduced to FPC I think by Florian, activated by little known switch -Sv, but it was never widely advertised, there are no test cases, and it was probably given up at some point in time and is now broken. See FPC bug tracker ID 0027870. Edit: I don't think SDL or OpenGL would make a performance difference with this specific "tunnel" code, because the bottleneck is the raytracing by the CPU. ---------------------------------------------------------------------- Graeme · 2017-02-03 10:42 Quote from: Nitorami on February 02, 2017, 03:22:56 pmNot me.... ! As part of my learning experience I’m heading up that task now. Using SDL2 and OpenGL. QuoteI try to summarise this topic for my own reference: Thanks for the summary and for everybody that contributed to this thread. It was all very educational and informative. QuoteEdit: I don’t think SDL or OpenGL would make a performance difference with this specific “tunnel” code, because the bottleneck is the raytracing by the CPU. You are right, as-is it wouldn’t improve much. I’ve decided to rewrite the demo completely using vectors and shaders instead. This should be a great learning experience for me. Both in SDL2 and OpenGL - of which I have never programmed with before (one is never too old to learn  ). I have been studying Java’s LWJGL (Lightweight Java Game Library) via excellent YouTube tutorials. I’m going to try and apply that same knowledge to SDL2 + OpenGL. Obviously this means the performance of Free Pascal will not really come into play, but hey, it should be fun. ---------------------------------------------------------------------- User137 · 2017-02-03 11:55 Quote from: Graeme on February 02, 2017, 11:45:47 amSo, who’s up for porting this flying tunnel demo to OpenGL 4 so we can do more FPS comparisons.  Where is the original? ---------------------------------------------------------------------- Graeme · 2017-02-03 12:38 Quote from: User137 on February 03, 2017, 12:55:39 pmWhere is the original? The original JavaScript [test] version from Notch (the creator of Minecraft) himself:    http://jsdo.it/notch/dB1E And here is a SDL + C port of the original JavaScript version (done by somebody else):    http://pastebin.com/jfjqAas8 ---------------------------------------------------------------------- lainz · 2017-02-03 12:41 The JavaScript version runs smoother than the Java version on my PC ---------------------------------------------------------------------- Leledumbo · 2017-02-03 12:47 Quote from: lainz on February 03, 2017, 01:41:38 pmThe JavaScript version runs smoother than the Java version on my PC  JavaScript engines commonly make a good use of multicore processors without the need to specify such in the code, while in Java it must be done explicitly. ---------------------------------------------------------------------- Graeme · 2017-02-03 12:55 Quote from: lainz on February 03, 2017, 01:41:38 pmThe JavaScript version runs smoother than the Java version on my PC  The tunnel is also smaller in the JavaScript version, so your viewing perspective is different and there is less to render. The JavaScript version does perform pretty impressive non the less - just goes to show how good the HTML5 Canvas is in modern web browsers. EDIT:   Here is an update from the original by Notch - this one implements the wider tunnel.   https://jsfiddle.net/9sbvsz11/1/ A nice to have, would be to implement a FPS counter too. Maybe later. EDIT #2:    Not sure if I did this right, but here is my JavaScript version with a FPS counter.    https://jsfiddle.net/9sbvsz11/2/ ---------------------------------------------------------------------- lainz · 2017-02-03 13:07 Quote from: Graeme on February 03, 2017, 01:55:11 pmThe tunnel is also smaller in the JavaScript version, so your viewing perspective is different and there is less to render. The JavaScript version does perform pretty impressive non the less - just goes to show how good the HTML5 Canvas is in modern web browsers. That's it. I changed it to 640x400 and performs almost the same like Java. Also the Java version runs as smooth if I change the resolution to 200x200. ---------------------------------------------------------------------- User137 · 2017-02-03 14:44 I wouldn't consider that a good example for graphics performance. OpenGL or graphics cards in general aren't optimized for changing individual pixels in the program code. Even the more modern Minecraft is using textures in quads (or triangles). ---------------------------------------------------------------------- Graeme · 2017-02-03 16:10 Quote from: User137 on February 03, 2017, 03:44:25 pmI wouldn’t consider that a good example for graphics performance. OpenGL or graphics cards in general aren’t optimized for changing individual pixels in the program code. Even the more modern Minecraft is using textures in quads (or triangles). And that is exactly what I’m going to do. Strange thing is, all the SDL (v1 and v2) with OpenGL usage examples I have seen are pretty horribly written. All procedurely written with near zero code reuse. I’m about to change that. So far I’ve written a BaseModel, Renderer (render the vertices we have stored in the VBO’s), Loader (for VBO’s and VAO’s handling and cleanup) and a DisplayManager (setting up SDL window and OpenGL context) class. Tons of code reuse is already possible  - even between different projects, where classes can now be used as-is. This will all be released as part of my Graphics Contest 2017 entry. ---------------------------------------------------------------------- lainz · 2017-02-03 16:38 Quote from: Graeme on February 03, 2017, 05:10:22 pmQuote from: User137 on February 03, 2017, 03:44:25 pmI wouldn’t consider that a good example for graphics performance. OpenGL or graphics cards in general aren’t optimized for changing individual pixels in the program code. Even the more modern Minecraft is using textures in quads (or triangles). And that is exactly what I’m going to do. Strange thing is, all the SDL (v1 and v2) with OpenGL usage examples I have seen are pretty horribly written. All procedurely written with near zero code reuse. I’m about to change that. So far I’ve written a BaseModel, Renderer (render the vertices we have stored in the VBO’s), Loader (for VBO’s and VAO’s handling and cleanup) and a DisplayManager (setting up SDL window and OpenGL context) class. Tons of code reuse is already possible  - even between different projects, where classes can now be used as-is. This will all be released as part of my Graphics Contest 2017 entry. Wow I will need to do something else to get a vote this year, you're doing a library, others are doing games. This will be a good year for the contest. ---------------------------------------------------------------------- Graeme · 2017-02-03 16:50 Quote from: lainz on February 03, 2017, 05:38:36 pmWow I will need to do something else to get a vote this year, you’re doing a library, others are doing games. This will be a good year for the contest. hahaha… Don’t get too worried, this is my very first foray into gaming and 3D graphics, but I’m finding it incredibly interesting. I don’t know why I haven’t tried it before. It is so much more fun than programming accounting software, reports or object persistence frameworks.  For the contest I’m actually going to submit a game (hopefully something playable), which will obviously use what I’ve described (reusable classes in a more OOP way). But up to now, I didn’t really think of the classes so far as a “library” - merely a more OOP approach to SDL and OpenGL. ---------------------------------------------------------------------- Handoko · 2017-02-03 16:54 Quote from: Graeme on February 03, 2017, 05:10:22 pmStrange thing is, all the SDL (v1 and v2) with OpenGL usage examples I have seen are pretty horribly written. All procedurely written with near zero code reuse. I heard SDL is often used to complement OpenGL, which I think you don't need SDL if you just want to write things related with OpenGL only. Perhaps you may want to try ZenGL. If I have to choose SDL or ZenGL, I will choose ZenGL. It has 3 big advantages: -  FreePascal are officially supported: 2.6.x & 2.4.x. and checked with Delphi 7 & XE2 - Can be static compiled with the application - It optimized with OpenGL, OpenGL ES 1.x and Direct3D More info: http://wiki.freepascal.org/Graphics_libraries http://www.zengl.org/wiki/doku.php?id=compilation:basics http://wiki.freepascal.org/ZenGL_Tutorial ---------------------------------------------------------------------- Graeme · 2017-02-03 17:31 Thanks Handoko. I’ll take a look at ZenGL. Incidentally I also looked at Allegro before I started, but the latest version of Allegro (v5.x if I remember correctly) is not support on FreeBSD (my development workstation). The latest versions of SDL2+OpenGL however are both supported on FreeBSD. The reason I included SDL2 in the mix is because I need it for game input, sound and text. I heard that OpenGL has a new “helper library” to accomplish the same, but I couldn’t find Object Pascal header translations for them. So SDL2 + OpenGL it is for now. ---------------------------------------------------------------------- skalogryz · 2017-02-03 18:16 Quote from: Graeme on February 03, 2017, 06:31:12 pmThe reason I included SDL2 in the mix is because I need it for game input, sound and text. I heard that OpenGL has a new “helper library” to accomplish the same, but I couldn’t find Object Pascal header translations for them. So SDL2 + OpenGL it is for now. Game Input is supported in native SDL2, no helper libraries required. 2 Handoko, SDL2 supports DirectX, OpenGL, OpenGLES as well. ---------------------------------------------------------------------- Akira1364 · 2017-02-03 18:42 I've recommended this in another thread, but it's worth repeating: you might want to try out the Castle Game Engine. It's written 100% in FPC, is very cross-platform (Windows, Linux,  OSX, iOS, Android), has built in support for pretty much anything you could want to do in a game (as well as an advanced OpenGL renderering system), and has no dependencies on any external libraries. It also includes an optional set of LCL components (but again, has no overall dependencies on Lazaus or the LCL whatsoever.) ---------------------------------------------------------------------- Handoko · 2017-02-03 22:32 Yes, Castle Game Engine is really a good game engine that worth to have a look. I ever tried it although I never learn it seriously. I notice these notable features: - Plenty of 3D features - Scene manager - It has a build tool to make Android games - Good support on their forum and many demo examples ---------------------------------------------------------------------- Paul_ · 2017-04-16 11:28 - ZenGL is dead, but structure is very interesting and code is good for learning - SDL seems unnecessarily complicated For 2D and Windows here is also SFML: http://forum.lazarus.freepascal.org/index.php/topic,33877 It have community, support, lot of features, shaders, it's simple. ---------------------------------------------------------------------- Graeme · 2017-04-16 12:11 PaulG, I don't know why you say SDL is unnecessary complicated - could you elaborate? I was totally new to SDL and OpenGL 2 months ago. Yet using SDL2 to set up my OpenGL window was really simple. After that I'm using OpenGL API calls directly to do the rest of my rendering, including using shaders. ---------------------------------------------------------------------- Carver413 · 2017-04-16 17:16 Quote from: Graeme on April 16, 2017, 02:11:21 pmPaulG, I don't know why you say SDL is unnecessary complicated - could you elaborate? I was totally new to SDL and OpenGL 2 months ago. Yet using SDL2 to set up my OpenGL window was really simple. After that I'm using OpenGL API calls directly to do the rest of my rendering, including using shaders. I dont think any of these frameworks are overly difficult to learn but really none offer an optimal solution. I am using Sdl2 + Opengl, I chose to use Sdl for better support of other Os's but that really doesn't work because Opengl isn't supported equally on all targets. so now my code could only work on two systems provided there graphic cards are up to par. lately I've been trying to seperate these dependencies so that my code would be more adaptable to other frameworks. my first approach was to put all dependences into a separate framework but this only creates new dependences  that would be tied to my framework. so now I'm looking at advanced records as a solution. they have come a long way since I started using them, I see now they support Initialize and finalize witch would be perfect for closing up buffers and such. by using records we can avoid having to adapt to someone else's framework unless we choose to do so. we could even go as far as dropping these hi level frameworks all together by targeting individual Os's. you and I could share the same X code without me having to adapt fpGui or you having to adapt the explorer. ---------------------------------------------------------------------- Graeme · 2017-04-18 08:30 Quote from: Carver413 on April 16, 2017, 07:16:05 pmI am using Sdl2 + Opengl, I chose to use Sdl for better support of other Os's but that really doesn't work because Opengl isn't supported equally on all targets. so now my code could only work on two systems provided there graphic cards are up to par. Again, I'm not sure that is any fault of SDL's. OpenGL abilities are based on the GPU and the graphics drivers you have installed. The most popular graphics systems probably being NVIDIA, AMD, and they both support up to OpenGL 4 very well. Based on my own SDL2+OpenGL code, I can't see why my program would only be supported on select platforms. If those platforms have OpenGL 4 support (which is the API I'm targeting) via their graphics drivers, everything should work just fine. Note that OpenGL 4 has been around for years. ---------------------------------------------------------------------- Thaddy · 2017-04-18 08:35 Oh, well, OpenGL is already an abstraction, DirectWhatever is an abstraction, SDL is an abstraction ON TOP OF THOSE. That does not mean any negative or positive. It only means a lot of you have to learn a lot about architecture. For the simple minds (and advanced X platform programmers) SDL is the easiest to learn. But both lower level ones are almost just as easy or difficult. In the end it is always: I want to write a game but I know jack sh*t about matrices or basic collision detection math (isn't even in opengl) and I don't want to learn it. Won't go... The basics is simply a vector x,y,z,l,r.f.b,u,d That's a nine vector matrix.(81 square) It's simple. Not counting gravity...  and some other... Positive is if you can solve matrices, you can solve game programming. Sigh. ---------------------------------------------------------------------- User137 · 2017-04-18 11:13 OpenGL is directly accessing the GPU, same as DirectX is. They are not at all referring to each other in any way. SDL is also quite direct at what it does, but it is only optional. Now that you mention matrix math, i can show some code    https://github.com/Zaflis/nxpascal/blob/master/src/nxMath3D.pas  Someone once said that time is better spent at making games, not at making engines. There are a few around there that have figured out most of this for you. What's left is to apply your ideas in simple ways, such as: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var a, b, c: TMatrix; // Common 4x4 matrixbegin  c:=a * b; // Matrix multiplicationend; ---------------------------------------------------------------------- Paul_ · 2017-04-20 15:35 Quote from: Graeme on April 16, 2017, 02:11:21 pmI don't know why you say SDL is unnecessary complicated - could you elaborate?. It's about structure and ergonomy. I have some experience with SDL 1.x it was reallly chaotic and difficult to use. If you look how e.g. ZenGL is done it makes big difference in coding, how you use functions, it's very compact and so. Maybe in SDL 2 it's better but if you look at Wiki pages, documentation.. I'm not sure. Of course it depends on what you will do, if you need only OpenGL window so it's not big deal. ---------------------------------------------------------------------- Akira1364 · 2017-05-12 02:31 Quote from: PaulG on April 20, 2017, 05:35:16 pmQuote from: Graeme on April 16, 2017, 02:11:21 pmI don't know why you say SDL is unnecessary complicated - could you elaborate?. It's about structure and ergonomy. I have some experience with SDL 1.x it was reallly chaotic and difficult to use. If you look how e.g. ZenGL is done it makes big difference in coding, how you use functions, it's very compact and so. Maybe in SDL 2 it's better but if you look at Wiki pages, documentation.. I'm not sure. Of course it depends on what you will do, if you need only OpenGL window so it's not big deal. IMO neither ZenGL alone or SDL with "OpenGL on top" are the way to go these days. ZenGL is not only entirely constructed from deprecated, slow functionality, but also is barely object oriented at all and seems to have been pretty obviously written by someone who spent most of their life writing C89 code and not Object Pascal. (Nothing wrong with that on its own, but it's not what you want with a game engine.) SDL/SDL2 on the other hand boil down to simplistic window management functionality and certainly aren't "engines" of any kind. So yeah, if you're looking to write OpenGL applications that will stand the test of time in Object Pascal, I would definitely recommend you use something like Castle or TERRA that is actually actively maintained and written "with the future in mind". ---------------------------------------------------------------------- FPK · 2017-05-13 09:57 As the topic came up on fpc-pascal I will answer here. I had a look at it (I used the code posted here: http://forum.lazarus.freepascal.org/i ndex.php/topic,35555.msg235937.html#msg235937). First of all, there is a big difference between i386 and x86-64. All JIT based languages probably use x86-64. So please, compare only the x86-64 results. FPC generates at certain places not perfect code, in trunk I will fix a few of these things.