sdlrendermax2d.bmx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. ' Copyright (c) 2021-2022 Bruce A Henderson
  2. '
  3. ' This software is provided 'as-is', without any express or implied
  4. ' warranty. In no event will the authors be held liable for any damages
  5. ' arising from the use of this software.
  6. '
  7. ' Permission is granted to anyone to use this software for any purpose,
  8. ' including commercial applications, and to alter it and redistribute it
  9. ' freely, subject to the following restrictions:
  10. '
  11. ' 1. The origin of this software must not be misrepresented; you must not
  12. ' claim that you wrote the original software. If you use this software
  13. ' in a product, an acknowledgment in the product documentation would be
  14. ' appreciated but is not required.
  15. '
  16. ' 2. Altered source versions must be plainly marked as such, and must not be
  17. ' misrepresented as being the original software.
  18. '
  19. ' 3. This notice may not be removed or altered from any source
  20. ' distribution.
  21. '
  22. SuperStrict
  23. Rem
  24. bbdoc: Graphics/SDLRender Max2D
  25. about:
  26. The SDLRender Max2D module provides an SDL-backend SDLRender driver for #Max2D.
  27. End Rem
  28. Module SDL.SDLRenderMax2D
  29. ModuleInfo "Version: 1.00"
  30. ModuleInfo "License: zlib/libpng"
  31. ModuleInfo "History: 1.00"
  32. ModuleInfo "History: Initial release"
  33. Import BRL.Max2D
  34. Import SDL.SDLGraphics
  35. Import SDL.SDLRender
  36. Import Math.Polygon
  37. Private
  38. Global _driver:TSDLRenderMax2DDriver
  39. Global _preferredRenderer:Int = -1
  40. Function Pow2Size:Int( n:Int )
  41. Local t:Int = 1
  42. While t < n
  43. t :* 2
  44. Wend
  45. Return t
  46. End Function
  47. Function AdjustTexSize( width:Int Var, height:Int Var )
  48. 'calc texture size
  49. width = Pow2Size( width )
  50. height = Pow2Size( height )
  51. End Function
  52. Public
  53. Type TSDLRenderImageFrame Extends TImageFrame
  54. Field u0#, v0#, u1#, v1#, uscale#, vscale#
  55. Field pixmap:TPixmap
  56. Field surface:TSDLSurface
  57. Field texture:TSDLTexture
  58. Field renderer:TSDLRenderer
  59. Method New()
  60. End Method
  61. Method Delete()
  62. If texture Then
  63. texture.Destroy()
  64. texture = Null
  65. End If
  66. If surface Then
  67. surface.Free()
  68. surface = Null
  69. End If
  70. pixmap = Null
  71. End Method
  72. Method Draw( x0#,y0#,x1#,y1#,tx#,ty#,sx#,sy#,sw#,sh# ) Override
  73. Local u0# = sx * uscale
  74. Local v0# = sy * vscale
  75. Local u1# = ( sx + sw ) * uscale
  76. Local v1# = ( sy + sh ) * vscale
  77. _driver.DrawTexture( texture, u0, v0, u1, v1, x0, y0, x1, y1, tx, ty, Self )
  78. End Method
  79. Function CreateFromPixmap:TSDLRenderImageFrame( src:TPixmap,flags:Int )
  80. Local tex_w:Int = src.width
  81. Local tex_h:Int = src.height
  82. Local width:Int = Min( src.width, tex_w )
  83. Local height:Int = Min( src.height, tex_h )
  84. If src.format <> PF_RGBA8888 And src.format <> PF_RGB888 Then
  85. src = src.Convert( PF_RGBA8888 )
  86. End If
  87. 'done!
  88. Local frame:TSDLRenderImageFrame=New TSDLRenderImageFrame
  89. frame.renderer = _driver.renderer
  90. frame.pixmap = src
  91. frame.surface = TSDLSurface.CreateRGBFrom(src.pixels, src.width, src.height, BitsPerPixel[src.format], src.pitch, $000000ff:UInt, $0000ff00:UInt, $00ff0000:UInt, $ff000000:UInt)
  92. frame.texture = frame.renderer.CreateTextureFromSurface(frame.surface)
  93. frame.uscale = 1.0 / tex_w
  94. frame.vscale = 1.0 / tex_h
  95. frame.u1 = width * frame.uscale
  96. frame.v1 = height * frame.vscale
  97. Return frame
  98. End Function
  99. End Type
  100. Type TSDLRenderMax2DDriver Extends TMax2DDriver
  101. Field drawColor:SDLColor = New SDLColor(255, 255, 255, 255)
  102. Field clsColor:SDLColor = New SDLColor(0, 0, 0, 255)
  103. Field renderer:TSDLRenderer
  104. Field ix#,iy#,jx#,jy#
  105. Field state_blend:Int
  106. Method Create:TSDLRenderMax2DDriver()
  107. If Not SDLGraphicsDriver() Return Null
  108. Return Self
  109. End Method
  110. 'graphics driver overrides
  111. Method GraphicsModes:TGraphicsMode[]() Override
  112. Return SDLGraphicsDriver().GraphicsModes()
  113. End Method
  114. Method AttachGraphics:TMax2DGraphics( widget:Byte Ptr,flags:Long ) Override
  115. Local g:TSDLGraphics=SDLGraphicsDriver().AttachGraphics( widget,flags )
  116. If g Return TMax2DGraphics.Create( g,Self )
  117. End Method
  118. Method CreateGraphics:TMax2DGraphics( width:Int,height:Int,depth:Int,hertz:Int,flags:Long,x:Int,y:Int ) Override
  119. Local g:TSDLGraphics=SDLGraphicsDriver().CreateGraphics( width,height,depth,hertz,flags,x,y )
  120. If g Return TMax2DGraphics.Create( g,Self )
  121. End Method
  122. Method SetGraphics( g:TGraphics ) Override
  123. If Not g
  124. TMax2DGraphics.ClearCurrent
  125. SDLGraphicsDriver().SetGraphics Null
  126. Return
  127. EndIf
  128. Local t:TMax2DGraphics=TMax2DGraphics(g)
  129. Assert t And TSDLGraphics( t._graphics )
  130. Local gfx:TSDLGraphics = TSDLGraphics( t._graphics )
  131. SDLGraphicsDriver().SetGraphics gfx
  132. Local flags:UInt
  133. If gfx._context.flags & GRAPHICS_SWAPINTERVAL1 Then
  134. flags :| SDL_RENDERER_PRESENTVSYNC
  135. End If
  136. renderer = TSDLRenderer.Create(gfx._context.window, _preferredRenderer, flags)
  137. t.MakeCurrent
  138. End Method
  139. Method Flip:Int( sync:Int ) Override
  140. renderer.Present()
  141. End Method
  142. Method ToString$() Override
  143. Return "SDLRenderer"
  144. End Method
  145. Method CreateFrameFromPixmap:TSDLRenderImageFrame( pixmap:TPixmap,flags:Int ) Override
  146. Local frame:TSDLRenderImageFrame
  147. frame=TSDLRenderImageFrame.CreateFromPixmap( pixmap,flags )
  148. Return frame
  149. End Method
  150. Method SetBlend( blend:Int ) Override
  151. If blend=state_blend Return
  152. state_blend=blend
  153. Select blend
  154. Case MASKBLEND
  155. renderer.SetDrawBlendMode(SDL_BLENDMODE_BLEND)
  156. Case SOLIDBLEND
  157. renderer.SetDrawBlendMode(SDL_BLENDMODE_NONE)
  158. Case ALPHABLEND
  159. renderer.SetDrawBlendMode(SDL_BLENDMODE_BLEND)
  160. Case LIGHTBLEND
  161. renderer.SetDrawBlendMode(SDL_BLENDMODE_ADD)
  162. Case SHADEBLEND
  163. renderer.SetDrawBlendMode(SDL_BLENDMODE_MOD)
  164. Default
  165. renderer.SetDrawBlendMode(SDL_BLENDMODE_NONE)
  166. End Select
  167. End Method
  168. Method SetAlpha( alpha# ) Override
  169. If alpha>1.0 alpha=1.0
  170. If alpha<0.0 alpha=0.0
  171. drawColor.a=alpha*255
  172. End Method
  173. Method SetLineWidth( width# ) Override
  174. 'glLineWidth width
  175. End Method
  176. Method SetColor( red:Int,green:Int,blue:Int ) Override
  177. drawColor.r = Min(Max(red,0),255)
  178. drawColor.g = Min(Max(green,0),255)
  179. drawColor.b = Min(Max(blue,0),255)
  180. renderer.SetDrawColor(drawColor.r, drawColor.g, drawColor.b, drawColor.a)
  181. End Method
  182. Method SetColor( color:SColor8 ) Override
  183. drawColor.r=color.r
  184. drawColor.g=color.g
  185. drawColor.b=color.b
  186. renderer.SetDrawColor(drawColor.r, drawColor.g, drawColor.b, drawColor.a)
  187. End Method
  188. Method SetClsColor( red:Int,green:Int,blue:Int ) Override
  189. clsColor.r = Min(Max(red,0),255)
  190. clsColor.g = Min(Max(green,0),255)
  191. clsColor.b = Min(Max(blue,0),255)
  192. clsColor.a = 255
  193. End Method
  194. Method SetClsColor( color:SColor8 ) Override
  195. clsColor.r=color.r
  196. clsColor.g=color.g
  197. clsColor.b=color.b
  198. clsColor.a = 255
  199. End Method
  200. Method SetViewport( x:Int,y:Int,w:Int,h:Int ) Override
  201. If x=0 And y=0 And w=GraphicsWidth() And h=GraphicsHeight()
  202. renderer.SetClipRect()
  203. Else
  204. renderer.SetClipRect(x, y, w, h)
  205. EndIf
  206. End Method
  207. Method SetTransform( xx#,xy#,yx#,yy# ) Override
  208. ix=xx
  209. iy=xy
  210. jx=yx
  211. jy=yy
  212. End Method
  213. Method Cls() Override
  214. renderer.SetDrawColor(clsColor.r, clsColor.g, clsColor.b, clsColor.a)
  215. renderer.Clear()
  216. renderer.SetDrawColor(drawColor.r, drawColor.g, drawColor.b, drawColor.a)
  217. End Method
  218. Method Plot( x#,y# ) Override
  219. renderer.DrawPoint(Int(x+.5),Int(y+.5))
  220. End Method
  221. Method DrawLine( x0#,y0#,x1#,y1#,tx#,ty# ) Override
  222. renderer.DrawLine(Int(x0*ix+y0*iy+tx+.5), Int(x0*jx+y0*jy+ty+.5), Int(x1*ix+y1*iy+tx+.5), Int(x1*jx+y1*jy+ty+.5))
  223. End Method
  224. Method DrawRect( x0#,y0#,x1#,y1#,tx#,ty# ) Override
  225. Local StaticArray vertices:SDLVertex[4]
  226. Local vert:SDLVertex Ptr = vertices
  227. vert.position.x = x0 * ix + y0 * iy + tx
  228. vert.position.y = x0 * jx + y0 * jy + ty
  229. vert.color = _driver.drawColor
  230. vert :+ 1
  231. vert.position.x = x1 * ix + y0 * iy + tx
  232. vert.position.y = x1 * jx + y0 * jy + ty
  233. vert.color = _driver.drawColor
  234. vert :+ 1
  235. vert.position.x = x1 * ix + y1 * iy + tx
  236. vert.position.y = x1 * jx + y1 * jy + ty
  237. vert.color = _driver.drawColor
  238. vert :+ 1
  239. vert.position.x = x0 * ix + y1 * iy + tx
  240. vert.position.y = x0 * jx + y1 * jy + ty
  241. vert.color = _driver.drawColor
  242. Local StaticArray indices:Int[6]
  243. indices[0] = 0
  244. indices[1] = 2
  245. indices[2] = 1
  246. indices[3] = 0
  247. indices[4] = 3
  248. indices[5] = 2
  249. renderer.Geometry(Null, vertices, 4, indices, 6)
  250. End Method
  251. Method DrawOval( x0#,y0#,x1#,y1#,tx#,ty# ) Override
  252. Local StaticArray vertices:SDLVertex[50]
  253. Local vert:SDLVertex Ptr = vertices
  254. Local vc:int
  255. Local StaticArray indices:Int[147]
  256. local ic:int
  257. Local xr#=(x1-x0)*.5
  258. Local yr#=(y1-y0)*.5
  259. local r:Float = (xr + yr) * 0.5
  260. Local segs:Int = Min(49, 360 / acos(2 * (1 - 0.5 / r)^2 - 1))
  261. x0:+xr
  262. y0:+yr
  263. ' center
  264. vert.position.x = x0 * ix + y0 * iy + tx
  265. vert.position.y = x0 * jx + y0 * jy + ty
  266. vert.color = _driver.drawColor
  267. vert :+ 1
  268. vc :+ 1
  269. For Local i:Int=0 Until segs
  270. Local th#=i*360#/segs
  271. Local x#=x0+Cos(th)*xr
  272. Local y#=y0-Sin(th)*yr
  273. vert.position.x = x * ix + y * iy + tx
  274. vert.position.y = x * jx + y * jy + ty
  275. vert.color = _driver.drawColor
  276. vert :+ 1
  277. vc :+ 1
  278. Next
  279. For Local i:Int=0 Until segs - 1
  280. indices[i * 3] = 0
  281. indices[i * 3 + 1] = i + 1
  282. indices[i * 3 + 2] = i + 2
  283. ic :+ 3
  284. Next
  285. ' connect last & first
  286. Local i:Int = segs - 1
  287. indices[i * 3] = 0
  288. indices[i * 3 + 1] = i + 1
  289. indices[i * 3 + 2] = 1
  290. ic :+ 3
  291. renderer.Geometry(Null, vertices, vc, indices, ic)
  292. End Method
  293. Method DrawPoly( xy#[],handle_x#,handle_y#,origin_x#,origin_y#, indices:Int[] ) Override
  294. If xy.length<6 Or (xy.length&1) Return
  295. If Not indices Then
  296. indices = TriangulatePoly(xy)
  297. End If
  298. Local verts:Int = xy.Length / 2
  299. Local v:Byte Ptr = StackAlloc(verts * SizeOf(SDLVertex))
  300. Local vertPtr:SDLVertex Ptr = bmx_SDL_bptr_to_SDLVertexPtr(v)
  301. Local vert:SDLVertex Ptr = vertPtr
  302. For Local i:Int=0 Until verts
  303. Local x:Float = xy[i * 2] + handle_x
  304. Local y:Float = xy[i * 2 + 1] + handle_y
  305. vert.position.x = x*ix+y*iy+origin_x
  306. vert.position.y = x*jx+y*jy+origin_y
  307. vert.color = _driver.drawColor
  308. vert :+ 1
  309. Next
  310. renderer.Geometry(Null, vertPtr, verts, indices, indices.Length)
  311. End Method
  312. Method DrawPixmap( p:TPixmap,x:Int,y:Int ) Override
  313. Local img:TImage = LoadImage(p, 0)
  314. DrawImage(img, x, y)
  315. End Method
  316. Method DrawTexture( texture:TSDLTexture, u0#, v0#, u1#, v1#, x0#, y0#, x1#, y1#, tx#, ty#, img:TImageFrame = Null )
  317. Local StaticArray vertices:SDLVertex[4]
  318. Local vert:SDLVertex Ptr = vertices
  319. vert.position.x = x0 * ix + y0 * iy + tx
  320. vert.position.y = x0 * jx + y0 * jy + ty
  321. vert.color = _driver.drawColor
  322. vert.texCoord.x = u0
  323. vert.texCoord.y = v0
  324. vert :+ 1
  325. vert.position.x = x1 * ix + y0 * iy + tx
  326. vert.position.y = x1 * jx + y0 * jy + ty
  327. vert.color = _driver.drawColor
  328. vert.texCoord.x = u1
  329. vert.texCoord.y = v0
  330. vert :+ 1
  331. vert.position.x = x1 * ix + y1 * iy + tx
  332. vert.position.y = x1 * jx + y1 * jy + ty
  333. vert.color = _driver.drawColor
  334. vert.texCoord.x = u1
  335. vert.texCoord.y = v1
  336. vert :+ 1
  337. vert.position.x = x0 * ix + y1 * iy + tx
  338. vert.position.y = x0 * jx + y1 * jy + ty
  339. vert.color = _driver.drawColor
  340. vert.texCoord.x = u0
  341. vert.texCoord.y = v1
  342. Local StaticArray indices:Int[6]
  343. indices[0] = 0
  344. indices[1] = 2
  345. indices[2] = 1
  346. indices[3] = 0
  347. indices[4] = 3
  348. indices[5] = 2
  349. Select state_blend
  350. Case ALPHABLEND
  351. texture.SetBlendMode(SDL_BLENDMODE_BLEND)
  352. Case MASKBLEND
  353. texture.SetBlendMode(SDL_BLENDMODE_BLEND)
  354. Case SOLIDBLEND
  355. texture.SetBlendMode(SDL_BLENDMODE_NONE)
  356. Case LIGHTBLEND
  357. texture.SetBlendMode(SDL_BLENDMODE_ADD)
  358. Case SHADEBLEND
  359. texture.SetBlendMode(SDL_BLENDMODE_MOD)
  360. Default
  361. texture.SetBlendMode(SDL_BLENDMODE_NONE)
  362. End Select
  363. renderer.Geometry(texture, vertices, 4, indices, 6)
  364. End Method
  365. Method GrabPixmap:TPixmap( x:Int,y:Int,w:Int,h:Int ) Override
  366. Local blend:Int = state_blend
  367. SetBlend SOLIDBLEND
  368. Local p:TPixmap = CreatePixmap( w,h,PF_RGBA8888 )
  369. renderer.ReadPixels(SDL_PIXELFORMAT_ABGR8888, p.pixels, p.pitch, x, y, w, h)
  370. SetBlend blend
  371. Return p
  372. End Method
  373. Method SetResolution( width#,height# ) Override
  374. renderer.SetLogicalSize(Int(width), Int(height))
  375. End Method
  376. End Type
  377. Rem
  378. bbdoc: Get SDLRender Max2D Driver
  379. about:
  380. The returned driver can be used with #SetGraphicsDriver to enable SDLRender Max2D
  381. rendering.
  382. End Rem
  383. Function SDLRenderMax2DDriver:TSDLRenderMax2DDriver()
  384. Global _done:Int
  385. If Not _done
  386. _driver=New TSDLRenderMax2DDriver.Create()
  387. _done=True
  388. EndIf
  389. Return _driver
  390. End Function
  391. Local driver:TSDLRenderMax2DDriver=SDLRenderMax2DDriver()
  392. If driver SetGraphicsDriver driver
  393. Rem
  394. bbdoc: Defines the preferred renderer, by name.
  395. about: Available renderers vary by platform. If @renderer is not found, default will be used.
  396. End Rem
  397. Function SDLSetPreferredRenderer( renderer:String )
  398. For Local i:int = 0 Until SDLGetNumRenderDrivers()
  399. Local info:SDLRendererInfo
  400. SDLGetRenderDriverInfo(i, info)
  401. If info.GetName() = renderer Then
  402. _preferredRenderer = i
  403. Return
  404. End If
  405. Next
  406. _preferredRenderer = -1
  407. End Function
  408. Rem
  409. bbdoc: Marks a renderer to be prioritized over others, by name.
  410. about: Available renderers vary by platform. If @renderer is not found or
  411. cannot be initialized later then, normal default will be used.
  412. End Rem
  413. Function SDLPrioritizeRenderer( renderer:String, priority:ESDLHintPriority = ESDLHintPriority.SDL_HINT_DEFAULT)
  414. For Local i:Int = 0 Until SDLGetNumRenderDrivers()
  415. Local info:SDLRendererInfo
  416. SDLGetRenderDriverInfo(i, info)
  417. If info.GetName() = renderer Then
  418. SDLSetHintWithPriority("SDL_RENDER_DRIVER", renderer, priority)
  419. Exit
  420. End If
  421. Next
  422. End Function