Proper raycast examples (now with textures :)

Share your advanced PureBasic knowledge/code with the community.
Godai
Enthusiast
Enthusiast
Posts: 171
Joined: Thu Oct 05, 2006 8:13 pm

Post by Godai »

Got the bug. Setting 24-bpp fullscreen? Only on Linux I guess :)
On many Windows it's only 32-bit (or 16) :)
GBeebe
Enthusiast
Enthusiast
Posts: 263
Joined: Sat Oct 09, 2004 6:52 pm
Location: Franklin, PA - USA
Contact:

Post by GBeebe »

Sweet, so you got it working then? Does the floor/ceiling tiles fit right on your windows computer? As for cleaning it up and making it match the C++ tutorial and what not, i'll just post what i have and let you do that :) You need an image named "sprite.bmp" now.

Code: Select all

; Raycasting example: has variable image height and direct screen access.

; Some general stuff
Global mapWidth.l = 24
Global mapHeight.l = 24
Global screenWidth.l =320
Global screenHeight.l = 200
Global texWidth.l = 64
Global texHeight.l = 64

Global Dim PixelZ.d (screenWidth, screenHeight) ;Pixel Z buffer
Global *Screen.l    ;Pointer to screen pixel data
Global BPP.b  ;screen bytes per pixel

;Structure that holds Sprite info
Structure Structure_Graphics
    Sprite.l    ;pb sprite
    *Pointer.l  ;pointer to pixel data
    Width.l  ;Width of the graphic (not necessary as of yet, because all widths in this example are 64 pixels)
    Height.l  ;Height of the graphic (very necessary for variable heights)
EndStructure

Global Dim gfx.Structure_Graphics(0)
Global gfx_count.l = -1  ;# of items in our gfx structured array

Structure Structure_Sprite
    x.d
    y.d
    index.l
    
    distance.d
EndStructure

Global NewList spr.Structure_Sprite()
;Global spr_count.l = -1


Procedure.f FindAngle(X.f, Y.f)
If 0 < X.f
    ;Calculate the gradient of the line joining A and B.
    gradient.f=(-Y.f)/(X.f)
    ;Calculate the angle in radians.
    angleRads.f = ATan(gradient)
    ;Convert to degrees if required.
    angleDegs.f = 180*angleRads/#PI


If angleDegs < 0 : angleDegs + 360 : EndIf
ProcedureReturn angleDegs 

ElseIf 0 > X.f

