OPTION _EXPLICIT
CONST WORK_W = 320
CONST WORK_H = 180
CONST SCREEN_W = 1280
CONST SCREEN_H = 720
CONST GRADIENT_TOTAL = 6
CONST PARTICLE_TOTAL = 260
TYPE GradientStopType
T AS SINGLE
R AS INTEGER
G AS INTEGER
B AS INTEGER
END TYPE
TYPE GradientType
StopCount AS INTEGER
StopData(0 To 7) AS GradientStopType
Lut(0 To 255, 0 To 2) AS _UNSIGNED _BYTE
END TYPE
TYPE FlowLayerType
Amp(0 To 3) AS SINGLE
FreqX(0 To 3) AS SINGLE
FreqY(0 To 3) AS SINGLE
Speed(0 To 3) AS SINGLE
END TYPE
TYPE SaverStateType
Gradients(0 To 5) AS GradientType
Layers(0 To 2) AS FlowLayerType
END TYPE
DIM SHARED saver AS SaverStateType
DIM SHARED imgScreen AS LONG
DIM SHARED imgWork AS LONG
DIM SHARED memWork AS _MEM
DIM SHARED memPixels AS _MEM
DIM SHARED gradientSpan AS SINGLE
DIM SHARED mouseStartX AS LONG
DIM SHARED mouseStartY AS LONG
DIM SHARED activeLut(0 TO 255, 0 TO 2) AS INTEGER
REDIM SHARED pixelData(0) AS _UNSIGNED LONG
REDIM SHARED glowData(0) AS SINGLE
REDIM SHARED coordX(0) AS SINGLE
REDIM SHARED coordY(0) AS SINGLE
REDIM SHARED distData(0) AS SINGLE
REDIM SHARED angData(0) AS SINGLE
REDIM SHARED partX(0) AS SINGLE
REDIM SHARED partY(0) AS SINGLE
REDIM SHARED partVx(0) AS SINGLE
REDIM SHARED partVy(0) AS SINGLE
DIM done AS INTEGER
DIM tm AS SINGLE
RANDOMIZE TIMER
gradientSpan = 8.5
imgScreen = _NEWIMAGE(SCREEN_W, SCREEN_H, 32)
SCREEN imgScreen
_FULLSCREEN _SQUAREPIXELS
_TITLE "QB64PE Plasma Saver"
imgWork = _NEWIMAGE(WORK_W, WORK_H, 32)
InitScene
DO WHILE _MOUSEINPUT
LOOP
mouseStartX = _MOUSEX
mouseStartY = _MOUSEY
_MOUSEHIDE
DO
tm = TIMER
RenderFrame tm
_DISPLAY
_LIMIT 60
done = 0
HandleExit done
_LIMIT 20
LOOP UNTIL done <> 0
_MOUSESHOW
_MEMFREE memWork
_MEMFREE memPixels
IF imgWork <= -2 THEN _FREEIMAGE imgWork: imgWork = 0
SCREEN 0
IF imgScreen <= -2 THEN _FREEIMAGE imgScreen: imgScreen = 0
END
SUB InitScene
DIM workCount AS LONG
DIM i AS LONG
DIM x AS LONG
DIM y AS LONG
DIM idx AS LONG
DIM nx AS SINGLE
DIM ny AS SINGLE
workCount = WORK_W * WORK_H
REDIM pixelData(0 TO workCount - 1) AS _UNSIGNED LONG
REDIM glowData(0 TO workCount - 1) AS SINGLE
REDIM coordX(0 TO workCount - 1) AS SINGLE
REDIM coordY(0 TO workCount - 1) AS SINGLE
REDIM distData(0 TO workCount - 1) AS SINGLE
REDIM angData(0 TO workCount - 1) AS SINGLE
REDIM partX(0 TO PARTICLE_TOTAL - 1) AS SINGLE
REDIM partY(0 TO PARTICLE_TOTAL - 1) AS SINGLE
REDIM partVx(0 TO PARTICLE_TOTAL - 1) AS SINGLE
REDIM partVy(0 TO PARTICLE_TOTAL - 1) AS SINGLE
memPixels = _MEM(pixelData())
memWork = _MEMIMAGE(imgWork)
SeedLayers
InitGradients
idx = 0
FOR y = 0 TO WORK_H - 1
ny = (y - WORK_H * 0.5) / WORK_H
FOR x = 0 TO WORK_W - 1
nx = (x - WORK_W * 0.5) / WORK_H
coordX(idx) = nx
coordY(idx) = ny
distData(idx) = SQR(nx * nx + ny * ny)
angData(idx) = _ATAN2(ny, nx)
idx = idx + 1
NEXT x
NEXT y
FOR i = 0 TO PARTICLE_TOTAL - 1
partX(i) = RND * (WORK_W - 1)
partY(i) = RND * (WORK_H - 1)
partVx(i) = (RND - 0.5) * 0.2
partVy(i) = (RND - 0.5) * 0.2
NEXT i
END SUB
SUB SeedLayers
saver.Layers(0).Amp(0) = 0.42
saver.Layers(0).Amp(1) = 0.36
saver.Layers(0).Amp(2) = 0.28
saver.Layers(0).Amp(3) = 0.21
saver.Layers(0).FreqX(0) = 2.2
saver.Layers(0).FreqX(1) = 3.7
saver.Layers(0).FreqX(2) = 5.5
saver.Layers(0).FreqX(3) = 7.8
saver.Layers(0).FreqY(0) = 1.7
saver.Layers(0).FreqY(1) = 2.8
saver.Layers(0).FreqY(2) = 4.4
saver.Layers(0).FreqY(3) = 6.1
saver.Layers(0).Speed(0) = 0.38
saver.Layers(0).Speed(1) = 0.57
saver.Layers(0).Speed(2) = 0.83
saver.Layers(0).Speed(3) = 1.10
saver.Layers(1).Amp(0) = 0.35
saver.Layers(1).Amp(1) = 0.29
saver.Layers(1).Amp(2) = 0.23
saver.Layers(1).Amp(3) = 0.18
saver.Layers(1).FreqX(0) = 1.9
saver.Layers(1).FreqX(1) = 3.2
saver.Layers(1).FreqX(2) = 4.9
saver.Layers(1).FreqX(3) = 6.7
saver.Layers(1).FreqY(0) = 2.4
saver.Layers(1).FreqY(1) = 3.8
saver.Layers(1).FreqY(2) = 5.3
saver.Layers(1).FreqY(3) = 7.5
saver.Layers(1).Speed(0) = 0.31
saver.Layers(1).Speed(1) = 0.49
saver.Layers(1).Speed(2) = 0.74
saver.Layers(1).Speed(3) = 0.96
saver.Layers(2).Amp(0) = 0.26
saver.Layers(2).Amp(1) = 0.21
saver.Layers(2).Amp(2) = 0.17
saver.Layers(2).Amp(3) = 0.13
saver.Layers(2).FreqX(0) = 2.8
saver.Layers(2).FreqX(1) = 4.5
saver.Layers(2).FreqX(2) = 6.3
saver.Layers(2).FreqX(3) = 8.4
saver.Layers(2).FreqY(0) = 2.1
saver.Layers(2).FreqY(1) = 3.5
saver.Layers(2).FreqY(2) = 5.8
saver.Layers(2).FreqY(3) = 7.9
saver.Layers(2).Speed(0) = 0.27
saver.Layers(2).Speed(1) = 0.44
saver.Layers(2).Speed(2) = 0.68
saver.Layers(2).Speed(3) = 0.89
END SUB
SUB InitGradients
DIM i AS LONG
DIM c AS INTEGER
saver.Gradients(0).StopCount = 6
saver.Gradients(0).StopData(0).T = 0.00: saver.Gradients(0).StopData(0).R = 5: saver.Gradients(0).StopData(0).G = 2: saver.Gradients(0).StopData(0).B = 18
saver.Gradients(0).StopData(1).T = 0.18: saver.Gradients(0).StopData(1).R = 40: saver.Gradients(0).StopData(1).G = 0: saver.Gradients(0).StopData(1).B = 98
saver.Gradients(0).StopData(2).T = 0.38: saver.Gradients(0).StopData(2).R = 0: saver.Gradients(0).StopData(2).G = 92: saver.Gradients(0).StopData(2).B = 188
saver.Gradients(0).StopData(3).T = 0.60: saver.Gradients(0).StopData(3).R = 0: saver.Gradients(0).StopData(3).G = 220: saver.Gradients(0).StopData(3).B = 180
saver.Gradients(0).StopData(4).T = 0.82: saver.Gradients(0).StopData(4).R = 255: saver.Gradients(0).StopData(4).G = 210: saver.Gradients(0).StopData(4).B = 70
saver.Gradients(0).StopData(5).T = 1.00: saver.Gradients(0).StopData(5).R = 255: saver.Gradients(0).StopData(5).G = 255: saver.Gradients(0).StopData(5).B = 255
saver.Gradients(1).StopCount = 6
saver.Gradients(1).StopData(0).T = 0.00: saver.Gradients(1).StopData(0).R = 2: saver.Gradients(1).StopData(0).G = 8: saver.Gradients(1).StopData(0).B = 20
saver.Gradients(1).StopData(1).T = 0.16: saver.Gradients(1).StopData(1).R = 0: saver.Gradients(1).StopData(1).G = 45: saver.Gradients(1).StopData(1).B = 130
saver.Gradients(1).StopData(2).T = 0.37: saver.Gradients(1).StopData(2).R = 0: saver.Gradients(1).StopData(2).G = 180: saver.Gradients(1).StopData(2).B = 235
saver.Gradients(1).StopData(3).T = 0.58: saver.Gradients(1).StopData(3).R = 90: saver.Gradients(1).StopData(3).G = 255: saver.Gradients(1).StopData(3).B = 180
saver.Gradients(1).StopData(4).T = 0.80: saver.Gradients(1).StopData(4).R = 240: saver.Gradients(1).StopData(4).G = 255: saver.Gradients(1).StopData(4).B = 120
saver.Gradients(1).StopData(5).T = 1.00: saver.Gradients(1).StopData(5).R = 255: saver.Gradients(1).StopData(5).G = 255: saver.Gradients(1).StopData(5).B = 255
saver.Gradients(2).StopCount = 6
saver.Gradients(2).StopData(0).T = 0.00: saver.Gradients(2).StopData(0).R = 8: saver.Gradients(2).StopData(0).G = 0: saver.Gradients(2).StopData(0).B = 10
saver.Gradients(2).StopData(1).T = 0.18: saver.Gradients(2).StopData(1).R = 70: saver.Gradients(2).StopData(1).G = 0: saver.Gradients(2).StopData(1).B = 50
saver.Gradients(2).StopData(2).T = 0.38: saver.Gradients(2).StopData(2).R = 180: saver.Gradients(2).StopData(2).G = 0: saver.Gradients(2).StopData(2).B = 120
saver.Gradients(2).StopData(3).T = 0.60: saver.Gradients(2).StopData(3).R = 255: saver.Gradients(2).StopData(3).G = 70: saver.Gradients(2).StopData(3).B = 60
saver.Gradients(2).StopData(4).T = 0.82: saver.Gradients(2).StopData(4).R = 255: saver.Gradients(2).StopData(4).G = 190: saver.Gradients(2).StopData(4).B = 40
saver.Gradients(2).StopData(5).T = 1.00: saver.Gradients(2).StopData(5).R = 255: saver.Gradients(2).StopData(5).G = 255: saver.Gradients(2).StopData(5).B = 230
saver.Gradients(3).StopCount = 6
saver.Gradients(3).StopData(0).T = 0.00: saver.Gradients(3).StopData(0).R = 3: saver.Gradients(3).StopData(0).G = 0: saver.Gradients(3).StopData(0).B = 25
saver.Gradients(3).StopData(1).T = 0.18: saver.Gradients(3).StopData(1).R = 0: saver.Gradients(3).StopData(1).G = 20: saver.Gradients(3).StopData(1).B = 95
saver.Gradients(3).StopData(2).T = 0.38: saver.Gradients(3).StopData(2).R = 70: saver.Gradients(3).StopData(2).G = 0: saver.Gradients(3).StopData(2).B = 160
saver.Gradients(3).StopData(3).T = 0.60: saver.Gradients(3).StopData(3).R = 255: saver.Gradients(3).StopData(3).G = 0: saver.Gradients(3).StopData(3).B = 170
saver.Gradients(3).StopData(4).T = 0.82: saver.Gradients(3).StopData(4).R = 0: saver.Gradients(3).StopData(4).G = 220: saver.Gradients(3).StopData(4).B = 255
saver.Gradients(3).StopData(5).T = 1.00: saver.Gradients(3).StopData(5).R = 255: saver.Gradients(3).StopData(5).G = 255: saver.Gradients(3).StopData(5).B = 255
saver.Gradients(4).StopCount = 6
saver.Gradients(4).StopData(0).T = 0.00: saver.Gradients(4).StopData(0).R = 0: saver.Gradients(4).StopData(0).G = 8: saver.Gradients(4).StopData(0).B = 16
saver.Gradients(4).StopData(1).T = 0.16: saver.Gradients(4).StopData(1).R = 0: saver.Gradients(4).StopData(1).G = 80: saver.Gradients(4).StopData(1).B = 55
saver.Gradients(4).StopData(2).T = 0.37: saver.Gradients(4).StopData(2).R = 80: saver.Gradients(4).StopData(2).G = 200: saver.Gradients(4).StopData(2).B = 70
saver.Gradients(4).StopData(3).T = 0.58: saver.Gradients(4).StopData(3).R = 255: saver.Gradients(4).StopData(3).G = 245: saver.Gradients(4).StopData(3).B = 110
saver.Gradients(4).StopData(4).T = 0.82: saver.Gradients(4).StopData(4).R = 255: saver.Gradients(4).StopData(4).G = 110: saver.Gradients(4).StopData(4).B = 20
saver.Gradients(4).StopData(5).T = 1.00: saver.Gradients(4).StopData(5).R = 255: saver.Gradients(4).StopData(5).G = 255: saver.Gradients(4).StopData(5).B = 255
saver.Gradients(5).StopCount = 6
saver.Gradients(5).StopData(0).T = 0.00: saver.Gradients(5).StopData(0).R = 6: saver.Gradients(5).StopData(0).G = 4: saver.Gradients(5).StopData(0).B = 12
saver.Gradients(5).StopData(1).T = 0.16: saver.Gradients(5).StopData(1).R = 38: saver.Gradients(5).StopData(1).G = 0: saver.Gradients(5).StopData(1).B = 92
saver.Gradients(5).StopData(2).T = 0.37: saver.Gradients(5).StopData(2).R = 155: saver.Gradients(5).StopData(2).G = 0: saver.Gradients(5).StopData(2).B = 165
saver.Gradients(5).StopData(3).T = 0.58: saver.Gradients(5).StopData(3).R = 255: saver.Gradients(5).StopData(3).G = 70: saver.Gradients(5).StopData(3).B = 140
saver.Gradients(5).StopData(4).T = 0.82: saver.Gradients(5).StopData(4).R = 255: saver.Gradients(5).StopData(4).G = 210: saver.Gradients(5).StopData(4).B = 110
saver.Gradients(5).StopData(5).T = 1.00: saver.Gradients(5).StopData(5).R = 255: saver.Gradients(5).StopData(5).G = 255: saver.Gradients(5).StopData(5).B = 255
FOR i = 0 TO GRADIENT_TOTAL - 1
BuildGradientLut saver.Gradients(i)
NEXT i
FOR i = 0 TO 255
FOR c = 0 TO 2
activeLut(i, c) = saver.Gradients(0).Lut(i, c)
NEXT c
NEXT i
END SUB
SUB BuildGradientLut (g AS GradientType)
DIM i AS INTEGER
DIM s AS INTEGER
DIM t AS SINGLE
DIM leftT AS SINGLE
DIM rightT AS SINGLE
DIM k AS SINGLE
DIM r AS INTEGER
DIM gg AS INTEGER
DIM b AS INTEGER
FOR i = 0 TO 255
t = i / 255
s = 0
DO WHILE s < g.StopCount - 2
IF t <= g.StopData(s + 1).t THEN EXIT DO
s = s + 1
LOOP
leftT = g.StopData(s).t
rightT = g.StopData(s + 1).t
IF rightT > leftT THEN
k = (t - leftT) / (rightT - leftT)
ELSE
k = 0
END IF
r = g.StopData(s).r + (g.StopData(s + 1).r - g.StopData(s).r) * k
gg = g.StopData(s).g + (g.StopData(s + 1).g - g.StopData(s).g) * k
b = g.StopData(s).b + (g.StopData(s + 1).b - g.StopData(s).b) * k
IF r < 0 THEN r = 0 ELSE IF r > 255 THEN r = 255
IF gg < 0 THEN gg = 0 ELSE IF gg > 255 THEN gg = 255
IF b < 0 THEN b = 0 ELSE IF b > 255 THEN b = 255
g.Lut(i, 0) = r
g.Lut(i, 1) = gg
g.Lut(i, 2) = b
NEXT i
END SUB
SUB BlendPalette (ga AS INTEGER, gb AS INTEGER, k AS SINGLE)
DIM i AS INTEGER
DIM c AS INTEGER
DIM v AS INTEGER
FOR i = 0 TO 255
FOR c = 0 TO 2
v = saver.Gradients(ga).Lut(i, c) + (saver.Gradients(gb).Lut(i, c) - saver.Gradients(ga).Lut(i, c)) * k
IF v < 0 THEN v = 0 ELSE IF v > 255 THEN v = 255
activeLut(i, c) = v
NEXT c
NEXT i
END SUB
SUB FadeGlow
DIM i AS LONG
DIM workCount AS LONG
workCount = WORK_W * WORK_H
FOR i = 0 TO workCount - 1
glowData(i) = glowData(i) * 0.945
IF glowData(i) < 0.002 THEN glowData(i) = 0
NEXT i
END SUB
SUB UpdateParticles (tm AS SINGLE)
DIM i AS LONG
DIM k AS INTEGER
DIM nx AS SINGLE
DIM ny AS SINGLE
DIM ax AS SINGLE
DIM ay AS SINGLE
DIM speedMul AS SINGLE
DIM power AS SINGLE
FOR i = 0 TO PARTICLE_TOTAL - 1
nx = (partX(i) - WORK_W * 0.5) / WORK_H
ny = (partY(i) - WORK_H * 0.5) / WORK_H
ax = 0
ay = 0
FOR k = 0 TO 3
ax = ax + SIN(nx * saver.Layers(0).FreqX(k) + ny * saver.Layers(1).FreqY(k) + tm * saver.Layers(0).Speed(k)) * saver.Layers(0).Amp(k)
ay = ay + COS(ny * saver.Layers(1).FreqX(k) - nx * saver.Layers(2).FreqY(k) - tm * saver.Layers(1).Speed(k)) * saver.Layers(1).Amp(k)
NEXT k
partVx(i) = partVx(i) * 0.92 + ax * 0.11
partVy(i) = partVy(i) * 0.92 + ay * 0.11
speedMul = 0.55 + 0.22 * SIN(tm * 0.70 + i * 0.11)
partX(i) = partX(i) + partVx(i) * speedMul + SIN(tm * 0.17 + i * 0.07) * 0.15
partY(i) = partY(i) + partVy(i) * speedMul + COS(tm * 0.19 + i * 0.09) * 0.15
IF partX(i) < 0 THEN partX(i) = partX(i) + WORK_W
IF partX(i) >= WORK_W THEN partX(i) = partX(i) - WORK_W
IF partY(i) < 0 THEN partY(i) = partY(i) + WORK_H
IF partY(i) >= WORK_H THEN partY(i) = partY(i) - WORK_H
power = 0.55 + 0.75 * (0.5 + 0.5 * SIN(tm * 1.45 + i * 0.37))
StampGlow partX(i), partY(i), power
NEXT i
END SUB
SUB StampGlow (cx AS SINGLE, cy AS SINGLE, power AS SINGLE)
DIM ix AS LONG
DIM iy AS LONG
DIM x AS LONG
DIM y AS LONG
DIM dx AS LONG
DIM dy AS LONG
DIM idx AS LONG
DIM weight AS SINGLE
ix = INT(cx)
iy = INT(cy)
FOR dy = -2 TO 2
y = iy + dy
IF y >= 0 AND y < WORK_H THEN
FOR dx = -2 TO 2
x = ix + dx
IF x >= 0 AND x < WORK_W THEN
idx = y * WORK_W + x
weight = (3 - ABS(dx)) * (3 - ABS(dy)) * 0.030 * power
glowData(idx) = glowData(idx) + weight
IF glowData(idx) > 2.6 THEN glowData(idx) = 2.6
END IF
NEXT dx
END IF
NEXT dy
END SUB
SUB RenderFrame (tm AS SINGLE)
DIM workCount AS LONG
DIM i AS LONG
DIM phase AS SINGLE
DIM wholePhase AS LONG
DIM ga AS INTEGER
DIM gb AS INTEGER
DIM mixK AS SINGLE
DIM plasma AS SINGLE
DIM shadeIndex AS INTEGER
DIM shine AS SINGLE
DIM r AS INTEGER
DIM g AS INTEGER
DIM b AS INTEGER
workCount = WORK_W * WORK_H
FadeGlow
UpdateParticles tm
phase = tm / gradientSpan
wholePhase = INT(phase)
ga = wholePhase MOD GRADIENT_TOTAL
gb = (ga + 1) MOD GRADIENT_TOTAL
mixK = phase - wholePhase
BlendPalette ga, gb, mixK
FOR i = 0 TO workCount - 1
plasma = 128
plasma = plasma + 62 * SIN(distData(i) * 15.0 - tm * 1.70 + SIN(angData(i) * 4.0 + tm * 0.72) * 1.8)
plasma = plasma + 40 * SIN(coordX(i) * 12.0 + tm * 1.15)
plasma = plasma + 36 * COS(coordY(i) * 14.0 - tm * 0.96)
plasma = plasma + 28 * SIN((coordX(i) + coordY(i)) * 16.0 + tm * 0.43)
plasma = plasma + 18 * COS((coordX(i) * coordX(i) + coordY(i) * coordY(i)) * 40.0 - tm * 0.81)
plasma = plasma + glowData(i) * 48.0
shadeIndex = INT(plasma)
IF shadeIndex < 0 THEN shadeIndex = 0 ELSE IF shadeIndex > 255 THEN shadeIndex = 255
shine = glowData(i)
r = activeLut(shadeIndex, 0) + shine * 70
g = activeLut(shadeIndex, 1) + shine * 55
b = activeLut(shadeIndex, 2) + shine * 88
IF r < 0 THEN r = 0 ELSE IF r > 255 THEN r = 255
IF g < 0 THEN g = 0 ELSE IF g > 255 THEN g = 255
IF b < 0 THEN b = 0 ELSE IF b > 255 THEN b = 255
pixelData(i) = _RGB32(r, g, b)
NEXT i
_MEMCOPY memPixels, memPixels.OFFSET, memPixels.SIZE TO memWork, memWork.OFFSET
_PUTIMAGE (0, 0)-(SCREEN_W - 1, SCREEN_H - 1), imgWork, 0
END SUB
SUB HandleExit (done AS INTEGER)
IF _KEYHIT <> 0 THEN
done = -1
EXIT SUB
END IF
END SUB
|