Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- BlitzBASIC 2 PlayBASIC Conversion Tool WIP - Episode 06 - 3D Gouraud Shaded Torus - 14th March 2022
- Blog: https://www.underwaredesign.com/forums/index.php?topic=4625.msg30589#msg30589
- Watch: https://www.youtube.com/watch?v=algDfggRTgc&ab_channel=PlayBasic
- ----------------------------------------------------------------------------------------------
- hello and welcome back here we are
- tackling this blitz basic to play basic
- converter in today's episode we're
- actually going to look at
- the lovely taurus that's spinning around
- on the screen
- the current level of the build pretty
- much puts us at a workable state now it
- doesn't produce working code for this
- example
- but i'll put it on screen
- for you
- and we'll write and it's pretty cool
- okay let's take a look at the original
- blitz code
- it was written in 2001 this example and
- it's quite a nice example when running
- as you've already seen
- but the whole thing is
- all in software there's no hardware
- acceleration no internal polygon
- rendering in it
- all the poly rendering is done
- uh
- well brute force really
- it's drawing a batch of polygons doing
- this stuff here trying out vertices
- sorting the faces etc
- so a lot of work has been done
- that's my key point here that's the the
- takeaway point is that there's a lot of
- work being done
- until we come right down to the software
- rendering this example is doing groud
- shaded polygons and they're also light
- source which just makes it look a bit
- more interesting
- what i've actually done is i've taken
- the original code
- and attached the data statements because
- it was selectable in the original
- our translator at the moment doesn't
- understand include statement so we
- couldn't have that
- set up this way
- this way we can just pass it through as
- one big blob and get a blob out
- back to the translation
- so let's run the translator now we'll
- write in normal mode so we can see the
- the speed of the conversion
- uh it's about a thousand lines i think
- no sorry it's 2000 lines but most of
- those data statements so don't get too
- excited
- so we're doing our conversion in about a
- hundred and you know i'll be generous
- say 150 milliseconds not bad
- if we run into bug mode it'll take a lot
- longer so it's spitting out a lot of
- data to the console
- we've got about half a second there all
- up so the console is over here
- that's our code
- that's been translated
- the data statements didn't need to be
- translated at all so they've just passed
- through
- uh where are we our program code up here
- has been converted
- we go up the top we can see that's the
- start of our code and
- sorry above this is the information
- about the scopes what local variables
- there were
- how many times they were used etc some
- are used very frequently some are used
- hardly ever
- so we i think we'll be able to use that
- to our advantage and give tips about the
- conversion
- uh for each scope
- yeah you know
- let's not get him ahead of ourselves
- let's just get this thing converted
- so let's grab all this
- head down the bottom yeah okay grab that
- thing
- and uh quit out of this
- okay i've already set up a
- an empty project for us to paste into so
- let's paste our code
- from our conversion across
- so we're getting 2
- 700-ish lines of blitzcode
- now we've got an include file up the
- front here sorry let's grab that before
- we've inserted an include file this is
- coming from our my own wrapper at the
- moment to emulate blitz functions
- um let's kind of see how we go
- uh see how far we get without
- our dying
- i know some functions here we're going
- to need to remap like this read
- statements here
- pb has a different syntax for data
- statements
- i've got some collisions there too but
- we'll go through them so we can you can
- sort of follow what's happening with
- this stuff we compile
- right so our first
- first problem is this read statement
- uh
- reading traditional basic is is a
- command
- and we don't support that we actually
- have a read data function
- to grab the next uh bit of data off of
- the data
- we can think of a data like a stack
- can't you
- now
- it's really just like an index to it
- to a table but
- so branch ahead
- uh vertex signal vertex we've got some
- data statements there put those there
- get rid of those thanks
- i can see some problems with this
- already
- and they're not to do with the
- translation they did to do with
- differences in
- well
- how one language
- likes to use keywords in one one uh
- doesn't oh undo that thing so what i'll
- just do then
- delayed that terrible
- some dummy reads there so that day has
- got some empty stuff in it
- don't need the reed stavens there of
- course
- pull them out
- quick save
- let's just see what the next thing is
- doesn't like about this is
- uh yeah i thought it would like this
- actually see how we've got a type name
- called vertex and an array called vertex
- now
- it can't really distinguish between the
- two
- obviously in blips you're allowed to do
- that
- oh in pv you can't so what we'll do is
- we'll
- put like a lowercase t in front of the
- type names
- and
- so
- it's in front of vertex
- i thought a poly was another one as well
- poly was one
- and
- all light source was one
- okay
- so like south park there yeah eric you
- know there you go
- that was my mistake terrell
- ah here we go so this is a byproduct of
- the wrapping pepe likes that it's um
- functions to have
- a pair of brackets on them
- okay
- this is something that popped up when i
- was doing the a monster truck a most to
- play basic conversion
- in blitz um it's valid to have a
- variable called fps
- in pb that's the name of a function
- so
- the error is going
- hang on what are you trying to do with
- fps you can't do that with this so we
- have to rename this um
- when i did the amos converter it would
- just put a prefix in front of these ones
- that's what we'll do now we'll just go
- yep
- anything that's fps
- just call it local fps yeah
- i'm going to call it anything we want to
- do there's ones over there too
- hidden away anymore
- can't see any more of those so let's
- just compile and see how we go
- oh text yeah text is a bit of a pain
- because of the conversion
- i've got a version of text that'll do
- strings but here we've got a combination
- of
- string data and integer data so we have
- to have like a string wrapper around
- this
- for the amos converter i did
- actually
- that's actually what i did is it went
- through it it
- did a rough reese
- a rough sort of bracketing of these
- these things here just assuming that
- they're integers or whatever
- i might just get rid of the wrapping for
- this
- command
- because text is pretty much text there's
- not much we're just drawing stuff in the
- current font
- i will have to actually put strings
- around these
- isn't that terrible oh good goodness
- goodness gracious
- uh
- put the closing bracket on
- yeah it's definitely something we should
- definitely try and tackle
- and then the variable collision stuff
- too that could be a problem with big
- code bases
- um i forgot about that one
- next one let's just hit compile again
- see how we got
- that flip need some brackets
- flip is basically sink
- you know
- places plays in play basic lands just
- flipping the back buff for the front
- buffer
- hey
- that's a long way through
- lock buffer
- i think it blitz it requires a parameter
- and we'll let's set up to
- set up so that surface 0
- is the screen so we'll just put lock
- buffer 0
- for that and there's another collision
- there see how it's got rgb equals
- this
- expression wow i'm surprised it's done
- like that
- um
- we'll leave that there
- just to show you that that's going to
- upset play basics see how this variable
- name here it's going hey you've got a
- function
- using the function name in some wacky
- way what are you doing
- ah we'll just call it
- put l in front of it for local or
- something
- you can so how far we get
- right pixel
- uh
- oh it's got a surfacing on the end
- point zero for surface
- you know
- pretend like we know what we're doing
- unlock buffer no
- zero for surface yep good on you
- fantastic no no
- oh man so on
- so the functions ex
- yeah okay
- so the bottom there we're exporting a
- integer which is a assumed return from
- from the translation
- um so for this exit function here we
- have the same
- same response
- otherwise you might just get some stack
- misalignment
- um there is an error for that actually
- if you get one
- press on dudes let's go
- yeah oh
- yeah
- yeah some basics will allow you to do
- if expression and then then and then as
- long as there's nothing following them
- then you can you can use an end if
- statement we don't do that
- i must trap this one and cut it out or
- just add it to the phrase at some point
- lock buffer it's going to be screen
- isn't it
- unlock's going to be the
- screen right pixel
- one two three
- pv
- back buffer same collision
- issue there
- so that we're constructing a color and
- then running it to the screen so i've
- got a lot of work to draw a pixel
- yeah so it's going to run pretty pretty
- terribly initially but um i know we can
- speed it up
- when we get this thing going
- same drama
- don't need the then statements thanks
- hit save
- ah we've got through the code that's
- cool
- got a die in front of the label anymore
- what else we got
- chords
- you can pile again
- one more
- surely that must be the end of the data
- let's hit run
- wow it's running
- and it
- actually is running but there's some
- problems with it
- as you can see
- and one of the problems is not what you
- what you're expecting
- i did put this the other day and ran
- into the same same drama so
- i know roughly what the what this issue
- is going to be
- so before we tackle that i'll just
- demonstrate we're working
- why is working up front
- so
- we won't draw um the polygons as groud
- we'll just draw them as a set of
- vertices
- the function's already in here
- hopefully it should work there you go
- in other words the code that handles the
- rotation uh projection etc and
- the polysorting that's all actually
- working
- what's not working is this drawing this
- draw polygon function
- uh
- if we cut poly out
- put one of these line savings in now
- this has the old syntax see how it's got
- the the backslash
- that's the blitz syntax
- because this code was inside a comment
- and this wasn't converted
- um quick save
- let's hit
- run
- hmm so we are actually working
- that's pretty cool i like that
- and the rate's not too bad either we're
- getting you know 10s and 15s etc
- uh
- we can do better now
- sorry
- i might just put a space bar
- on this main loop where are we really
- i've set an exit time there so if it
- runs for a number of frames it'll exit
- by itself i might drop that down to 50
- frames
- um
- it sounds like a short time but
- uh when we get this we start tackling
- this um
- this poly rendering routine it's very
- slow initially because of all the
- wrapping
- it has a few bugs in it too that we've
- got to actually track down
- so it'll run for 50 foot and i'll run
- for
- 200 frames 250 frames okay
- or until hit the space bar all this guy
- all the escape go
- spacebar good
- right let's tackle this draw polly
- go to
- the groud poly function
- um
- i think what we'll do is
- so we'll actually have a look at this uh
- oh are we drawing the lines
- or not what are we drawing
- all right that's a little
- that's the x
- for this row
- it's the x from the next row and we'll
- draw it in like a
- green maybe
- so i should draw a strip for where the
- hot each horizontal strip of the
- the polynomial's drawing is
- um
- should
- now clearly the lines are outside of the
- polygons because the polygons are these
- white lines here
- and our lines are way outside that so
- something's not right
- i do know what the problem actually is
- so i'll talk you through it this one
- here
- it's in this edge function
- where we're lying on
- well
- let's go back a bit you might have
- noticed that all of the values here
- for coordinates
- uh see how we've got x1
- and then we've got rgb coordinates for
- it we've got x2 rgb coordinates
- uh these are to draw
- down the edge of the polygons as it's
- being scanned converted
- now when we have a triangle we we work
- out what's the top point
- and we work out what edges we need to
- draw and we draw
- ideally from the top to the bottom you
- can actually draw in any whatever your
- order you like
- as long as you end up with a bunch of
- lists bunch of spans
- that represent the shape
- now this doesn't work
- because here we've got a translation
- where we're going
- we're subtracting x1 from x2 and then
- shifting it up 8 bits
- if x1 x2 are positive
- that's fine
- and it's the same goes for y1 y2 if
- that's positive that's fine
- but at any point
- we end up with something that's that's
- negative
- we're mixing signed arithmetic with
- bitwise arithmetic
- so something between how the shift
- operator works in blitz and how the
- shift operator works in pv is different
- here i'm just moving the bits just going
- hey
- shift the bits up who cares about the
- side of it
- so we've actually got to do a division
- here or sorry multiplication
- so so
- if we shift something
- if we shift something up eight bits
- i'll just call it scala i guess
- so we're just going
- um
- we can do it like this
- we can compute that scala
- that's the level of precision
- which is going to be an integer value of
- 256.
- so we could substitute in here
- we're multiplying this sorry wrong
- operator
- now because pv is interpreted
- the cost of having in an integer mold or
- an integer shift is not that great
- to be honest
- it's really almost nothing
- well actually i wonder there too see how
- we've got
- we've got a shift and then in addition i
- wonder if the precedence
- of this is actually a problem
- let's just check that
- hey we're here now let's just do it yeah
- come on
- i know you're bored i know you want to
- see it running fantastic yeah
- this is computing our edges if our
- engines look normal then that's our
- problem that it's not
- there's not a difference between the
- shift it's a difference between the
- precedence of the operators
- i don't know
- let's find out together
- hey that's the problem
- that's nice to know
- yeah all right
- just to check that
- that means we can get away with we don't
- need to do
- those modifications we can just go yeah
- all right do your thing dude
- do this that's very good do this thing
- very good
- lovely long as it still works
- the slide performance is actually
- a common problem with direct draw
- applications all right so that that's
- actually solved
- our problem so
- if we go back
- that's our pixel rendering loop
- that's our line rendering rendering loop
- now if we do
- something
- simple like we go a lock buffer here
- so we're drawing all of these lines
- batched up with and we're locking the
- surface
- that should
- make people a lot happier when we're
- doing this job
- should
- yeah it's much happier with that
- cool
- now we know the the
- vertex locations are accurate we know
- that our
- they're all the same so now we need to
- tackle this in a loop and i know this
- three slides could take you know
- quite a while to render so i'll put that
- abort case
- back into the code
- of you know
- i have it be uh
- 20 frames
- see how bad we get how bad it runs up
- from up front
- about a frame a second
- but
- it is running
- can we improve on this you better
- how we're going to do it well the same
- old way we always do it
- like in the buffers dude
- so we know it works and all of our
- efforts there have been have not been in
- vain so
- get rid of the line drawing stuff there
- for a second
- go up to
- and draw a polygon and go have a look at
- the draw
- oh
- that's right below it
- right
- now
- right pixel is pretty much a wrapper
- around
- the
- the dot function so we can substitute
- right pixel
- with dot we don't need to know the
- buffer all the time we don't
- people work that stuff out for us so we
- could just do this
- dot c which is the colored version
- for the lrgb and that should help us out
- a lot
- doesn't seem like it has though does it
- and
- the main reason for that is that we are
- drawing
- 500 polygons in every scan line of those
- polygons which is going to be let's say
- each polygon's got 20 scan lines so
- that's
- 570 times 20.
- that's how many times we are locking and
- unlocking the surface
- that's a lot
- uh so what we need to do what we should
- do really is that rather than lock the
- buffer
- every time we draw a strip draw one one
- span
- which is how this is has provisioned for
- it before
- go up to the
- animal drawer these four those
- so here we go
- would you look at that
- so we're running actual translated blitz
- basic code
- uh it's drawing every polygon dot by dot
- we've got some buffer management control
- in there
- we're drawing lots of extra dots there
- too so i bet they they don't have great
- uh buff sorry
- buffer management stuff in them as well
- but we're still doing something that's
- not great though isn't it we're locking
- the buffers
- every time we draw a polygon so if we
- draw the more polygons we draw
- in this case here if we if
- we have 500 polygons and half of those
- polygons are visible
- so let's say 250 on average
- then
- we're going to be drawing attempting to
- lock the buffer and unlock it
- 250 times so we want to actually
- probably a better solution would be to
- lock the buffers
- at the start of the polygon batching and
- then release it at the end
- let's try that then so let's draw a
- polygon routine here
- we're running through and doing all this
- good stuff so we'll just do the locking
- it at this level
- and strip out the other stuff we added
- before
- where are we there we are there we are
- so it locks the current surface by the
- way if you're not familiar
- uh draw vertices
- there's no buff although there is some
- there that's not too bad
- sorry
- let's go to grab polygon find that thing
- we don't need to lock the buffer in here
- so
- we can do our strip
- render our strips
- and the buffer state is being managed on
- a higher level so we don't need to have
- all this pleasing thank you with those
- that there's this low level here
- that shouldn't make it perform much
- better
- should
- and does
- now we're capturing the screen we're
- drawing a bunch of dots as well so you
- know
- it's not bad
- it's just a complete translation of the
- same application
- uh clearly the inner loop here has some
- things there we could probably get rid
- of
- like
- if we know we're never drawing outside
- of the display
- constraints
- we can swap dot with uh fast
- fast dot
- and we probably should do
- here i think we're always rendering to
- the same surface
- so that would mean our our lock would be
- appropriate for the for the same surface
- all the time
- but you've got to be careful with that
- stuff
- one way to ensure that's never going to
- was going to work as we can read
- if you ask
- us pb to read a pixel from the surface
- it will see the locking every time so we
- read one pixel at the start of the batch
- of all the polygons then we never needed
- to do it again
- if you're jumping around changing images
- you're rendering to locking something
- unlocking it
- the
- the optimizations that track the lock
- state can
- can you know they can work against you i
- know
- i'm a terrible person
- should be the same
- cool
- that's pretty good some stuff in here
- too yeah i could grab the
- grab this thing here
- um
- just call it
- this is your index
- grab your index from there
- save reading that array three times
- so i'll read it once and then just throw
- it away
- those kind of you know there's micro
- optimizations you can run through and do
- those things yourself
- um
- you probably probably always treat your
- colors separately and have the light
- source computed
- or you've got more actually
- you can clip the range there's for
- example c2 equals
- clip range
- c2
- north of 255
- you know
- that sort of thing
- um you're probably not really winning
- back any performance by doing those
- things but it can just reduce your code
- it's pretty cool i like it
- i like it a lot ah right
- that's our translation for you um hope
- you enjoyed that
- let's say we wanted to push this a bit
- further we could we could make this a
- bit more play basic friendly
- get rid of the dot rendering stuff
- draw vertices get rid of that
- don't really need it let's check this
- thing out
- that's nice
- uh one thing we could do is obviously
- since we're in pv land
- now draw a polygon
- now
- let's head down to
- our draw a line where are those
- this particular section of code here
- that's it's forming an rgb color
- what we couldn't do is we could of
- course
- use the rgb function
- rgb
- was it rt
- uh gt and then bt
- we don't have to do this in software so
- we you know we're two function calls
- that approximate
- this is
- we get rid of a shift a shift and two
- additions
- but we substitute them for one function
- call
- let's try it
- it's pretty hard to know
- if if we've won much back in that i
- would say we probably have
- obviously the best way to do this in pv
- is actually to do this
- let's draw a groud strip from x1
- from r1 g1
- b1
- to x2 rgb
- it's going to be
- r2
- blue 2
- and green two and
- on the y row so we can just get rid of
- all of that really
- yeah
- it's pretty comfortable now it's
- obviously we're switching a lot of the
- the runtime dependency to command set
- dependencies
- uh which is because the built-in
- function for drawing a grad strip is
- pretty much
- well it's pretty optimal you know
- compared to
- i don't know how many cycles this takes
- to
- to execute through the through the
- runtime but
- every single pixel is doing that
- i guess what you could do is you could
- use some of the
- [Music]
- the paired pixel optimization stuff
- where you
- you know when you draw
- you unroll the this inner loop a bit
- further you draw pairs of pixels you
- know in one pass compute them etc and
- that actually works pretty well to be
- honest
- and you draw a pair of dots
- at one time rather than a single lot
- that makes that can be beneficial
- because you're drawing
- or you're saving
- some overhead from calling a function
- which in the runtime is quite expensive
- so even though this is relatively fast
- you know this is the fully
- fully interpreted rendering loop
- so we're probably somewhere in that you
- know in the
- between 30 to 60 frames per second
- which is stunning to me
- while it's been captured or
- now this is going to be you know
- comparing to the
- the native loop that draws ground pixels
- it's not that much detriment it's
- probably twice as fast let's say
- if i converted the whole thing to use
- the groud polygon
- it would be much faster again
- but i want
- i'll
- just revert the code back to how it was
- and you can
- tackle this yourself
- what if we avoided drawing the line at
- all and just drew
- a ground line in here
- so we computed the start of the line
- x1 yep go for it
- x2 is going to equal
- it's the here
- so we just need these
- rgb
- values here
- and that function should pretty much
- work the way it was working before
- we've got x y x one y is the same
- let's try her out
- i think for this approach we're pretty
- much um
- at maximize our throughput for it
- to draw strips
- to get quicker we're gonna have to go to
- drawing polygons
- just draw the whole thing
- um
- grab triangle x1 y1
- rgb
- one x2 y2
- rgb2
- x3
- y3 rgb3
- exit function to avoid all that other
- stuff at the bottom there
- you know
- uh so rgb one equals rgb rgb
- g1 b1
- because the command expects uh the
- parameters to be fed to it
- as colors
- um
- that are compressed
- so they're packed together as
- rgb rather than separate rgb
- fields
- all right
- let's give it a go
- goodness gracious
- oh
- i've got a return to zero
- yeah no surprises there
- is you can see it kind of peaking at a
- few hundred frames per second
- what if we just keep those in the code
- or have uh
- i'll make three different versions of it
- so version two
- which will just be the
- the line optimization and version three
- will be the full polygon rendering
- thing so we'll just
- cut all of that out
- so version three of the
- function will be this
- don't need anything below that
- version two will be the
- so doing all this work here great all
- going well and then we're doing this
- so we
- using ground strip to do for this
- version
- uh
- where are we and
- for the original version we just you
- were doing
- as it was the stock version
- uh
- just
- restore that to how it was cut all that
- stuff there out again
- excuse this video for being so long
- so the inner loop no we want the actual
- pixel rendering
- run it give it a test
- we're back to the normal software
- rendering
- which is still pretty good
- cool
- what if we put a switch in there
- to choose which rendering method we
- wanted
- to
- [Music]
- global uh render
- random method equals zero by default
- uh at the bottom here we'll just
- display this to the user
- i don't draw up there actually
- so i'll come down about
- that lori 60 random method
- random
- random method
- and
- just call it render
- yeah i'll do that
- everything on the end here render
- sorry method
- come on
- i know it's light it's not that light
- add a bit of crappy logic up front you
- know
- all the good stuff
- select
- uh render
- method
- case zero
- top
- this is the fast dot
- in a loop
- then select
- a couple of those
- two
- this is the
- ground
- strip
- round triangle
- um
- so we'll just have a
- bit of a check here um
- i don't know if the answer is press or
- something
- whatever
- uh this bump that
- bigger than two
- making it a zero it's kind of a default
- case
- i couldn't be bothered
- isn't that terrible
- now i could use like
- call function in this and do some
- as9
- kind of crap
- uh we we'll just have the polygon
- rendering stuff wherever that's going to
- uh draw a poly
- select random method
- have a select case
- very old school
- all right so we were method one method
- two i'll make this correlate here
- actually method one
- method two um
- uh sorry i didn't think this was
- going what
- what the hell
- all right so method one is the
- ground strip version and polygon
- 2 is the full blown polygon version
- let's try it out so we can check them
- side by side
- all right so looking at the the fast dot
- which is the original emulation of the
- blitz code
- we're switching to ground strip mode
- which is we're drawing the inner strips
- with our groud strip command
- we're peaking at 125 frames per second
- we're averaging around over 60 frames
- per second now
- all in software
- on the interpreter so with polygon
- we're hitting 250 frames per second
- the average is coming up and up and up
- now of course that's going to be
- quickest because we're doing the
- we're passing control from the
- interpreter
- to machine code to fill the triangle and
- come back
- i hope this was insightful have you
- learned something hope you've interested
- in something
- thanks for watching i'll see you next
- time
- bye
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement