Compare commits

..

41 Commits

Author SHA1 Message Date
1b45c515d4 différence M1 - M2 2025-12-29 16:57:16 +01:00
ebd2ba2e51 interferences réalistes 2025-12-29 16:40:55 +01:00
e78af26734 readme 2025-12-29 15:30:19 +01:00
42d69b6ce4 readme 2025-12-29 15:28:34 +01:00
8d42cda17f readme 2025-12-29 15:22:05 +01:00
5010c30886 odrre 2025-12-29 15:21:09 +01:00
bcdc8b1baa todo 2025-12-29 15:01:34 +01:00
40213d7e69 target fps 2025-12-29 15:00:48 +01:00
99fbef5c4b auto resize desktop 2025-12-29 14:46:33 +01:00
a4c62bc3a4 todo 2025-12-29 14:05:45 +01:00
a71641b989 web finish 2025-12-29 14:04:12 +01:00
ea3530c01e web background color 2025-12-29 13:59:09 +01:00
7b5cf06bd0 todo 2025-12-29 13:54:06 +01:00
1255038efb rm 2025-12-29 13:53:22 +01:00
60c3754dd6 raylib folder 2025-12-29 13:52:39 +01:00
a3d4ad3922 glsl folder 2025-12-29 13:49:27 +01:00
fad31cdd2f edit 2025-12-29 13:47:25 +01:00
fa9d871479 web compilation 2025-12-29 13:43:05 +01:00
adb6b8b315 zoom edit 2025-12-28 17:26:24 +01:00
f779618c7c rm .bin 2025-12-28 17:14:07 +01:00
d474c0e670 zoom speed 2025-12-28 17:13:38 +01:00
a82295ee6b todo 2025-12-28 17:06:42 +01:00
cd8200436b todo 2025-12-28 17:06:03 +01:00
911deefbf5 multiple labmda 2025-12-28 17:04:49 +01:00
d8e178fe06 spectrum 2025-12-28 15:58:02 +01:00
acbda14a43 todo 2025-12-28 15:31:31 +01:00
88d6ff6532 todo 2025-12-28 15:21:49 +01:00
03b3351b50 todo 2025-12-28 14:15:36 +01:00
ba1572b11c inclinaison Y de M1 2025-12-28 14:15:12 +01:00
e476666ff7 todo 2025-12-28 14:09:28 +01:00
f94b4628ed cuve de gaz 2025-12-28 14:08:19 +01:00
71e063c001 todo update 2025-12-28 13:43:32 +01:00
fddec3f04b agrandir la figure d'interf 2025-12-28 13:42:30 +01:00
1b87a6fb9e todo 2025-12-28 11:44:07 +01:00
200e9a44b7 variation de valeur précise (lent) / accel) 2025-12-28 11:43:25 +01:00
37b5ce3951 variation de valeur précise (lent) / accel) 2025-12-28 11:42:32 +01:00
088d5b7739 add README.md 2025-12-28 11:12:18 +01:00
c0465113d0 GPU processing 2025-12-28 11:09:01 +01:00
08cac5c6e9 conflit2 2025-12-28 10:45:29 +01:00
664cb1e93d conflit 2025-12-28 10:45:14 +01:00
7dbd638ac1 ui amelioration 2025-12-28 10:42:48 +01:00
11 changed files with 2530 additions and 116 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/raylib_ignore
/web
michelson

View File

@ -3,6 +3,13 @@ michelson: main.c
clean:
rm -f michelson
rm -r web
run:
./michelson
web: main.c
mkdir -p web && emcc -o web/index.html main.c -Os -Wall -std=c99 -DPLATFORM_WEB -s USE_GLFW=3 -s ALLOW_MEMORY_GROWTH=1 -I. --shell-file minshell.html --preload-file glsl/michelson_web.frag raylib/libraylib.web.a
webrun:
cd web && python -m http.server 8000 && cd ..

65
README.md Normal file
View File

