Das ganze läuft mit über 60 Frames auf 640x480-Bildschirm auf beim 3.0 Ghz Pentium 4 flüsig. Ab 800x600 gehts in Richung 32 Frames, dennoch bietet sich auch die "Autostretch-Variante" an, mit der ein WindowedScreen verdoppelt wird und dadurch der fehlende Detailgrad ausgeglichen wird.
Schauts euch einfach mal an.
Hab oben einen Frame-Begrenzer eingebaut, damit der Effekt auch sichtbar wird ...
Läuft nur auf 8bit, 24bit u. 32bit (war zu faul 16 bit auch noch zu zerhacken...)
8bit verwendet direkt die Screen-Palette.
Code: Alles auswählen
; Interpolation auf Palettenbasis
; (c) Max 'Kekskiller' Beutling
#IMAGE_SIZE_DIVIDER = 1 ;weder teiler für die bildhöhe -> je höher desto schneller, aber auch desto geblurrter...
#MAX_FRAMES = 17 ;anzahl der maximalen frames
;------------------------------------------------------------------------------------------------------------------------------
; fenster öffnen...
InitSprite()
OpenWindow(0, 0,0, 640,480, "interpolation test", #PB_Window_ScreenCentered|#PB_Window_TitleBar|#PB_Window_SystemMenu)
OpenWindowedScreen(WindowID(0), 0,0, WindowWidth(0)/#IMAGE_SIZE_DIVIDER,WindowHeight(0)/#IMAGE_SIZE_DIVIDER, 1,0,0)
AddKeyboardShortcut(0, #PB_Shortcut_F1, 0)
AddKeyboardShortcut(0, #PB_Shortcut_F2, 1)
; enstellungen...
Global field_w.w, field_h.w, block_width.w, block_height.w
field_w = 64
field_h = 48
block_width = WindowWidth(0) / #IMAGE_SIZE_DIVIDER / field_w
block_height = WindowHeight(0) / #IMAGE_SIZE_DIVIDER / field_h
; vorbereiten...
Global Dim field.l(field_w-1,field_h-1)
; einzelne farben -> unabhängig von der anzahl der farben hat die funktion weiterhin konstante geschwindigkeit. so kann man theoretisch ganze
;farbkombinationen vorberechnen, um sie später schneller einzuzeichnen!
Global gradient_color_count.c, gradient_presets.c
gradient_presets = 4
Global Dim gradient_color_count(gradient_presets)
Global Dim gradient_colors.l(gradient_presets-1, 20) ;temporär mal zwanzig, is ja nur nen test...
; nette farben!
gradient_color_count(0) = 9
gradient_colors(0, 0) = $00ff00
gradient_colors(0, 1) = $00ffab
gradient_colors(0, 2) = $00ffff
gradient_colors(0, 3) = $00abff
gradient_colors(0, 4) = $0000ff
gradient_colors(0, 5) = $ab00ff
gradient_colors(0, 6) = $ff00ff
gradient_colors(0, 7) = $ff00ab
gradient_colors(0, 8) = $ff0000
; wetterkarte (oder so in diese richtung!)
gradient_color_count(1) = 5
gradient_colors(1, 0) = $00ff00
gradient_colors(1, 1) = $00ffab
gradient_colors(1, 2) = $00ffff
gradient_colors(1, 3) = $00abff
gradient_colors(1, 4) = $0000ff
; plasmastream
gradient_color_count(2) = 7
gradient_colors(2, 0) = $ff0000
gradient_colors(2, 1) = $ff5500
gradient_colors(2, 2) = $ffaa00
gradient_colors(2, 3) = $ffee00
gradient_colors(2, 4) = $ffff00
gradient_colors(2, 5) = $ffabab
gradient_colors(2, 6) = $ff00ff
; schwarz, grau, weiß
gradient_color_count(3) = 3
gradient_colors(3, 0) = $000000
gradient_colors(3, 1) = $898989
gradient_colors(3, 2) = $ffffff
Global current_preset.c
current_preset = 0
;farbveränderungsmodi
Global current_mode.c, modes.c
current_mode = 1
modes = 3
;------------------------------------------------------------------------------------------------------------------------------
; strukturen
Structure CHAR
c.c
EndStructure
Structure RGB
r.c
g.c
b.c
EndStructure
Structure RGBA
r.c
g.c
b.c
a.c
EndStructure
Structure interpol_pixel
StructureUnion
c.CHAR
rgb.RGB
rgba.RGBA
EndStructureUnion
EndStructure
; adressen/größen u. procs fürs rendern
Global *_interpol_buffer.l
Global _interpol_pitch.l
Global _interpol_bytes.c
Global _interpol_format.c
Procedure GetInterpolationBuffer() ; <- sollte vor jeder renderschleife aufgerufen werden, am besten direkt nach jedem startdrawing..
*_interpol_buffer = DrawingBuffer()
_interpol_pitch = DrawingBufferPitch()
_interpol_format = DrawingBufferPixelFormat()
Select _interpol_format
Case #PB_PixelFormat_8Bits : _interpol_bytes = 1
Case #PB_PixelFormat_15Bits : _interpol_bytes = 2
Case #PB_PixelFormat_16Bits : _interpol_bytes = 2
Case #PB_PixelFormat_24Bits_RGB : _interpol_bytes = 3
Case #PB_PixelFormat_24Bits_BGR : _interpol_bytes = 3
Case #PB_PixelFormat_32Bits_RGB : _interpol_bytes = 4
Case #PB_PixelFormat_32Bits_BGR : _interpol_bytes = 4
EndSelect
EndProcedure
; ~~ Die Prozedur ~~
; Parameter:
; x.w = x-position
; y.w = y-position
; w.w = breite
; h.w = höhe
; *colors.RGBA = pointer auf array mit farbwerten, kann gan popeliges array mit long-werten sein
; hauptsache die index-nummern der farben gehen nicht über die anzahl der element hinaus!
; col1.c = index der oberen, linken farbe
; col2.c = index der oberen, rechten farbe
; col3.c = index der unteren, rechten farbe
; col4.c = index der unteren, linken farbe
Procedure DrawInterpolatedBox(x.w,y.w, w.w,h.w, *colors.RGBA, col1.c, col2.c, col3.c, col4.c)
Protected zx.l, zy.l
; brauchen hier nur die index-übergangswerte berechnen -> ist halt nur 1 wert fürn index
Protected g1to2.f, g3to4.f, g4to1.f
g1to2 = (col2 - col1) / w
g3to4 = (col3 - col4) / w
g4to1 = (col4 - col1) / h
; für schreiben der werte
Protected *drawpos.interpol_pixel, linepush.l ; der "zeilenvorschub" für eine pixelzeile, sprich die anzahl pixel zum nächsten zeilenanfang
*drawpos = *_interpol_buffer + y * _interpol_pitch + x * _interpol_bytes ; pointer auf 1. pixel setzen
linepush = _interpol_pitch - _interpol_bytes * w ; zeilenvorschub errechnen (pixelzeilenlänge - breite einer pixelzeile des interpolationsrechteckes)
Protected *destcol.RGBA
Protected destcol_index_float.f
Protected a1.f, a2.f
Protected index_step.f
Protected destcol_index.w ;ACHTUNG: beschissenerweise MUSS das ein Wordwert sein. Aufgrund der Instabilität von Float kommen teilweise extrem kleine
;negative Zahlen raus, die durch diese Rechnung als 255-Zahl interpretiert werden, WENN man ein char As Zahl nimmt.
;Ein Word muss daher her!
For zy = 0 To h-1
; startfarbe setzen
destcol_index_float = col1 + g4to1 * zy
; alpha-anteile von oberem u. unterem farbübergang errechnen
a1 = zy / h
a2 = 1.0 - a1
;übergangswert vorberechnen (wird fortlaufend addiert)
index_step = g1to2 * a2 + g3to4 * a1
For zx = 0 To w-1
; farbe erhöhen
destcol_index_float + index_step
; index aufrunden
; (Die Floatumwandlung frisst ziemlich viel Geschwindigkeit! Leider ist sie nötig, damit die Darstellung auch korrekt ist...)
destcol_index = Int(destcol_index_float)
If destcol_index_float - destcol_index > 0.5
destcol_index + 1
EndIf
; je nach pixeltiefe unterschiedlich formatiert einzeichnen (bisher nur 8, 24 und 32!)
If _interpol_format = #PB_PixelFormat_8Bits
*drawpos\c\c = destcol_index
ElseIf _interpol_format = #PB_PixelFormat_24Bits_RGB
*destcol = *colors + destcol_index * SizeOf(RGBA)
*drawpos\rgb\r = *destcol\r
*drawpos\rgb\g = *destcol\g
*drawpos\rgb\b = *destcol\b
ElseIf _interpol_format = #PB_PixelFormat_24Bits_BGR
*destcol = *colors + destcol_index * SizeOf(RGBA)
*drawpos\rgb\b = *destcol\r
*drawpos\rgb\g = *destcol\g
*drawpos\rgb\r = *destcol\b
ElseIf _interpol_format = #PB_PixelFormat_32Bits_RGB
*destcol = *colors + destcol_index * SizeOf(RGBA)
*drawpos\rgba\r = *destcol\r
*drawpos\rgba\g = *destcol\g
*drawpos\rgba\b = *destcol\b
ElseIf _interpol_format = #PB_PixelFormat_32Bits_BGR
*destcol = *colors + destcol_index * SizeOf(RGBA)
*drawpos\rgba\b = *destcol\r
*drawpos\rgba\g = *destcol\g
*drawpos\rgba\r = *destcol\b
EndIf
; auf nächsten pixel zeigen
*drawpos + _interpol_bytes
Next
; zeilenvorschub auf bildschirm
*drawpos + linepush
Next
EndProcedure
;------------------------------------------------------------------------------------------------------------------------------
; paar funktionen...
Procedure Randomize()
Protected zx.l, zy.l
For zy = 0 To field_h-1
For zx = 0 To field_w-1
Select current_mode
Case 0
field(zx,zy) = Random(gradient_color_count(current_preset)-1)
Case 1
field(zx,zy) + 1
If field(zx,zy) > gradient_color_count(current_preset)-1
field(zx,zy) = Random(gradient_color_count(current_preset)-1)
EndIf
Case 2
field(zx,zy) - 1
If field(zx,zy) < 0
field(zx,zy) = Random(gradient_color_count(current_preset)-1)
EndIf
EndSelect
Next
Next
EndProcedure
Procedure DrawArray()
Protected zx.l, zy.l
For zy = 0 To field_h-2
For zx = 0 To field_w-2
DrawInterpolatedBox(zx*block_width,zy*block_height, block_width,block_height, @gradient_colors(current_preset, 0), field(zx,zy), field(zx+1,zy), field(zx+1,zy+1), field(zx,zy+1))
Next
Next
EndProcedure
;------------------------------------------------------------------------------------------------------------------------------
; hauptschleife...
Global time.l, fps.l, delay.l, framedelay.l
framedelay.l = 1000 / #MAX_FRAMES
MessageRequester("Info", "F1 = toggel color presets" + Chr(10) + "F2 = toggle color change mode", #MB_OK)
Repeat
Select WindowEvent()
Case #PB_Event_CloseWindow
End
Case #PB_Event_Menu
Select EventMenu()
Case 0
current_preset + 1
If current_preset >= gradient_presets
current_preset = 0
EndIf
Case 1
current_mode + 1
If current_mode >= modes
current_mode = 0
EndIf
EndSelect
EndSelect
Randomize()
ClearScreen($111111)
StartDrawing(ScreenOutput())
time = ElapsedMilliseconds()
GetInterpolationBuffer()
DrawArray()
delay = ElapsedMilliseconds() - time
If delay = 0
SetWindowTitle(0, "FPS: 60+")
Else
fps = 1000 / delay
SetWindowTitle(0, "FPS: " + Str(fps))
EndIf
StopDrawing()
FlipBuffers()
;nötige verzögerung berechnen
If delay < framedelay
Delay(framedelay - delay)
EndIf
ForEver
Btw: Spielt mal mit den Werten u. Einstellungen rum. Da ergeben sich teilweise wunderhübsche Animationen ...