Code archives/Graphics/Mode7 & live 2d tiles

This code has been declared by its author to be Public Domain code.

Download source code

Mode7 & live 2d tiles by Casaber2016
It's great flexible base for any kind of game that needs live tiles (animated oceans, grass etc per frame for example). Also includes a fullblown mode7 ontop which is great to learn from.

This uses "slow" pixels and no hardware acc, despite this it reaches well above steady smooth 60 fps on most devices. It's also good project to optimize further and play around with.

I see this forum is full of retro gamers so I think this will be appriciated well. So I put this here.
Have fun !!

Donīt forget to try the different commenting/uncomenting as it changes the experience totally.
Rem ------------------------------------------
 ___     ____  _____  _____   ______   ______  
|    \  /    |/     \|     \ |   ___| |___   | 
|     \/     ||     ||      \|   ___|   /   /  
|__/\__/|____|\_____/|______/|______|  |___|   

' Check the source for the important lines to comment / uncomment one at a time.
' 
' In 2d mode you can draw, showing the beginning of collision detection of tiles.
' And you may scroll around in this 16MB world, create any size you need.

EndRem

Global buffer:Int[128*128]
Local img2:TPixmap=LoadPixmap(LoadBank("http::s14.postimg.org/xotmro9vh/128x1282.png"))
For yy=0 To 127 ; For xx=0 To 127 ; buffer(xx+yy*128) = ReadPixel(img2,xx,yy) ; Next ; Next
AddHook FlipHook,irq,Null ; Global fps:Int , fpstotal:Int , msstart:Float , ms:Float = MilliSecs()

Global map[4096,4096] ; For yy=0 To 316 ; For xx=0 To 475; map[xx,yy]=Rnd(127) ; Next ; Next
For temp=0 To 255 ; map[temp,0]=temp ; Next
Global cmap[4096,4096] ; For yy=0 To 316 ; For xx=0 To 475; cmap[xx,yy]=Rnd(15) ; Next ; Next
Global wx:Int , wy:Int , cx:Int , c:Int = buffer[0] , cols:Int[16] , s:Int = 2
RestoreData colors ; For temp=0 To 15 ; ReadData cols[temp] ; Next
writetomap "                                            ",0,0
writetomap " These letters And symbols are live tiles   ",0,1
writetomap " Changing tiles, color of tiles and         ",0,2
writetomap " even the atlas at pixel level, each frame  ",0,3
writetomap " perfect base for platformers or shootemups ",0,4
writetomap "                                            ",0,5

Global xres:Int = 1024 , yres:Int = 768 , pixels:Int[xres*yres] ' Set resolution here.
Local a:Float = 0 , x:Float = 0 , y:Float = 0 , dx:Float = 0 , dy:Float = 0 , speed:Float = 0
Global space_z:Float = 50 , horizon:Int = 20, scale:Float = 1000 , obj_scale:Float = 50 ' Set view and scale here.
Global pmap:Int[1024*1024] ; Global img:TPixmap = LoadPixmap(LoadBank("http::static.monstermmorpg.com/images/maps/Meteor-Falls.png"))
For y=0 To 1023 ; For x=0 To 1023 ; pmap(x+y*1024) = ReadPixel(img,x,y) ; Next ; Next ' Load png 1024 x 1024

GLGraphics xres,yres,0,60,GRAPHICS_BACKBUFFER | GRAPHICS_DEPTHBUFFER ; glViewport 0,0,xres,yres ' Set 0 for Windowed, 32 for Fullscreen here.
glMatrixMode GL_PROJECTION ; glLoadIdentity ; glOrtho 0,xres,yres,0,0,1 ; glPixelZoom 1,-1 ; glRasterPos2i 0,0 '; HideMouse

Repeat

' Uncomment this if you want only live tiles, this example uses punctated letters and symbols as tiles. This makes for beutiful dynamic landscapes of gameplay.
' For yy = 0 To 1023 ; For xx = 0 To 1023 ; pmap[yy*1024+xx] = 0 ; Next ; Next