;Calculate the gradient of the line joining A and B.
gradient.f=(Y.f)/(-X.f)
;Calculate the angle in radians.
angleRads.f = ATan(gradient)
;Convert to degrees if required.
angleDegs.f = (180*angleRads/#PI) + 180

If angleDegs < 0 : angleDegs + 360 : EndIf
ProcedureReturn angleDegs

Else ; X is 0
If 0 > Y.f
  ProcedureReturn 90
Else 
  ProcedureReturn 270
EndIf  
EndIf
EndProcedure

Procedure Set_Pixel_(*surface.l, w, x, y, color)
;sets pixel data in a buffer (*surface), assums that color is in the correct format
;(w) width of image is needed to determin correct position.
;Global BPP already needs to be set elsewhere.
    PokeB(*surface + ( (y * w + x) * bpp ) + 0, PeekB(@color + 0) ) 
    PokeB(*surface + ( (y * w + x) * bpp ) + 1, PeekB(@color + 1) ) 
    PokeB(*surface + ( (y * w + x) * bpp ) + 2, PeekB(@color + 2) ) 
    ;PokeB(*surface +( (y * w + x) * bpp ) + 3, PeekB(@color + 3) )  ;not using alpha

EndProcedure

Procedure.l Get_Pixel_(*surface.l, w, x, y)
;returns a color (long) from pixel data
;*surface is the pointer to pixel data.
;(w) width of image is needed to determin correct position.
;Global BPP already needs to be set elsewhere.
    retColor.l
    PokeB(@retColor.l + 0, PeekB(*surface + ((y * w + x) * BPP) + 0))
    PokeB(@retColor.l + 1, PeekB(*surface + ((y * w + x) * BPP) + 1))
    PokeB(@retColor.l + 2, PeekB(*surface + ((y * w + x) * BPP) + 2))
    ;PokeB(@retColor.l + 3, PeekB(*surface + ((y * w + x) * BPP) + 3))  ;not using alpha

ProcedureReturn retColor
EndProcedure

Structure Structure_RGB
    r.b
    g.b
    b.b
    a.b ;alpha
EndStructure

Global RGB_fix.Structure_RGB


Procedure.l RGBf(r.b, g.b, b.b)
rgb_.l
PokeB(@rgb_ + RGB_fix\r, r)
PokeB(@rgb_ + RGB_fix\g, g)
PokeB(@rgb_ + RGB_fix\b, b)


ProcedureReturn rgb_

EndProcedure

Procedure.l LoadGraphic(FileName.s, Type.b)
gfx_count + 1
ReDim gfx.Structure_Graphics(gfx_count)

gfx(gfx_count)\Sprite = LoadSprite(#PB_Any, FileName.s)
StartDrawing(SpriteOutput(gfx(gfx_count)\Sprite))
    gfx(gfx_count)\Pointer = DrawingBuffer()    ;get the pointer to sprite data
StopDrawing()
gfx(gfx_count)\Width = SpriteWidth(gfx(gfx_count)\Sprite)
gfx(gfx_count)\Height = SpriteHeight(gfx(gfx_count)\Sprite)

ProcedureReturn gfx_count
EndProcedure

Procedure.l LoadSpr(x.d, y.d, image)
;spr_count + 1
;ReDim spr.Structure_Sprite(spr_count)
AddElement(spr())
spr()\x = x
spr()\y = y
spr()\index = image

ProcedureReturn ListIndex(spr())
EndProcedure


; Map container
Global Dim worldMap.b(mapWidth, mapHeight)
Global Dim floorMap.b(mapWidth, mapHeight)

;; Texture
;Global Dim tex.l(texWidth,texWidth)

; Declare render funcs
Declare RenderTexturedWalls()

; Read map
Global x.l = 0
Global y.l = 0
For y.l = 0 To mapHeight-1
  For x.l = 0 To mapWidth-1
    Read.b worldMap(x, y)
  Next x
Next y
;floors ;cause i don't want every floor tile to be the same.
For y.l = 0 To mapHeight-1
  For x.l = 0 To mapWidth-1
    Read.b floorMap(x, y)
  Next x
Next y

InitKeyboard() : InitSprite() : InitMouse()

;OpenWindow(0, 0, 0, screenWidth , screenHeight, "Raycast Example #2", #PB_Window_ScreenCentered | #PB_Window_MinimizeGadget | #PB_Window_SizeGadget)
;OpenWindowedScreen(WindowID(0), 0, 0, screenWidth, screenHeight, 0, 0, 0)
OpenScreen(screenWidth, screenHeight, 24, "")

;We only need to call StartDrawing(ScreenOutput()) once to grab the pointer to the drawing buffer.
; That address never changes while the program is running and we'll have it forever.
StartDrawing(ScreenOutput())
    ;grab a pointer to the screen data
    *Screen = DrawingBuffer()
    ;fix endian problem and get ScreenBPP   (on my computer the pixel format is BBGGRR, but incase yours is different...)
    Select DrawingBufferPixelFormat()
        Case #PB_PixelFormat_24Bits_RGB  ; 3 bytes per pixel (RRGGBB)
            RGB_fix\R = 0 : RGB_fix\G = 1 : RGB_fix\B = 2
            BPP = 3
        Case #PB_PixelFormat_24Bits_BGR  ; 3 bytes per pixel (BBGGRR)
            RGB_fix\B = 0 : RGB_fix\G = 1 : RGB_fix\R = 2
            BPP = 3
        Case #PB_PixelFormat_32Bits_RGB  ; 4 bytes per pixel (RRGGBB)
            RGB_fix\R = 0 : RGB_fix\G = 1 : RGB_fix\B = 2
            BPP = 4
        Case #PB_PixelFormat_32Bits_BGR  ; 4 bytes per pixel (BBGGRR)
            RGB_fix\B = 0 : RGB_fix\G = 1 : RGB_fix\R = 2
            BPP = 4
    EndSelect        
StopDrawing()
    

;LOAD TEXTURES HERE
LoadGraphic("grass1.bmp", 0)
LoadGraphic("colorstone.bmp", 0) ;1
LoadGraphic("gen2.bmp", 0)
LoadGraphic("greystone.bmp", 0)
LoadGraphic("greystone.bmp", 0)
LoadGraphic("gen1.bmp", 0)          ;5 is a 64x128 image
a = LoadGraphic("sprite.bmp", 0)
LoadSpr(16.5, 15.5, a)
   
; Start position
Global posX.f = 22
Global posY.f = 12

; Initial direction vector
Global dirX.f = -1
Global dirY.f = 0

; 2D camera plane
Global planeX.f = 0
Global planeY.f = 0.66

; Frame timing
Global time.f = 0
Global oldTime.f = 0

;my skybox images are each 320x100
sky1 = LoadSprite(#PB_Any, "sky1.bmp")
sky2 = LoadSprite(#PB_Any, "sky2.bmp")
sky3 = LoadSprite(#PB_Any, "sky3.bmp")
sky4 = LoadSprite(#PB_Any, "sky4.bmp")

; Main loop
Repeat
 Dim PixelZ.d(screenWidth, screenHeight)
  ; Pump window events
  ;Global Event.l = WindowEvent()
 
    ClearScreen(0)
    skyoff = -(FindAngle(planeX*1000, planeY*1000) * 3.55)
    DisplaySprite(sky4, skyoff - 320, 0)
    DisplaySprite(sky1, skyoff , 0)
    DisplaySprite(sky2, skyoff + 320, 0)
    DisplaySprite(sky3, skyoff + 640, 0)
    DisplaySprite(sky4, skyoff + 960, 0)
    DisplaySprite(sky1, skyoff + 1280, 0)
    
    ; Render textured walls
    RenderTexturedWalls()
 
; Flip buffers
  FlipBuffers()
 
  ; Check keyboard + timed movement
  ExamineKeyboard()
  ExamineMouse()
   
  ; Calculate frame timing
  oldTime = time;
  time = ElapsedMilliseconds();
  Global frameTime.f = (time - oldTime) / 1000.0
 
  ; Set FPS in title bar (wonky in PB. Dunno why. Works in C++/Flash version ;)
  ;SetWindowTitle(0, "Raycast Example #1 (FPS: " + Str(Int(1.0 / frameTime)) + ")")

  ; Calculate speed modifiers (constant values are squares/second and radians/second)
  Global moveSpeed.f = frameTime * 5.0
  ;Global rotSpeed.f = frameTime * 3.0
  Global rotSpeed.f = -MouseDeltaX() / 15 * frameTime
 
 ;some debug stuff
 If KeyboardPushed(#PB_Key_Space)
    ;Debug "X: " + StrF(posX) + " Y: " + StrF(posY)
    ;Debug "pX: " + StrF(planeX) + " pY: " + StrF(planeY)
    ;Debug "A: " + StrF(FindAngle(planeX*1000, planeY*1000))
    Debug MouseDeltaX()
 EndIf
 
 ;step right?
 If KeyboardPushed(#PB_Key_Right)
    If worldMap(Int(posX + planeX * moveSpeed), Int(posY)) = 0
      posX = posX + ( planeX * moveSpeed)
    EndIf
   
    If worldMap(Int(posX), Int(posY +  planeY * moveSpeed)) = 0
      posY = posY + ( planeY * moveSpeed)
    EndIf 
 EndIf
 
 ;step left?
 If KeyboardPushed(#PB_Key_Left)
     If worldMap(Int(posX - planeX * moveSpeed),Int(posY)) = 0
      posX = posX - (planeX * moveSpeed)
    EndIf
   
    If worldMap(Int(posX),Int(posY - planeY * moveSpeed)) = 0
      posY = posY - (planeY * moveSpeed)
    EndIf 
 EndIf
 
  ; Move forward?
  If KeyboardPushed(#PB_Key_Up)  
    
    If worldMap(Int(posX + dirX * moveSpeed), Int(posY)) = 0
      posX = posX + (dirX * moveSpeed)
    EndIf
   
    If worldMap(Int(posX), Int(posY + dirY * moveSpeed)) = 0
      posY = posY + (dirY * moveSpeed)
    EndIf
 
  EndIf
 
  ; Move back?
  If KeyboardPushed(#PB_Key_Down)
 
    If worldMap(Int(posX - dirX * moveSpeed),Int(posY)) = 0
      posX = posX - (dirX * moveSpeed)
    EndIf
   
    If worldMap(Int(posX),Int(posY - dirY * moveSpeed)) = 0
      posY = posY - (dirY * moveSpeed)
    EndIf
 
  EndIf
 
  ; Rotate right? (Both camera and camera plane needs to be rotated)
  ;If KeyboardPushed(#PB_Key_Right)
  If MouseDeltaX() <> 0
    
    Global oldDirX.f = dirX
    dirX = dirX * Cos(rotSpeed) - dirY * Sin(rotSpeed)
    dirY = oldDirX * Sin(rotSpeed) + dirY * Cos(rotSpeed)
    Global oldPlaneX.f = planeX
    planeX = planeX * Cos(rotSpeed) - planeY * Sin(rotSpeed)
    planeY = oldPlaneX * Sin(rotSpeed) + planeY * Cos(rotSpeed)
   
  EndIf
 
 
 
 
Until  KeyboardPushed(#PB_Key_Escape)


; Render textured walls
Procedure RenderTexturedWalls()

  ; Misc vars
  Protected x.l = 0
 
  ; Draw some boxes
  ;Box(0,0,screenWidth, screenHeight/2, RGB(10,10,255))
  
 
  ; Render wall strips for each vertical screen row (640 in this case. 320 in good old Wolfenstein)
  For x.l = 0 To screenWidth-1
 
      ; Calculate ray position and direction
      Protected cameraX.f = 2 * x / screenWidth-1
      Protected rayPosX.f = posX
      Protected rayPosY.f = posY
      Protected rayDirX.f = dirX + planeX * cameraX
      Protected rayDirY.f = dirY + planeY * cameraX
     
      ; Determine map tile we're in
      Protected mapX.l = Int(rayPosX)
      Protected mapY.l = Int(rayPosY)
     
      ; Length of ray from current position to next x or y-side
      Protected sideDistX.f = 0
      Protected sideDistY.f = 0
           
      ; Length of ray from one x or y-side to next x or y-side
      Protected deltaDistX.f = Sqr(1 + (rayDirY * rayDirY) / (rayDirX * rayDirX))
      Protected deltaDistY.f = Sqr(1 + (rayDirX * rayDirX) / (rayDirY * rayDirY))
      Protected perpWallDist.f

      ; What direction to step in x or y-direction (either +1 or -1)
      Protected stepX.l
      Protected stepY.l

      ; Was a wall hit, and if so which side
      Protected hit.l = 0
      Protected side.l

      ; Calculate step and initial sideDist
      If rayDirX < 0
        stepX = -1
        sideDistX = (rayPosX - mapX) * deltaDistX
      Else
        stepX = 1
        sideDistX = (mapX + 1.0 - rayPosX) * deltaDistX  
      EndIf
     
      If (rayDirY < 0)
        stepY = -1
        sideDistY = (rayPosY - mapY) * deltaDistY 
      Else
        stepY = 1
        sideDistY = (mapY + 1.0 - rayPosY) * deltaDistY 
      EndIf

      ; Perform DDA algorithm for true hit detection
      While hit = 0
       
        ; Jump to next map square depending on direction
        If sideDistX < sideDistY
       
          sideDistX = sideDistX + deltaDistX
          mapX = mapX + stepX
          side = 0
       
        Else
       
          sideDistY = sideDistY + deltaDistY
          mapY = mapY + stepY
          side = 1
         
        EndIf
       
        ; See if ray has hit a wall
        If MapX < 0 Or MapX > mapWidth Or MapY < 0 Or MapY > mapHeight
            hit = 1
        Else
            
        If worldMap(mapX, mapY) > 0 
            ;hit = 1
            ; Calculate distance projected onto camera direction (includes fisheye removal)
            If side = 0
                perpWallDist = Abs((mapX - rayPosX + (1 - stepX) / 2) / rayDirX)
            Else
                perpWallDist = Abs((mapY - rayPosY + (1 - stepY) / 2) / rayDirY)
            EndIf
            ; Calculate height of line to draw onto screen
                           
            Protected lineHeight.l = Abs(Int(screenHeight / perpWallDist))  * (gfx(worldMap(mapX, mapY))\Height / 64)
            Protected halves.d = gfx(worldMap(mapX, mapY))\Height / 32
            
            ; Calculate lowest and highest pixel for current line strip
            Protected drawStart.l = (-lineHeight * ( (halves-1) / halves) + (screenHeight / 2) )
            If drawStart < 0
                drawStart = 0
            EndIf
            
            Protected drawEnd.l = (lineHeight * (1 / halves) + (screenHeight / 2) )
            If drawEnd >= screenHeight
                drawEnd = screenHeight ;- 1
            EndIf
            
            ; Determine exact point where wall was hit for texture generation
            Protected wallX.f
            If side = 1
                wallX = rayPosX + ((mapY - rayPosY + (1 - stepY) / 2) / rayDirY) * rayDirX
            Else
                wallX = rayPosY + ((mapX - rayPosX + (1 - stepX) / 2) / rayDirX) * rayDirY
            EndIf
            
            wallX = wallX - Int(wallX); What no floor? Also added abs because of this. Line should be 'wallX = wallX - Floor(wallX)'
            wallX = Abs(wallX) ; Should not be here, but since we got no floor :)
       
            ; Calculate x coordinate on the texture
            Protected texX.l = Int(wallX * texWidth);
            If side = 0 And rayDirX > 0
                texX = texWidth - texX - 1
            EndIf
            
            If side = 1 And rayDirY < 0
                texX = texWidth - texX - 1
            EndIf
     
            ; Render textured strip
            Protected y.l = 0
            For y = drawStart To drawEnd - 1
                If PixelZ(x, y)  > perpWallDist Or PixelZ(x, y) = 0 
                    Protected d.l = y * 256 - screenHeight *128 + lineHeight * 128 ;Avoid floats
                    Protected texY.l = ((d * gfx(worldMap(mapX, mapY))\height) / (lineHeight)) / 256 
                    color = Get_Pixel_(gfx(worldMap(mapX, mapY))\Pointer, gfx(worldMap(mapx, mapy))\width, texX, texY+((halves-2)*16))
       
                    If color <> 16711935
                        ; Again shift to darken color depending on side
                        If side = 1
                            color = (color >> 1) & 8355711
                        EndIf
                        ; Draw pixel
       
                        Light = ((perpWallDist*255)/5)      ;!
                        If Light < 0 : Light = 0 : EndIf
                        If Light > 255 : Light = 255 : EndIf
                        Factor.f = (255 - Light)/255
       
                        Red_ = Red(color) *Factor
                        Green_ = Green(color)*Factor
                        Blue_ = Blue(color)*Factor
                        
                        color = RGB(red_, green_, blue_)
                        Set_Pixel_(*screen, screenWidth, x, y, color)
                        PixelZ(x, y) = perpWallDist
                    Else
                        If worldMap(mapX, mapY) <> 1
                            Hit = 0
                            
                        EndIf    
                    EndIf
               EndIf    
            
                
            Next
            
;            //FLOOR CASTING
        Protected floorXWall.d, floorYWall.d    ;x, y position of the floor textel at the bottom of the wall
;
;      //4 different wall directions possible
        If side = 0 And rayDirX > 0
            floorXWall = mapX
            floorYWall = mapY + wallX
        ElseIf side = 0 And rayDirX < 0
            floorXWall = mapX + 1.0
            floorYWall = mapY + wallX
        ElseIf side = 1 And rayDirY > 0
            floorXWall = mapX + wallX
            floorYWall = mapY
        Else
            floorXWall = mapX + wallX
            floorYWall = mapY + 1.0
        EndIf
        
        Protected distWall.d, distPlayer.d, currentDist.d
        distWall = perpWallDist
        distPlayer = 0
        
        If drawEnd < 0 : drawEnd = screenHeight : EndIf
        
        For y = drawEnd + 1 To screenHeight
            currentDist = screenHeight / (2 * y - screenHeight)
            weight.d = (currentDist - distPlayer) / (distWall - distPlayer)
                
            Protected currentFloorX.d = weight * floorXWall + (1 - weight) * posX
            Protected currentFloorY.d = weight * floorYWall + (1 - weight) * posY
            If floorMap(Int(currentFloorX), Int(currentFloorY)) <> 0
                a = floorMap(Int(currentFloorX), Int(currentFloorY)) - 1
                floorTexX.l = Int(currentFloorX * texWidth) % texWidth
                floorTexY.l = Int(currentFloorY * texHeight) % texHeight
                If PixelZ(x, y) = 0
                    color = Get_Pixel_(gfx(a)\Pointer, gfx(a)\Width, floorTexX, floorTexY)
                    
                    Light = ((currentDist*255)/5)       ;!
                        If Light < 0 : Light = 0 : EndIf
                        If Light > 255 : Light = 255 : EndIf
                        Factor.f = (255 - Light)/255
       
                        Red_ = Red(color) *Factor
                        Green_ = Green(color)*Factor
                        Blue_ = Blue(color)*Factor
                        color = RGB(red_, green_, blue_)
                    Set_Pixel_(*screen, screenWidth, x, y, color)
                    ;PixelZ(x, y) = 0.0001  ;set this to a low # so we don't draw the same pixel again.
                EndIf
                ;I am not using ceilings here because of variable wall height, but if you'd like to:
                ;If PixelZ(x, screenHeight-y) = 0
                ;    color = Get_Pixel_(gfx(0)\Pointer, gfx(0)\Width, floorTexX, floorTexY)
                ;    Set_Pixel_(*screen, screenWidth, x, screenHeight - y, color)
                ;    ;PixelZ(x, screenHeight-y) = 0.0001  ;set this to a low # so we don't draw the same pixel again.
                ;EndIf     
            EndIf     
        Next
;  End of floors casting
            
        EndIf  
        EndIf 
      Wend
      
  Next
    
;     //SPRITE CASTING
;     //sort sprites from far To close
;     For(int i = 0; i < numSprites; i++)
    ForEach spr()
;     {
;       spriteOrder[i] = i;
;       spriteDistance[i] = ((posX - sprite[i].x) * (posX - sprite[i].x) + (posY - sprite[i].y) * (posY - sprite[i].y)); //sqrt not taken, unneeded
        spr()\Distance = ((posX - spr()\x)*(posX - spr()\x) + (posY - spr()\y)*(posY - spr()\y))
;     }
    Next
;     combSort(spriteOrder, spriteDistance, numSprites);
    SortStructuredList(spr(), #PB_Sort_Ascending, OffsetOf(Structure_Sprite\distance), #PB_Sort_Double)
;     //after sorting the sprites, do the projection And draw them
;     For(int i = 0; i < numSprites; i++)
    ForEach spr()    
;     {
;       //translate sprite position To relative To camera
;       double spriteX = sprite[spriteOrder[i]].x - posX;
        spriteX.d = spr()\x - posX
;       double spriteY = sprite[spriteOrder[i]].y - posY;
        spriteY.d = spr()\y - posY
;          
;       //transform sprite With the inverse camera matrix
;       // [ planeX   dirX ] -1                                       [ dirY      -dirX ]
;       // [               ]       =  1/(planeX*dirY-dirX*planeY) *   [                 ]
;       // [ planeY   dirY ]                                          [ -planeY  planeX ]
;       
;       double invDet = 1.0 / (planeX * dirY - dirX * planeY); //required for correct matrix multiplication
        invDet.d = 1.0 / (planeX * dirY - dirX * planeY)
;       
;       double transformX = invDet * (dirY * spriteX - dirX * spriteY);
        transformX.d = invDet * (dirY * spriteX - dirX * spriteY)
;       double transformY = invDet * (-planeY * spriteX + planeX * spriteY); //this is actually the depth inside the screen, that what Z is in 3D       
        transformY.d = invDet * (-planeY * spriteX + planeX * spriteY)
;             
;       int spriteScreenX = Int((w / 2) * (1 + transformX / transformY));
        spriteScreenX = Int((screenWidth / 2) * (1 + transformX / transformY))
;       
;       //calculate height of the sprite on screen
;       int spriteHeight = Abs(Int(h / (transformY))); //using "transformY" instead of the real distance prevents fisheye
        spriteHeight = Abs(Int(screenHeight / (transformY)))
;       //calculate lowest And highest pixel To fill in current stripe
;       int drawStartY = -spriteHeight / 2 + h / 2;
        drawStartY = -spriteHeight / 2 + screenHeight / 2
;       If(drawStartY < 0) drawStartY = 0;
        If drawStartY < 0 : drawStartY = 0 : EndIf
;       int drawEndY = spriteHeight / 2 + h / 2;
        drawEndY = SpriteHeight / 2 + screenHeight / 2
;       If(drawEndY >= h) drawEndY = h - 1;
        If drawEndY => screenHeight : drawEndY = screenHeight - 1 :EndIf
;       
;       //calculate width of the sprite
;       int spriteWidth = Abs( Int (h / (transformY)));
        SpriteWidth = Abs(Int(screenHeight / (transformY)))
;       int drawStartX = -spriteWidth / 2 + spriteScreenX;
        drawStartX = -SpriteWidth / 2 + spriteScreenX
;       If(drawStartX < 0) drawStartX = 0;
        If drawStartX < 0 : drawStartX = 0 : EndIf
;       int drawEndX = spriteWidth / 2 + spriteScreenX;
        drawEndX = SpriteWidth / 2 + spritescreenX
;       If(drawEndX >= w) drawEndX = w - 1;
        If drawEndX => screenWidth : drawEndX = screenWidth - 1 : EndIf
;       
;       //loop through every vertical stripe of the sprite on screen
;       For(int stripe = drawStartX; stripe < drawEndX; stripe++)
        For stripe = drawStartX To drawEndX - 1
;       {
;         int texX = Int(256 * (stripe - (-spriteWidth / 2 + spriteScreenX)) * texWidth / spriteWidth) / 256;
            texX = Int(256 * (stripe - ( -SpriteWidth / 2 + spritescreenX)) * texWidth / SpriteWidth) / 256
;         //the conditions in the If are:
;         //1) it's in front of camera plane so you don't see things behind you
;         //2) it's on the screen (left)
;         //3) it's on the screen (right)
;         //4) ZBuffer, With perpendicular distance
;         If(transformY > 0 && stripe > 0 && stripe < w && transformY < ZBuffer[stripe])  
            If transformY > 0 And stripe > 0 And stripe < screenWidth 
                
;         For(int y = drawStartY; y < drawEndY; y++) //for every pixel of the current stripe
            For y = drawStartY To drawEndY - 1
                If PixelZ(stripe, y) > transformY Or PixelZ(stripe, y) = 0
;         {
;           int d = (y) * 256 - h * 128 + spriteHeight * 128; //256 and 128 factors to avoid floats
                d = y * 256 - screenHeight * 128 + SpriteHeight * 128
;           int texY = ((d * texHeight) / spriteHeight) / 256;
                texY = ((d * texHeight) / SpriteHeight) / 256
;           Uint32 color = texture[sprite[spriteOrder[i]].texture][texWidth * texY + texX]; //get current color from the texture
                color = Get_Pixel_(gfx(spr()\index)\Pointer, texWidth, TexX, TexY)
;           If((color & 0x00FFFFFF) != 0) buffer[stripe][y] = color; //paint pixel if it isn't black, black is the invisible color
                If color <> 16711935
                    Light = ((transformY*255)/5)        ;!
                        If Light < 0 : Light = 0 : EndIf
                        If Light > 255 : Light = 255 : EndIf
                        Factor.f = (255 - Light)/255
       
                        Red_ = Red(color) *Factor
                        Green_ = Green(color)*Factor
                        Blue_ = Blue(color)*Factor
                        
                        color = RGB(red_, green_, blue_)
                    Set_Pixel_(*screen, screenWidth, stripe, y, color)
                EndIf
                EndIf
            Next
                
            EndIf
        Next  
    Next
;         }
;       }
;     }    
EndProcedure

; Map data
DataSection

  Data.b  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
  Data.b  1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
  Data.b  1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
  Data.b  1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
  Data.b  1,0,0,0,0,0,2,2,2,2,2,0,0,0,0,3,0,3,0,0,0,0,0,1
  Data.b  1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1
  Data.b  1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,3,0,0,0,0,0,0,0,1
  Data.b  1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1
  Data.b  1,0,0,0,0,0,2,2,0,2,2,0,0,0,0,3,0,3,0,3,0,0,0,1
  Data.b  1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
  Data.b  1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
  Data.b  1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
  Data.b  1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
  Data.b  1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
  Data.b  1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
  Data.b  1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
  Data.b  1,4,4,4,4,4,4,4,4,0,0,0,0,0,2,5,1,2,0,0,0,0,0,1
  Data.b  1,4,0,4,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
  Data.b  1,4,0,0,0,0,5,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
  Data.b  1,4,0,4,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
  Data.b  1,4,0,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
  Data.b  1,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
  Data.b  1,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
  Data.b  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
  
  ;floors
  Data.b  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  Data.b  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  Data.b  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  Data.b  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  Data.b  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  Data.b  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  Data.b  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  Data.b  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  Data.b  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  Data.b  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  Data.b  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  Data.b  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  Data.b  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  Data.b  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  Data.b  0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0
  Data.b  0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0
  Data.b  0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0
  Data.b  0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0
  Data.b  0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0
  Data.b  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  Data.b  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  Data.b  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  Data.b  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  Data.b  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

EndDataSection
Coolman
Enthusiast
Enthusiast
Posts: 103
Joined: Sat Sep 03, 2005 4:07 pm

Post by Coolman »

Godai wrote:Invalid memory access on windows in line 146: StartDrawing(ScreenOutput())
Try this :

OpenScreen(screenWidth, screenHeight, 32, "")

it works but it is very slow and the display is disrupted, however, great job

8)
*** Excuse my bad English, I uses has translating program ***
GBeebe
Enthusiast
Enthusiast
Posts: 263
Joined: Sat Oct 09, 2004 6:52 pm
Location: Franklin, PA - USA
Contact:

Post by GBeebe »

Yea, I don't know why, I have this problem on the Windows machines that I've tested it on, but not any of the Linux machines. I'm not sure where the problem is with that.

The 32 bit problem, yea, I think Godai figured that one out already, As for it being slow, try it with the Debugger off.
User avatar
Rook Zimbabwe
Addict
Addict
Posts: 4322
Joined: Tue Jan 02, 2007 8:16 pm
Location: Cypress TX
Contact:

Post by Rook Zimbabwe »

Invalid memory access on windows in line 146: StartDrawing(ScreenOutput())
I have a similar issue with the latest and linr 178... I think it is the same command.

XP Pro SP 3 PB 4.3 final

OK I mashed it around... I think the 24 is the key I don't support 24 at that graphics depth but 32 and 16 work...

Now If only someone would hast a link to the sprite files or include tham as images for us to click and save!

HINT! 8)
Binarily speaking... it takes 10 to Tango!!!

Image
http://www.bluemesapc.com/
Godai
Enthusiast
Enthusiast
Posts: 171
Joined: Thu Oct 05, 2006 8:13 pm

Post by Godai »

Well. I think the current examples are broken and we need solid examples where the speed is acceptable. This runs fine 640x480 in both Flash and C++

Also changing to 32-bit or 16-bit still crashes for me. I think the examples should auto-download images like the first ones :)

Just my 2 cents
GBeebe
Enthusiast
Enthusiast
Posts: 263
Joined: Sat Oct 09, 2004 6:52 pm
Location: Franklin, PA - USA
Contact:

Post by GBeebe »

There's nothing special about the images i'm using here, I just uploaded the ones that I did to show variable image height and skybox... If that's what ur asking.

Here's a slight optimisation, I think, if you're going to force 32 bit. Replaced PokeB and PeekB lines with one PokeL and PeekL.

Code: Select all

Procedure Set_Pixel_(*surface.l, w, x, y, color)
;sets pixel data in a buffer (*surface), assums that color is in the correct format
;(w) width of image is needed to determin correct position.
;Global BPP already needs to be set elsewhere.

PokeL(*surface + ( (y * w + x) * bpp ) + 0, color)
EndProcedure

Global retColor.l

Procedure.l Get_Pixel_(*surface.l, w, x, y)
;returns a color (long) from pixel data
;*surface is the pointer to pixel data.
;(w) width of image is needed to determin correct position.
;Global BPP already needs to be set elsewhere.

ProcedureReturn PeekL(*surface + ((y * w + x) * BPP) )
EndProcedure
I was using 24 bits thinking it would be faster than 32 bits... but according to the help on OpenScreen 32 bits is faster. My guess to that is becasue there isn't a 3 byte variable. My video card doesn't support 24 bits either, but SDL automatically bumps up to the next valid screen mode, also I can't use 320*200, but SDL takes care of that by using a 640*480 screen and placing the 320*200 surface in it.
Post Reply