## Tutorial: Software 3d and matrix manipulations.

Game development specific discussions.
podvornyak
Posts: 148
Joined: Nov 12, 2007 11:46
Location: Russia

### Tutorial: Software 3d and matrix manipulations.

Tutorial is about matrix multiplications and hardware independent graphic. If you have a questions or corrections, post them.

Code: Select all

`' nblJIG 2013' Esc - exit.' W - move forward.' S - move backward' A - strafe left' D - strafe right' C - strafe down' SPACE - strafe up' Q - tilt left' E - tilt right' What is the matrix? Matrix is just an array. No more, no less.' That array contain a specified values. What special about them?' Nothing. That values is just scalars. What does it mean?' Simple. Let say you have a value X = 2, and you want to scale that value' ten times. So you just need to multiply X with ten. X*10=20' In that case 10 is scalar. If that scalar will be -0.5, then X become' X*-0.5 = -1. That is how matrixes work. Then why matrixes is so popular?' It is cause of martix multiplication. Let's say you need move one million' 3d points to specified angle in 3d environment. First you'll move each' point around x and than around y to get result position.' With matrixes it became one operation - vector with matrix multiplication.' And not only rotate. Even move and scale in the same one operation.' To do this you need to get the matrix containing all that transformations.' To get that matrix you need multiply five matrixes - matrix of translation,' matrix of transformation and three matrixes of rotation (x, y, z)' If you think that is to complicate preparations, you can count by yourself,' but when you get the final matrix you will change your mind.' Let's define matrix now. Matrix is two dimensional array.data 1, 0, 0, 0data 0, 1, 0, 0data 0, 0, 1, 0data 0, 0, 0, 1' That is an 4X4 matrix and it suit in most cases. With those values' it is a SINGLE matrix. Single matrix do nothing. It is just like a clear page.' In this code i use one dimensional array to store values. ' Allocate some storages.dim as single ptr matrix_global = allocate(sizeof(single)*16)dim as single ptr matrix_rotate_x = allocate(sizeof(single)*16)dim as single ptr matrix_rotate_y = allocate(sizeof(single)*16)dim as single ptr matrix_rotate_z = allocate(sizeof(single)*16)dim as single ptr matrix_translate = allocate(sizeof(single)*16)dim as single ptr matrix_buffer = allocate(sizeof(single)*16)dim as single ptr matrix_result_one = allocate(sizeof(single)*16)dim as single ptr matrix_result_two = allocate(sizeof(single)*16)' Differend storages will contain differen values, so that why i've' define eight storages. Global matrix will contain final matrix of' all transformations. Rotate matrixes will contain sinus and cosinus' values of rotation angles. Translate will contain translation values' Last three matrixes will contain special defined transformation values' and matrix multiplication results.' All storages for now not even clean, so let's assign to them SINGLE' matrix values from DATA block of code.' Template variables of typedim shared as integer idim shared as single value_single ' for each value of all storagesfor i = 0 to 15   ' Read value from data block of code,   read value_single      ' and assign.   matrix_global    [i] = value_single   matrix_rotate_x  [i] = value_single   matrix_rotate_y  [i] = value_single   matrix_rotate_z  [i] = value_single   matrix_translate [i] = value_single   matrix_buffer    [i] = value_singlenext i' To see how each matrix values should look i'll type them in comments' Rotation x matrix'   1 |     0  |      0  | 0 '   0 | cos(x) | -sin(x) | 0'   0 | sin(x) |  cos(x) | 0'   0 |     0  |      0  | 1' Rotation y matrix'    cos(y) | 0 | sin(y) | 0'         0 | 1 |      0 | 0'   -sin(y) | 0 | cos(y) | 0'         0 | 0 |      0 | 1'' Rotation z matrix'   cos(z) | -sin(z) | 0 | 0'   sin(z) |  cos(z) | 0 | 0'        0 |       0 | 1 | 0'        0 |       0 | 0 | 1' Translation matrix'   1 | 0 | 0 | x'   0 | 1 | 0 | y'   0 | 0 | 1 | z'   0 | 0 | 0 | 1'' That is how matrixes looks like. If you wish to know more about' matrix dimensions and types you can search information over internet.' In this tutorial i don't spot on other transformation matrixes, cause' we don't use them.' Well. For easy access to matrixes values i'll assign pointers' to some of them.' Defining names of pointers.dim shared as single ptr cos_angle_x1, cos_angle_x2, _                   cos_angle_y1, cos_angle_y2, _                   cos_angle_z1, cos_angle_z2, _                   sin_angle_x, sin_angle_x_minus, _                   sin_angle_y, sin_angle_y_minus, _                   sin_angle_z, sin_angle_z_minus, _                   translate_x, translate_y, translate_z, _                   camera_distance                   ' Assign pointers to matrixes variables.cos_angle_x1      = @matrix_rotate_x sin_angle_x_minus   = @matrix_rotate_x sin_angle_x      = @matrix_rotate_x cos_angle_x2      = @matrix_rotate_x cos_angle_y1      = @matrix_rotate_y sin_angle_y      = @matrix_rotate_y sin_angle_y_minus   = @matrix_rotate_y cos_angle_y2      = @matrix_rotate_y cos_angle_z1      = @matrix_rotate_z sin_angle_z_minus   = @matrix_rotate_z sin_angle_z      = @matrix_rotate_z cos_angle_z2      = @matrix_rotate_z translate_x = @matrix_translate translate_y = @matrix_translate translate_z = @matrix_translate camera_distance = @matrix_buffer ' Now we need angles values to calculate trigonometric values.' Angles of rotation variables.dim shared as single angle_x, angle_y, angle_z' Next step is functions.' First is function that refill all matrixes with new values.sub matrixes_refill' Function assume nothing and return nothing.' It calculate trigonometric values and assign them to matrixes.   *cos_angle_x1      = cos(angle_x)   *cos_angle_x2      = *cos_angle_x1   *sin_angle_x      = sin(angle_x)   *sin_angle_x_minus   = -(*sin_angle_x)   *cos_angle_y1      = cos(angle_y)   *cos_angle_y2      = *cos_angle_y1   *sin_angle_y      = sin(angle_y)   *sin_angle_y_minus   = -(*sin_angle_y)   *cos_angle_z1      = cos(angle_z)   *cos_angle_z2      = *cos_angle_z1   *sin_angle_z      = sin(angle_z)   *sin_angle_z_minus   = -(*sin_angle_z)end sub' Next, we need function that copy values of one matrix to another.sub matrix_copy (a as single ptr, b as single ptr)' Function assume two pointers to arrays and copy values from a to b   for i =  0 to 15         b[i] = a[i]   next iend sub' And most important functions.' Multiplication of two matrixes.' Rule of multiplication is: "Multiply row with column". Lets make it.sub multiply_matrix (a as single ptr, b as single ptr, c as single ptr)' Function assume three pointers to arrays, multiply values from' b array to value from a array and put the result in c array.   c = a*b   + a*b  + a*b   + a*b   c = a*b   + a*b  + a*b   + a*b   c = a*b   + a*b  + a*b  + a*b   c = a*b   + a*b  + a*b  + a*b      c = a*b   + a*b  + a*b   + a*b   c = a*b   + a*b  + a*b   + a*b   c = a*b   + a*b  + a*b  + a*b   c = a*b   + a*b  + a*b  + a*b      c = a*b   + a*b  + a*b  + a*b   c = a*b   + a*b  + a*b  + a*b   c = a*b  + a*b  + a*b + a*b   c = a*b  + a*b  + a*b + a*b   c = a*b + a*b + a*b  + a*b   c = a*b + a*b + a*b  + a*b   c = a*b + a*b + a*b + a*b   c = a*b + a*b + a*b + a*b' You can use iteration cycles for this function, but it will' significantly reduce calculation speed.end sub' Multiplication matrix with vector.' Same rule, except - result is vector.sub multiply_vector (a as single ptr, b as single ptr, c as single ptr)' Function assume one matrix array pointer, two vector array pointers,' multiply values from b array to value from a array' and put the result in c array.   c = a*b  + a*b  + a*b  + a*b   c = a*b  + a*b  + a*b  + a*b   c = a*b  + a*b  + a*b + a*b   c = a*b + a*b + a*b + a*bend sub' What next? We need to get vectors. Vectors? Yes - them.' But where? Simple - load obj file or generate array of 3d-points. Yes -' x, y and z values of point is a vector. Null vector actually. And those we' will transform with matrixes - 3d geometry. But our vector suppose to be' 4-value point. The value of the 4-th variable must be 1. That is it. So let's load' some geometry. You can use your own *.obj file, or download file from' post link.' Type vector contain four values x, y, z, 1type TYPE_VECTOR   as single position(3) => {0,0,0,1}end type' Resizable array of vector type variables.redim shared as TYPE_VECTOR vertex(0)' function to load *.obj filessub load_obj_file(filename as string, _                offset_x as single = 0, offset_y as single = 0, offset_z as single = 0)             dim as integer file, dimension, lenght, i      dim as string buffer, value, symbol      file = freefile      open filename for binary access read as #file      if (file<>0) then      while not eof(file)         line input #file, buffer         lenght = len(buffer)         select case mid(buffer, 1, 2)            case "v "               dimension = 0               for i = lenght to 2 step -1                  symbol = mid(buffer, i, 1)                  if symbol <> " " then                     value = symbol + value                  else      if dimension = 0 then vertex(ubound(vertex)).position(dimension) = val(value)+offset_x      if dimension = 1 then vertex(ubound(vertex)).position(dimension) = val(value)+offset_y      if dimension = 2 then vertex(ubound(vertex)).position(dimension) = val(value)+offset_z      dimension += 1      value = ""                  end if               next i      redim preserve as TYPE_VECTOR vertex(lbound(vertex) to ubound(vertex)+1)            end select         wend      end if   close #fileend sub' You can assign offset to loaded geometry by adding three values after' filename argument, x, y, zload_obj_file "file.obj", , , -900' Also you can load more than one file. Call function again, with new arguments.' load_obj_file "file.obj"' Now we put all together.' Window size and bit depth.dim as integer screen_width=1024, screen_height=768, bit_depth = 32' Position of pixel on screen, mouse position and event check for mouse and keyboard.dim as integer screen_x, screen_y, mouse_x, mouse_y, event_check = 0' Middle screen position.dim as integer screen_width_half = screen_width/2, _            screen_height_half = screen_height/2' Fps calculation variables.dim as double time_last, time_current, fps_count, fps_value' Get current system time.time_last = timer' Start window.screenres screen_width, screen_height, bit_depth, 0, 0' Set mouse in the middle of the window and hide system cursor.' On start, if cursor is out of starting window borders the values' of position is unpredictable. I'll Fix it with ScreenEvent function' at final stage. Just move mouse untill you see geometry.setmouse screen_width_half, screen_height_half, 0' Name window.windowtitle "matrix-shmatrix-mathematics"' Define pointer and assign it to back buffer.dim as ubyte ptr frame_buffer = screenptr' Start main cyclewhile not multikey(&h01) ' Esc key for exit      ' get current time   time_current=timer   ' increment fps counter   fps_count += 1      'check - is one second passed by?   if time_current > time_last + 1 then         ' store current time,      time_last = time_current      ' store actual fps      fps_value = fps_count      ' drop down counter to zero      fps_count = 0   end if   ' clean delta values   *translate_x = 0   *translate_y = 0   *translate_z = 0   angle_x = 0   angle_y = 0   angle_z = 0   ' get mouse current position values   getmouse (mouse_x, mouse_y)      ' if mouse position values not equal to middle of window position   if mouse_x<>screen_width_half or mouse_y<>screen_height_half then         ' store delta values. X mouse movment is rotation around Y aixs. Same for Y movement.      angle_y = (screen_width_half - mouse_x)/500      angle_x = (screen_height_half - mouse_y)/500            ' set back mouse in the middle of the window      setmouse(screen_width_half, screen_height_half)            ' check event on      event_check = 1   end if   ' if key is pressed - store delta value and check event on   if multikey(&h1e) then *translate_x = 0.1:  event_check = 1: end if ' a   if multikey(&h20) then *translate_x = -0.1: event_check = 1: end if ' d   if multikey(&h2c) then                      event_check = 1: end if ' z   if multikey(&h2d) then                      event_check = 1: end if ' x   if multikey(&h2e) then *translate_y = 0.1:  event_check = 1: end if ' c   if multikey(&h39) then *translate_y = -0.1: event_check = 1: end if ' space   if multikey(&h11) then *translate_z = -0.1: event_check = 1: end if ' w   if multikey(&h1f) then *translate_z = 0.1:  event_check = 1: end if ' s   if multikey(&h10) then angle_z = -0.004:    event_check = 1: end if ' q   if multikey(&h12) then angle_z = 0.004:     event_check = 1: end if ' e   ' event check is on?   if event_check then      ' refill matrixes with new delta values      matrixes_refill()      ' Before start multiplying matrixes, assign negative translation value -1000' to buffer matrix. It is necessary cause we did not create any camera and' all transformations going around projection plane. We can' say that middle of projection plane is camera point of view (POV).' With assigning negative distance value we telling that, actually' camera is behind projection plane and transformations should happen' around camera position, not around camera POV. If you need more clues' about projection plane, let me know.      *camera_distance=-1000 ' matrix_buffer' Now we start multiply matrixes. We got matrix with first transformation - ' translation of camera position. Also, after refilling other matrixes ' with new delta values we can multiply them to our first transformation.' Lets do this.            ' multiplying buffer matrix with translation matrix, adding more      ' translations to our transformations.      multiply_matrix (matrix_buffer, matrix_translate, matrix_result_one)            ' multiplying result matrix with rotation matrixes.      ' watchout name of variables. i'm crossing it to evade copying values      multiply_matrix (matrix_result_one, matrix_rotate_x, matrix_result_two)      multiply_matrix (matrix_result_two, matrix_rotate_y, matrix_result_one)      multiply_matrix (matrix_result_one, matrix_rotate_z, matrix_result_two)            ' All transvormations is multiplyed to matrix. Now we can move back      ' camera position in positive dirrection.      *camera_distance=1000 ' matrix_buffer            ' and add this transformation to matrix      ' multiplying last result to buffer matrix      multiply_matrix ( matrix_result_two, matrix_buffer, matrix_result_one)            ' and last multiplication      ' multiply transformations that already happen before, stored in global matrix.      ' Yes - at the first itteration of cycle that matrix is clean, but if you look to next string      ' of code, you'll see that we use matrix_copy function and it argumented with global      ' matrix. On each cycle iteration we just adding some delta transformations to global matrix.      multiply_matrix ( matrix_result_one, matrix_global, matrix_result_two)            ' copying result values to global matrix      matrix_copy ( matrix_result_two, matrix_global)            'off event check      event_check = 0         end if' Ok. We got global transformation matrix and next step is transform ' geometry with that and draw it on screen.   screenlock   cls   ' Cause we use UBYTE pointer to back buffer we must assign color   ' values to each channel of RGBA except Alpha channel.      ' To spot how do this easy i've put defination of temporal pointer   ' to back buffer memory in here, but better you move it outside   ' main cycle. Also i'll define temporal storage to hold transformed   ' values of one vertex, and that defination must be moved outside   ' cycle to.   ' This is a temporal variable to hold one vertex values.   dim as single cursor(3) => {0,0,0,1}   ' defining pointer to current memory position   dim as ubyte ptr tmp      ' Now we go throug all vertexes of geometry, deform them with   ' multiply_vector function, calculate projection position of   ' pixel on screen and add color to that pixel.   for i = 0 to ubound(vertex)-1         ' multiplying vector (vertex of geometry) with global matrix      multiply_vector (matrix_global, @vertex(i).position(0), @cursor(0))      ' we got position of vertex after transition and rotation      ' stored in cursor() array.            ' calculating screen pixel position      screen_x = screen_width_half  + cursor(0)*1000/(cursor(2)+1000)      screen_y = screen_height_half - cursor(1)*1000/(cursor(2)+1000)            ' That is it - we know pixel position on screen. Last thing      ' is add color value to this pixel.            ' Check  - is pixel fit the window size and point is in front of camera?      if ((screen_x < screen_width and screen_x > -1) and _                    (screen_y < screen_height and screen_y> -1)) and _                     cursor(2)>-1000 then                  ' we using 32 bit color (24 bit acrually, last one is alpha         ' channel). It mean that for color of each pixel on screen,         ' four bytes allocated in frame buffer - Red, Green, Blue         ' and Alpha. Alpha is the last byte, but other is going in         ' back order - BGRA. Why is it? I Don't know. Anyway - you         ' can use uinteger pointer to back buffer and assign all         ' bytes at once with RGBA(r,g,b,a) function. But it would be         ' harder to compare color value of pixel from buffer with         ' your value-to-assign. It may become more complicated.                  ' store memory adress of first byte of color value.         tmp = frame_buffer + screen_y*screen_width*4 + screen_x*4                  ' blue component is high enough?         if *tmp < 195 then            ' increment blue value            *tmp += 60         end if                  ' increment pointer         tmp += 1                  ' green component is high enough?         if *tmp < 225 then            ' increment green value            *tmp += 30         end if                  ' increment pointer         tmp +=1                   ' red component is high enough?         if *tmp < 245 then            ' increment red value            *tmp += 10         end if      end if   next i      ' Displaying fps and amount of vertexes.   draw string (0,10), "fps: "+ str(fps_value)   draw string (0,20), "vertexes: "+ str(ubound(vertex)-1)   screenunlock   sleep 1wenddeallocate matrix_globaldeallocate matrix_rotate_xdeallocate matrix_rotate_ydeallocate matrix_rotate_zdeallocate matrix_translatedeallocate matrix_bufferdeallocate matrix_result_onedeallocate matrix_result_two' That is all. Hope you find this tutorial interesting... at least.end`