' Comment this if you want only static landscape.
alive ; display wx,wy,0,0,1024,1024 ' Render tiles

speed = speed + KeyDown(KEY_UP)*0.1-KeyDown(KEY_DOWN)*0.1 ; speed=Max(-5,Min(5,speed))
a = a               - KeyDown(KEY_LEFT)+KeyDown(KEY_RIGHT) ; a = a Mod 360
dx = speed * Cos (a) ; dy =  speed * Sin (a) ; x :+ dx ; y :+ dy
drawplane a,x,y

' For normal 2d tiles, uncomment this.
' readinputs ; for yy = 0 To yres ; For xx = 0 To 1023 ; pixels[yy*xres+xx] = pmap[yy*1024+xx]  ; Next ; Next
glDrawPixels xres,yres,GL_BGRA,GL_UNSIGNED_BYTE,pixels
	Delay 1 ; Flip 1
Until KeyHit(KEY_ESCAPE) Or AppTerminate()
End

Function drawplane(a:Float,cx:Float,cy:Float)
	Local sx:Int , sy:Int , d:Float , hs:Float , maskx:Int = 1023 , masky:Int = 1023 
	Local dx:Float , dy:Float , spx:Float,spy:Float 
	For sy = 0 Until yres-1 Step 2
		d = space_z*scale / Float(sy + horizon) ; hs = d / scale ; dx = -Sin(a) * hs ; dy = Cos(a) * hs
		spx = cx + d*Cos(a) - Float(xres) / 2 * dx ; spy = cy + d*Sin(a) - Float(xres) / 2 * dy
		For sx = 0 Until xres-1 ; pixels[sx+sy*xres] = pmap[(Int(spx) & maskx) + ( (Int(spy) & masky)*1024)] ; spx :+ dx ; spy :+ dy ; Next
	Next
End Function

Function alive()
	For temp=1 To 16 ; buffer[Int(Rand(0,15))+Int((Rand(0,15))*128)]=$ffffffff * Int(Rand(0,1)) ; Next
	cx=(cx+1) Mod 128 ; For tempy=0 To 15 ; For temp=0 To 15+32 ; buffer[16+temp+((0+tempy)*128)]=buffer[0+temp+cx+(16+tempy)*128] ; Next ; Next ; For temp=1 To 1600 ; cmap[Rnd(400),Rnd(250)]=Rnd(16) ; Next
End Function

Function display(wx,wy,ofx=0,ofy=0,sx=640,sy=400) 
	scrx = wx & 15 ; scry = wy & 15 ; mapx = wx Shr 4 ; mapy = wy Shr 4
	cnty = 0 ; For y = mapy To mapy+(sy Shr 4+1)
	cntx = 0 ; For x = mapx To mapx+(sx Shr 4+1)
	tilex = map(x,y) & 15 ; tiley = map(x,y) Shr 4
	colour = cols(cmap(x,y)) ; xx = cntx - scrx + ofx ; yy=cnty - scry + ofy
	For ty = 0 To 7 ; For tx = 0 To 7
	If (xx+tx+tx >= ofx) And (yy+ty+ty >= ofy) And (xx+tx+tx < ofx+sx) And (yy+ty+ty < ofy+sy).. ' Mind the steps
 	 And buffer[tilex Shl 3 + tx + (tiley Shl 3 + ty)*128] <> c Then pmap[xx+tx+tx+(yy+ty+ty)*1024] = colour 
	Next ; Next
	cntx = cntx+16 ; Next
	cnty = cnty+16 ; Next
End Function

Function readinputs()
	wx=wx-s*KeyDown(KEY_LEFT)+s*KeyDown(KEY_RIGHT) ; wy=wy-s*KeyDown(KEY_UP)+s*KeyDown(KEY_DOWN) ; wx=Max(0,Min(10000,wx)) ; wy=Max(0,Min(10000,wy))
	mx = MouseX() ; my = MouseY() ; xxx = (wx+mx) Sar 4 ; yyy = (wy+my) Sar 4 ; If MouseDown(1) Then map(xxx,yyy) = 42 ; cmap(xxx,yyy) = 7
End Function

Function writetomap(t$,x,y)
	For tempx = 0 To Len(t$)-1 ; temp = Asc(Mid$(t$,1+tempx,1)) ; map[tempx+x,y] = temp ; cmap[tempx+x,y] = 14 ; Next
End Function

Function irq:Object(id,data:Object,context:Object)	
	Return data
End Function

#colors
DefData $000000,$FFFFFF,$68372B,$70A4B2,$6F3D86,$588D43,$352879,$B8C76F,$6F4F25,$433900,$9A6759,$444444,$6C6C6C,$9AD284,$6C5EB5,$959595

Comments

Dan2016
Great, thanks.


BlitzSupport2016
Very nice! Runs great here.

Two minor quibbles:

1) Doesn't work with Brucey's BMX-NG as it's not SuperStrict-compliant. Also uses () brackets for array access, which seems to be allowed in standard Max, but arguably shouldn't be... again, this fails in BMX-NG.

2) The demo defaults to using the "live tiles", and I just thought it was a graphical glitch at first! Perhaps it could use a toggle to turn live tiles on? (Would leave them off by default.)

Really nice results, though.


Casaber2016
Thanks.

Iīm not into superstrict at the moment, does that help to optimize the inner workings or is it for tidying definitions etc? My thought is.. it is probably possible to do easly for someone who know it, I just havn't ever used superstrict yet.

Yes I wanted a very hybrid demo, showing alot of things without pressing keys, it looks glitchy but it is not. I wanted some choices inside the comments instead.


Casaber2016
Let's try it again to show of that "Aliveness" abit better.
I keep the original becuase this is a light version of it.

This upcoming one also shows of Bmax's weakneses in CPU usage when combining huge Inner loops and conditions, it makes it very slow. That's also why I skipped every other pixel in the 1st one.
Here you go.

Live tiles, abit more sensible demo. But the above code is the real workhorse which brings all this, so donīt use this.
This is just a demo.

Global buffer:Int[256*256] ; Local img2:TPixmap=LoadPixmap(LoadBank("http::www.foxhack.net/files/blog/2008/01-09-charadata.png"))  ' Load a 256x256 Atlas with 8x8 tiles
For yy=0 To 255 ; For xx=0 To 255 ; buffer(xx+yy*256) = ReadPixel(img2,xx,yy) ; Next ; Next
Global map[4096,4096] , wx:Int , wy:Int , cx:Int , c:Int = buffer[0] , s:Int = 2 , xres:Int = 1024 , yres:Int = 768 , pixels:Int[xres*yres]
Local a:Float = 0 , x:Float = 0 , y:Float = 0 , dx:Float = 0 , dy:Float = 0 , speed:Float = 0
Global space_z:Float = 50 , horizon:Int = 20, scale:Float = 1000 , obj_scale:Float = 50 , pmap:Int[1024*1024] 

' Fill world with atlas 1:1 side by side
For worldy=0 To 4095 Step 32 ; For worldx=0 To 4095 Step 32 ; For temp2=0 To 31 ; For temp=0 To 31 ;	map(temp+worldx,temp2+worldy)=temp+temp2*32 ; Next ; Next ; Next ; Next
GLGraphics xres,yres,0,60,GRAPHICS_BACKBUFFER | GRAPHICS_DEPTHBUFFER ; glViewport 0,0,xres,yres
glMatrixMode GL_PROJECTION ; glLoadIdentity ; glOrtho 0,xres,yres,0,0,1 ; glPixelZoom 1,-1 ; glRasterPos2i 0,0 