@ -0,0 +1,65 @@
# Simulateur d'Interféromètre de Michelson
Une simulation interactive temps réel et physiquement réaliste de l'interféromètre de Michelson. Ce projet permet de visualiser les figures d'interférences (franges et anneaux) en manipulant les composants optiques (miroirs, source lumineuse, milieu).
![Aperçu du simulateur](img/screenshot.png)
## Fonctionnalités
### Contrôle et Simulation
* **Miroir Mobile (M1) :** Translation et inclinaison sur deux axes.
* **Sources Lumineuses :**
* Spectre (380nm - 780nm).
* Gestion de **sources polychromatiques** (ajout/suppression de longueurs d'onde multiples).
* Rendu additif des couleurs.
* **Milieux dispersifs :** Ajout d'une cuve de gaz avec indice de réfraction variable n pour visualiser le déphasage.
### Performance & Rendu
* **Rendu GPU :** Calcul des interférences par **shader (GLSL)** pour des performances élevées.
* **Interface UI :** `raygui`.
* **Optimisation :** Sélecteur de **FPS Cible** (30, 60, 120, 144, Illimité).
* **Vues :** Schéma optique 2D + Vue "Écran".
## Installation et Compilation
### Prérequis
* **[Raylib](https://www.raylib.com/)**
* **[Emscripten](https://github.com/emscripten-core/emscripten/)**
### Compilation (Linux / Mac)
```bash
make
make run
```
ou
```bash
gcc main.c -o michelson -lraylib -lGL -lm -lpthread -ldl -lrt -lX11
./michelson
```
### Version Web (Emscripten)
```bash
make web
make webrun
```
ou
```bash
mkdir -p web && emcc -o web/index.html main.c -Os -Wall -std=c99 -DPLATFORM_WEB -s USE_GLFW=3 -s ALLOW_MEMORY_GROWTH=1 -I. --shell-file minshell.html --preload-file glsl/michelson_web.frag raylib/libraylib.web.a
```
## Contrôles Utilisateur
| Action | Commande |
| --- | --- |
| **Plein Écran** | Touche `F` |
| **Sélectionner une longueur d'onde** | `Clic Gauche` sur le spectre |
| **Ajouter une longueur d'onde** | `Clic Droit` sur une zone vide du spectre |
| **Supprimer une longueur d'onde** | `Clic Droit` sur une ligne existante |
| **Régler les miroirs** | Sliders / boutons `+` / `-` |
| **Précision / Vitesse** | Maintenir `Shift` |
## Physique du projet
Calcule de l'intensité lumineuse en tout point de l'écran en se basant sur la différence de marche.

85
glsl/michelson.frag Normal file
View File

@ -0,0 +1,85 @@
#version 330
// Entrées (de Raylib)
in vec2 fragTexCoord;
in vec4 fragColor;
out vec4 finalColor;
uniform vec2 center;
uniform float screenHeight;
//uniform vec2 resolution;
uniform float d1;
uniform float d2;
//uniform float lambda;
uniform float angleM1;
uniform float angleM1_Y;
uniform float zoom;
uniform float lambdas[10];
uniform int lambdasCount;
const float PI = 3.14159265359;
vec3 WavelengthToRGB(float l) {
float r = 0.0; float g = 0.0; float b = 0.0;
if (l >= 380.0 && l < 440.0) { r = -(l - 440.0) / (440.0 - 380.0); b = 1.0; }
else if (l >= 440.0 && l < 490.0) { g = (l - 440.0) / (490.0 - 440.0); b = 1.0; }
else if (l >= 490.0 && l < 510.0) { g = 1.0; b = -(l - 510.0) / (510.0 - 490.0); }
else if (l >= 510.0 && l < 580.0) { r = (l - 510.0) / (580.0 - 510.0); g = 1.0; }
else if (l >= 580.0 && l < 645.0) { r = 1.0; g = -(l - 645.0) / (645.0 - 580.0); }
else if (l >= 645.0 && l <= 780.0) { r = 1.0; }
float factor = 1.0;
if (l >= 380.0 && l < 420.0) factor = 0.3 + 0.7 * (l - 380.0) / (420.0 - 380.0);
else if (l >= 380.0 && l <= 645.0) factor = 1.0;
else if (l > 700.0 && l <= 780.0) factor = 0.3 + 0.7 * (780.0 - l) / (780.0 - 700.0);
return vec3(r * factor, g * factor, b * factor);
}
void main() {
float pixelX = gl_FragCoord.x;
float pixelY = screenHeight - gl_FragCoord.y;
// Diff de marche du à l'axe (2 * e) + micro -> nano
float deltaLnm = 2.0 * (d1 - d2) * 1000.0;
float relX = (pixelX - center.x) * zoom;
float relY = (pixelY - center.y) * zoom;
// r^2
float radiusSq = relX * relX + relY * relY;
// Diff de marche du au coin d'air
float wDelta = (relX * angleM1 + relY * angleM1_Y) * 200.0;
float cosFactor = 1.0 - (radiusSq * 0.000004);
float currDelta = (deltaLnm * cosFactor) + wDelta;
vec3 accumColor = vec3(0.0);
for(int i = 0; i < 10; i++) {
if (i >= lambdasCount) break;
float l = lambdas[i];
if (l < 1.0) l = 550.0;
vec3 baseColorVec = WavelengthToRGB(l);
float K = PI / l;
float phase = currDelta * K;
float intensity = cos(phase);
intensity = intensity * intensity;
accumColor += baseColorVec * intensity;
}
// finalColor = vec4(accumColor, 1.0);
// float K = PI / lambda;
// float phase = currDelta * K;
// float intensity = cos(phase);
// intensity = intensity * intensity;
// vec3 finalVec = baseColorVec * intensity;
//finalColor = vec4(finalVec, 1.0);
finalColor = vec4(accumColor, 1.0);
}

75
glsl/michelson_web.frag Normal file
View File

@ -0,0 +1,75 @@
#version 100
precision highp float;
varying vec2 fragTexCoord;
varying vec4 fragColor;
uniform vec2 center;
uniform float screenHeight;
uniform float d1;
uniform float d2;
uniform float angleM1;
uniform float angleM1_Y;
uniform float zoom;
uniform float lambdas[10];
uniform int lambdasCount;
const float PI = 3.14159265359;
vec3 WavelengthToRGB(float l) {
float r = 0.0; float g = 0.0; float b = 0.0;
if (l >= 380.0 && l < 440.0) { r = -(l - 440.0) / (440.0 - 380.0); b = 1.0; }
else if (l >= 440.0 && l < 490.0) { g = (l - 440.0) / (490.0 - 440.0); b = 1.0; }
else if (l >= 490.0 && l < 510.0) { g = 1.0; b = -(l - 510.0) / (510.0 - 490.0); }
else if (l >= 510.0 && l < 580.0) { r = (l - 510.0) / (580.0 - 510.0); g = 1.0; }
else if (l >= 580.0 && l < 645.0) { r = 1.0; g = -(l - 645.0) / (645.0 - 580.0); }
else if (l >= 645.0 && l <= 780.0) { r = 1.0; }
float factor = 1.0;
if (l >= 380.0 && l < 420.0) factor = 0.3 + 0.7 * (l - 380.0) / (420.0 - 380.0);
else if (l >= 380.0 && l <= 645.0) factor = 1.0;
else if (l > 700.0 && l <= 780.0) factor = 0.3 + 0.7 * (780.0 - l) / (780.0 - 700.0);
return vec3(r * factor, g * factor, b * factor);
}
void main() {
float pixelX = gl_FragCoord.x;
float pixelY = screenHeight - gl_FragCoord.y;
float deltaLnm = 2.0 * (d1 - d2) * 1000.0;
float relX = (pixelX - center.x) * zoom;
float relY = (pixelY - center.y) * zoom;
float radiusSq = relX * relX + relY * relY;
float wDelta = (relX * angleM1 + relY * angleM1_Y) * 200.0;
float cosFactor = 1.0 - (radiusSq * 0.000004);
float currDelta = (deltaLnm * cosFactor) + wDelta;
vec3 accumColor = vec3(0.0);
for(int i = 0; i < 10; i++) {
if (i >= lambdasCount) break;
float l = lambdas[i];
if (l < 1.0) l = 550.0;
vec3 baseColorVec = WavelengthToRGB(l);
float K = PI / l;
float phase = currDelta * K;
float intensity = cos(phase);
intensity = intensity * intensity;
accumColor += baseColorVec * intensity;
}
gl_FragColor = vec4(accumColor, 1.0);
}

BIN
img/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

626
main.c
View File

@ -1,18 +1,32 @@
#include "raylib.h"
#include "raylib/raylib.h"
#include <math.h>
#include <stdio.h>
#define RAYGUI_IMPLEMENTATION
#include "raygui.h"
#include "raylib/raygui.h"
#if defined(PLATFORM_WEB)
#include <emscripten/emscripten.h>
#endif
#define UI_WIDTH 400
#define UI_WIDTH 450
#define COLOR_BG (Color){ 25, 25, 30, 255 }
#define COLOR_PANEL (Color){ 40, 40, 45, 255 }
#define COLOR_ACCENT (Color){ 0, 120, 240, 255 }
#define COLOR_TEXT_DIM (Color){ 180, 180, 190, 255 }
#define COLOR_TEXT_SEC (Color){ 160, 160, 170, 255 }
#define MAX_WAVELENGTHS 10
typedef struct {
float d1;
float d2;
float lambda;
float lambdas[MAX_WAVELENGTHS];
int lambdasCount;
int selectedLambdaIndex;
float angleM1;
float angleM1_Y;
Vector2 center;
bool gaz;
float nGaz;
int targetFps;
} Michelson;
Color WavelengthToColor(float lambda) {
@ -32,85 +46,167 @@ Color WavelengthToColor(float lambda) {
return (Color){(unsigned char)(r * factor * 255), (unsigned char)(g * factor * 255), (unsigned char)(b * factor * 255), 255};
}
void DrawInterferenceView(Michelson *mic, Rectangle rec) {
DrawText("ECRAN", rec.x, rec.y - 30, 20, WHITE);
void DrawLaserBeam(Vector2 start, Vector2 end, Color color, float thickness) {
DrawLineEx(start, end, thickness * 4.0f, Fade(color, 0.15f));
DrawLineEx(start, end, thickness * 2.0f, Fade(color, 0.4f));
DrawLineEx(start, end, thickness, color);
}
DrawRectangleRec(rec, BLACK);
DrawRectangleLinesEx(rec, 2, DARKGRAY);
bool GuiButtonRepeat(Rectangle bounds, const char* text, bool shouldRepeat) {
bool clicked = GuiButton(bounds, text);
bool held = CheckCollisionPointRec(GetMousePosition(), bounds) && IsMouseButtonDown(MOUSE_LEFT_BUTTON) && shouldRepeat;
return clicked || held;
}
void DrawInterferenceViewGPU(Michelson *mic, Rectangle rec, Shader shader, bool *isFullscreen) {
Color baseColor = WavelengthToColor(mic->lambda);
// Diff de marche du à l'axe (2 * e) + micro -> nano
float deltaLnm = 2.0f * (mic->d1 - mic->d2) * 1000.0f;
DrawRectangleRec((Rectangle){rec.x - 4, rec.y - 30, rec.width + 8, rec.height + 34}, COLOR_PANEL);
DrawText("ECRAN", rec.x, rec.y - 26, 20, COLOR_TEXT_DIM);
const char* btnText = *isFullscreen ? "PETIT" : "GRAND";
if (GuiButton((Rectangle){rec.x + rec.width - 80, rec.y - 28, 80, 24}, btnText)) {
*isFullscreen = !(*isFullscreen);
}
if (CheckCollisionPointRec(GetMousePosition(), (Rectangle){rec.x + rec.width - 80, rec.y - 28, 80, 24})) {
DrawText("(Touche F)", rec.x + rec.width - 160, rec.y - 22, 10, GRAY);
}
// Shader glsl
float centerX = rec.x + rec.width / 2.0f;
float centerY = rec.y + rec.height / 2.0f;
float center[2] = { centerX, centerY };
//float scrHeight = (float)GetScreenHeight();
float scrHeight = 1080.0f;
float zoom = *isFullscreen ? 0.7 : 1;
float addedOpticalPathOneWay = 0.0f;
if (mic->gaz) {
addedOpticalPathOneWay = 100.0f * (mic->nGaz - 1.0f);
}
float d2_effective = mic->d2 + addedOpticalPathOneWay;
SetShaderValue(shader, GetShaderLocation(shader, "center"), center, SHADER_UNIFORM_VEC2);
SetShaderValue(shader, GetShaderLocation(shader, "screenHeight"), &scrHeight, SHADER_UNIFORM_FLOAT);
SetShaderValue(shader, GetShaderLocation(shader, "d1"), &mic->d1, SHADER_UNIFORM_FLOAT);
SetShaderValue(shader, GetShaderLocation(shader, "d2"), &d2_effective, SHADER_UNIFORM_FLOAT);
float lambdasData[MAX_WAVELENGTHS];
for(int i = 0; i < MAX_WAVELENGTHS; i++) {
if (i < mic->lambdasCount) lambdasData[i] = mic->lambdas[i];
else lambdasData[i] = 0.0f;
}
int locLambdas = GetShaderLocation(shader, "lambdas");
int locCount = GetShaderLocation(shader, "lambdasCount");
SetShaderValueV(shader, locLambdas, lambdasData, SHADER_UNIFORM_FLOAT, MAX_WAVELENGTHS);
SetShaderValue(shader, locCount, &mic->lambdasCount, SHADER_UNIFORM_INT);
//SetShaderValue(shader, GetShaderLocation(shader, "lambda"), &mic->lambda, SHADER_UNIFORM_FLOAT);
SetShaderValue(shader, GetShaderLocation(shader, "angleM1"), &mic->angleM1, SHADER_UNIFORM_FLOAT);
SetShaderValue(shader, GetShaderLocation(shader, "angleM1_Y"), &mic->angleM1_Y, SHADER_UNIFORM_FLOAT);
SetShaderValue(shader, GetShaderLocation(shader, "zoom"), &zoom, SHADER_UNIFORM_FLOAT);
// GPU
BeginShaderMode(shader);
DrawRectangleRec(rec, WHITE);
EndShaderMode();
DrawRectangleLinesEx(rec, 1, Fade(COLOR_ACCENT, 0.3f));
DrawRectangleLinesEx(rec, 2, COLOR_PANEL);
int cx = rec.x + rec.width / 2;
int cy = rec.y + rec.height / 2;
// Dessin pixel par pixel lent... => faire avec gpu
for (int y = rec.y; y < rec.y + rec.height; y++) {
for (int x = rec.x; x < rec.x + rec.width; x++) {
float relX = (float)(x - cx);
float relY = (float)(y - cy);
float radiusSq = relX * relX + relY * relY;
// Diff de marche lamme d'air 2 * e cos(i) mais petits angles => cos(i) ~ 1 - i^2/2 mais i ~ r/f et r^2 = x^2 + y^2
float ringFactor = radiusSq * 0.065f;
// Diff de marche dut au coin d'air
float wDelta = relX * mic->angleM1 * 200.0f;
float currDelta = deltaLnm - ringFactor + wDelta;
// Formule de Fresnel : I = I_0 * cos^2(phi)
float phase = (PI * currDelta) / mic->lambda;
float intensity = cosf(phase);
intensity = intensity * intensity;
Color pixColor = {(unsigned char)(baseColor.r * intensity), (unsigned char)(baseColor.g * intensity), (unsigned char)(baseColor.b * intensity), 255 };
DrawPixel(x, y, pixColor);
}
}
// croix centre
DrawLine(cx - 10, cy, cx + 10, cy, Fade(WHITE, 0.5f));
DrawLine(cx, cy - 10, cx, cy + 10, Fade(WHITE, 0.5f));
}
void DrawMichelsonSchema (Michelson *mic) {
Vector2 c = mic->center;
Color laserColor = WavelengthToColor(mic->lambda);
//Color laserColor = WavelengthToColor(mic->lambda);
float thickness = 4.0f;
float thickness = 3.0f;
float sourceLen = 450.0f;
float screenLen = 450.0f;
float mirrorSize = 140.0f;
// Source
Vector2 startSource = {c.x - sourceLen, c.y};
DrawLineEx(startSource, c, thickness, laserColor);
DrawRectangle(startSource.x - 20, startSource.y - 15, 20, 30, DARKGRAY);
DrawText("Source", startSource.x - 30, startSource.y - 40, 20, LIGHTGRAY);
// Miroir M2 (fixe)
Vector2 posM2 = {c.x + mic->d2, c.y};
DrawLineEx(c, posM2, thickness, laserColor);
DrawLineEx(c, (Vector2){c.x, c.y + screenLen}, thickness, Fade(laserColor, 0.6f));
DrawRectangle(posM2.x, posM2.y - (mirrorSize / 2), 12, mirrorSize, LIGHTGRAY);
DrawRectangle(posM2.x, posM2.y - (mirrorSize / 2) + 2, 4, mirrorSize - 4, WHITE);
DrawText("M2", posM2.x + 20, posM2.y - 10, 20, GRAY);
// Miroir M1 (mobile)
Vector2 posM1 = {c.x, c.y - mic->d1};
DrawLineEx(c, posM1, thickness, laserColor);
// Projection rayon sur écran (corection tangente)
Vector2 endPointM2 = {c.x, c.y + screenLen};
float angleRad = -(mic->angleM1 * 2.0f) * (PI / 180.0f);
float yScreen = c.y + screenLen;
float vertDist = yScreen - posM1.y;
float xOff = vertDist * tanf(angleRad);
Vector2 endPointRetour = { posM1.x + xOff, yScreen };
DrawLineEx(posM1, endPointRetour, thickness, Fade(laserColor, 0.6f));
// Laser
BeginBlendMode(BLEND_ADDITIVE);
/*
// Source
DrawLaserBeam(startSource, c, laserColor, thickness);
// Miroir M2 (fixe)
Vector2 posM2 = {c.x + mic->d2, c.y};
DrawLaserBeam(c, posM2, laserColor, thickness);
// Miroir M1 (mobile)
Vector2 posM1 = {c.x, c.y - mic->d1};
DrawLaserBeam(c, posM1, laserColor, thickness);
// Projection rayon sur écran (corection tangente)
float angleRad = -(mic->angleM1 * 2.0f) * (PI / 180.0f);
float yScreen = c.y + screenLen;
float vertDist = yScreen - posM1.y;
float xOff = vertDist * tanf(angleRad);
Vector2 endPointRetour = { posM1.x + xOff, yScreen };
DrawLaserBeam(posM1, endPointRetour, Fade(laserColor, 0.6f), thickness);
Vector2 endPointM2 = {c.x, c.y + screenLen};
DrawLaserBeam(c, endPointM2, Fade(laserColor, 0.5f), thickness);
*/
float alphaFactor = 1.0f / (float)(mic->lambdasCount > 0 ? mic->lambdasCount : 1);
if(alphaFactor < 0.3f) alphaFactor = 0.3f; // Min de visibilité
for(int i=0; i<mic->lambdasCount; i++) {
Color laserColor = WavelengthToColor(mic->lambdas[i]);
laserColor = Fade(laserColor, alphaFactor);
// Source -> Centre
DrawLaserBeam(startSource, c, laserColor, thickness);
// Centre -> Miroir M2 (fixe)
DrawLaserBeam(c, posM2, laserColor, thickness);
// Centre -> Miroir M1 (mobile)
DrawLaserBeam(c, posM1, laserColor, thickness);
// Retour M1 -> Ecran
DrawLaserBeam(posM1, endPointRetour, Fade(laserColor, 0.6f), thickness);
// Retour M2 -> Ecran
DrawLaserBeam(c, endPointM2, Fade(laserColor, 0.5f), thickness);
}
EndBlendMode();
// Source
DrawRectangle(startSource.x - 30, startSource.y - 20, 30, 40, DARKGRAY);
DrawRectangleLines(startSource.x - 30, startSource.y - 20, 30, 40, GRAY);
DrawText("Source", startSource.x - 50, startSource.y - 50, 20, LIGHTGRAY);
if (mic->gaz) {
float cellDist = 80.0f;
float cellW = 60.0f;
float cellH = 40.0f;
Rectangle cellRect = {c.x + cellDist, c.y - cellH / 2, cellW, cellH};
DrawRectangleRec(cellRect, Fade(BLUE, 0.15f + (mic->nGaz - 1.0f) * 2.0f));
DrawRectangleLinesEx(cellRect, 2, SKYBLUE);
DrawText(TextFormat("n=%.3f", mic->nGaz), c.x + cellDist, c.y + 25, 10, SKYBLUE);
}
// M2
DrawRectangle(posM2.x, posM2.y - (mirrorSize / 2), 12, mirrorSize, LIGHTGRAY);
DrawRectangle(posM2.x, posM2.y - (mirrorSize / 2) + 2, 4, mirrorSize - 4, WHITE);
DrawText("M2", posM2.x + 20, posM2.y - 10, 20, GRAY);
// M1
Rectangle recM1 = {posM1.x, posM1.y, mirrorSize, 12.0f};
Vector2 originM1 = {mirrorSize / 2, 6.0f};
DrawRectanglePro(recM1, originM1, mic->angleM1, LIGHTGRAY);
@ -121,87 +217,385 @@ void DrawMichelsonSchema (Michelson *mic) {
// Séparatrice
float sepLen = 220.0f;
Rectangle sepRec = {c.x, c.y, 4.0f, sepLen};
Rectangle sepRec = {c.x, c.y, 6.0f, sepLen};
Vector2 sepOrigin = {2.0f, sepLen / 2};
DrawRectanglePro(sepRec, sepOrigin, -45.0f, Fade(SKYBLUE, 0.4f));
DrawRectanglePro((Rectangle){c.x, c.y, 1.0f, sepLen}, (Vector2){0.5f, sepLen / 2}, -45.0f, Fade(WHITE, 0.5f));
DrawRectanglePro((Rectangle){c.x, c.y, 2.0f, sepLen}, (Vector2){1.0f, sepLen / 2}, -45.0f, Fade(WHITE, 0.4f));
DrawRectangle(c.x - 300, yScreen, 600, 15, DARKGRAY);
DrawText("Ecran", c.x - 20, yScreen + 20, 20, GRAY);
DrawRectangle(c.x - 300, yScreen, 600, 15, COLOR_PANEL);
DrawText("Ecran", c.x - 20, yScreen + 20, 20, COLOR_TEXT_DIM);
}
void DrawControlPanel(Michelson *mic) {
DrawRectangle(0, 0, UI_WIDTH, GetScreenHeight(), (Color){30, 30, 30, 255});
DrawLine(UI_WIDTH, 0, UI_WIDTH, GetScreenHeight(), WHITE);
DrawRectangle(0, 0, UI_WIDTH, GetScreenHeight(), Fade(COLOR_PANEL, 0.95f));
DrawLine(UI_WIDTH, 0, UI_WIDTH, GetScreenHeight(), Fade(WHITE, 0.1f));
int startX = 30;
int startY = 30;
int buttonWidth = 60;
int spacing = 20;
int contentWidth = UI_WIDTH - 60;
int sliderWidth = contentWidth - buttonWidth - spacing - 15;
static int holdTimer = 0;
if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) holdTimer++;
else holdTimer = 0;
bool shouldRepeat = (holdTimer > 30 && (holdTimer % 3 == 0)); // Répète / 3 frames
GuiSetStyle(DEFAULT, TEXT_SIZE, 18);
GuiSetStyle(DEFAULT, BASE_COLOR_NORMAL, 0x404040FF);
GuiSetStyle(DEFAULT, BORDER_COLOR_NORMAL, 0x808080FF);
GuiSetStyle(DEFAULT, TEXT_COLOR_NORMAL, 0xFFFFFFFF);
int startX = 20;
int startY = 30;
int contentWidth = UI_WIDTH - 40;
int btnSize = 30;
int spectrumWidth = contentWidth - (btnSize * 2) - 10;
int sliderWidth = spectrumWidth;
GuiSetStyle(DEFAULT, TEXT_SIZE, 16);
GuiSetStyle(DEFAULT, BASE_COLOR_NORMAL, 0x2D2D2DFF);
GuiSetStyle(DEFAULT, BASE_COLOR_FOCUSED, 0x454545FF);
GuiSetStyle(DEFAULT, BASE_COLOR_PRESSED, 0x1A1A1AFF);
GuiSetStyle(DEFAULT, TEXT_COLOR_NORMAL, 0xFFFFFFFF);
GuiSetStyle(DEFAULT, BORDER_COLOR_NORMAL, 0x505050FF);
GuiSetStyle(DEFAULT, BORDER_COLOR_FOCUSED, 0x0078D7FF);
GuiSetStyle(DEFAULT, BACKGROUND_COLOR, 0x1E1E1EFF);
DrawText("PARAMETRES", startX, startY, 30, WHITE);
DrawLine(startX, startY + 35, startX + contentWidth, startY + 35, COLOR_ACCENT);
// Sliders
bool speedMode = IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT);
const char* modeTxtStatus = speedMode ? "(SHIFT ACTIF: VITESSE RAPIDE)" : "(Maintenir SHIFT pour accelerer)";
Color statusColor = speedMode ? ORANGE : GRAY;
DrawText(modeTxtStatus, startX, startY + 45, 10, statusColor);
// Longueur d'onde
startY += 80;
DrawText(TextFormat("Longueur d'onde: %.0f nm", mic->lambda), startX, startY, 20, LIGHTGRAY);
GuiSlider((Rectangle){startX, startY + 30, contentWidth - 45, 30}, NULL, NULL, &mic->lambda, 380, 780);
DrawRectangle(startX + contentWidth - 35, startY + 30, 35, 30, WavelengthToColor(mic->lambda));
startY += 100;
DrawText(TextFormat("Position M1 (d1): %.1f um", mic->d1), startX, startY, 20, ORANGE);
GuiSlider((Rectangle){startX, startY + 30, sliderWidth, 30}, NULL, NULL, &mic->d1, 100, 600);
if (GuiButton((Rectangle){startX + sliderWidth + spacing + 15, startY + 30, buttonWidth, 30}, "Egal")) mic->d1 = mic->d2;
startY += 100;
DrawText(TextFormat("Inclinaison M1: %.2f deg", mic->angleM1), startX, startY, 20, ORANGE);
GuiSlider((Rectangle){startX, startY + 30, sliderWidth, 30}, "-1", "+1", &mic->angleM1, -1.0f, 1.0f);
if (GuiButton((Rectangle){startX + sliderWidth + spacing + 15, startY + 30, buttonWidth, 30}, "0.0")) mic->angleM1 = 0.0f;
DrawText("SPECTRE (Clic Droit: +/-)", startX, startY, 20, COLOR_TEXT_SEC);
const char* modeTxt = (fabs(mic->angleM1) < 0.01f) ? "MODE: LAME D'AIR" : "MODE: COIN D'AIR";
Color modeColor = (fabs(mic->angleM1) < 0.01f) ? SKYBLUE : GREEN;
DrawText(modeTxt, startX, startY + 75, 20, modeColor);
int spectrumHeight = 35;
Rectangle spectrumRect = {startX, startY + 25, contentWidth, spectrumHeight};
// spectre
for (int i = 0; i < spectrumRect.width; i++) {
float prog = (float)i / spectrumRect.width;
float l = 380.0f + prog * (780.0f - 380.0f);
DrawLine(spectrumRect.x + i, spectrumRect.y, spectrumRect.x + i, spectrumRect.y + spectrumRect.height, WavelengthToColor(l));
}
DrawRectangleLinesEx(spectrumRect, 1, GRAY);
startY += 140;
DrawRectangleLines(startX - 10, startY - 10, contentWidth + 20, 100, GRAY);
DrawText("Données", startX, startY, 20, LIGHTGRAY);
Vector2 mousePos = GetMousePosition();
float stepLambda = speedMode ? 0.7f : 0.03f;
if (CheckCollisionPointRec(mousePos, spectrumRect)) {
float mouseRatio = (mousePos.x - spectrumRect.x) / spectrumRect.width;
float mouseLambda = 380.0f + mouseRatio * (780.0f - 380.0f);
if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) {
if (mic->selectedLambdaIndex >= 0 && mic->selectedLambdaIndex < mic->lambdasCount) {
mic->lambdas[mic->selectedLambdaIndex] = mouseLambda;
}
}
if (IsMouseButtonPressed(MOUSE_RIGHT_BUTTON)) {
int foundIdx = -1;
for(int i = 0; i < mic->lambdasCount; i++) {
if (fabs(mic->lambdas[i] - mouseLambda) < 15.0f) {
foundIdx = i; break;
}
}
if (foundIdx != -1) {
if (mic->lambdasCount > 1) {
for(int k=foundIdx; k < mic->lambdasCount - 1; k++) {
mic->lambdas[k] = mic->lambdas[k+1];
}
mic->lambdasCount--;
mic->selectedLambdaIndex = 0;
}
} else {
if (mic->lambdasCount < MAX_WAVELENGTHS) {
mic->lambdas[mic->lambdasCount] = mouseLambda;
mic->selectedLambdaIndex = mic->lambdasCount;
mic->lambdasCount++;
}
}
}
}
//curseur
for (int i = 0; i < mic->lambdasCount; i++) {
if (mic->lambdas[i] < 380) mic->lambdas[i] = 380;
if (mic->lambdas[i] > 780) mic->lambdas[i] = 780;
float ratio = (mic->lambdas[i] - 380.0f) / (780.0f - 380.0f);
float lineX = spectrumRect.x + ratio * spectrumRect.width;
bool isSel = (i == mic->selectedLambdaIndex);
Color lineCol = isSel ? WHITE : GRAY;
float thick = isSel ? 3.0f : 2.0f;
DrawLineEx((Vector2){lineX, spectrumRect.y}, (Vector2){lineX, spectrumRect.y + spectrumRect.height}, thick, lineCol);
if(isSel) DrawTriangle((Vector2){lineX-5, spectrumRect.y-6}, (Vector2){lineX+5, spectrumRect.y-6}, (Vector2){lineX, spectrumRect.y}, WHITE);
}
// selction labmda
startY += spectrumHeight + 35;
if (mic->selectedLambdaIndex >= mic->lambdasCount)
mic->selectedLambdaIndex = 0;
float* currentVal = &mic->lambdas[mic->selectedLambdaIndex];
if (GuiButtonRepeat((Rectangle){startX, startY, 40, 30}, "-", shouldRepeat))
*currentVal -= stepLambda;
DrawRectangle(startX + 45, startY, contentWidth - 90, 30, COLOR_PANEL);
DrawRectangleLines(startX + 45, startY, contentWidth - 90, 30, GRAY);
Color activeCol = WavelengthToColor(*currentVal);
DrawRectangle(startX + 50, startY + 5, 20, 20, activeCol);
DrawText(TextFormat("%.1f nm", *currentVal), startX + 80, startY + 5, 20, WHITE);
if (GuiButtonRepeat((Rectangle){startX + contentWidth - 40, startY, 40, 30}, "+", shouldRepeat))
*currentVal += stepLambda;
// lambda acrifs
startY += 45;
DrawText("Longueurs d'onde actives :", startX, startY, 20, GRAY);
startY += 25;
int cols = 5;
int btnW = (contentWidth - (cols - 1) * 5) / cols;
int btnH = 30;
for(int i = 0; i < mic->lambdasCount; i++) {
int r = i / cols;
int c = i % cols;
Rectangle rectBtn = {startX + c * (btnW + 5), startY + r * (btnH + 5), btnW, btnH};
bool isSel = (i == mic->selectedLambdaIndex);
Color cVal = WavelengthToColor(mic->lambdas[i]);
if (GuiButton(rectBtn, TextFormat("%.0f", mic->lambdas[i])))
mic->selectedLambdaIndex = i;
if (isSel)
DrawRectangleLinesEx(rectBtn, 2, WHITE);
DrawRectangle(rectBtn.x + 2, rectBtn.y + 2, 5, rectBtn.height - 4, cVal);
}
int rows = (mic->lambdasCount + cols - 1) / cols;
startY += (rows * (btnH + 5)) + 20;
// Pos M1 M2 (d1 - d2)
startY += 0;
float currentDiff = mic->d1 - mic->d2;
DrawText(TextFormat("Distance M1 - M2: %.2f um", currentDiff), startX, startY, 20, ORANGE);
// Pas des + et -
float stepD1 = speedMode ? 0.05f : 0.006f;
if (GuiButtonRepeat((Rectangle){startX, startY + 30, btnSize, 25}, "-", shouldRepeat)) mic->d1 -= stepD1;
float sliderVal = currentDiff;
GuiSlider((Rectangle){startX + btnSize + 5, startY + 30, sliderWidth - 75, 25}, NULL, NULL, &sliderVal, -100.0f, 100.0f);
mic->d1 = mic->d2 + sliderVal;
if (GuiButtonRepeat((Rectangle){startX, startY + 30, btnSize, 25}, "-", shouldRepeat)) mic->d1 -= stepD1;
if (GuiButtonRepeat((Rectangle){startX + btnSize + sliderWidth - 65, startY + 30, btnSize, 25}, "+", shouldRepeat)) mic->d1 += stepD1;
if (GuiButton((Rectangle){startX + contentWidth - 60, startY + 30, 60, 25}, "Egal")) mic->d1 = mic->d2;
// Angle M1 X
startY += 90;
DrawText(TextFormat("Inclinaison M1: %.3f deg", mic->angleM1), startX, startY, 20, ORANGE);
float stepAngle = speedMode ? 0.05f : 0.0006f;
if (GuiButtonRepeat((Rectangle){startX, startY + 30, btnSize, 25}, "-", shouldRepeat)) mic->angleM1 -= stepAngle;
GuiSlider((Rectangle){startX + btnSize + 5, startY + 30, sliderWidth - 75, 25}, 0, 0, &mic->angleM1, -1.0f, 1.0f);
if (GuiButtonRepeat((Rectangle){startX + btnSize + sliderWidth - 65, startY + 30, btnSize, 25}, "+", shouldRepeat)) mic->angleM1 += stepAngle;
if (GuiButton((Rectangle){startX + contentWidth - 60, startY + 30, 60, 25}, "Zero")) mic->angleM1 = 0.0f;
// Angles M1 Y
startY += 90;
stepAngle = speedMode ? 0.05f : 0.0006f;
DrawText(TextFormat("Inclinaison Y: %.3f deg", mic->angleM1_Y), startX, startY, 20, ORANGE);
if (GuiButtonRepeat((Rectangle){startX, startY + 30, btnSize, 25}, "-", shouldRepeat)) mic->angleM1_Y -= stepAngle;
GuiSlider((Rectangle){startX + btnSize + 5, startY + 30, sliderWidth - 75, 25}, 0, 0, &mic->angleM1_Y, -1.0f, 1.0f);
if (GuiButtonRepeat((Rectangle){startX + btnSize + sliderWidth - 65, startY + 30, btnSize, 25}, "+", shouldRepeat)) mic->angleM1_Y += stepAngle;
if (GuiButton((Rectangle){startX + contentWidth - 60, startY + 30, 60, 25}, "Zero")) mic->angleM1_Y = 0.0f;
// Status
startY += 70;
bool isLameAir = (fabs(mic->angleM1) < 0.001f);
const char* modeTxt = isLameAir ? "LAME D'AIR" : "COIN D'AIR";
Color modeColor = isLameAir ? SKYBLUE : GREEN;
DrawRectangle(startX, startY, contentWidth, 30, Fade(modeColor, 0.2f));
DrawRectangleLines(startX, startY, contentWidth, 30, modeColor);
DrawText(modeTxt, startX + 10, startY + 8, 20, modeColor);
// Cuve de gaz
startY += 50;
DrawLine(startX, startY - 10, startX + contentWidth, startY - 10, Fade(GRAY, 0.3f));
DrawText("Cuve de Gaz (Indice n)", startX, startY, 20, SKYBLUE);
GuiCheckBox((Rectangle){startX, startY + 30, 20, 20}, "Cuve", &mic->gaz);
if (mic->gaz) {
DrawText(TextFormat("n = %.4f", mic->nGaz), startX + 150, startY + 30, 20, WHITE);
float stepN = speedMode ? 0.001f : 0.00005f;
if (GuiButtonRepeat((Rectangle){startX, startY + 55, btnSize, 25}, "-", shouldRepeat)) mic->nGaz -= stepN;
GuiSlider((Rectangle){startX + btnSize + 5, startY + 55, sliderWidth - 10, 25}, NULL, NULL, &mic->nGaz, 1.000f, 1.100f);
if (GuiButtonRepeat((Rectangle){startX + btnSize + sliderWidth, startY + 55, btnSize, 25}, "+", shouldRepeat)) mic->nGaz += stepN;
if (mic->nGaz < 1.0f) mic->nGaz = 1.0f;
//startY += 90;
}
// Données
startY += 100;
DrawLine(startX, startY - 10, startX + contentWidth, startY - 10, GRAY);
DrawText("DONNEES TEMPS REEL", startX, startY, 20, GRAY);
float delta = 2 * (mic->d1 - mic->d2);
DrawText(TextFormat("Delta = %.2f um", delta), startX, startY + 35, 22, WHITE);
DrawText(TextFormat("Delta = %.2f um", delta), startX, startY + 35, 20, WHITE);
float p = (delta * 1000.0f) / mic->lambda;
DrawText(TextFormat("Ordre p = %.2f", p), startX, startY + 65, 22, LIGHTGRAY);
float refLambda = mic->lambdas[mic->selectedLambdaIndex];
float p = (delta * 1000.0f) / refLambda;
DrawText(TextFormat("Ordre p = %.2f", p), startX, startY + 65, 20, WHITE);
// FPS
int bottomY = GetScreenHeight() - 40;
int perfStartY = bottomY - 80;
DrawLine(startX, perfStartY - 10, startX + contentWidth, perfStartY - 10, GRAY);
DrawText("PERFORMANCES (Cible FPS)", startX, perfStartY, 20, GRAY);
int fpsValues[] = {0, 30, 60, 120, 144};
const char* fpsTexts[] = {"MAX", "30", "60", "120", "144"};
int fpsCount = 5;
int fpsSpacing = 5;
int fpsBtnW = (contentWidth - (fpsSpacing * (fpsCount - 1))) / fpsCount;
for (int i = 0; i < fpsCount; i++) {
Rectangle fpsRect = {startX + i * (fpsBtnW + fpsSpacing), perfStartY + 30, fpsBtnW, 25};
bool isCurrent = (mic->targetFps == i);
if (GuiButton(fpsRect, fpsTexts[i])) {
mic->targetFps = i;
SetTargetFPS(fpsValues[i]);
}
if (isCurrent) {
DrawRectangleLinesEx(fpsRect, 2, COLOR_ACCENT);
DrawRectangle(fpsRect.x + 2, fpsRect.y + 2, fpsRect.width-4, fpsRect.height-4, Fade(COLOR_ACCENT, 0.2f));
}
}
// Bas
DrawLine(0, bottomY, UI_WIDTH, bottomY, Fade(WHITE, 0.1f));
int fps = GetFPS();
Color fpsColor = (fps >= 100) ? COLOR_ACCENT : (fps >= 60 ? GREEN : (fps >= 30 ? ORANGE : RED));
int currentFpsVal = fpsValues[mic->targetFps];
DrawText("STATUT:", startX, bottomY + 12, 20, COLOR_TEXT_DIM);
DrawText(TextFormat("%i FPS (%s)", fps, (currentFpsVal == 0 ? "Max" : TextFormat("%i", currentFpsVal))), startX + 100, bottomY + 12, 20, fpsColor);
}
int main () {
SetConfigFlags(FLAG_MSAA_4X_HINT);
InitWindow(1920, 1080, "Interferometre de Michelson");
SetTargetFPS(60);
Michelson mic = {0};
Shader shader;
bool isFullscreen = false;
Rectangle normalBounds = {0};
Rectangle fullScreenBounds = {0};
#if !defined(PLATFORM_WEB)
RenderTexture2D target;
#endif
Michelson mic = {0};
mic.center = (Vector2){ UI_WIDTH + (1920 - UI_WIDTH) / 2.0f - 100, 1080 / 2.0f };
mic.d1 = 250.0f;
mic.d2 = 250.0f;
mic.lambda = 550.0f;
mic.angleM1 = 0.0f;
void UpdateDrawFrame(void) {
if (IsKeyPressed(KEY_F)) {
isFullscreen = !isFullscreen;
}
Rectangle screenViewBounds = {1920 - 530, 50, 500, 500};
//Rectangle screenViewBounds = {400, 0, 1080, 1080};
while (!WindowShouldClose()) {
Rectangle currentViewBounds = isFullscreen ? fullScreenBounds : normalBounds;
#if defined(PLATFORM_WEB)
BeginDrawing();
ClearBackground(BLACK);
ClearBackground(COLOR_BG);
float gridThick = 1.1f;
float gridAlpha = 0.03f;
// Grille fond
for(int i = UI_WIDTH; i < 1920; i += 100) {
DrawLineEx((Vector2){i, 0}, (Vector2){i, 1080}, gridThick, Fade(WHITE, gridAlpha));
}
for(int i = 0; i < 1080; i += 100) {
DrawLineEx((Vector2){UI_WIDTH, i}, (Vector2){1920, i}, gridThick, Fade(WHITE, gridAlpha));
}
DrawMichelsonSchema(&mic);
DrawControlPanel(&mic);
DrawInterferenceView(&mic, screenViewBounds);
DrawInterferenceViewGPU(&mic, currentViewBounds, shader, &isFullscreen);
EndDrawing();
}
#else
float scale = fminf((float)GetScreenWidth() / 1920, (float)GetScreenHeight() / 1080);
float newWidth = 1920 * scale;
float newHeight = 1080 * scale;
float offsetX = (GetScreenWidth() - newWidth) * 0.5f;
float offsetY = (GetScreenHeight() - newHeight) * 0.5f;
SetMouseOffset(-offsetX, -offsetY);
SetMouseScale(1.0f / scale, 1.0f / scale);
BeginTextureMode(target);
ClearBackground(COLOR_BG);
float gridThick = 1.1f;
float gridAlpha = 0.03f;
// Grille fond
//for(int i = UI_WIDTH; i < 1920; i += 100) DrawLine(i, 0, i, 1080, Fade(WHITE, 0.05f));
//for(int i = 0; i < 1080; i += 100) DrawLine(UI_WIDTH, i, 1920, i, Fade(WHITE, 0.05f));
for(int i = UI_WIDTH; i < 1920; i += 100) {
DrawLineEx((Vector2){i, 0}, (Vector2){i, 1080}, gridThick, Fade(WHITE, gridAlpha));
}
for(int i = 0; i < 1080; i += 100) {
DrawLineEx((Vector2){UI_WIDTH, i}, (Vector2){1920, i}, gridThick, Fade(WHITE, gridAlpha));
}
DrawMichelsonSchema(&mic);
DrawControlPanel(&mic);
DrawInterferenceViewGPU(&mic, currentViewBounds, shader, &isFullscreen);
EndTextureMode();
BeginDrawing();
ClearBackground(COLOR_BG);
Rectangle sourceRec = {0.0f, 0.0f, (float)target.texture.width, -(float)target.texture.height};
Rectangle destRec = { offsetX, offsetY, newWidth, newHeight };
DrawTexturePro(target.texture, sourceRec, destRec, (Vector2){0, 0}, 0.0f, WHITE);
EndDrawing();
#endif
}
int main () {
#if defined(PLATFORM_WEB)
InitWindow(1920, 1080, "Interferometre de Michelson");
SetConfigFlags(FLAG_MSAA_4X_HINT);
#else
SetConfigFlags(FLAG_WINDOW_RESIZABLE | FLAG_MSAA_4X_HINT);
InitWindow(1280, 720, "Interferometre de Michelson");
#endif
SetTargetFPS(0);
#if defined(PLATFORM_WEB)
shader = LoadShader(0, "glsl/michelson_web.frag");
#else
shader = LoadShader(0, "glsl/michelson.frag");
#endif
#if !defined(PLATFORM_WEB)
target = LoadRenderTexture(1920, 1080);
SetTextureFilter(target.texture, TEXTURE_FILTER_BILINEAR);
#endif
mic.center = (Vector2){ UI_WIDTH + (1920 - UI_WIDTH) / 2.0f - 100, 1080 / 2.0f };
mic.d1 = 265.0f;
mic.d2 = 250.0f;
mic.lambdas[0] = 550.0f;
mic.lambdasCount = 1;
mic.selectedLambdaIndex = 0;
mic.angleM1 = 0.0f;
mic.angleM1_Y = 0.0f;
mic.nGaz = 1.0f;
mic.gaz = false;
normalBounds = (Rectangle){1920 - 530, 50, 500, 500};
fullScreenBounds = (Rectangle){UI_WIDTH + 10, 40, 1920 - UI_WIDTH - 20, 1030};
#if defined(PLATFORM_WEB)
emscripten_set_main_loop(UpdateDrawFrame, 0, 1);
#else
while (!WindowShouldClose()) {
UpdateDrawFrame();
}
#endif
CloseWindow();
return 0;
}

58
minshell.html Normal file
View File

@ -0,0 +1,58 @@
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Interferometre Michelson - Web</title>
<style>
body {
margin: 0;
padding: 0;
background-color: #19191e;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
width: 100vw;
}
canvas.emscripten {
border: 0px none;
background-color: #19191e;
display: block;
aspect-ratio: 16 / 9;
max-width: 100vw;
max-height: 100vh;
height: auto;
width: auto;
box-shadow: 0 0 20px rgba(0,0,0,0.5);
image-rendering: -moz-crisp-edges;
image-rendering: -webkit-optimize-contrast;
image-rendering: crisp-edges;
image-rendering: pixelated;
}
</style>
</head>
<body>
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" tabindex=-1></canvas>
<script type='text/javascript'>
var Module = {
print: (function() {
return function(text) { console.log(text); };
})(),
printErr: function(text) { console.error(text); },
canvas: (function() {
var canvas = document.getElementById('canvas');
return canvas;
})()
};
</script>
{{{ SCRIPT }}}
</body>
</html>

BIN
raylib/libraylib.web.a Normal file

Binary file not shown.

1727
raylib/raylib.h Normal file

File diff suppressed because it is too large Load Diff