FILE.OBJ file 200k points 5.7 mb

If you interested in another software 3d tutorial, about drawing polygons, let me know.
Last edited by podvornyak on Sep 06, 2013 0:05, edited 20 times in total.
petan
Posts: 683
Joined: Feb 16, 2010 15:34
Location: Europe
Contact:

### Re: Tutorial: Software 3d and matrix manipulations.

Seeing inverted motions - my mouse <-> blue cloud on monitor.
e.g.: Mouse goes down, but cloud goes up.
podvornyak
Posts: 148
Joined: Nov 12, 2007 11:46
Location: Russia

### Re: Tutorial: Software 3d and matrix manipulations.

petan wrote:...

Blue cloud? Try to fly closer with W key or farther with S key. Yes - it is a free camera - if you move mouse down the view move up... like when you turn your head...
Last edited by podvornyak on Jun 13, 2013 9:56, edited 1 time in total.
petan
Posts: 683
Joined: Feb 16, 2010 15:34
Location: Europe
Contact:

### Re: Tutorial: Software 3d and matrix manipulations.

Aha, in such manner thinked, understanding, thx.
For my last missing thing (4D visualisation on really huge data) I am laboring on independent camera features - motion&view, t.m. camera moving in one direction and I can change among front-back-left-right-up-down cameraview (like in fly-fight-combat games).
FotonCat
Posts: 37
Joined: Nov 26, 2009 11:47
Location: Russia
Contact:

### Re: Tutorial: Software 3d and matrix manipulations.

Thank you very much for such easy to understand 3d matrix tutorial! It will be very useful for me to learn how matrixes work in the 3d software rendering, because I'm developing my own 3d software renderer currently. :) Good job!
dodicat
Posts: 5988
Joined: Jan 10, 2006 20:30
Location: Scotland

### Re: Tutorial: Software 3d and matrix manipulations.

Here's a simple Y axis rotate and some mouse movements and mousewheel using the obj file:

Code: Select all

`type V3    as single x,y,z    Declare Function PointRotate(As v3,As v3,As v3=Type<v3>(1,1,1)) As v3end type#define vct type <V3>#define onscreen xx>=0 and xx<xres and yy>=0 and yy<yres#macro ppset(_x,_y,colour)pixel=row+pitch*(_y)+4*(_x)*pixel=(colour)#endmacroOperator + (v1 As v3,v2 As v3) As v3Return Type<v3>(v1.x+v2.x,v1.y+v2.y,v1.z+v2.z)End OperatorOperator -(v1 As v3,v2 As v3) As v3Return Type<v3>(v1.x-v2.x,v1.y-v2.y,v1.z-v2.z)End OperatorOperator * (f As Single,v1 As v3) As v3 Return vct(f*v1.x,f*v1.y,f*v1.z)End OperatorOperator *(v1 As v3,f As Single) As v3Return f*v1End OperatorFunction v3.PointRotate(_point As v3,Angle As v3,scale As v3=Type<v3>(1,1,1)) As v3    Dim As v3 p=vct(This-_point)    Dim As v3 rot,temp    Dim As Single s=Sin(angle.x),c=Cos(angle.x)    temp=vct((p.y)*C+(-p.z)*S,(p.z)*C+(p.y)*S)    rot.y=temp.x    s=Sin(angle.y):c=Cos(angle.y)    temp=vct((temp.y)*C+(-p.x)*S,(p.x)*C+(temp.y)*S)    rot.z=temp.x    s=Sin(angle.z):c=Cos(angle.z)    temp=vct((temp.y)*C+(-rot.y)*S,(rot.y)*C+(temp.y)*S)    rot.x=temp.x:rot.y=temp.y    Return vct((scale.x*rot.x+_point.x),(scale.y*rot.y+_point.y),(scale.z*rot.z+_point.z))End Functionredim shared as V3 vertex(0)sub load_obj_file(filename as string, _                offset_x as single = 0, offset_y as single = 0, offset_z as single = 0)             dim as integer file, dimension, lenght, i      dim as string buffer, value, symbol      file = freefile      open filename for binary access read as #file      if (file<>0) then      while not eof(file)         line input #file, buffer         lenght = len(buffer)         select case mid(buffer, 1, 2)            case "v "               dimension = 0               for i = lenght to 2 step -1                  symbol = mid(buffer, i, 1)                  if symbol <> " " then                     value = symbol + value                  else      if dimension = 0 then vertex(ubound(vertex)).x = val(value)+offset_x      if dimension = 1 then vertex(ubound(vertex)).y = val(value)+offset_y      if dimension = 2 then vertex(ubound(vertex)).z = val(value)+offset_z      dimension += 1      value = ""                  end if               next i      redim preserve as V3 vertex(lbound(vertex) to ubound(vertex)+1)            end select         wend      end if   close #fileend subsub blow(v() as V3,mag as double,d as V3)    for n as integer=lbound(V) to ubound(V)    V(n)=mag*V(n)+D    next nend subload_obj_file "file.obj", , , -900Dim As Any Pointer rowDim As Integer pitch,xres,yresDim As Uinteger Pointer pixelScreen 20,32row=ScreenptrScreeninfo xres,yres,,,pitchblow(vertex(),10,vct(xres/2,yres/2-200,9000))dim as integer cx=xres/2dim as integer cy=yres/2dim as V3 C=vct(cx,cy,0)dim as V3 angledim as single pi=4*atn(1)dim as integer mx,my,wheeldim as V3 mouse,scaledo    getmouse mx,my,wheel    scale=vct(1+wheel/10,1+wheel/10,1+wheel/10)    mouse=vct(mx,my,0)-C    angle.z=-pi    angle.y=angle.y+.1    screenlock    cls    for z as integer=lbound(vertex) to ubound(vertex)        var t=vertex(z).pointrotate(C,angle,scale)        dim as integer xx=t.x+mouse.x,yy=t.y+mouse.y       if onscreen then        ppset(xx,yy,rgb(0,0,255))        end if        next z    screenunlock    sleep 1,1    loop until len(inkey) `
podvornyak
Posts: 148
Joined: Nov 12, 2007 11:46
Location: Russia

### Re: Tutorial: Software 3d and matrix manipulations.

dodicat wrote:...

What about it? Can't say that is clear... except it work three time slower.
dodicat
Posts: 5988
Joined: Jan 10, 2006 20:30
Location: Scotland

### Re: Tutorial: Software 3d and matrix manipulations.

It's not as fast as yours, only a simple alternative and a bit of a mess around.

Here it is again with some perspective added.
Now she is Port and Starboard handed.

Code: Select all

` Type V3    As Single x,y,z    Declare Function PointRotate(As v3,As v3,As v3=Type<v3>(1,1,1)) As v3End Type#define map(a,b,x,c,d) ((d)-(c))*((x)-(a))/((b)-(a))+(c)#define vct type <V3>#define onscreen xx>=0 and xx<xres and yy>=0 and yy<yres#macro ppset(_x,_y,colour)pixel=row+pitch*(_y)+(_x)*4*pixel=(colour)#endmacroOperator + (v1 As v3,v2 As v3) As v3Return Type<v3>(v1.x+v2.x,v1.y+v2.y,v1.z+v2.z)End OperatorOperator -(v1 As v3,v2 As v3) As v3Return Type<v3>(v1.x-v2.x,v1.y-v2.y,v1.z-v2.z)End OperatorOperator * (f As Single,v1 As v3) As v3 Return vct(f*v1.x,f*v1.y,f*v1.z)End OperatorOperator *(v1 As v3,f As Single) As v3Return f*v1End OperatorFunction v3.PointRotate(_point As v3,Angle As v3,scale As v3=Type<v3>(1,1,1)) As v3    Dim As v3 p=vct(This-_point)    Dim As v3 rot,temp    Dim As Single s=Sin(angle.x),c=Cos(angle.x)    temp=vct((p.y)*C+(-p.z)*S,(p.z)*C+(p.y)*S)    rot.y=temp.x    s=Sin(angle.y):c=Cos(angle.y)    temp=vct((temp.y)*C+(-p.x)*S,(p.x)*C+(temp.y)*S)    rot.z=temp.x    s=Sin(angle.z):c=Cos(angle.z)    temp=vct((temp.y)*C+(-rot.y)*S,(rot.y)*C+(temp.y)*S)    rot.x=temp.x:rot.y=temp.y    Return vct((scale.x*rot.x+_point.x),(scale.y*rot.y+_point.y),(scale.z*rot.z+_point.z))End FunctionRedim Shared As V3 vertex(0)Sub load_obj_file(filename As String, _    offset_x As Single = 0, offset_y As Single = 0, offset_z As Single = 0)        Dim As Integer file, dimension, lenght, i    Dim As String buffer, value, symbol        file = Freefile    Open filename For Binary Access Read As #file        If (file<>0) Then        While Not Eof(file)            Line Input #file, buffer            lenght = Len(buffer)            Select Case Mid(buffer, 1, 2)            Case "v "                dimension = 0                For i = lenght To 2 Step -1                    symbol = Mid(buffer, i, 1)                    If symbol <> " " Then                        value = symbol + value                    Else                        If dimension = 0 Then vertex(Ubound(vertex)).x = Val(value)+offset_x                        If dimension = 1 Then vertex(Ubound(vertex)).y = Val(value)+offset_y                        If dimension = 2 Then vertex(Ubound(vertex)).z = Val(value)+offset_z                        dimension += 1                        value = ""                    End If                Next i                Redim Preserve As V3 vertex(Lbound(vertex) To Ubound(vertex)+1)            End Select        Wend    End If    Close #fileEnd SubSub blow(v() As V3,mag As Double,d As V3)    For n As Integer=Lbound(V) To Ubound(V)        V(n)=mag*V(n)+D    Next nEnd SubFunction apply_perspective(p As V3,eyepoint As V3) As V3    Dim As Single   w=1+(p.z/eyepoint.z)    Return vct((p.x-eyepoint.x)/w+eyepoint.x,(p.y-eyepoint.y)/w+eyepoint.y,(p.z-eyepoint.z)/w+eyepoint.z)End Functionload_obj_file "file.obj", , , -900Dim As Any Pointer rowDim As Integer pitch,xres,yresDim As Uinteger Pointer pixelScreen 20,32row=ScreenptrScreeninfo xres,yres,,,pitchblow(vertex(),10,vct(xres/2,yres/2-200,9000))Dim As Integer cx=xres/2Dim As Integer cy=yres/2Dim As V3 C=vct(cx,cy,0)Dim As V3 angleDim As Single pi=4*Atn(1)Dim As Integer mx,my,wheelDim As V3 mouse,scaleangle.z=-piDo    Getmouse mx,my,wheel    scale=vct(1+wheel/10,1+wheel/10,1+wheel/10)    mouse=vct(mx,my,0)-C    angle.y=angle.y+.1    Screenlock    Cls    For z As Integer=Lbound(vertex) To Ubound(vertex)        var t=vertex(z).pointrotate(C,angle,scale)        t=apply_perspective(t,vct(cx,cy,500))        Dim As Integer xx=t.x+mouse.x,yy=t.y+mouse.y        dim as integer col=map(-900*scale.x,900*scale.x,t.z,250,10)        If onscreen Then            ppset(xx,yy,Rgb(col,255-col,.8*col))        End If    Next z    Screenunlock    Sleep 1,1    Loop Until Len(Inkey) `
podvornyak
Posts: 148
Joined: Nov 12, 2007 11:46
Location: Russia

### Re: Tutorial: Software 3d and matrix manipulations.

dodicat wrote:simple alternative
Ah... I see. Syntax depth always welcome. I gonna love it soon - reading uncommented code. No joke. It is part of the deal to become programer, i think... true programer. XD
dodicat
Posts: 5988
Joined: Jan 10, 2006 20:30
Location: Scotland

### Re: Tutorial: Software 3d and matrix manipulations.

Hi podvornyak.
I've made loads of rotators, but nothing really fast, so I'll take note of your 4 X 4 matrix method.

If you want perspective then you need another (perspective) matrix 4 X 4, and another Matrix multiply.
How would this affect your own speed, have you tried it?

Sorry about lack of code comments, I didn't really think it worthy, it's only fun code, nobody would be expected to use it, especially for a huge number of points, e.g. bitmaps e.t.c.
podvornyak
Posts: 148
Joined: Nov 12, 2007 11:46
Location: Russia

### Re: Tutorial: Software 3d and matrix manipulations.

...
Last edited by podvornyak on Jun 17, 2013 18:57, edited 11 times in total.
dodicat
Posts: 5988
Joined: Jan 10, 2006 20:30
Location: Scotland

### Re: Tutorial: Software 3d and matrix manipulations.

Yea Podvornyak, couldn't get it to run.
Look forward to your updated code.

Here's another type of 3D rotator, Rodrigues.

http://en.wikipedia.org/wiki/Rodrigues' ... on_formula

I've done a simple example with four points.
With this rotator you can use either a single axis to rotate round or you can define ANY three axis as the base space.

This type of thing is quite good at say viewing orbits with different axial tilts.

Probably for thousands of points it would be quite slow due to the vector computations.

I've set the three axis as normal x,y and z, but they can be changed.
This is not meant to be anything pictorial, but just runs through Rodrigues method.
The mouse moves the centre of rotation X and Y, the wheel for Z

Code: Select all