Repeat
	For yy = 0 To 1023 ; For xx = 0 To 1023 ; pmap[yy*1024+xx] = 0 ; Next ; Next
	display wx,wy,0,0,1024,1024
	speed = speed + KeyDown(KEY_UP)*0.1-KeyDown(KEY_DOWN)*0.1 ; speed=Max(-5,Min(5,speed))
	a = a - KeyDown(KEY_LEFT)+KeyDown(KEY_RIGHT) ; a = a Mod 360
	dx = speed * Cos (a) ; dy =  speed * Sin (a) ; x :+ dx ; y :+ dy
	drawplane a,x,y
	alive
	'readinputs ; For yy = 0 To yres ; For xx = 0 To 1023 ; pixels[yy*xres+xx] = pmap[yy*1024+xx]  ; Next ; Next ' Show 2D
	glDrawPixels xres,yres,GL_BGRA,GL_UNSIGNED_BYTE,pixels
	Delay 1 ; Flip 1
Until KeyHit(KEY_ESCAPE) Or AppTerminate()
End

Function readinputs()
	wx=wx-s*KeyDown(KEY_LEFT)+s*KeyDown(KEY_RIGHT) ; wy=wy-s*KeyDown(KEY_UP)+s*KeyDown(KEY_DOWN) ; wx=Max(0,Min(10000,wx)) ; wy=Max(0,Min(10000,wy))
	mx = MouseX() ; my = MouseY() ; xxx = (wx+mx) Sar 3 ; yyy = (wy+my) Sar 3; If MouseDown(1) Then map(xxx,yyy) = 42
End Function

Function alive()
	For temp=1 To 16 ; buffer[Int(Rand(0,15))+Int((Rand(0,15))*128)]=$ffffffff * Int(Rand(0,1)) ; Next
	cx=cx+1 Mod 128 ; For tempy=0 To 15 ; For temp=0 To 15+32 ; buffer[16+temp+((0+tempy)*128)]=buffer[0+temp+cx+(16+tempy)*128] ; Next ; Next
End Function

Function drawplane(a:Float,cx:Float,cy:Float) ' This might need optimzation too but it has not as intens loops so actually it does not need at all as much as display() does.
	Local sx:Int , sy:Int , d:Float , hs:Float , maskx:Int = 1023 , masky:Int = 1023 
	Local dx:Float , dy:Float , spx:Float,spy:Float 
	For sy = 0 Until yres-1 Step 2
		d = space_z*scale / Float(sy + horizon) ; hs = d / scale ; dx = -Sin(a) * hs ; dy = Cos(a) * hs
		spx = cx + d*Cos(a) - Float(xres) / 2 * dx ; spy = cy + d*Sin(a) - Float(xres) / 2 * dy
		For sx = 0 Until xres-1 ; pixels[sx+sy*xres] = pmap[(Int(spx) & maskx) + ( (Int(spy) & masky)*1024)] ; spx :+ dx ; spy :+ dy ; Next
	Next
End Function

Function display(wx,wy,ofx=0,ofy=0,sx=640,sy=400) ' Here's where most optimization is needed (as it is it can't keep up with steady 60 fps on average machines, every teeny fraction of Bmax knowledge should be put in here. Unrolling helps, less conditions helps.
	scrx = wx & 7 ; scry = wy & 7 ; mapx = wx Shr 3 ; mapy = wy Shr 3
	cnty = 0 ; For y = mapy To mapy+(sy Shr 3+1)
	cntx = 0 ; For x = mapx To mapx+(sx Shr 3+1)
	tilex = map(x,y) & 31 ; tiley = map(x,y) Shr 5 ' 32 tiles per line in atlas
	xx = cntx - scrx + ofx ; yy=cnty - scry + ofy
	For ty = 0 To 7 ; For tx = 0 To 7
	If xx+tx >= ofx And yy+ty >= ofy And xx+tx < ofx+sx And yy+ty < ofy+sy ..
 	 Then pmap[xx+tx+(yy+ty)Shl 10] = buffer[tilex Shl 3 + tx + (tiley Shl 3 + ty) Shl 8]
	Next ; Next
	cntx = cntx+8 ; Next
	cnty = cnty+8 ; Next
End Function



SLotman2016
This should help a little:
(I'm using the code from the first post, not the last one...)



Sorry if I idented your code - it was easier for me to understand what was going on ;)

What I did was to precompute as much as I could in both routines *outside* of the loops.

For example, on "display" you were computing yy+ty+ty 64 times * 3 * how many times the for x / for y outer loops runs.
I don't know how much of a toll this means nowadays, but I know every little bit helps, so... :)


Brucey2016
Sorry if I idented your code - it was easier for me to understand what was going on

And for most of everyone else too, I'd imagine. Thanks.


AdamStrange2016
@Casaber Your code is ingenious and superb. But you really need to use super strict and also learn to indent you code and separate it so it is readable :)

