A EXPERIMENTAL (OLDSCHOOL) 2D 8-BIT 256 COLOR SOFTWARE RENDERER
Written in PureBasic 6.0 (C-Backend) and FASM 1.73.30

Download (v.alpha 13): https://www.dropbox.com/s/etjp55fauk3ow ... 3.zip?dl=0
Documentation: https://www.dropbox.com/s/shjnreko4fd3y ... 0.txt?dl=0
Turorials (1 - 5): viewtopic.php?p=590990#p590990
Features:
- supports palettes, sprites, tiles, layers, fonts, animations, clipping, collisions (pixel & rect), input handling (mouse & keyboard)
- supports normal and relative mouse positions (window or screenspace) plus clipping & hiding of the cursor
- full access to all surface (frame, sprite, tile) and palette buffers
- screenshots of surfaces in native or screen resolution
- support for bitmap images (direct) and for any other image format indirect (handle to a bitmap)
- basic drawing functions dot, line, square, fill
- palette color cycling and palette presets (grayscale, vga ,ega, cga, random)
- all surfaces can draw or manipulate each other (there are also effect filters)
- change the rendersize (native resolution) and toggle between fullscreen and windowed mode on the fly
- can render into a window or a window control (ex. canvas)
- it is possible to retain the aspect ratio if the host window or control gets resized
- comes with a custom fileformat to store and load palettes and surfaces
- garbage collection ensures that all resources get cleaned up on release
- its definetly fast enough for small to midsize retro game projects
- blitter (drawing) callbacks allow for the easy implementation of custom filters and effects
Cons:
- may flicker (depending on the hardware)
- scaling may cause artefacts
- its not that fast (it is a software renderer after all)
- no rotation for sprites
- documentation is incomplete (i will release tutorials and see where this goes)
Interface:
Code: Select all
EnableExplicit
;--------------------------------------------------------------------------------------
; RPix - RetroPixel GFX Library
; A EXPERIMENTAL (OLDSCHOOL) 2D 8-BIT 256 COLOR SOFTWARE RENDERER
; Written in PureBasic 6.0 C-Backend and FASM 1.73.30
;--------------------------------------------------------------------------------------
; Version: dev.25.05 (alpha 11)
; Author: Mijikai
; Platform: Windows (x64)
;--------------------------------------------------------------------------------------
; Copyright 2022 by Mijikai all rights reserved
;--------------------------------------------------------------------------------------
; License:
; Attribution-NonCommercial-NoDerivatives 4.0 International:
; https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode
;--------------------------------------------------------------------------------------
Import "rpix.lib"
rpixInterface.i(WindowHandle.i,ScreenWidth.i = #Null,ScreenHeight.i = #Null,Aspect.i = #False,FrameRate.i = 60)
rpixWindowOpen.i(WindowType.i,Width.i,Height.i,ScreenWidth.i = #Null,ScreenHeight.i = #Null,Aspect.i = #False,FrameRate.i = 60)
rpixWindowTitle(*Interface,Title.s)
rpixWindowExit.i(*Interface)
rpixWindowClose.i(*Interface)
rpixVersion.i()
EndImport
#RPIX_VERSION = $0011
Enumeration RPIX_WINDOW
#RPIX_WINDOW_NORMAL
#RPIX_WINDOW_SCREEN
#RPIX_WINDOW_POPUP
#RPIX_WINDOW_SIZEABLE
EndEnumeration
Enumeration RPIX_PALETTE
#RPIX_PALETTE_GRAYSCALE
#RPIX_PALETTE_VGA
#RPIX_PALETTE_EGA
#RPIX_PALETTE_CGA
#RPIX_PALETTE_RANDOM
EndEnumeration
Enumeration RPIX_ROP
#RPIX_ROP_COPY
#RPIX_ROP_MASK
#RPIX_ROP_TINT
#RPIX_ROP_TEST
#RPIX_ROP_PROC
EndEnumeration
Enumeration RPIX_CHANGE
#RPIX_MATH_ADD
#RPIX_MATH_MUL
#RPIX_FILTER_1
#RPIX_FILTER_2
#RPIX_FILTER_3
#RPIX_FILTER_4
#RPIX_FILTER_5
#RPIX_FILTER_6
#RPIX_FILTER_7
#RPIX_FILTER_8
EndEnumeration
Structure RPIX_PIXEL_STRUCT
p.a[0]
EndStructure
Structure RPIX_RECT_STRUCT
x.l
y.l
w.l
h.l
EndStructure
Structure RPIX_DRAW_STRUCT
*dst.RPIX_PIXEL_STRUCT
dst_span.i
dst_rect.RPIX_RECT_STRUCT
*src.RPIX_PIXEL_STRUCT
src_span.i
src_rect.RPIX_RECT_STRUCT
*parameter
EndStructure
Interface RPIX
WindowHandle.i()
ScreenToggle.i()
ScreenMode.i()
OutputDevice.i()
OutputAspect.i(Flag.i)
OutputResize.i(Width.i,Height.i)
OutputSize.i(*Width.Integer,*Height.Integer)
OutputView.i(*X.Integer,*Y.Integer,*Width.Integer,*Height.Integer)
OutputMap.i(X.i,Y.i,*X.Integer,*Y.Integer)
OutputClip.i(X.i,Y.i,Width.i,Height.i,Center.i = #False)
OutputUnclip.i()
Buffer.i(*BufferSize.Integer = #Null)
BufferWrite.i(*Surface,Raw.i = #False)
BufferRead.i(*Surface,Raw.i = #False)
BufferSet.i(X.i,Y.i,Index.i)
BufferGet.i(X.i,Y.i,*Index.Ascii)
BufferFill.i(Index.i = #Null)
BufferReplace.i(IndexA.i,IndexB.i)
BufferSwap.i(IndexA.i,IndexB.i)
BufferChange.i(Mode.i,Value.i = #Null,Flag.i = #False)
BufferScroll.i(Amount.i,Vertical.i = #False)
BufferFlip.i(Vertical.i = #False)
BufferSurface.i(Copy.i = #True)
BufferSurfaceSave.i(File.s)
BufferDraw.i()
BufferDrawEvent.i(*Frames.Integer = #Null,*Time.Double = #Null)
Draw.i(*Memory,Width.i,Height.i,X.i,Y.i,Center.i = #False)
DrawMask.i(*Memory,Width.i,Height.i,X.i,Y.i,IndexMask.i,Center.i = #False)
DrawTint.i(*Memory,Width.i,Height.i,X.i,Y.i,IndexMask.i,IndexTint.i,Center.i = #False)
DrawTest.i(*Memory,Width.i,Height.i,X.i,Y.i,IndexMask.i,IndexTest.i,Center.i = #False)
DrawRect.i(*Memory,Span.i,X.i,Y.i,SrcX.i,SrcY.i,SrcW.i,SrcH.i,Center.i = #False)
DrawRectMask.i(*Memory,Span.i,X.i,Y.i,SrcX.i,SrcY.i,SrcW.i,SrcH.i,IndexMask.i,Center.i = #False)
DrawRectTint.i(*Memory,Span.i,X.i,Y.i,SrcX.i,SrcY.i,SrcW.i,SrcH.i,IndexMask.i,IndexTint.i,Center.i = #False)
DrawRectTest.i(*Memory,Span.i,X.i,Y.i,SrcX.i,SrcY.i,SrcW.i,SrcH.i,IndexMask.i,IndexTest.i,Center.i = #False)
DrawProc.i(*Proc,*Parameter,*Memory,Width.i,Height.i,X.i,Y.i,Center.i = #False)
DrawProcRect.i(*Proc,*Parameter,*Memory,Span.i,X.i,Y.i,SrcX.i,SrcY.i,SrcW.i,SrcH.i,Center.i = #False)
DrawBuffer.i(Rop.i,Surface.i,X.i,Y.i,SrcX.i,SrcY.i,SrcWidth.i,SrcHeight.i,IndexA.i = #Null,IndexB.i = #Null,Center.i = #False)
DrawPixel.i(Rop.i,*Dst,X.i,Y.i,DstW.i,DstH.i,*Src,SrcSpan.i,SrcX.i,SrcY.i,SrcW.i,SrcH.i,IndexA.i = #Null,IndexB.i = #Null,Center.i = #False)
DrawText.i(Surface.i,X.i,Y.i,Text.s,IndexTint.i,CenterH.i = #False,CenterV.i = #False)
DrawTextSpacingGet.i()
DrawTextSpacingSet.i(Spacing.i)
DrawTextMapChr.i(Code.i)
DrawTextMapAscii.i(*Ascii)
DrawTextSize.i(Text.s)
DrawPalette.i(Surface.i,X.i,Y.i,Center.i = #False)
DrawLine.i(Surface.i,X1.i,Y1.i,X2.i,Y2.i,Index.i)
DrawBox.i(Surface.i,X.i,Y.i,Width.i,Height.i,Index.i,Filled.i = #False,Center.i = #False)
DrawCircle.i(Surface.i,X.i,Y.i,Radius.i,Bend.i,Index.i)
DrawFill.i(Surface.i,X.i,Y.i,IndexFill.i,IndexSkip.i = #Null,Skip.i = #False)
TestPoint.i(PosX.i,PosY.i,X.i,Y.i,Width.i,Height.i)
TestPointEx.i(PosX.i,PosY.i,X.i,Y.i,Width.i,Height.i,Center.i = #False)
TestRect.i(DstX.i,DstY.i,DstW.i,DstH,SrcX.i,SrcY.i,SrcW.i,SrcH.i)
TestRectEx.i(DstX.i,DstY.i,DstW.i,DstH,DstCenter.i,SrcX.i,SrcY.i,SrcW.i,SrcH.i,SrcCenter.i)
TestSurface.i(DstSurface.i,DstX.i,DstY.i,SrcSurface.i,SrcX.i,SrcY.i)
TestSurfaceEx.i(DstSurface.i,DstX.i,DstY.i,DstCenter.i,SrcSurface.i,SrcX.i,SrcY.i,SrcCenter.i)
TestPixel.i(*Memory,Width.i,Height.i,X.i,Y.i,IndexMask.i,IndexTest.i,Center.i = #False)
TestPixelRect.i(*Memory,Span.i,X.i,Y.i,SrcX.i,SrcY.i,SrcW.i,SrcH.i,IndexMask.i,IndexTest.i,Center.i = #False)
TestPixelSurface.i(DstSurface.i,SrcSurface.i,X.i,Y.i,IndexMask.i,IndexTest.i,Center.i = #False)
TestPixelRegion.i(DstSurface.i,SrcRegion.i,Animation.i,Index.i,X.i,Y.i,IndexMask.i,IndexTest.i,Center.i = #False)
PalettePreset.i(Palette.i,Preset.i)
PaletteCreate.i()
PaletteLoad.i(*Palette,File.s = #Null$)
PaletteCatch.i(*Memory)
PaletteFill.i(Color.i = #Null)
PaletteSet.i(Index.i,Color.i)
PaletteGet.i(Index.i,*Color.Long)
PaletteReplace.i(ColorA.i,ColorB.i)
PaletteSwap.i(IndexA.i,IndexB.i,Colors.i)
PaletteCycle.i(Index.i,Colors.i,Steps.i)
PaletteSave.i(File.s)
SurfaceCreate.i(Width.i,Height.i)
SurfaceLoad.i(*Surface,File.s = #Null$)
SurfaceCatch.i(*Memory,Width.i,Height.i,Copy.i = #False)
SurfaceBitmap.i(Handle.i,*Bitmap = #Null,File.s = #Null$)
AnimationCreate.i(Start.i,Stop.i,Cycle.i,Active.i = #True,Once.i = #False,Last.i = #False)
AnimationUpdate.i()
LayerProc.i(Layer.i,*Proc,*Parameter)
LayerProcess.i()
LayerReset.i()
BitmapCreate.i(Surface.i,Palette.i = #Null,File.s = #Null$)
BitmapSize.i(*Bitmap)
BitmapFree.i(*Bitmap)
BitmapScreenshot.i(File.s)
TimerEvent.i(FrameRate.i)
TimerWait.i(*Frames.Integer = #Null,*Time.Double = #Null)
TimerTick.i(*Tick.Double)
TimerDelay.i(Milliseconds.i)
InputUpdate.i(MouseHide.i = #False,MouseClip.i = #False,MouseRelative.i = #False)
InputAvailable.i()
InputMouseActive.i()
InputMousePosition.i(*OutX.Integer,*OutY.Integer)
InputMouseTranslate.i(*OutX.Integer,*OutY.Integer)
InputMouseWheel.i(*Value.Integer = #Null)
InputKeyActive.i()
InputKeyDown.i(Code.i)
InputKeyUp.i(Code.i)
InputKeyToggle.i(Code.i)
InputKeyChar.i(*Char)
InputKeyCode.i(*Code)
InputKeyMapToChar.i(Code.i)
InputKeyMapToCode.i(Char.s)
InputFlush.i()
Release.i()
EndInterface
Interface RPIX_PALETTE
Use.i(SwapPalette.i = #False)
Buffer.i(*BufferSize.Integer = #Null)
BufferWrite.i(*Palette,Raw.i = #False)
BufferRead.i(*Palette,Raw.i = #False)
BufferFill.i(Color.i = #Null)
BufferSet.i(Index.i,Color.i)
BufferGet.i(Index.i,*Color)
BufferReplace.i(ColorA.i,ColorB.i)
BufferSwap.i(IndexA.i,IndexB.i,Colors.i)
BufferCycle.i(Index.i,Colors.i,Steps.i)
LayerUse.i(Layer.i,SwapPalette.i = #False)
LayerReplace.i(Layer.i,ColorA.i,ColorB.i)
LayerSwap.i(Layer.i,IndexA.i,IndexB.i,Color.i)
LayerCycle.i(Layer.i,Index.i,Colors.i,Steps.i)
Duplicate.i()
Save.i(File.s)
Release.i()
EndInterface
Interface RPIX_SURFACE
OutputSize.i(*width,*Height)
OutputClip.i(X.i,Y.i,Width.i,Height.i,Center.i = #False)
OutputUnclip.i()
Buffer.i(*BufferSize.Integer = #Null)
BufferWrite.i(*Surface,Raw.i = #False)
BufferRead.i(*Surface,Raw.i = #False)
BufferSet.i(X.i,Y.i,Index.i)
BufferGet.i(X.i,Y.i,*Index)
BufferFill.i(Index.i = #Null)
BufferReplace.i(IndexA.i,IndexB.i)
BufferSwap.i(IndexA.i,IndexB.i)
BufferChange.i(Mode.i,Value.i = #Null,Flag.i = #False)
BufferScroll.i(Amount.i,Vertical.i = #False)
BufferFlip.i(Verical.i = #False)
Draw.i(Surface.i,X.i,Y.i,Center.i = #False)
DrawMask.i(Surface.i,X.i,Y.i,IndexMask.i,Center.i = #False)
DrawTint.i(Surface.i,X.i,Y.i,IndexMask.i,IndexTint.i,Center.i = #False)
DrawTest.i(Surface.i,X.i,Y.i,IndexMask.i,IndexTest.i,Center.i = #False)
DrawRect.i(Surface.i,X.i,Y.i,SrcX.i,SrcY.i,SrcW.i,SrcH.i,Center.i = #False)
DrawRectMask.i(Surface.i,X.i,Y.i,SrcX.i,SrcY.i,SrcW.i,SrcH.i,IndexMask.i,Center.i = #False)
DrawRectTint.i(Surface.i,X.i,Y.i,SrcX.i,SrcY.i,SrcW.i,SrcH.i,IndexMask.i,IndexTint.i,Center.i = #False)
DrawRectTest.i(Surface.i,X.i,Y.i,SrcX.i,SrcY.i,SrcW.i,SrcH.i,IndexMask.i,IndexTest.i,Center.i = #False)
DrawProc.i(*Proc,*Parameter,Surface.i,X.i,Y.i,Center.i = #False)
DrawProcRect.i(*Proc,*Parameter,Surface.i,X.i,Y.i,SrcX.i,SrcY.i,SrcW.i,SrcH.i,Center.i = #False)
Test.i(Surface.i,X.i,Y.i,IndexMask.i,IndexTest.i,Center.i = #False)
TestRect.i(Surface.i,X.i,Y.i,SrcX.i,SrcY.i,SrcW.i,SrcH.i,IndexMask.i,IndexTest.i,Center.i = #False)
LayerClip.i(Layer.i,X.i,Y.i,Width.i,Height.i,Center.i = #False)
LayerUnclip.i(Layer.i)
LayerReplace.i(Layer.i,IndexA.i,IndexB.i)
LayerSwap.i(Layer.i,IndexA.i,IndexB.i)
LayerChange.i(Mode.i,Value.i = #Null,Flag.i = #False)
LayerScroll.i(Layer.i,Amount.i = 1,Vertical.i = #False)
LayerFlip.i(Layer.i,Verical.i)
LayerDraw.i(Layer.i,Rop.i,Surface.i,X.i,Y.i,Par1.i,Par2.i = #Null,Par3.i = #Null)
LayerDrawRect.i(Layer.i,Rop.i,Surface.i,X.i,Y.i,SrcX.i,SrcY.i,SrcW.i,SrcH.i,Par1.i,Par2.i = #Null,Par3.i = #Null)
RegionCreate.i(CountX.i,CountY.i,X.i,Y.i,Width.i,Height.i,OffsetX.i = #Null,OffsetY.i = #Null)
Duplicate.i()
Save.i(File.s)
Release.i()
EndInterface
Interface RPIX_REGION
Count.i()
OutputSize.i(*Width,*Height)
Draw.i(Surface.i,Animation.i,Index.i,X.i,Y.i,Center.i = #False)
DrawMask.i(Surface.i,Animation.i,Index.i,X.i,Y.i,IndexMask.i,Center.i = #False)
DrawTint.i(Surface.i,Animation.i,Index.i,X.i,Y.i,IndexMask.i,IndexTint.i,Center.i = #False)
DrawTest.i(Surface.i,Animation.i,Index.i,X.i,Y.i,IndexMask.i,IndexTest.i,Center.i = #False)
DrawText.i(Surface.i,X.i,Y.i,Text.s,CenterH.i = #False,CenterV.i = #False)
DrawTextMask.i(Surface.i,X.i,Y.i,Text.s,IndexMask.i,CenterH.i = #False,CenterV.i = #False)
DrawTextTint.i(Surface.i,X.i,Y.i,Text.s,IndexMask.i,IndexTint.i,CenterH.i = #False,CenterV.i = #False)
DrawProc.i(*Proc,*Parameter,Surface.i,Animation.i,Index.i,X.i,Y.i,Center.i = #False)
DrawProcText.i(*Proc,*Parameter,Surface.i,X.i,Y.i,Text.s,CenterH.i = #False,CenterV.i = #False)
Test.i(Surface.i,Animation.i,Index.i,X.i,Y.i,IndexMask.i,IndexTest.i,Center.i = #False)
LayerDraw.i(Layer.i,Rop.i,Surface.i,Animation.i,Index,X.i,Y.i,Par1.i,Par2.i = #Null,Par3.i = #Null)
LayerDrawText.i(Layer.i,Rop.i,Surface.i,X.i,Y.i,Text.s,Par1.i,Par2.i = #Null,Par3.i = #Null,Par4.i = #Null)
FontRegister.i(Offset.i,Layout.s,Spacing.i)
FontSpacingGet.i()
FontSpacingSet.i(Spacing.i)
FontMapChr.i(Code.i)
FontMapAscii.i(*Ascii)
FontTextSize.i(Text.s)
Release.i()
EndInterface
Interface RPIX_ANIMATION
Run.i(Flag.i = #True,Reset.i = #False)
RunOnce.i(Flag.i = #True,Reset.i = #False)
Running.i()
FrameStart.i(Frame.i)
FrameStop.i(Frame.i)
FrameCycleSet.i(Cycle.i)
FrameCycleGet.i()
FrameSet.i(Frame.i)
FrameGet.i()
FrameReport.i(*Frame)
FrameCount.i()
Release.i()
EndInterface
; DrawProc - Callback Example:
; Procedure.i Callback(*Draw.RPIX_DRAW_STRUCT)
; With *Draw
; \dst + \dst_rect\x + (\dst_rect\y * \dst_span);<- calculate the destination address
; \src + \src_rect\x + (\src_rect\y * \src_span);<- calculate the source address
; Repeat
; CopyMemory(\src,\dst,\dst_rect\w);<- copy a span of pixels defined by the destination rect width
; \dst + \dst_span;<- advance to next scanline / span
; \src + \src_span
; \dst_rect\h - 1;<- cover the whole height of the destination rect
; Until \dst_rect\h = #Null
; ProcedureReturn
; EndWith
; EndProcedure
More images:


Have fun