`Setenviron("fbgfx=GDI")Type v3    As Single x,y,z    As Uinteger colour    Declare Property length As Single    Declare Property unit As v3    Declare Function AxialRotate(As v3,As Single,As v3) As v3    Declare Function CentreRotate(As v3,As v3=Type<v3>(1,1,1)) As v3    Declare Function perspective(eyepoint As v3) As v3End Type'short cuts to save typing#define vct Type<v3>#define dot *#define cross ^'The three axisDim Shared As V3  X_axis,Y_axis,Z_axis'Some vector operators:Operator + (v1 As v3,v2 As v3) As v3Return Type<v3>(v1.x+v2.x,v1.y+v2.y,v1.z+v2.z)End OperatorOperator -(v1 As v3,v2 As v3) As v3Return Type<v3>(v1.x-v2.x,v1.y-v2.y,v1.z-v2.z)End OperatorOperator * (f As Single,v1 As v3) As v3 'pre mult by scalarReturn vct(f*v1.x,f*v1.y,f*v1.z)End OperatorOperator *(v1 As v3,f As Single) As v3  'post mult by scalarReturn f*v1End OperatorOperator * (v1 As v3,v2 As v3) As Single 'dot productReturn v1.x*v2.x+v1.y*v2.y+v1.z*v2.zEnd OperatorOperator ^ (v1 As v3,v2 As v3) As v3     'cross productReturn Type<v3>(v1.y*v2.z-v2.y*v1.z,-(v1.x*v2.z-v2.x*v1.z),v1.x*v2.y-v2.x*v1.y)End OperatorProperty v3.length As SingleReturn Sqr(this.x*this.x+this.y*this.y+this.z*this.z)End Property' ~ normalizeProperty v3.unit As v3Dim n As Single=this.lengthIf n=0 Then n=1e-20Return vct(this.x/n,this.y/n,this.z/n)End PropertyFunction v3.perspective(eyepoint As v3) As v3    Dim As Single   w=1+(this.z/eyepoint.z)    If w=0 Then w=1e-20    Var result=(This-eyepoint)*(1/w)+eyepoint    result.colour=this.colour    Return resultEnd Function'Rotate about a given axis direction (Rodrigue method)'norm in the function is passed as a unit vector (the axis)Function v3.AxialRotate(centre As v3,Angle As Single,norm As v3) As v3    Dim As v3 V=This-centre,result    result=(V*Cos(Angle)+(Norm cross V)*Sin(Angle)+Norm*(Norm dot V)*(1-Cos(Angle)))+centre    result.colour=this.colour    Return resultEnd Function'General rotate about  any three axis'using the Axial rotate about the chosen axisFunction V3.CentreRotate(ctr As v3,Ang As v3) As V3    Var t1=this.AxialRotate(ctr,Ang.x,x_axis)    Var t2=t1.AxialRotate(ctr,Ang.y,y_axis)    Return t2.AxialRotate(ctr,Ang.z,z_axis)End Function'================  End of Rotation necessities ========================'FOR RUNNING EXAMPLE:'QuicksortSub Qsort(array() As V3,begin As Integer,Finish As Uinteger)    Dim As Integer i=begin,j=finish     Dim As V3 x =array(((I+J)\2))    While  I <= J        While array(I).z > X.z            I+=1        Wend        While array(J).z < X.z            J-=1        Wend        If I<=J Then            Swap array(I),array(J)            I+=1            J-=1        End If    Wend    If J > begin Then Qsort(array(),begin,J)    If I < Finish Then Qsort(array(),I,Finish)End Sub'speed regulatorsFunction framecounter() As Integer    Var t1=Timer,t2=t1    Static As Double t3,frames,answer    frames=frames+1    If (t2-t3)>=1 Then        t3=t2        answer=frames        frames=0    End If    Return answerEnd FunctionFunction regulate(MyFps As Integer,Byref fps As Integer) As Integer    fps=framecounter    Static As Double timervalue    Static As Double delta,lastsleeptime,sleeptime    Var k=1/myfps    If Abs(fps-myfps)>1 Then        If fps<Myfps Then delta=delta-k Else delta=delta+k    End If    sleeptime=lastsleeptime+((1/myfps)-(Timer-timervalue))*(2000)+delta    If sleeptime<1 Then sleeptime=1    lastsleeptime=sleeptime    timervalue=Timer    Return sleeptimeEnd Function'============================================================'define any three axis of rotation'here, just the normal X,Y,Z X_axis=vct(1,0,0)Y_axis=vct(0,1,0)Z_axis=vct(0,0,1)'always normalize any axis (.unit), although here they are already done hereX_axis=X_Axis.unitY_axis=Y_Axis.unitZ_axis=Z_axis.unit'map used for radius on Z axis#define map(a,b,x,c,d) ((d)-(c))*((x)-(a))/((b)-(a))+(c)Dim As Integer xres,yresScreen 20,32Screeninfo xres,yresDim As v3 centre  'Centre of rotationDim As V3 ang     'angle of rotationDim As V3 ScreenEyepoint=(xres/2,yres/2,500) 'for the perspective'set up 8 points to rotate'That is the corners of a boxRedim  As V3 array()Redim As V3 rotated()Dim As V3 ptsFor n As Integer=1 To 8    Select Case n    Case 1:pts=vct(-1, 1,-1)    Case 2:pts=vct( 1, 1,-1)    Case 3:pts=vct( 1,-1,-1)    Case 4:pts=vct(-1,-1,-1)    Case 5:pts=vct(-1, 1, 1)    Case 6:pts=vct( 1, 1, 1)    Case 7:pts=vct( 1,-1, 1)    Case 8:pts=vct(-1,-1, 1)    End Select    Redim Preserve array(1 To Ubound(array)+1)    'magnify and translate the points to suit screen    pts=100*pts+vct(xres/2,yres/2,0)    'vectors also have a colour field    pts.colour=Rgb(Rnd*255,Rnd*255,Rnd*255)    array(Ubound(array))=ptsNext n'set up an array to hold all rotated pointsRedim rotated(Lbound(array) To Ubound(array))Dim As Integer mx,my,wheelDim As Integer FPS,sleeptime 'Speed calmersDo    sleeptime=regulate(50,FPS)    Getmouse mx,my,wheel    centre=vct(mx,my,wheel*10)        'increment the angle of rotation    ang=vct(ang.x+.01,ang.y+.02,ang.z+.03)        'rotate all with perspective    For n As Integer=Lbound(array) To Ubound(array)        rotated(n)=array(n).CentreRotate(centre,ang)        rotated(n)=rotated(n).perspective(ScreenEyePoint)    Next n        'sort to paint furthest first    Qsort(rotated(),Lbound(rotated),Ubound(rotated))         Screenlock    Cls    Draw String (20,20),"FPS = " & FPS    Draw String(mx,my-70),"Centre of rotation"    Draw String (mx,my-50),"(" &centre.x & "," & centre.y & "," & centre.z & ")"        'draw to screen, radius depending on Z distance    For n As Integer=Lbound(array) To Ubound(array)        Var rad=map(200,-200,rotated(n).z,5,15)        If rad<2 Then rad=2        Circle(rotated(n).x,rotated(n).y),rad,rotated(n).colour ,,,,f    Next n        Screenunlock    Sleep sleeptime,1Loop Until Len(Inkey)Sleep `
podvornyak
Posts: 148
Joined: Nov 12, 2007 11:46
Location: Russia

### Re: Tutorial: Software 3d and matrix manipulations.

Polygon filling and z buffer.

engine_software.bi

Code: Select all