Here is the corrected code for the rest of us:
superstrict


Global buffer:Int[256*256]
Local img2:TPixmap=LoadPixmap(LoadBank("http::www.foxhack.net/files/blog/2008/01-09-charadata.png"))  ' Load a 256x256 Atlas with 8x8 tiles

local xx:int
local yy:int
For yy = 0 To 255
	For xx = 0 To 255
		buffer[xx+yy*256] = ReadPixel(img2,xx,yy)
	Next
Next

Global map:int[4096,4096];
global wx:Int
global wy:Int
global cx:Int
global c:Int = buffer[0]
global s:Int = 2
global xres:Int = 1024
global yres:Int = 768
global pixels:Int[xres*yres]

Local a:Float = 0
local x:Float = 0
local y:Float = 0
local dx:Float = 0
local dy:Float = 0
local speed:Float = 0

Global space_z:Float = 50
global horizon:Int = 20
global scale:Float = 1000
global obj_scale:Float = 50
global pmap:Int[1024*1024] 


' Fill world with atlas 1:1 side by side
local worldx:int
local worldy:int
local temp2:int
local temp:int
For worldy = 0 To 4095 Step 32
	For worldx = 0 To 4095 Step 32
		For temp2 = 0 To 31
			For temp = 0 To 31
				map[temp+worldx, temp2+worldy] = temp+temp2*32
			Next
		Next
	Next
Next

GLGraphics xres,yres,0,60,GRAPHICS_BACKBUFFER | GRAPHICS_DEPTHBUFFER
glViewport 0,0,xres,yres
glMatrixMode GL_PROJECTION
glLoadIdentity
glOrtho 0,xres,yres,0,0,1
glPixelZoom 1,-1
glRasterPos2i 0,0 

Repeat
  	display wx,wy,0,0,1024,1024
	speed = speed + KeyDown(KEY_UP)*0.1-KeyDown(KEY_DOWN)*0.1
	speed=Max(-5,Min(5,speed))
	a = a - KeyDown(KEY_LEFT)+KeyDown(KEY_RIGHT)
	a = a Mod 360
	dx = speed * Cos (a)
	dy = speed * Sin (a)
	x :+ dx
	y :+ dy
	drawplane a,x,y
	alive
	'readinputs ; For yy = 0 To yres ; For xx = 0 To 1023 ; pixels[yy*xres+xx] = pmap[yy*1024+xx]  ; Next ; Next ' Show 2D
	glDrawPixels xres,yres,GL_BGRA,GL_UNSIGNED_BYTE,pixels
	Delay 1
	Flip 1
Until KeyHit(KEY_ESCAPE) Or AppTerminate()
End






Function readinputs()
	wx=wx-s*KeyDown(KEY_LEFT)+s*KeyDown(KEY_RIGHT)
	wy=wy-s*KeyDown(KEY_UP)+s*KeyDown(KEY_DOWN)
	wx=Max(0,Min(10000,wx))
	wy=Max(0,Min(10000,wy))
	local mx:int = MouseX()
	local my:int = MouseY()
	local xxx:int = (wx+mx) Sar 3
	local yyy:int = (wy+my) Sar 3
	If MouseDown(1) Then map[xxx,yyy] = 42
