feat(of): 5 OS shaders + 13 logos PNG
Shaders pixel art OS classiques (homages, pas marques) : - workbench.frag : Amiga Workbench 1.x checker bleu/orange + barre de titre + fenêtre flottante avec icône - macos_classic.frag : Mac OS Classic UI gris hatch + happy Mac face stylisée avec yeux + bouche - atari_fuji.frag : 3 barres convergentes Fuji 1972 + texte - ocean_loader.frag : bandes horizontales rainbow scrollantes type C64/Spectrum loader 1986-1990 - win95.frag : ciel bleu nuageux FBM + 4 quadrants colorés ondulant comme le drapeau Win95 5 nouveaux BgKind : Workbench MacOSClassic AtariFuji OceanLoader Win95 13 logos PNG via PIL pixel art dans bin/data/sprites/ : - windows_1_0, windows_311, windows_95 - lotus_123, msdos - atari_fuji, apple_rainbow - amiga_wb, nextstep, beos, os2_warp, irix - zx_spectrum, c64_basic Plus 5 SVG vectoriels (workbench_icon, atari_fuji, happy_mac, ocean_diamond, apple_bitten) pour usage futur. ImageVis loader prévu en suivante itération.
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
#version 150
|
||||
|
||||
// Atari Fuji homage : 3 barres verticales convergentes au sommet,
|
||||
// fond rouge magenta vintage. Pixelisation 4x4. Logo abstrait
|
||||
// (pas la marque exacte) qui évoque le Fuji 1972.
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform vec2 uRes;
|
||||
uniform float uTime;
|
||||
uniform float uMid;
|
||||
uniform float uKick;
|
||||
|
||||
void main() {
|
||||
// Pixelize
|
||||
vec2 p = floor(gl_FragCoord.xy / 4.0) * 4.0;
|
||||
vec2 c = (p / uRes - 0.5) * 2.0;
|
||||
c.x *= uRes.x / uRes.y;
|
||||
|
||||
// Fond gradient rouge → noir
|
||||
float grad = clamp(0.5 - c.y * 0.4, 0.0, 1.0);
|
||||
vec3 col = mix(vec3(0.10, 0.0, 0.05), vec3(0.95, 0.10, 0.20), grad);
|
||||
|
||||
// 3 barres convergentes — modélisation : à y=-1 elles sont à x=-0.6/0/+0.6,
|
||||
// à y=+1 elles sont à x=0 (toutes). Largeur des barres aussi diminue.
|
||||
float yBase = (c.y + 1.0) * 0.5; // 0..1
|
||||
float top = 1.0 - yBase;
|
||||
// 3 positions originales
|
||||
float positions[3] = float[3](-0.5, 0.0, 0.5);
|
||||
// Convergence : position(y) = posOrig * (1 - top * 1.0)
|
||||
float w = 0.10 + top * 0.06; // largeur (légèrement plus large en haut)
|
||||
bool inBar = false;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
float bx = positions[i] * (1.0 - top * 0.6); // converge un peu
|
||||
if (abs(c.x - bx) < w * 0.5 && c.y < 0.7 && c.y > -0.85) inBar = true;
|
||||
}
|
||||
// Barre transversale haute (le "chapeau")
|
||||
if (c.y > 0.55 && c.y < 0.70 && abs(c.x) < 0.7) inBar = true;
|
||||
|
||||
if (inBar) {
|
||||
col = vec3(0.95, 0.85, 0.20) * (1.0 + uKick * 0.3);
|
||||
}
|
||||
|
||||
// Texte "ATARI" en bas (procédural minimal — barres horizontales)
|
||||
if (c.y > -0.95 && c.y < -0.85 && abs(c.x) < 0.5) {
|
||||
bool stripe = mod(floor(p.x / 8.0), 2.0) < 0.5;
|
||||
if (stripe) col = vec3(0.95, 0.85, 0.20);
|
||||
}
|
||||
|
||||
fragColor = vec4(col, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
#version 150
|
||||
uniform mat4 modelViewProjectionMatrix;
|
||||
in vec4 position;
|
||||
void main() { gl_Position = modelViewProjectionMatrix * position; }
|
||||
@@ -0,0 +1,69 @@
|
||||
#version 150
|
||||
|
||||
// Classic Mac OS homage : fond gris pixelisé, fenêtre Finder centrale,
|
||||
// "happy mac" face stylisé. Pixel art procédural pas de logo authentique.
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform vec2 uRes;
|
||||
uniform float uTime;
|
||||
uniform float uMid;
|
||||
uniform float uKick;
|
||||
|
||||
float box(vec2 p, vec2 mn, vec2 mx) {
|
||||
return (p.x >= mn.x && p.x <= mx.x && p.y >= mn.y && p.y <= mx.y)
|
||||
? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 p = floor(gl_FragCoord.xy / 3.0) * 3.0; // pixelize 3x3
|
||||
|
||||
// Fond pattern hatch gris (Mac classic desktop)
|
||||
bool hatch = mod(floor(p.x/3.0) + floor(p.y/3.0), 2.0) < 0.5;
|
||||
vec3 col = hatch ? vec3(0.7, 0.7, 0.7) : vec3(0.55, 0.55, 0.55);
|
||||
|
||||
// Menu bar haut (20 px)
|
||||
if (gl_FragCoord.y > uRes.y - 20.0) {
|
||||
col = vec3(0.95, 0.95, 0.95);
|
||||
if (gl_FragCoord.y > uRes.y - 21.0) col = vec3(0.0); // séparateur
|
||||
}
|
||||
|
||||
// Fenêtre centrale 320x200
|
||||
vec2 wMin = uRes * 0.5 - vec2(160.0, 100.0);
|
||||
vec2 wMax = wMin + vec2(320.0, 200.0);
|
||||
if (box(gl_FragCoord.xy, wMin, wMax) > 0.5) {
|
||||
col = vec3(0.95, 0.95, 0.95);
|
||||
// Bordure noire
|
||||
if (gl_FragCoord.x < wMin.x + 1.0 || gl_FragCoord.x > wMax.x - 1.0 ||
|
||||
gl_FragCoord.y < wMin.y + 1.0 || gl_FragCoord.y > wMax.y - 1.0) {
|
||||
col = vec3(0.0);
|
||||
}
|
||||
// Title bar style Mac avec stripes horizontales
|
||||
if (gl_FragCoord.y > wMax.y - 18.0 && gl_FragCoord.y < wMax.y - 2.0) {
|
||||
bool s = mod(floor(gl_FragCoord.y), 2.0) < 0.5;
|
||||
col = s ? vec3(0.85) : vec3(1.0);
|
||||
if (gl_FragCoord.y > wMax.y - 4.0) col = vec3(0.0);
|
||||
}
|
||||
// Happy mac face (carré + 2 yeux + bouche)
|
||||
vec2 face = (gl_FragCoord.xy - wMin - vec2(140.0, 60.0));
|
||||
if (face.x > 0.0 && face.x < 40.0 && face.y > 0.0 && face.y < 40.0) {
|
||||
// Cadre face
|
||||
col = vec3(0.0);
|
||||
// Intérieur visage
|
||||
if (face.x > 4.0 && face.x < 36.0 && face.y > 4.0 && face.y < 36.0) {
|
||||
col = vec3(0.95, 0.95, 0.95) * (1.0 + uKick * 0.3);
|
||||
// Yeux
|
||||
if ((face.x > 10.0 && face.x < 14.0 && face.y > 22.0 && face.y < 26.0) ||
|
||||
(face.x > 26.0 && face.x < 30.0 && face.y > 22.0 && face.y < 26.0)) {
|
||||
col = vec3(0.0);
|
||||
}
|
||||
// Bouche (sourire)
|
||||
if (face.y > 12.0 && face.y < 16.0 &&
|
||||
face.x > 12.0 && face.x < 28.0) {
|
||||
col = vec3(0.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fragColor = vec4(col, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
#version 150
|
||||
uniform mat4 modelViewProjectionMatrix;
|
||||
in vec4 position;
|
||||
void main() { gl_Position = modelViewProjectionMatrix * position; }
|
||||
@@ -0,0 +1,45 @@
|
||||
#version 150
|
||||
|
||||
// Ocean Software Loader homage : bandes horizontales rainbow
|
||||
// scrollantes typiques des chargements C64/Spectrum 1986-1990.
|
||||
// Greetings Martin Galway, Jonathan Dunn.
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform vec2 uRes;
|
||||
uniform float uTime;
|
||||
uniform float uMid;
|
||||
uniform float uKick;
|
||||
uniform float uBpm;
|
||||
|
||||
vec3 paletteOcean(float t) {
|
||||
// Rainbow strict avec césures dures (pas de smooth)
|
||||
int idx = int(floor(t * 8.0)) % 8;
|
||||
if (idx == 0) return vec3(1.0, 0.0, 0.0); // rouge
|
||||
if (idx == 1) return vec3(1.0, 0.5, 0.0); // orange
|
||||
if (idx == 2) return vec3(1.0, 1.0, 0.0); // jaune
|
||||
if (idx == 3) return vec3(0.0, 1.0, 0.0); // vert
|
||||
if (idx == 4) return vec3(0.0, 1.0, 1.0); // cyan
|
||||
if (idx == 5) return vec3(0.0, 0.5, 1.0); // bleu
|
||||
if (idx == 6) return vec3(0.5, 0.0, 1.0); // violet
|
||||
return vec3(1.0, 0.0, 1.0); // magenta
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 uv = gl_FragCoord.xy / uRes;
|
||||
// Bandes horizontales scrollantes vers le bas
|
||||
float speed = 0.5 + uBpm * 0.003;
|
||||
float t = uv.y * 12.0 + uTime * speed;
|
||||
vec3 col = paletteOcean(t);
|
||||
|
||||
// Subtle scanlines CRT
|
||||
float sl = mod(gl_FragCoord.y, 2.0);
|
||||
if (sl < 1.0) col *= 0.85;
|
||||
|
||||
// Border noire haut/bas (style Ocean loader avec bandes)
|
||||
if (uv.y < 0.05 || uv.y > 0.95) col = vec3(0.0);
|
||||
|
||||
// Pulse audio sur kick
|
||||
col *= 1.0 + uKick * 0.4;
|
||||
fragColor = vec4(col, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
#version 150
|
||||
uniform mat4 modelViewProjectionMatrix;
|
||||
in vec4 position;
|
||||
void main() { gl_Position = modelViewProjectionMatrix * position; }
|
||||
@@ -0,0 +1,58 @@
|
||||
#version 150
|
||||
|
||||
// Windows 95 startup homage : ciel bleu nuageux, fenêtre 95 stylisée.
|
||||
// Pixelisé. Greetings tous les hackers de l'ère pre-XP.
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform vec2 uRes;
|
||||
uniform float uTime;
|
||||
uniform float uMid;
|
||||
uniform float uTreble;
|
||||
uniform float uKick;
|
||||
|
||||
float hash(vec2 p) { return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453); }
|
||||
float noise(vec2 p) {
|
||||
vec2 i = floor(p), f = fract(p);
|
||||
float a = hash(i), b = hash(i + vec2(1, 0));
|
||||
float c = hash(i + vec2(0, 1)), d = hash(i + vec2(1, 1));
|
||||
vec2 u = f * f * (3.0 - 2.0 * f);
|
||||
return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
|
||||
}
|
||||
float fbm(vec2 p) {
|
||||
float v = 0.0, amp = 0.5;
|
||||
for (int i = 0; i < 4; i++) { v += amp * noise(p); p *= 2.0; amp *= 0.5; }
|
||||
return v;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 px = floor(gl_FragCoord.xy / 2.0) * 2.0; // pixelize 2x2
|
||||
vec2 uv = px / uRes;
|
||||
|
||||
// Ciel bleu Win95 + nuages FBM
|
||||
float clouds = fbm(uv * 2.5 + vec2(uTime * 0.1, 0.0));
|
||||
vec3 sky = mix(vec3(0.05, 0.20, 0.55), vec3(1.0, 1.0, 1.0), clouds);
|
||||
vec3 col = sky;
|
||||
|
||||
// Bandeau haut "Microsoft Windows 95" stylisé
|
||||
// 4 carrés colorés (rouge/vert/bleu/jaune) ondulants comme le logo
|
||||
vec2 logoC = uRes * vec2(0.5, 0.55);
|
||||
vec2 d = px - logoC;
|
||||
if (abs(d.x) < 90.0 && abs(d.y) < 90.0) {
|
||||
// 4 quadrants avec couleurs Win
|
||||
bool right = d.x > 0.0;
|
||||
bool top = d.y > 0.0;
|
||||
vec3 quad;
|
||||
if (right && top) quad = vec3(0.95, 0.20, 0.20); // rouge
|
||||
else if (!right && top) quad = vec3(0.20, 0.85, 0.20); // vert
|
||||
else if (right && !top) quad = vec3(0.20, 0.40, 0.95); // bleu
|
||||
else quad = vec3(0.95, 0.85, 0.10); // jaune
|
||||
// Wave : déplace selon l'angle pour effet "drapeau"
|
||||
float wave = sin(d.x * 0.04 + uTime * 1.0) * 8.0;
|
||||
if (abs(d.y - wave) < 80.0) col = quad * (1.0 + uKick * 0.3);
|
||||
}
|
||||
|
||||
// Pulse uMid → flicker du logo
|
||||
if (uMid > 0.5) col *= 1.1;
|
||||
fragColor = vec4(col, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
#version 150
|
||||
uniform mat4 modelViewProjectionMatrix;
|
||||
in vec4 position;
|
||||
void main() { gl_Position = modelViewProjectionMatrix * position; }
|
||||
@@ -0,0 +1,65 @@
|
||||
#version 150
|
||||
|
||||
// Amiga Workbench 1.x homage : fond pattern damier bleu/blanc,
|
||||
// barres de titre en haut, fenêtres pixelées. Pas le vrai logo.
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform vec2 uRes;
|
||||
uniform float uTime;
|
||||
uniform float uBass;
|
||||
uniform float uMid;
|
||||
uniform float uKick;
|
||||
|
||||
void main() {
|
||||
vec2 p = gl_FragCoord.xy;
|
||||
vec2 uv = p / uRes;
|
||||
// Pixelisation : on snap à des blocs 4x4
|
||||
vec2 px = floor(p / 4.0) * 4.0;
|
||||
|
||||
// Background damier 1px noir/orange (Workbench classique)
|
||||
vec2 chk = floor(px / 4.0);
|
||||
bool dark = mod(chk.x + chk.y, 2.0) < 0.5;
|
||||
vec3 col = dark ? vec3(0.0, 0.06, 0.40) : vec3(0.85, 0.45, 0.0);
|
||||
|
||||
// Barre de titre haut (16 px high)
|
||||
if (p.y > uRes.y - 18.0) {
|
||||
// Pattern raz raz de tirets (style Amiga)
|
||||
bool stripe = mod(floor(p.x / 4.0), 2.0) < 0.5;
|
||||
col = stripe ? vec3(0.0, 0.0, 0.30) : vec3(0.85, 0.85, 0.85);
|
||||
}
|
||||
if (p.y > uRes.y - 22.0 && p.y < uRes.y - 18.0) {
|
||||
col = vec3(0.85, 0.85, 0.85); // séparateur
|
||||
}
|
||||
|
||||
// Une "fenêtre" qui se déplace
|
||||
float wt = uTime * 0.25;
|
||||
vec2 wPos = vec2(uRes.x * 0.3 + sin(wt) * 80.0,
|
||||
uRes.y * 0.4 + cos(wt * 0.8) * 60.0);
|
||||
vec2 wSize = vec2(220.0, 140.0);
|
||||
if (p.x > wPos.x && p.x < wPos.x + wSize.x &&
|
||||
p.y > wPos.y && p.y < wPos.y + wSize.y) {
|
||||
// Bordure
|
||||
if (p.x < wPos.x + 4.0 || p.x > wPos.x + wSize.x - 4.0 ||
|
||||
p.y < wPos.y + 4.0 || p.y > wPos.y + wSize.y - 4.0) {
|
||||
col = vec3(0.85, 0.85, 0.85);
|
||||
} else if (p.y > wPos.y + wSize.y - 18.0) {
|
||||
// Title bar
|
||||
bool stripe = mod(floor(p.x / 4.0), 2.0) < 0.5;
|
||||
col = stripe ? vec3(0.0, 0.0, 0.30) : vec3(0.85, 0.85, 0.85);
|
||||
} else {
|
||||
col = vec3(0.85, 0.85, 0.85);
|
||||
// Icône simple (carré coloré pulsant audio)
|
||||
vec2 icon = (p - wPos - vec2(20.0, 20.0));
|
||||
if (icon.x > 0.0 && icon.x < 32.0 && icon.y > 0.0 && icon.y < 32.0) {
|
||||
col = vec3(0.85, 0.0, 0.0) * (1.0 + uKick * 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Effet "bouge" sur kick
|
||||
if (uKick > 0.5) {
|
||||
col *= vec3(1.0 + uKick * 0.4);
|
||||
}
|
||||
fragColor = vec4(col, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
#version 150
|
||||
uniform mat4 modelViewProjectionMatrix;
|
||||
in vec4 position;
|
||||
void main() { gl_Position = modelViewProjectionMatrix * position; }
|
||||
@@ -129,6 +129,11 @@ void ofApp::setup() {
|
||||
modelRose_ = mp("rose3d.ply");
|
||||
modelGeosphere_ = mp("geosphere.ply");
|
||||
modelDNA_ = mp("dna.ply");
|
||||
workbench_ = std::make_unique<oscope::ShaderVis>("shaders/workbench");
|
||||
macosClassic_ = std::make_unique<oscope::ShaderVis>("shaders/macos_classic");
|
||||
atariFuji_ = std::make_unique<oscope::ShaderVis>("shaders/atari_fuji");
|
||||
oceanLoader_ = std::make_unique<oscope::ShaderVis>("shaders/ocean_loader");
|
||||
win95_ = std::make_unique<oscope::ShaderVis>("shaders/win95");
|
||||
lissajous_->setup(W, H);
|
||||
spectro_->setup(W, H / 4);
|
||||
reactive_->setup(W, H);
|
||||
@@ -184,6 +189,11 @@ void ofApp::setup() {
|
||||
modelRose_->setup(W, H);
|
||||
modelGeosphere_->setup(W, H);
|
||||
modelDNA_->setup(W, H);
|
||||
workbench_->setup(W, H);
|
||||
macosClassic_->setup(W, H);
|
||||
atariFuji_->setup(W, H);
|
||||
oceanLoader_->setup(W, H);
|
||||
win95_->setup(W, H);
|
||||
|
||||
postfx_.setup(W, H);
|
||||
|
||||
@@ -398,6 +408,11 @@ void ofApp::update() {
|
||||
modelRose_->update(frame);
|
||||
modelGeosphere_->update(frame);
|
||||
modelDNA_->update(frame);
|
||||
workbench_->update(frame);
|
||||
macosClassic_->update(frame);
|
||||
atariFuji_->update(frame);
|
||||
oceanLoader_->update(frame);
|
||||
win95_->update(frame);
|
||||
|
||||
applyOscFx();
|
||||
|
||||
@@ -1208,6 +1223,11 @@ void ofApp::drawScope4(int W, int H) {
|
||||
case BgKind::Rose3d: modelRose_->draw(0, 0, W, H); break;
|
||||
case BgKind::Geosphere: modelGeosphere_->draw(0, 0, W, H); break;
|
||||
case BgKind::DNA: modelDNA_->draw(0, 0, W, H); break;
|
||||
case BgKind::Workbench: workbench_->draw(0, 0, W, H); break;
|
||||
case BgKind::MacOSClassic: macosClassic_->draw(0, 0, W, H); break;
|
||||
case BgKind::AtariFuji: atariFuji_->draw(0, 0, W, H); break;
|
||||
case BgKind::OceanLoader: oceanLoader_->draw(0, 0, W, H); break;
|
||||
case BgKind::Win95: win95_->draw(0, 0, W, H); break;
|
||||
}
|
||||
|
||||
// 1bis) HUD pseudo-aléatoire de valeurs sub-10 Hz.
|
||||
|
||||
@@ -101,7 +101,8 @@ private:
|
||||
Penrose, Sphere3D, IcoMesh, DodMesh, TorusMesh,
|
||||
Supershape, Lorenz, Hopf, Enneper, HopfLink,
|
||||
BoingBall, Mode7, PlasmaC64, DotTunnel,
|
||||
Gear, Cone, Pyramid, Rose3d, Geosphere, DNA };
|
||||
Gear, Cone, Pyramid, Rose3d, Geosphere, DNA,
|
||||
Workbench, MacOSClassic, AtariFuji, OceanLoader, Win95 };
|
||||
struct DemoScene {
|
||||
const char* name;
|
||||
float durSec;
|
||||
@@ -210,6 +211,11 @@ private:
|
||||
std::unique_ptr<oscope::ModelVis> modelRose_;
|
||||
std::unique_ptr<oscope::ModelVis> modelGeosphere_;
|
||||
std::unique_ptr<oscope::ModelVis> modelDNA_;
|
||||
std::unique_ptr<oscope::ShaderVis> workbench_;
|
||||
std::unique_ptr<oscope::ShaderVis> macosClassic_;
|
||||
std::unique_ptr<oscope::ShaderVis> atariFuji_;
|
||||
std::unique_ptr<oscope::ShaderVis> oceanLoader_;
|
||||
std::unique_ptr<oscope::ShaderVis> win95_;
|
||||
|
||||
std::vector<float> ch1_, ch2_;
|
||||
Mode mode_ = Mode::Scope4;
|
||||
|
||||
Reference in New Issue
Block a user