`' nblJIG 2013' If you dont understand matrix calculations mechanism, check code sample at first post.' Data block contain SINGLE MATRIX values.data 1, 0, 0, 0data 0, 1, 0, 0data 0, 0, 1, 0data 0, 0, 0, 1' System variables. Keyboard, mouse, time...dim shared as integer screen_width = 1024, screen_height = 768, bit_depth = 32, _               screen_width_half , screen_height_half, screen_size, _               fps_count, fps_value   screen_width_half = screen_width/2   screen_height_half = screen_height/2   screen_size = screen_width*screen_heightdim as double time_last, time_current, time_framedim as integer mouse_x, mouse_y, mouse_buttion, mouse_wheel, _            mouse_focus, mouse_focus_last, event_checkdim as single move_shiftdim as byte face_visable' Matrix storagesdim as single ptr matrix_global    = new singledim as single ptr matrix_rotate_x  = new singledim as single ptr matrix_rotate_y  = new singledim as single ptr matrix_rotate_z  = new singledim as single ptr matrix_translate = new singledim as single ptr matrix_buffer    = new singledim as single ptr matrix_result_1  = new singledim as single ptr matrix_result_2  = new single' Angle of rotation storagesdim shared as single angle_x, angle_y, angle_z' Pointers to matrix storage valuesdim shared as single ptr cos_angle_x1, cos_angle_x2, _                   cos_angle_y1, cos_angle_y2, _                   cos_angle_z1, cos_angle_z2, _                   sin_angle_x, sin_angle_x_minus, _                   sin_angle_y, sin_angle_y_minus, _                   sin_angle_z, sin_angle_z_minus, _                   translate_x, translate_y, translate_z, _                   camera_distance' Pointers assignation.cos_angle_x1      = @matrix_rotate_x sin_angle_x_minus   = @matrix_rotate_x sin_angle_x         = @matrix_rotate_x cos_angle_x2      = @matrix_rotate_x cos_angle_y1      = @matrix_rotate_y sin_angle_y         = @matrix_rotate_y sin_angle_y_minus   = @matrix_rotate_y cos_angle_y2      = @matrix_rotate_y cos_angle_z1      = @matrix_rotate_z sin_angle_z_minus   = @matrix_rotate_z sin_angle_z         = @matrix_rotate_z cos_angle_z2      = @matrix_rotate_z translate_x = @matrix_translate  translate_y = @matrix_translate  translate_z = @matrix_translate  camera_distance = @matrix_buffer ' Function to refill trigonometric values in matrix storagessub matrix_refill(x as ubyte = 1, y as ubyte = 1, z as ubyte = 1)   if x then      *cos_angle_x1      = cos(angle_x)      *cos_angle_x2      = *cos_angle_x1      *sin_angle_x      = sin(angle_x)      *sin_angle_x_minus   = -(*sin_angle_x)   end if   if y then      *cos_angle_y1      = cos(angle_y)      *cos_angle_y2      = *cos_angle_y1      *sin_angle_y      = sin(angle_y)      *sin_angle_y_minus   = -(*sin_angle_y)   end if   if z then      *cos_angle_z1      = cos(angle_z)      *cos_angle_z2      = *cos_angle_z1      *sin_angle_z      = sin(angle_z)      *sin_angle_z_minus   = -(*sin_angle_z)   end ifend sub' Function of matrix with matrix multiplying.sub multiply_matrix(a as single ptr, b as single ptr, c as single ptr)   c = a*b   + a*b  + a*b   + a*b   c = a*b   + a*b  + a*b   + a*b   c = a*b   + a*b  + a*b  + a*b   c = a*b   + a*b  + a*b  + a*b      c = a*b   + a*b  + a*b   + a*b   c = a*b   + a*b  + a*b   + a*b   c = a*b   + a*b  + a*b  + a*b   c = a*b   + a*b  + a*b  + a*b      c = a*b   + a*b  + a*b  + a*b   c = a*b   + a*b  + a*b  + a*b   c = a*b  + a*b  + a*b + a*b   c = a*b  + a*b  + a*b + a*b   c = a*b + a*b + a*b  + a*b   c = a*b + a*b + a*b  + a*b   c = a*b + a*b + a*b + a*b   c = a*b + a*b + a*b + a*bend sub' Function of vector with matrix multiplying.sub multiply_vector(a as single ptr, b as single ptr, c as single ptr)   c = a*b  + a*b  + a*b  + a*b   c = a*b  + a*b  + a*b  + a*b   c = a*b  + a*b  + a*b + a*b   c = a*b + a*b + a*b + a*bend sub' Function of copying matrix values to other storage.sub matrix_copy(a as single ptr, b as single ptr)   b=a:   b=a:   b=a:   b=a   b=a:   b=a:   b=a:   b=a   b=a:   b=a:   b=a: b=a   b=a: b=a: b=a: b=aend sub' Filling matrix storages with SINGLE MATRIX values.dim as single value_singlefor i as integer = 0 to 15   read value_single   matrix_global    [i] = value_single   matrix_rotate_x  [i] = value_single   matrix_rotate_y  [i] = value_single   matrix_rotate_z  [i] = value_single   matrix_translate [i] = value_single   matrix_buffer    [i] = value_singlenext i' Defining and allocating storage for image data.dim shared as uinteger ptr frame_imageframe_image = new uinteger[screen_size]' Function that copy data' Used to copy image data to back buffer of screen.' Simple memory copying.sub frame_copy (source as uinteger ptr, target as uinteger ptr)   for i as uinteger = 0 to screen_size-1      *(target+i) = *(source+i)   next iend sub' Function that clean data.' Used to clean image data.' Simple memory filling.sub frame_clean(target as uinteger ptr)   for i as uinteger = 0 to screen_size-1      *(target+i) = 0   next iend sub' Defining and allocating storage for pixel drawing check.dim shared as single ptr z_bufferz_buffer = new single[screen_size]' Function to clean z buffer values.sub clean_z_buffer()   for i as integer = 0 to screen_size-1      *(z_buffer+i) = 0   next iend sub' Variables for 3d vertex calculations.dim shared as single screen_z, z_buffer_value' Variables for 2d pixel calculations.dim shared as integer pixel_ax, pixel_ay, pixel_bx, pixel_by, pixel_cx, pixel_cy' Function that draw filled triangle at image data storage.sub draw_triangle(c as uinteger)   dim as integer x1, x2, y, position, size   ' Sort 3 pixels to order ay < by < cy   if pixel_by > pixel_cy then   swap pixel_by, pixel_cy: swap pixel_bx, pixel_cx: end if   if pixel_ay > pixel_cy then swap pixel_ay, pixel_cy: swap pixel_ax, pixel_cx: end if   if pixel_ay > pixel_by then swap pixel_ay, pixel_by: swap pixel_ax, pixel_bx: end if   ' In case polygon is less than one pixel size.   if pixel_cy = pixel_ay then return      ' Calculating start and end pixels for each scanline.   for y = pixel_ay to pixel_cy step 1      x1 = pixel_ax+(y-pixel_ay)*(pixel_cx-pixel_ax)/(pixel_cy-pixel_ay)      if y < pixel_by then         x2 = pixel_ax+(y-pixel_ay)*(pixel_bx-pixel_ax)/(pixel_by-pixel_ay)      else         if pixel_cy = pixel_by then            x2 = pixel_bx         else            x2 = pixel_bx+(y-pixel_by)*(pixel_cx-pixel_bx)/(pixel_cy-pixel_by)         end if      end if      if x1 > x2 then swap x1, x2      ' Position of the start pixel in storage      position = y*screen_width+x1      ' Amount of the pixels in line.      size = x2-x1      for i as integer = 0 to size         ' Compare z distance of the face center point         ' with buffer value.         if z_buffer_value > *(z_buffer+position+i) then         ' Set color         *(frame_image+position+i) = c         ' Set buffer value         *(z_buffer+position+i) = z_buffer_value         end if      next i   next yend sub' Defining geometry storagetype TYPE_VERTEX   as single ptr p   declare constructor ()   declare destructor ()end typeconstructor TYPE_VERTEX ()   this.p = new single   this.p = 1end constructordestructor TYPE_VERTEX ()   delete[] this.p   this.p = 0end destructortype TYPE_FACE   as uinteger v(2) ' vertexes numbers   as uinteger n(2) ' normals numbers   as uinteger fc ' color value   declare constructor ()end typeconstructor TYPE_FACE ()   dim as ubyte ccc = 100+rnd*155   this.fc = rgba(ccc, ccc, ccc, 0)end constructortype TYPE_GEOMETRY   as uinteger vn ' vertexes amount number   as uinteger nn ' faces amount number   as uinteger fn ' faces amount number   as TYPE_VERTEX ptr v ' pointer to vertexes storage   as TYPE_VERTEX ptr n ' pointer to normals storage   as TYPE_FACE ptr f   ' pointer to faces storage   declare constructor (as integer, as integer, as integer)   declare destructor ()end typeconstructor TYPE_GEOMETRY(vertexes as integer, normals as integer, faces as integer)   this.vn = vertexes   this.nn = normals   this.fn = faces   this.v = new TYPE_VERTEX[this.vn]   this.n = new TYPE_VERTEX[this.nn]   this.f = new TYPE_FACE[this.fn]end constructordestructor TYPE_GEOMETRY ()   delete[] this.v   delete[] this.n   delete[] this.f   this.v=0   this.n=0   this.f=0end destructor' Temporal pointer to geometry type variabledim shared as TYPE_GEOMETRY ptr ptr_geometry' Loding geometry from *.obj format file.' Loads only triangulated mesh. Faces requied.function load_obj_file(filename as string) as TYPE_GEOMETRY ptr   dim as integer file, dimension, lenght, map, amount_vertex=0, amount_normal=0, amount_face=0   dim as string buffer, value, symbol   file = freefile   if (open (filename for binary access read as #file)) = 0 then      while not eof(file)         line input #file, buffer         select case mid(buffer, 1, 2)         case "v "            amount_vertex += 1         case "vn"            amount_normal += 1         case "f "            amount_face += 1         end select      wend      ptr_geometry = new TYPE_GEOMETRY(amount_vertex, amount_normal, amount_face)      amount_vertex=0      amount_normal=0      amount_face=0      seek file, 1      while not eof(file)         line input #file, buffer         lenght = len(buffer)         select case mid(buffer, 1, 2)         case "v "            dimension = 2            for i as integer = lenght to 2 step -1               symbol = mid(buffer, i, 1)               if symbol = " " then                  ptr_geometry->v[amount_vertex].p[dimension] = val(value)                  dimension -= 1                  value = ""               elseif dimension > -1 then                  value = symbol + value               end if            next i            amount_vertex += 1         case "vn"            dimension = 2            for i as integer = lenght to 3 step -1               symbol = mid(buffer, i, 1)               if symbol = " " and dimension > -1 then                  ptr_geometry->n[amount_normal].p[dimension] = val(value)                  dimension -= 1                  value = ""               elseif dimension > -1 then                  value = symbol + value               end if            next i            amount_normal += 1         case "f "            map=2            dimension = 2            for i as integer = lenght to 2 step -1               symbol = mid(buffer, i, 1)               if symbol = " " and dimension > -1 then                  ptr_geometry->f[amount_face].v(dimension) = val(value)-1                  dimension -= 1                  map = 2                  value = ""               elseif symbol = "/" and map = 2 then                  ptr_geometry->f[amount_face].n(dimension) = val(value)-1                  map -= 1                  value = ""               elseif symbol = "/" and map = 1 then                  value = ""               elseif dimension > -1 then                  value = symbol + value               end if            next i            amount_face += 1         end select      wend      close #file            print amount_face, amount_normal, amount_vertex      if ptr_geometry->vn>0 and ptr_geometry->fn>0 then         return ptr_geometry         ptr_geometry = 0      else         delete ptr_geometry         ptr_geometry = 0         end         return 0      end if   else      print "no such file or access denide"   end ifend function' Now to the *.bas file...`

engine_software.bas

Code: Select all