End Function

Function alive()
	local temp:int
	local tempy:int
	For temp = 1 To 16
		buffer[Int(Rand(0,15))+Int((Rand(0,15))*128)]=$ffffffff * Int(Rand(0,1))
	Next
	
	cx=cx+1 Mod 128
	For tempy = 0 To 15
		For temp = 0 To 15+32
			buffer[16+temp+((0+tempy)*128)] = buffer[0+temp+cx+(16+tempy)*128]
		Next
	Next
End Function

Function drawplane(a:Float,cx:Float,cy:Float) ' This might need optimzation too but it has not as intens loops so actually it does not need at all as much as display() does.
	Local sx:Int
	local sy:Int
	local d:Float
	local hs:Float
	local maskx:Int = 1023
	local masky:Int = 1023 
	Local dx:Float
	local dy:Float
	local spx:Float
	local spy:Float 
	
	For sy = 0 Until yres-1 Step 2
		d = space_z*scale / Float(sy + horizon)
		hs = d / scale
		dx = -Sin(a) * hs
		dy = Cos(a) * hs
		spx = cx + d*Cos(a) - Float(xres) / 2 * dx
		spy = cy + d*Sin(a) - Float(xres) / 2 * dy
		
		For sx = 0 Until xres-1
			pixels[sx+sy*xres] = pmap[(Int(spx) & maskx) + ( (Int(spy) & masky)*1024)]
			spx :+ dx
			spy :+ dy
		Next
	Next
End Function