`' nblJIG 2013' Esc - exit.' W - move forward.' S - move backward' A - strafe left' D - strafe right' C - strafe down' SPACE - strafe up' Q - tilt left' E - tilt right' SHIFT - hold to increase movment speed' First - iclude a *.bi file#include "engine_software.bi"' Load geometry.dim as TYPE_GEOMETRY ptr o1 = load_obj_file("file.obj")' Create empty copy of geometry.dim as TYPE_GEOMETRY ptr o2 = new TYPE_GEOMETRY(o1->vn, o1->nn, o1->fn)' Copy vertex and normal numbers of the face.for i as integer = 0 to o1->fn-1o2->f[i].v(0)=o1->f[i].v(0)o2->f[i].v(1)=o1->f[i].v(1)o2->f[i].v(2)=o1->f[i].v(2)o2->f[i].n(0)=o1->f[i].n(0)o2->f[i].n(1)=o1->f[i].n(1)o2->f[i].n(2)=o1->f[i].n(2)o2->f[i].fc=o1->f[i].fcnext i' It is necessary to work with original data values, cause while transforming' original values we loose original data. So that why we should store' transformed values to copy storage or transform values on demand and' do not store transformations at all. Limitation of floating point calculation...' Starting window and doing other system related calls.screenres screen_width, screen_height, bit_depth, 0, 16windowtitle "matrix-shmatrix-mathematics"setmouse screen_width_half, screen_height_half, 0' After window is started, defining pointer to back buffer of screen.dim as uinteger ptr frame_buffer = screenptr' Starting main cycle of program.time_last = timerwhile not multikey(&h01)      ' fps calculations   time_current=timer   fps_count += 1      if time_current > time_last + 1 then      time_last = time_current      fps_value = fps_count      fps_count = 0   end if      ' Cleaning delta values   *translate_x = 0   *translate_y = 0   *translate_z = 0   angle_x = 0   angle_y = 0   angle_z = 0   ' Getting delta values   mouse_focus_last = mouse_focus   mouse_focus = getmouse (mouse_x, mouse_y)   if mouse_focus=0 then      if mouse_x<>screen_width_half or mouse_y<>screen_height_half then         angle_y = (screen_width_half - mouse_x)*0.001         angle_x = (screen_height_half - mouse_y)*0.001         setmouse(screen_width_half, screen_height_half)         event_check = 1      end if            move_shift = 1      if multikey(&h2a) then move_shift = 30 ' shift      if multikey(&h1e) then *translate_x = 0.1 * move_shift:  event_check = 1 ' a      if multikey(&h20) then *translate_x = -0.1 * move_shift: event_check = 1 ' d      if multikey(&h2c) then event_check = 1 ' z      if multikey(&h2d) then event_check = 1 ' x      if multikey(&h2e) then *translate_y = 0.1 * move_shift:  event_check = 1 ' c      if multikey(&h39) then *translate_y = -0.1 * move_shift: event_check = 1 ' space      if multikey(&h11) then *translate_z = -0.1 * move_shift: event_check = 1 ' w      if multikey(&h1f) then *translate_z = 0.1 * move_shift:  event_check = 1 ' s      if multikey(&h10) then angle_z = -0.005 * move_shift:    event_check = 1 ' q      if multikey(&h12) then angle_z = 0.005 * move_shift:     event_check = 1 ' e   end if   if mouse_focus_last <> mouse_focus then      *translate_x = 0      *translate_y = 0      *translate_z = 0      angle_x = 0      angle_y = 0      angle_z = 0   end if   ' Calculating view transformations.   if event_check then         matrix_refill()            *camera_distance=-1000      multiply_matrix  (matrix_buffer, matrix_translate, matrix_result_1)      multiply_matrix  (matrix_result_1, matrix_rotate_x, matrix_result_2)      multiply_matrix  (matrix_result_2, matrix_rotate_y, matrix_result_1)      multiply_matrix  (matrix_result_1, matrix_rotate_z, matrix_result_2)            *camera_distance=1000      multiply_matrix  (matrix_result_2, matrix_buffer, matrix_result_1)      multiply_matrix  (matrix_result_1, matrix_global, matrix_result_2)      matrix_copy      (matrix_result_2, matrix_global)      event_check = 0   end if   ' Applying view transformations to geometry and storing copy of geometry.   ' o1 to o2   for i as integer = 0 to o1->vn-1      multiply_vector (matrix_global, o1->v[i].p, o2->v[i].p)   next i   ' Cleaning image data and z_buffer values.   frame_clean(frame_image)   clean_z_buffer()   ' For each face of geometry   for i as integer = 0 to o2->fn-1      ' Calculating face z position.      screen_z = (o2->v[o2->f[i].v(0)].p + o2->v[o2->f[i].v(1)].p + o2->v[o2->f[i].v(2)].p)/3      ' Face is in front of view.      if screen_z > - 1000 then' Calculating screen positions for all, related to face, vertexes.pixel_ax = screen_width_half  + o2->v[o2->f[i].v(0)].p*1000/(o2->v[o2->f[i].v(0)].p+1000)pixel_ay = screen_height_half - o2->v[o2->f[i].v(0)].p*1000/(o2->v[o2->f[i].v(0)].p+1000)pixel_bx = screen_width_half  + o2->v[o2->f[i].v(1)].p*1000/(o2->v[o2->f[i].v(1)].p+1000)pixel_by = screen_height_half - o2->v[o2->f[i].v(1)].p*1000/(o2->v[o2->f[i].v(1)].p+1000)pixel_cx = screen_width_half  + o2->v[o2->f[i].v(2)].p*1000/(o2->v[o2->f[i].v(2)].p+1000)pixel_cy = screen_height_half - o2->v[o2->f[i].v(2)].p*1000/(o2->v[o2->f[i].v(2)].p+1000)' Check - is any pixels hit the screen?face_visable = 0if (pixel_ax > -1 and pixel_ax < screen_width) and (pixel_ay > -1 and pixel_ay < screen_height) then   face_visable += 1end ifif (pixel_bx > -1 and pixel_bx < screen_width) and (pixel_by > -1 and pixel_by < screen_height) then   face_visable += 1end ifif (pixel_cx > -1 and pixel_cx < screen_width) and (pixel_cy > -1 and pixel_cy < screen_height) then   face_visable += 1end if' And if all three pixels is on screen - draw triangle.' For other cases you can design your own functions that split one triangle' in 2 or 3 triangles to fit the screen. Cause we have all positions of' pixels it is not a problem to find intersection with screen sides and' create 1, 2 or 3 more pixels and pass them to draw triangle function.if face_visable = 3 then   ' Calculating z distance of face for z_buffer check.   z_buffer_value = 1+1/(screen_z + (-1000))   ' Draw triangle.   draw_triangle(o2->f[i].fc)end if      end if   next i      ' Time to put image on screen.   screenlock      ' Copy image data.   frame_copy(frame_image, frame_buffer)   draw string (0,10), "fps: "+ str(fps_value)   screenunlock   sleep 1   ' That is all. Hope you enjoy it. See you around.wendend`

Don't forget to place *.obj file near executable. http://yadi.sk/d/Fz8SEItW6Q_fF

If you cant compile or run this sample, keep in mind that is an example. But it work fine for me. Both linux and windows xp.
Last edited by podvornyak on Jul 02, 2013 17:57, edited 2 times in total.
podvornyak
Posts: 148
Joined: Nov 12, 2007 11:46
Location: Russia

### Re: Tutorial: Software 3d and matrix manipulations.

I deside to stop creation of "one more software 3d engine". Instead i'll try to get something new, cause my mind is full of inspiring ideas for a long time. No time to waste on old crap.

Exampe for now. Use W and S to move forward and backward for more impessive results. Anyway all keys and mouse events is enabled.

Code: Select all

`' nblJIG 2013' Esc - exit.' W - move forward.' S - move backward' A - strafe left' D - strafe right' C - strafe down' SPACE - strafe up' Q - tilt left' E - tilt right' SHIFT - increase movment speed'-----------------' base definations'-----------------dim shared as integer screen_width = 1000, screen_height = 1000, screen_bit = 32, _               screen_width_half , screen_height_half, screen_size, _               fps_count, fps_value   screen_width_half = screen_width/2   screen_height_half = screen_height/2   screen_size = screen_width*screen_heightdim as double time_last, time_current, time_framedim as integer mouse_x, mouse_y, mouse_buttion, mouse_wheel, _            mouse_focus, mouse_focus_last, event_checkdim as single move_shift'-------------------' matrix definations'-------------------dim shared as single ptr matrix_single: matrix_single = new singlematrix_single= 1: matrix_single= 0: matrix_single= 0: matrix_single= 0matrix_single= 0: matrix_single= 1: matrix_single= 0: matrix_single= 0matrix_single= 0: matrix_single= 0: matrix_single=1: matrix_single=0matrix_single=0: matrix_single=0: matrix_single=0: matrix_single=1dim shared as single ptr matrix_global: matrix_global = new singledim shared as single ptr matrix_geometry: matrix_geometry = new singledim shared as single ptr matrix_rotate_x: matrix_rotate_x = new singledim shared as single ptr matrix_rotate_y: matrix_rotate_y = new singledim shared as single ptr matrix_rotate_z: matrix_rotate_z = new singledim shared as single ptr matrix_translate: matrix_translate = new singledim shared as single ptr matrix_buffer: matrix_buffer = new singledim shared as single ptr matrix_result_1: matrix_result_1 = new singledim shared as single ptr matrix_result_2: matrix_result_2 = new singlesub matrix_copy(a as single ptr, b as single ptr)   b=a:   b=a:   b=a:   b=a   b=a:   b=a:   b=a:   b=a   b=a:   b=a:   b=a: b=a   b=a: b=a: b=a: b=aend subsub matrix_clean() matrix_copy(matrix_single, matrix_global) matrix_copy(matrix_single, matrix_geometry)  matrix_copy(matrix_single, matrix_translate) matrix_copy(matrix_single, matrix_rotate_x) matrix_copy(matrix_single, matrix_rotate_y) matrix_copy(matrix_single, matrix_rotate_z) matrix_copy(matrix_single, matrix_buffer) matrix_copy(matrix_single, matrix_result_1) matrix_copy(matrix_single, matrix_result_2)end submatrix_clean()dim shared as single angle_x, angle_y, angle_zdim shared as single ptr translate_x, translate_y, translate_z, _                   camera_distancetranslate_x = @matrix_translate  translate_y = @matrix_translate  translate_z = @matrix_translate  camera_distance = @matrix_buffer sub matrix_refill()      matrix_rotate_x     = cos(angle_x)      matrix_rotate_x  = matrix_rotate_x       matrix_rotate_x     = sin(angle_x)      matrix_rotate_x   = -matrix_rotate_x       matrix_rotate_y     = cos(angle_y)      matrix_rotate_y  = matrix_rotate_y       matrix_rotate_y   = sin(angle_y)      matrix_rotate_y   = -matrix_rotate_y       matrix_rotate_z       = cos(angle_z)      matrix_rotate_z       = matrix_rotate_z       matrix_rotate_z    = sin(angle_z)      matrix_rotate_z    = -matrix_rotate_z end subsub multiply_matrix(a as single ptr, b as single ptr, c as single ptr)   c = a*b   + a*b  + a*b   + a*b   c = a*b   + a*b  + a*b   + a*b   c = a*b   + a*b  + a*b  + a*b   c = a*b   + a*b  + a*b  + a*b      c = a*b   + a*b  + a*b   + a*b   c = a*b   + a*b  + a*b   + a*b   c = a*b   + a*b  + a*b  + a*b   c = a*b   + a*b  + a*b  + a*b      c = a*b   + a*b  + a*b  + a*b   c = a*b   + a*b  + a*b  + a*b   c = a*b  + a*b  + a*b + a*b   c = a*b  + a*b  + a*b + a*b   c = a*b + a*b + a*b  + a*b   c = a*b + a*b + a*b  + a*b   c = a*b + a*b + a*b + a*b   c = a*b + a*b + a*b + a*bend subsub multiply_vector(a as single ptr, b as single ptr, c as single ptr)   c = a*b  + a*b  + a*b  + a*b   c = a*b  + a*b  + a*b  + a*b   c = a*b  + a*b  + a*b + a*b   c = a*b + a*b + a*b + a*bend sub'---------------' 2d definations'---------------type TYPE_PIXEL   as integer x, y 'screen positiion   as uinteger c ' color   as ubyte v ' visableend typedim as TYPE_PIXEL pixel_current ' projected vertex'storage for last one 10 kk projection of vertexes'1000 X 1000 ~ 1 kk pixelsdim as TYPE_PIXEL ptr pixel = new TYPE_PIXELdim as uinteger current_pixel = 0dim shared as uinteger ptr frame_image ' memory for screen imageframe_image = new uinteger[screen_size]sub frame_copy (source as uinteger ptr, target as uinteger ptr)   for i as uinteger = 0 to screen_size-1      *(target+i) = *(source+i)   next iend subsub frame_clean(target as uinteger ptr)   for i as uinteger = 0 to screen_size-1      *(target+i) = 0   next iend sub'--------------'3d definations'--------------type TYPE_VERTEX   as single ptr p = new single ' position   as uinteger c ' colorend typetype TYPE_GEOMETRY   as uinteger vn ' vertexes amount   as TYPE_VERTEX ptr v   declare constructor (as uinteger)   declare destructor ()end typeconstructor TYPE_GEOMETRY (vertexes as uinteger)   this.vn = vertexes   if vn > 0 then this.v = new TYPE_VERTEX[this.vn]end constructordestructor TYPE_GEOMETRY ()   delete[] this.v   this.v=0end destructor' defining 3d octo-quad geometry storagedim as TYPE_GEOMETRY ptr o = new TYPE_GEOMETRY(8)'assigning valueso->v.p=1: o->v.p=-1: o->v.p=-1: o->v.p=1o->v.p=-1: o->v.p=1: o->v.p=-1: o->v.p=1 o->v.p=-1: o->v.p=-1: o->v.p=1: o->v.p=1o->v.p=1: o->v.p=1: o->v.p=1: o->v.p=1 o->v.p=1: o->v.p=1: o->v.p=-1: o->v.p=-1 o->v.p=-1: o->v.p=1: o->v.p=1: o->v.p=-1 o->v.p=1: o->v.p=-1: o->v.p=1: o->v.p=-1 o->v.p=-1: o->v.p=-1: o->v.p=-1: o->v.p=-1randomizeo->v.c = rgb(rnd*255, rnd*255, rnd*255)o->v.c = rgb(rnd*255, rnd*255, rnd*255)o->v.c = rgb(rnd*255, rnd*255, rnd*255)o->v.c = rgb(rnd*255, rnd*255, rnd*255)o->v.c = rgb(rnd*255, rnd*255, rnd*255)o->v.c = rgb(rnd*255, rnd*255, rnd*255)o->v.c = rgb(rnd*255, rnd*255, rnd*255)o->v.c = rgb(rnd*255, rnd*255, rnd*255)' on demand mastrix calculation storagesdim as TYPE_VERTEX ptr cursor = new TYPE_VERTEX'-----------' initialize'-----------screenres screen_width, screen_height, screen_bit, 0, 0setmouse screen_width_half, screen_height_half, 0dim as integer ptr frame_buffer = screenptrmatrix_global=-990 ' - move view closer to geometrytime_last = timer'------' main'------while not multikey(&h01)   ' fps   time_current=timer   fps_count += 1      if time_current > time_last + 1 then      time_last = time_current      fps_value = fps_count      fps_count = 0   end if   ' cleaninig   *translate_x = 0   *translate_y = 0   *translate_z = 0   angle_x = 0   angle_y = 0   angle_z = 0      ' input events   mouse_focus_last = mouse_focus   mouse_focus = getmouse (mouse_x, mouse_y)   if mouse_focus=0 then      if mouse_x<>screen_width_half or mouse_y<>screen_height_half then         angle_y = (screen_width_half - mouse_x)*0.001         angle_x = (screen_height_half - mouse_y)*0.001         setmouse(screen_width_half, screen_height_half)         event_check = 1      end if            move_shift = 1      if multikey(&h2a) then move_shift = 30 ' shift      if multikey(&h1e) then *translate_x = 0.1 * move_shift:  event_check = 1 ' a      if multikey(&h20) then *translate_x = -0.1 * move_shift: event_check = 1 ' d      if multikey(&h2c) then event_check = 1 ' z      if multikey(&h2d) then event_check = 1 ' x      if multikey(&h2e) then *translate_y = 0.1 * move_shift:  event_check = 1 ' c      if multikey(&h39) then *translate_y = -0.1 * move_shift: event_check = 1 ' space      if multikey(&h11) then *translate_z = -0.1 * move_shift: event_check = 1 ' w      if multikey(&h1f) then *translate_z = 0.1 * move_shift:  event_check = 1 ' s      if multikey(&h10) then angle_z = -0.005 * move_shift:    event_check = 1 ' q      if multikey(&h12) then angle_z = 0.005 * move_shift:     event_check = 1 ' e   end if      if mouse_focus_last <> mouse_focus then      *translate_x = 0      *translate_y = 0      *translate_z = 0      angle_x = 0      angle_y = 0      angle_z = 0   end if   ' view transformation matrix calculation   if event_check then      matrix_refill()      *camera_distance=-1000            multiply_matrix  (matrix_buffer, matrix_translate, matrix_result_1)      multiply_matrix  (matrix_result_1, matrix_rotate_x, matrix_result_2)      multiply_matrix  (matrix_result_2, matrix_rotate_y, matrix_result_1)      multiply_matrix  (matrix_result_1, matrix_rotate_z, matrix_result_2)            *camera_distance=1000      multiply_matrix  (matrix_result_2, matrix_buffer, matrix_result_1)      multiply_matrix  (matrix_result_1, matrix_global, matrix_result_2)      matrix_copy      (matrix_result_2, matrix_global)      event_check = 0   end if   ' geometry transformation matrix calculation   angle_x = 0.1*cos(timer)   angle_y = 0.1*sin(timer)   angle_z = 0.02*sin(timer)*cos(timer)   matrix_refill()   multiply_matrix(matrix_rotate_x, matrix_rotate_y, matrix_result_2)   multiply_matrix(matrix_result_2, matrix_rotate_z, matrix_result_1)   multiply_matrix(matrix_result_1, matrix_geometry, matrix_result_2)   matrix_copy(matrix_result_2, matrix_geometry)   'clean screen image   frame_clean(frame_image)   for i as integer = 0 to o->vn-1      ' apply transformation matrixes      multiply_vector(matrix_geometry, o->v[i].p, cursor.p)      cursor.p=1      multiply_vector(matrix_global, cursor.p , cursor.p)      if (cursor.p > - 1000) then         pixel_current.x = screen_width_half  + cursor.p*1000/(cursor.p+1000)         pixel_current.y = screen_height_half - cursor.p*1000/(cursor.p+1000)         if (pixel_current.x > -1 and pixel_current.x < screen_width) and (pixel_current.y > -1 and pixel_current.y < screen_height) then            pixel[current_pixel].x = pixel_current.x            pixel[current_pixel].y = pixel_current.y            pixel[current_pixel].c = o->v[i].c            pixel[current_pixel].v = 1            current_pixel += 1            if current_pixel > 1000000 then current_pixel = 0         end if      end if   next i   for i as integer = 0 to 1000000      if pixel[i].v > 0 then *(frame_image+pixel[i].y*screen_width+pixel[i].x) = pixel[i].c      pixel[i].c -= pixel[i].c/32 ' too expensive. speed doubles without that string.      ' but still you can play with divider. High value grant long trails.   next i   screenlock   frame_copy(frame_image, frame_buffer)   draw string (0,0), str(matrix_global)+" "+str(matrix_global)+" "+str(matrix_global)   draw string (0,10), "fps: "+ str(fps_value)   draw string (0,20), "vertexes: "+ str(o->vn)   screenunlock   sleep 1wendend` Next task is to get same result in 3d geometry... not just projection.
podvornyak
Posts: 148
Joined: Nov 12, 2007 11:46
Location: Russia

### Re: Tutorial: Software 3d and matrix manipulations.

Damn, i'm fast today. Done. Now in 3d. Taste it. Try ro use SHIFT while moving... see what happens. ^_^

Code: Select all