Function display(wx:int, wy:int, ofx:float = 0, ofy:float = 0, sx:int = 640, sy:int = 400) ' Here's where most optimization is needed (as it is it can't keep up with steady 60 fps on average machines, every teeny fraction of Bmax knowledge should be put in here. Unrolling helps, less conditions helps.
	local scrx:int
	local scry:int
	local mapx:int
	local mapy:int
	scrx = wx & 7
	scry = wy & 7
	mapx = wx Shr 3
	mapy = wy Shr 3
	
	local cnty:int = 0
	local cntx:int
	local ty:int
	local tx:int
	local x:int
	local y:int
	local tilex:int
	local tiley:int
	local xx:int
	local yy:int
	For y = mapy To mapy+(sy Shr 3+1)
		cntx = 0
		For x = mapx To mapx+(sx Shr 3+1)
			tilex = map[x,y] & 31
			tiley = map[x,y] Shr 5 ' 32 tiles per line in atlas
			xx = cntx - scrx + ofx
			yy=cnty - scry + ofy
			For ty = 0 To 7
				For tx = 0 To 7
					if xx+tx >= ofx And yy+ty >= ofy And xx+tx < ofx+sx And yy+ty < ofy+sy Then
						pmap[xx+tx+(yy+ty)Shl 10] = buffer[tilex Shl 3 + tx + (tiley Shl 3 + ty) Shl 8]
					end if
				Next
			Next
			cntx = cntx+8
		Next
		cnty = cnty+8
	Next
End Function



Casaber2016
I got response here, well thanks. Glad you like it, I thought this will help lot of coders, I guess it will help mostly those who understand.
I'lll try to clean things up but not like that, not with pure layout design, I will clean up the concepts. That's more important. It's a bit messy but this IS a work in progress okay. I should have mentioned that. This is not finished.

Well let me tell you about my style then, many people seem to think its a misstake. It's not. It has a long story.

I code in meaningful chunks, with deep meaning behind how they got there, and how I choose what to put where. Sometimes sloppy position ya but that's.. okay.
Usually I tidy things up at the end. Or not, if I'm in a hurry and want or need to share something quickly. I usually tell them that it's personal, I guess I forgot here.

I'm working with ppl where i need to take care about things like eye movements and the amount you have to use a touch, pen or mouse for instance, you donīt want to move about alot.
There's alot of meaningfdul reasons for that I wonīt go on that but, also I use screen real estate other reasons, one of them is to have a better glance and overview and a better feeling of my work when I'm working. Which is actually the backbone for using you know, indents (which basically is wasteful vertical way to do what Iīm trying to do.

I might share code sometimes with you. and if I do, you will get what I have.
Long long time ago I used vertical indents etc ALOT, and had very strict layout for many years before I knew how terrible it is. The goal , the INTENT, is a good one.
But how it is reached, is not.

I guess recommended those techniques 15 years ago. Now I am not convinced that it is a good idea in any common case. Just beacuse it's used everywhere does not mean it is good.
If you do it every day, then of course your eyes are used to it, and you are quick about it .And you want it that way.
So ya, I understand your feelings about that.


If anyone is interested in the details what Iīm doing we could talk some day.


SLotman2016
Guess you missed the whole part about optimizations I did?

I really don't care about your formatting, or why you do it like that - I wasn't criticizing or anything - as I said - and that's all there is to it - FOR ME, it's better that way to understand it.

The problems others may have with the formatting is specially aggravated since you posted in the code archive section - which is exactly to have code to show others how things are made.

I'd still say that's ok - but then you come and say that this is *still* a work in progress... so the code shouldn't be in the archives? (I'm really asking, I'm not an admin here or anything - at all.)

Anyway, sorry if my formatting caused all this trouble - keep coding and doing the cool work you're doing! :)


Casaber2016
I forgot about your optimization Slotman, sorry, that was a nice one.
Excellent move. I was not talking to you personally, just general announcement so no worries.


Casaber2016
I was thinking, ya.. it took ALONG time to me to decide, if it was worth uplaoding to the archives.

archives or no archives.. it's like a painting you know.. when is it ready? It never is. you can ALWAYS dab that extra slab of color onto it, you know?

Was I wrong this time?


Casaber2016
I think some ppl goe a kick out of it, if even only single person liked it, it was worth it.

It's small, it's very tinker-friendly. I think I let this stay up.


Casaber2016
I think you're right about archives should have a more.. carefully "outwards" designed code. ya.

I think i did the decision too fast. But i knew if i didnt do it know it would never happened. and it would be stuck in a thread wo ever getting seen by those who want it.


Casaber2016
And most of all, a big thanks goes for the more public version made here.

Very nice.


BlitzSupport2016
Nothing wrong with posting working code in the Code Archives! I do think it's worth taking into account the comments about code formatting and strictness.

Besides, you can always edit and update your Code Archives entries anyway -- there's no need to leave it static as you make improvements.


Guy Fawkes2016
Is there a Blitz3D version of this? I would REALLY like to try it out! :(

~GF


Casaber2016
I donīt have access to PC now, but it I think it might be nice to hear that this actually was B3D code originally of mine which I created on an EEE 701
(weak little but cute practical netbook). Where it run 60fps on. I converted this nto Bmax/opengl and then added MODE7 ontop.

I don't like to promise things that I can't keep, but I will try look for the original and then add the changes I've made.

I feel I want to do so many things now, I would love to add all the optimziations everyone's made here with my last one in the thread and make a single one.
And do a "proper" layout and conceptually easy to read code.

But I'm short of time right but I would really like to do that. The fact is that I'm already burned out so don't hold your breath, but I want to say B3D has what it takes to do the same. Absolutely, WRITEPIXELFAST will give 50-100% of the speed here.

About SUPERSTRICT I will try learn that whenever I can, I have my other foot now in Monkey 2 but I really enjoy BMax.
I hope strict does not force you using alot of odd symbols that brings nothing to the table. If so I will use it for sure.
Same goes with Monkey2 I guess.


Guy Fawkes2016
It would be AWESOME to be able to use this code in B3D for like a tile map loader and a small demo of moving a character in 8 directions like in Chrono Trigger with this thing. That would be freakin' SICK! (In a good way! ) :)

~GF


AdamStrange2016
@Casaber I took the display code and further optimised it for you. i then optimised the optimisations and came up with this:
Function display(wx:int, wy:int, ofx:int = 0, ofy:int = 0, sx:int = 640, sy:int = 400) ' Here's where most optimization is needed (as it is it can't keep up with steady 60 fps on average machines, every teeny fraction of Bmax knowledge should be put in here. Unrolling helps, less conditions helps.
	local scrx:int
	local scry:int
	local mapx:int
	local mapy:int
	scrx = wx & 7
	scry = wy & 7
	mapx = wx Shr 3
	mapy = wy Shr 3
	
	local cnty:int = 0
	local cntx:int
	local ty:int
	local tx:int
	local x:int
	local y:int
	local tilex:int
	local tiley:int
	local xx:int
	local yy:int
	
	local mapysy:int = mapy+(sy Shr 3+1)
	local mapxsx:int = mapx+(sx Shr 3+1)
	
	local yyty:int
	local tileyshl:int
	local yytyshl:int
	local tileyty:int
	local xxtx:int
	local ofxsx:int
	local tilexshl:int
	local tilexShltileyty:int
	local xxtxyy:int
	ofxsx = ofx+sx

	For y = mapy To mapysy
		yy = cnty - scry + ofy
		cntx = 0
		For x = mapx To mapxsx
			tilex = map[x,y] & 31
			tiley = map[x,y] Shr 5 ' 32 tiles per line in atlas
			tileyshl = tiley Shl 3
			tilexshl = tilex shl 3
			xx = cntx - scrx + ofx
			
			For ty = 0 To 7
				yyty = yy+ty
				
				if yyty >= ofy And yyty < ofy+sy Then
					yytyshl = yyty Shl 10
					tileyty = (tileyShl + ty) Shl 8
				
					xxtx = xx
					xxtxyy = xxtx + yytyshl 
					if xxtx >= ofx And xxtx < ofxsx Then
						tilexShltileyty = tilexShl + tileyty
						pmap[ xxtxyy ] = buffer[tilexShltileyty]
						xxtx :+ 1
						if xxtx < ofxsx Then
							tilexShltileyty :+ 1
							xxtxyy :+ 1
							pmap[ xxtxyy ] = buffer[tilexShltileyty]
							xxtx :+ 1
							if xxtx < ofxsx Then
								tilexShltileyty :+ 1
								xxtxyy :+ 1
								pmap[ xxtxyy ] = buffer[tilexShltileyty]
								xxtx :+ 1
								if xxtx < ofxsx Then
									tilexShltileyty :+ 1
									xxtxyy :+ 1
									pmap[ xxtxyy ] = buffer[tilexShltileyty]
									xxtx :+ 1
									if xxtx < ofxsx Then
										tilexShltileyty :+ 1
										xxtxyy :+ 1
										pmap[ xxtxyy ] = buffer[tilexShltileyty]
										xxtx :+ 1
										if xxtx < ofxsx Then
											tilexShltileyty :+ 1
											xxtxyy :+ 1
											pmap[ xxtxyy ] = buffer[tilexShltileyty]
											xxtx :+ 1
											if xxtx < ofxsx Then
												tilexShltileyty :+ 1
												xxtxyy :+ 1
												pmap[ xxtxyy ] = buffer[tilexShltileyty]
												xxtx :+ 1
												if xxtx < ofxsx Then
													tilexShltileyty :+ 1
													xxtxyy :+ 1
													pmap[ xxtxyy ] = buffer[tilexShltileyty]
												end if
											end if
										end if
									end if
								end if	
							end if	
						end if
					end if
				
				end if
				
			Next
			
			cntx = cntx+8
			
		Next
		
		cnty = cnty+8
	Next
End Function


in essence it is about removing the conditions and one set of loops plus pre calculating as much as possible.

It sort of shaves about 10-20% speed of your optimised version


Code Archives Forum