`' nblJIG 2013' Esc - exit.' W - move forward.' S - move backward' A - strafe left' D - strafe right' C - strafe down' SPACE - strafe up' Q - tilt left' E - tilt right' SHIFT - increase movment speed'-----------------' base definations'-----------------dim shared as integer screen_width = 1000, screen_height = 1000, screen_bit = 32, _               screen_width_half , screen_height_half, screen_size, _               fps_count, fps_valuescreen_width_half = screen_width/2screen_height_half = screen_height/2screen_size = screen_width*screen_heightdim as double time_last, time_current, time_framedim as integer mouse_x, mouse_y, mouse_buttion, mouse_wheel, _            mouse_focus, mouse_focus_last, event_checkdim as single move_shift'-------------------' matrix definations'-------------------dim shared as single ptr matrix_single: matrix_single = new singlematrix_single= 1: matrix_single= 0: matrix_single= 0: matrix_single= 0matrix_single= 0: matrix_single= 1: matrix_single= 0: matrix_single= 0matrix_single= 0: matrix_single= 0: matrix_single=1: matrix_single=0matrix_single=0: matrix_single=0: matrix_single=0: matrix_single=1dim shared as single ptr matrix_global: matrix_global = new singledim shared as single ptr matrix_geometry: matrix_geometry = new singledim shared as single ptr matrix_rotate_x: matrix_rotate_x = new singledim shared as single ptr matrix_rotate_y: matrix_rotate_y = new singledim shared as single ptr matrix_rotate_z: matrix_rotate_z = new singledim shared as single ptr matrix_translate: matrix_translate = new singledim shared as single ptr matrix_buffer: matrix_buffer = new singledim shared as single ptr matrix_result_1: matrix_result_1 = new singledim shared as single ptr matrix_result_2: matrix_result_2 = new singlesub matrix_copy(a as single ptr, b as single ptr)   b=a:   b=a:   b=a:   b=a   b=a:   b=a:   b=a:   b=a   b=a:   b=a:   b=a: b=a   b=a: b=a: b=a: b=aend subsub matrix_clean()   matrix_copy(matrix_single, matrix_global)   matrix_copy(matrix_single, matrix_geometry)        matrix_copy(matrix_single, matrix_translate)   matrix_copy(matrix_single, matrix_rotate_x)   matrix_copy(matrix_single, matrix_rotate_y)   matrix_copy(matrix_single, matrix_rotate_z)   matrix_copy(matrix_single, matrix_buffer)   matrix_copy(matrix_single, matrix_result_1)   matrix_copy(matrix_single, matrix_result_2)end submatrix_clean()dim shared as single angle_x, angle_y, angle_zdim shared as single ptr translate_x, translate_y, translate_z, _                     camera_distance   translate_x = @matrix_translate     translate_y = @matrix_translate     translate_z = @matrix_translate     camera_distance = @matrix_buffer sub matrix_refill()   matrix_rotate_x     = cos(angle_x)   matrix_rotate_x  = matrix_rotate_x    matrix_rotate_x     = sin(angle_x)   matrix_rotate_x   = -matrix_rotate_x    matrix_rotate_y     = cos(angle_y)   matrix_rotate_y  = matrix_rotate_y    matrix_rotate_y   = sin(angle_y)   matrix_rotate_y   = -matrix_rotate_y    matrix_rotate_z       = cos(angle_z)   matrix_rotate_z       = matrix_rotate_z    matrix_rotate_z    = sin(angle_z)   matrix_rotate_z    = -matrix_rotate_z end subsub multiply_matrix(a as single ptr, b as single ptr, c as single ptr)   c = a*b   + a*b  + a*b   + a*b   c = a*b   + a*b  + a*b   + a*b   c = a*b   + a*b  + a*b  + a*b   c = a*b   + a*b  + a*b  + a*b          c = a*b   + a*b  + a*b   + a*b   c = a*b   + a*b  + a*b   + a*b   c = a*b   + a*b  + a*b  + a*b   c = a*b   + a*b  + a*b  + a*b          c = a*b   + a*b  + a*b  + a*b   c = a*b   + a*b  + a*b  + a*b   c = a*b  + a*b  + a*b + a*b   c = a*b  + a*b  + a*b + a*b   c = a*b + a*b + a*b  + a*b   c = a*b + a*b + a*b  + a*b   c = a*b + a*b + a*b + a*b   c = a*b + a*b + a*b + a*bend subsub multiply_vector(a as single ptr, b as single ptr, c as single ptr)   c = a*b  + a*b  + a*b  + a*b   c = a*b  + a*b  + a*b  + a*b   c = a*b  + a*b  + a*b + a*b   c = a*b + a*b + a*b + a*bend subsub copy_vector(target as single ptr, source as single ptr)   target = source   target = source   target = source   target = sourceend sub'---------------' 2d definations'---------------type TYPE_PIXEL   as integer x, y 'screen positiion   as uinteger c ' color   as ubyte v ' visableend typedim as TYPE_PIXEL pixel_current ' projected vertexdim shared as uinteger ptr frame_image ' memory for screen imageframe_image = new uinteger[screen_size]sub frame_copy (source as uinteger ptr, target as uinteger ptr)   for i as uinteger = 0 to screen_size-1      *(target+i) = *(source+i)   next iend subsub frame_clean(target as uinteger ptr)   for i as uinteger = 0 to screen_size-1      *(target+i) = 0   next iend sub'--------------'3d definations'--------------type TYPE_VERTEX   as single ptr p = new single ' position   as uinteger c ' colorend typetype TYPE_GEOMETRY   as uinteger vn ' vertexes amount   as TYPE_VERTEX ptr v   declare constructor (as uinteger)   declare destructor ()end typeconstructor TYPE_GEOMETRY (vertexes as uinteger)   this.vn = vertexes   if vn > 0 then this.v = new TYPE_VERTEX[this.vn]end constructordestructor TYPE_GEOMETRY ()   delete[] this.v   this.v=0end destructor' defining 3d octo-quad geometry storagedim as TYPE_GEOMETRY ptr o = new TYPE_GEOMETRY(8)'assigning valueso->v.p=1: o->v.p=-1: o->v.p=-1: o->v.p=1o->v.p=-1: o->v.p=1: o->v.p=-1: o->v.p=1o->v.p=-1: o->v.p=-1: o->v.p=1: o->v.p=1o->v.p=1: o->v.p=1: o->v.p=1: o->v.p=1o->v.p=1: o->v.p=1: o->v.p=-1: o->v.p=-1o->v.p=-1: o->v.p=1: o->v.p=1: o->v.p=-1o->v.p=1: o->v.p=-1: o->v.p=1: o->v.p=-1o->v.p=-1: o->v.p=-1: o->v.p=-1: o->v.p=-1randomizeo->v.c = rgb(rnd*255, rnd*255, rnd*255)o->v.c = rgb(rnd*255, rnd*255, rnd*255)o->v.c = rgb(rnd*255, rnd*255, rnd*255)o->v.c = rgb(rnd*255, rnd*255, rnd*255)o->v.c = rgb(rnd*255, rnd*255, rnd*255)o->v.c = rgb(rnd*255, rnd*255, rnd*255)o->v.c = rgb(rnd*255, rnd*255, rnd*255)o->v.c = rgb(rnd*255, rnd*255, rnd*255)' on demand mastrix calculation storagesdim as TYPE_VERTEX cursor' storage for transformed geometrydim as  TYPE_VERTEX ptr vertex = new TYPE_VERTEX dim as uinteger current_vertex = 0'-----------' initialize'-----------screenres screen_width, screen_height, screen_bit, 0, 0setmouse screen_width_half, screen_height_half, 0dim as integer ptr frame_buffer = screenptrmatrix_global=-990 ' - move view closer to geometrytime_last = timer'------' main'------while not multikey(&h01)   ' fps   time_current=timer   fps_count += 1   if time_current > time_last + 1 then      time_last = time_current      fps_value = fps_count      fps_count = 0   end if   ' cleaninig   *translate_x = 0   *translate_y = 0   *translate_z = 0   angle_x = 0   angle_y = 0   angle_z = 0          ' input events   mouse_focus_last = mouse_focus   mouse_focus = getmouse (mouse_x, mouse_y)   if mouse_focus=0 then      if mouse_x<>screen_width_half or mouse_y<>screen_height_half then         angle_y = (screen_width_half - mouse_x)*0.001         angle_x = (screen_height_half - mouse_y)*0.001         setmouse(screen_width_half, screen_height_half)         event_check = 1      end if                move_shift = 1      if multikey(&h2a) then move_shift = 30 ' shift      if multikey(&h1e) then *translate_x = 0.1 * move_shift:  event_check = 1 ' a      if multikey(&h20) then *translate_x = -0.1 * move_shift: event_check = 1 ' d      if multikey(&h2c) then event_check = 1 ' z      if multikey(&h2d) then event_check = 1 ' x      if multikey(&h2e) then *translate_y = 0.1 * move_shift:  event_check = 1 ' c      if multikey(&h39) then *translate_y = -0.1 * move_shift: event_check = 1 ' space      if multikey(&h11) then *translate_z = -0.1 * move_shift: event_check = 1 ' w      if multikey(&h1f) then *translate_z = 0.1 * move_shift:  event_check = 1 ' s      if multikey(&h10) then angle_z = -0.005 * move_shift:    event_check = 1 ' q      if multikey(&h12) then angle_z = 0.005 * move_shift:     event_check = 1 ' e   end if          if mouse_focus_last <> mouse_focus then      *translate_x = 0      *translate_y = 0      *translate_z = 0      angle_x = 0      angle_y = 0      angle_z = 0   end if   if event_check then      matrix_refill()      *camera_distance=-1000            multiply_matrix  (matrix_buffer, matrix_translate, matrix_result_1)      multiply_matrix  (matrix_result_1, matrix_rotate_x, matrix_result_2)      multiply_matrix  (matrix_result_2, matrix_rotate_y, matrix_result_1)      multiply_matrix  (matrix_result_1, matrix_rotate_z, matrix_result_2)                *camera_distance=1000      multiply_matrix  (matrix_result_2, matrix_buffer, matrix_result_1)      multiply_matrix  (matrix_result_1, matrix_global, matrix_result_2)      matrix_copy      (matrix_result_2, matrix_global)      event_check = 0   end if   angle_x = 0.1*cos(timer)   angle_y = 0.1*sin(timer)   angle_z = 0.02*sin(timer)*cos(timer)   *translate_x=1*cos(timer)   *translate_x=1*sin(timer)   *translate_x=0.2*sin(timer)*cos(timer)   matrix_refill()   multiply_matrix(matrix_rotate_x, matrix_rotate_y, matrix_result_2)   multiply_matrix(matrix_result_2, matrix_rotate_z, matrix_result_1)   multiply_matrix(matrix_result_1, matrix_translate, matrix_result_2)   multiply_matrix(matrix_result_2, matrix_geometry, matrix_result_1)   matrix_copy(matrix_result_1, matrix_geometry)   frame_clean(frame_image)   for j as integer = 0 to 100000      multiply_vector(matrix_global, vertex[j].p , cursor.p)         if (cursor.p > - 1000) then            pixel_current.x = screen_width_half  + cursor.p*1000/(cursor.p+1000)            pixel_current.y = screen_height_half - cursor.p*1000/(cursor.p+1000)         if (pixel_current.x > -1 and pixel_current.x < screen_width) and (pixel_current.y > -1 and pixel_current.y < screen_height) then            *(frame_image+pixel_current.y*screen_width+pixel_current.x) = vertex[j].c         end if      end if   next j   for i as integer = 0 to o->vn-1   multiply_vector(matrix_geometry, o->v[i].p, cursor.p)   cursor.p=1   copy_vector(vertex[current_vertex].p, cursor.p)   vertex[current_vertex].c = o->v[i].c   current_vertex += 1   if current_vertex > 100000 then current_vertex = 0   next i   screenlock   frame_copy(frame_image, frame_buffer)   draw string (0,0), str(matrix_global)+" "+str(matrix_global)+" "+str(matrix_global)   draw string (0,10), "fps: "+ str(fps_value)   draw string (0,20), "vertexes: "+ str(o->vn)'   screensync   screenunlock   sleep 1wendend`

The idea is - get first value in data chunk and load the rest while displaying. Also, and more important, dynamicly generate geometry basing on cheap absolute data. Oh my god! It is alive! It's going to split!.. ^_^