update Readme
This commit is contained in:
parent
0d98a2077b
commit
d2775dbd4a
7 changed files with 193 additions and 18 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -2,3 +2,4 @@ voyager.code-workspace
|
||||||
.vscode
|
.vscode
|
||||||
build
|
build
|
||||||
*.err
|
*.err
|
||||||
|
assets/fond-320200.iff
|
||||||
|
|
|
||||||
11
README.md
11
README.md
|
|
@ -14,6 +14,17 @@ Affichage : **VGA Mode 13h** — 320×200, 256 couleurs, rendu Gouraud en virgul
|
||||||
* **Génération procédurale :** Création dynamique de géométries (Cubes, Sphères, Cylindres, Cônes, Plans, Tores, Surfaces mathématiques).
|
* **Génération procédurale :** Création dynamique de géométries (Cubes, Sphères, Cylindres, Cônes, Plans, Tores, Surfaces mathématiques).
|
||||||
* **Mode "Minimal Player" :** Capacité d'exporter la scène entière en un header statique C pour compiler un exécutable ultra-léger sans les fonctions de génération mathématique.
|
* **Mode "Minimal Player" :** Capacité d'exporter la scène entière en un header statique C pour compiler un exécutable ultra-léger sans les fonctions de génération mathématique.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Exemples
|
||||||
|
|
||||||
|

|
||||||
|
Vue en flatshading
|
||||||
|
|
||||||
|

|
||||||
|
Vue en Gouraud
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Structure du projet
|
## Structure du projet
|
||||||
|
|
|
||||||
BIN
assets/Capture-Flatshading.png
Normal file
BIN
assets/Capture-Flatshading.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 82 KiB |
BIN
assets/Capture-Gouraud.png
Normal file
BIN
assets/Capture-Gouraud.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 83 KiB |
|
|
@ -7,6 +7,7 @@ int main(void) {
|
||||||
Object3D *tank, *pws1, *pws2, *inst1, *inst2;
|
Object3D *tank, *pws1, *pws2, *inst1, *inst2;
|
||||||
Camera cam;
|
Camera cam;
|
||||||
Matrix3 rotX, rotY, orbit;
|
Matrix3 rotX, rotY, orbit;
|
||||||
|
Image *theme_img = NULL;
|
||||||
Image *bg_img = NULL;
|
Image *bg_img = NULL;
|
||||||
int special=0;
|
int special=0;
|
||||||
int anglex, angley, key, render, o;
|
int anglex, angley, key, render, o;
|
||||||
|
|
@ -15,7 +16,6 @@ int main(void) {
|
||||||
printf("Moteur 3D DOS (TESTING) - Version 0.15\n");
|
printf("Moteur 3D DOS (TESTING) - Version 0.15\n");
|
||||||
printf("Compile le %s a %s\n\n", __DATE__, __TIME__);
|
printf("Compile le %s a %s\n\n", __DATE__, __TIME__);
|
||||||
printf("Appuyez sur une touche pour demarrer le rendu...\n");
|
printf("Appuyez sur une touche pour demarrer le rendu...\n");
|
||||||
getch();
|
|
||||||
|
|
||||||
anglex = angley = key = 0;
|
anglex = angley = key = 0;
|
||||||
render = MODE_SOLID;
|
render = MODE_SOLID;
|
||||||
|
|
@ -31,88 +31,104 @@ int main(void) {
|
||||||
/* --- Construction de la sonde Voyager --- */
|
/* --- Construction de la sonde Voyager --- */
|
||||||
|
|
||||||
/* 1. Bus principal (décagone blanc) */
|
/* 1. Bus principal (décagone blanc) */
|
||||||
bus = add_cylinder(uni, 0, 0, 0, int_to_f(12), int_to_f(10), 10, COLOR7, 0);
|
bus = add_cylinder(uni, 0, 0, 0, int_to_f(12), int_to_f(10), 10, COLOR9, 0);
|
||||||
set_object_pos(bus, 0, 0, 0);
|
set_object_pos(bus, 0, 0, 0);
|
||||||
|
|
||||||
/* 1b. Réservoir d'hydrazine central (sphère dépassant sous le bus) */
|
/* 1b. Réservoir d'hydrazine central (sphère dépassant sous le bus) */
|
||||||
tank = add_sphere(uni, 0, 0, 0, int_to_f(6), 8, COLOR7, 0);
|
tank = add_sphere(uni, 0, 0, 0, int_to_f(6), 8, COLOR9, 0);
|
||||||
set_object_pos(tank, 0, int_to_f(-3), 0);
|
set_object_pos(tank, 0, int_to_f(-3), 0);
|
||||||
|
|
||||||
/* 2a. Antenne parabolique (Paraboloïde avec courbure réaliste) */
|
/* 2a. Antenne parabolique (Paraboloïde avec courbure réaliste) */
|
||||||
dish = add_paraboloid(uni, 0, 0, 0, int_to_f(25), int_to_f(8), 24, 4, COLOR7, 0);
|
dish = add_paraboloid(uni, 0, 0, 0, int_to_f(25), int_to_f(8), 24, 4, COLOR9, 0);
|
||||||
/* Pointant déjà vers le haut (+Y), on abaisse simplement sa base pour se reposer sur le bus */
|
/* Pointant déjà vers le haut (+Y), on abaisse simplement sa base pour se reposer sur le bus */
|
||||||
set_object_pos(dish, 0, int_to_f(9), 0);
|
set_object_pos(dish, 0, int_to_f(9), 0);
|
||||||
|
|
||||||
/* 2b. Mât central de l'antenne (treillis triangulaire) */
|
/* 2b. Mât central de l'antenne (treillis triangulaire) */
|
||||||
feed_boom = add_cylinder(uni, 0, 0, 0, int_to_f(1)/2, int_to_f(10), 3, COLOR7, 1);
|
feed_boom = add_cylinder(uni, 0, 0, 0, int_to_f(1)/2, int_to_f(10), 3, COLOR9, 1);
|
||||||
set_object_pos(feed_boom, 0, int_to_f(10), 0);
|
set_object_pos(feed_boom, 0, int_to_f(10), 0);
|
||||||
|
|
||||||
/* 2c. Sous-réflecteur de l'antenne (petit cône inversé) */
|
/* 2c. Sous-réflecteur de l'antenne (petit cône inversé) */
|
||||||
sub_dish = add_cone(uni, 0, 0, 0, int_to_f(3), int_to_f(2), 12, COLOR7, 0);
|
sub_dish = add_cone(uni, 0, 0, 0, int_to_f(3), int_to_f(2), 12, COLOR9, 0);
|
||||||
bake_object_rotation(uni, sub_dish, 180, 0, 0);
|
bake_object_rotation(uni, sub_dish, 180, 0, 0);
|
||||||
set_object_pos(sub_dish, 0, int_to_f(16), 0);
|
set_object_pos(sub_dish, 0, int_to_f(16), 0);
|
||||||
|
|
||||||
/* 3. Mât du RTG (Générateur thermoélectrique, structure en treillis carrée) */
|
/* 3. Mât du RTG (Générateur thermoélectrique, structure en treillis carrée) */
|
||||||
rtg_boom = add_cylinder(uni, 0, 0, 0, int_to_f(2), int_to_f(40), 4, COLOR11, 1);
|
rtg_boom = add_cylinder(uni, 0, 0, 0, int_to_f(2), int_to_f(40), 4, COLOR8, 1);
|
||||||
bake_object_rotation(uni, rtg_boom, 0, 0, 90); /* Couché sur l'axe X */
|
bake_object_rotation(uni, rtg_boom, 0, 0, 90); /* Couché sur l'axe X */
|
||||||
set_object_pos(rtg_boom, int_to_f(25), int_to_f(-2), 0);
|
set_object_pos(rtg_boom, int_to_f(25), int_to_f(-2), 0);
|
||||||
|
|
||||||
/* 4. RTG (Générateurs thermoélectriques, 3 segments en série) */
|
/* 4. RTG (Générateurs thermoélectriques, 3 segments en série) */
|
||||||
rtg1 = add_cylinder(uni, 0, 0, 0, int_to_f(4), int_to_f(5), 8, COLOR11, 0);
|
rtg1 = add_cylinder(uni, 0, 0, 0, int_to_f(4), int_to_f(5), 8, COLOR8, 0);
|
||||||
bake_object_rotation(uni, rtg1, 0, 0, 90);
|
bake_object_rotation(uni, rtg1, 0, 0, 90);
|
||||||
set_object_pos(rtg1, int_to_f(48), int_to_f(-2), 0);
|
set_object_pos(rtg1, int_to_f(48), int_to_f(-2), 0);
|
||||||
|
|
||||||
rtg2 = add_cylinder(uni, 0, 0, 0, int_to_f(4), int_to_f(5), 8, COLOR11, 0);
|
rtg2 = add_cylinder(uni, 0, 0, 0, int_to_f(4), int_to_f(5), 8, COLOR8, 0);
|
||||||
bake_object_rotation(uni, rtg2, 0, 0, 90);
|
bake_object_rotation(uni, rtg2, 0, 0, 90);
|
||||||
set_object_pos(rtg2, int_to_f(54), int_to_f(-2), 0);
|
set_object_pos(rtg2, int_to_f(54), int_to_f(-2), 0);
|
||||||
|
|
||||||
rtg3 = add_cylinder(uni, 0, 0, 0, int_to_f(4), int_to_f(5), 8, COLOR11, 0);
|
rtg3 = add_cylinder(uni, 0, 0, 0, int_to_f(4), int_to_f(5), 8, COLOR8, 0);
|
||||||
bake_object_rotation(uni, rtg3, 0, 0, 90);
|
bake_object_rotation(uni, rtg3, 0, 0, 90);
|
||||||
set_object_pos(rtg3, int_to_f(60), int_to_f(-2), 0);
|
set_object_pos(rtg3, int_to_f(60), int_to_f(-2), 0);
|
||||||
|
|
||||||
/* 5. Mât du magnétomètre (Très long, structure en treillis triangulaire) */
|
/* 5. Mât du magnétomètre (Très long, structure en treillis triangulaire) */
|
||||||
mag_boom = add_cylinder(uni, 0, 0, 0, int_to_f(1), int_to_f(70), 3, COLOR11, 1);
|
mag_boom = add_cylinder(uni, 0, 0, 0, int_to_f(1), int_to_f(70), 3, COLOR8, 1);
|
||||||
bake_object_rotation(uni, mag_boom, 0, 0, 90);
|
bake_object_rotation(uni, mag_boom, 0, 0, 90);
|
||||||
set_object_pos(mag_boom, int_to_f(-40), int_to_f(-2), 0);
|
set_object_pos(mag_boom, int_to_f(-40), int_to_f(-2), 0);
|
||||||
|
|
||||||
/* 6. Mât de la plateforme scientifique (vers l'avant, axe Z, treillis carrée) */
|
/* 6. Mât de la plateforme scientifique (vers l'avant, axe Z, treillis carrée) */
|
||||||
sci_boom = add_cylinder(uni, 0, 0, 0, int_to_f(2), int_to_f(30), 4, COLOR11, 1);
|
sci_boom = add_cylinder(uni, 0, 0, 0, int_to_f(2), int_to_f(30), 4, COLOR8, 1);
|
||||||
bake_object_rotation(uni, sci_boom, 90, 0, 0); /* Couché sur l'axe Z */
|
bake_object_rotation(uni, sci_boom, 90, 0, 0); /* Couché sur l'axe Z */
|
||||||
set_object_pos(sci_boom, 0, int_to_f(-2), int_to_f(-20));
|
set_object_pos(sci_boom, 0, int_to_f(-2), int_to_f(-20));
|
||||||
|
|
||||||
/* 7. Plateforme et caméras (cube gris) */
|
/* 7. Plateforme et caméras (cube gris) */
|
||||||
cam_box = add_box(uni, 0, 0, 0, int_to_f(6), int_to_f(6), int_to_f(6), COLOR11, 0);
|
cam_box = add_box(uni, 0, 0, 0, int_to_f(6), int_to_f(6), int_to_f(6), COLOR8, 0);
|
||||||
set_object_pos(cam_box, 0, int_to_f(-2), int_to_f(-35));
|
set_object_pos(cam_box, 0, int_to_f(-2), int_to_f(-35));
|
||||||
|
|
||||||
/* 8. Le célèbre Golden Record ! (Petit cylindre jaune/or collé sur le flanc) */
|
/* 8. Le célèbre Golden Record ! (Petit cylindre jaune/or collé sur le flanc) */
|
||||||
record = add_cylinder(uni, 0, 0, 0, int_to_f(3), int_to_f(1), 10, COLOR4, 0);
|
record = add_cylinder(uni, 0, 0, 0, int_to_f(3), int_to_f(1), 10, COLOR5, 0);
|
||||||
bake_object_rotation(uni, record, 0, 0, 90);
|
bake_object_rotation(uni, record, 0, 0, 90);
|
||||||
set_object_pos(record, int_to_f(12), int_to_f(0), int_to_f(5));
|
set_object_pos(record, int_to_f(12), int_to_f(0), int_to_f(5));
|
||||||
|
|
||||||
/* 9. Antennes PWS (Plasma Wave Subsystem) - Longs tubes filaires en V */
|
/* 9. Antennes PWS (Plasma Wave Subsystem) - Longs tubes filaires en V */
|
||||||
pws1 = add_cylinder(uni, 0, 0, 0, int_to_f(1)/2, int_to_f(60), 3, COLOR11, 1);
|
pws1 = add_cylinder(uni, 0, 0, 0, int_to_f(1)/2, int_to_f(60), 3, COLOR8, 1);
|
||||||
bake_object_rotation(uni, pws1, 0, 0, 90); /* 1. On le couche sur l'axe X */
|
bake_object_rotation(uni, pws1, 0, 0, 90); /* 1. On le couche sur l'axe X */
|
||||||
bake_object_rotation(uni, pws1, 0, 45, 0); /* 2. On l'écarte en V sur le plan XZ */
|
bake_object_rotation(uni, pws1, 0, 45, 0); /* 2. On l'écarte en V sur le plan XZ */
|
||||||
set_object_pos(pws1, int_to_f(-20), int_to_f(-5), int_to_f(20));
|
set_object_pos(pws1, int_to_f(-20), int_to_f(-5), int_to_f(20));
|
||||||
|
|
||||||
pws2 = add_cylinder(uni, 0, 0, 0, int_to_f(1)/2, int_to_f(60), 3, COLOR11, 1);
|
pws2 = add_cylinder(uni, 0, 0, 0, int_to_f(1)/2, int_to_f(60), 3, COLOR8, 1);
|
||||||
bake_object_rotation(uni, pws2, 0, 0, 90); /* 1. On le couche sur l'axe X */
|
bake_object_rotation(uni, pws2, 0, 0, 90); /* 1. On le couche sur l'axe X */
|
||||||
bake_object_rotation(uni, pws2, 0, -45, 0);/* 2. On l'écarte en V sur le plan XZ */
|
bake_object_rotation(uni, pws2, 0, -45, 0);/* 2. On l'écarte en V sur le plan XZ */
|
||||||
set_object_pos(pws2, int_to_f(-20), int_to_f(-5), int_to_f(-20));
|
set_object_pos(pws2, int_to_f(-20), int_to_f(-5), int_to_f(-20));
|
||||||
|
|
||||||
/* 10. Instruments optiques sur la plateforme scientifique (Télescopes/Caméras) */
|
/* 10. Instruments optiques sur la plateforme scientifique (Télescopes/Caméras) */
|
||||||
inst1 = add_cylinder(uni, 0, 0, 0, int_to_f(2), int_to_f(8), 6, COLOR7, 0);
|
inst1 = add_cylinder(uni, 0, 0, 0, int_to_f(2), int_to_f(8), 6, COLOR9, 0);
|
||||||
bake_object_rotation(uni, inst1, 90, 0, 0);
|
bake_object_rotation(uni, inst1, 90, 0, 0);
|
||||||
set_object_pos(inst1, int_to_f(-2), int_to_f(1), int_to_f(-38));
|
set_object_pos(inst1, int_to_f(-2), int_to_f(1), int_to_f(-38));
|
||||||
|
|
||||||
inst2 = add_cone(uni, 0, 0, 0, int_to_f(2), int_to_f(6), 8, COLOR7, 0);
|
inst2 = add_cone(uni, 0, 0, 0, int_to_f(2), int_to_f(6), 8, COLOR9, 0);
|
||||||
bake_object_rotation(uni, inst2, 90, 0, 0);
|
bake_object_rotation(uni, inst2, 90, 0, 0);
|
||||||
set_object_pos(inst2, int_to_f(2), int_to_f(1), int_to_f(-38));
|
set_object_pos(inst2, int_to_f(2), int_to_f(1), int_to_f(-38));
|
||||||
|
|
||||||
cam.pos.x = cam.pos.y = cam.pos.z = 0;
|
cam.pos.x = cam.pos.y = cam.pos.z = 0;
|
||||||
|
|
||||||
|
getch();
|
||||||
|
|
||||||
if (init_vga() != 0) { free(uni); return 1; }
|
if (init_vga() != 0) { free(uni); return 1; }
|
||||||
|
|
||||||
|
/* --- Thème de la palette --- */
|
||||||
|
/* Charge une image (ex: IFF 16 couleurs) pour en extraire la palette de base */
|
||||||
|
{
|
||||||
|
RGB base_palette[256]; /* Prévoir assez grand au cas où */
|
||||||
|
|
||||||
|
theme_img = load_iff8("THEME.LBM", base_palette);
|
||||||
|
if (theme_img) {
|
||||||
|
printf("Theme de couleurs 'THEME.LBM' charge. Generation des rampes de Gouraud...\n");
|
||||||
|
setup_vga_palette(base_palette);
|
||||||
|
remap_image_to_gouraud(theme_img);
|
||||||
|
bg_img = theme_img; /* On la conserve pour l'afficher en fond d'écran ! */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Optionnel : charger un fond (BMP 8-bit de 320x200 couleurs indexees) */
|
/* Optionnel : charger un fond (BMP 8-bit de 320x200 couleurs indexees) */
|
||||||
/* S'assurer que le fichier est bien généré avec les couleurs de votre palette moteur ! */
|
/* S'assurer que le fichier est bien généré avec les couleurs de votre palette moteur ! */
|
||||||
/* bg_img = load_bmp8("stars.bmp", NULL); */
|
/* bg_img = load_bmp8("stars.bmp", NULL); */
|
||||||
|
|
@ -185,6 +201,7 @@ int main(void) {
|
||||||
flip();
|
flip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* theme_img a déjà été libéré s'il a été chargé */
|
||||||
if (bg_img) free_image(bg_img);
|
if (bg_img) free_image(bg_img);
|
||||||
close_vga();
|
close_vga();
|
||||||
free(uni);
|
free(uni);
|
||||||
|
|
|
||||||
|
|
@ -153,5 +153,7 @@ void free_mesh(Mesh *m);
|
||||||
Image *create_image(int width, int height);
|
Image *create_image(int width, int height);
|
||||||
void free_image(Image *img);
|
void free_image(Image *img);
|
||||||
Image *load_bmp8(const char *filename, RGB *pal_out);
|
Image *load_bmp8(const char *filename, RGB *pal_out);
|
||||||
|
Image *load_iff8(const char *filename, RGB *pal_out);
|
||||||
|
void remap_image_to_gouraud(Image *img);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,28 @@ void free_image(Image *img) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void remap_image_to_gouraud(Image *img) {
|
||||||
|
int i, total;
|
||||||
|
if (!img || !img->data) return;
|
||||||
|
total = img->width * img->height;
|
||||||
|
for (i = 0; i < total; i++) {
|
||||||
|
/* Transforme l'index 0-15 vers l'index de luminosité max de sa rampe */
|
||||||
|
img->data[i] = (img->data[i] & 0x0F) << 4 | 15;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t read_be32(FILE *f) {
|
||||||
|
uint8_t b[4];
|
||||||
|
if (fread(b, 1, 4, f) != 4) return 0;
|
||||||
|
return ((uint32_t)b[0] << 24) | ((uint32_t)b[1] << 16) | ((uint32_t)b[2] << 8) | b[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t read_be16(FILE *f) {
|
||||||
|
uint8_t b[2];
|
||||||
|
if (fread(b, 1, 2, f) != 2) return 0;
|
||||||
|
return (b[0] << 8) | b[1];
|
||||||
|
}
|
||||||
|
|
||||||
Image *load_bmp8(const char *filename, RGB *pal_out) {
|
Image *load_bmp8(const char *filename, RGB *pal_out) {
|
||||||
FILE *f;
|
FILE *f;
|
||||||
uint8_t header[54];
|
uint8_t header[54];
|
||||||
|
|
@ -79,6 +101,128 @@ Image *load_bmp8(const char *filename, RGB *pal_out) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
|
||||||
|
Image *load_iff8(const char *filename, RGB *pal_out) {
|
||||||
|
FILE *f;
|
||||||
|
char buf[4];
|
||||||
|
char type[4];
|
||||||
|
int is_ilbm, is_pbm;
|
||||||
|
int width = 0, height = 0, nPlanes = 0, masking = 0, compression = 0;
|
||||||
|
long body_offset = 0;
|
||||||
|
Image *img;
|
||||||
|
int planes_to_read, row_bytes;
|
||||||
|
uint8_t *row_buf;
|
||||||
|
int y, p;
|
||||||
|
|
||||||
|
f = fopen(filename, "rb");
|
||||||
|
if (!f) return NULL;
|
||||||
|
|
||||||
|
if (fread(buf, 1, 4, f) != 4 || strncmp(buf, "FORM", 4) != 0) { fclose(f); return NULL; }
|
||||||
|
read_be32(f); /* Ignore form_size */
|
||||||
|
if (fread(type, 1, 4, f) != 4) { fclose(f); return NULL; }
|
||||||
|
|
||||||
|
is_ilbm = (strncmp(type, "ILBM", 4) == 0);
|
||||||
|
is_pbm = (strncmp(type, "PBM ", 4) == 0);
|
||||||
|
if (!is_ilbm && !is_pbm) { fclose(f); return NULL; }
|
||||||
|
|
||||||
|
while (fread(buf, 1, 4, f) == 4) {
|
||||||
|
uint32_t chunk_size = read_be32(f);
|
||||||
|
long next_chunk = ftell(f) + chunk_size;
|
||||||
|
if (chunk_size & 1) next_chunk++; /* Les chunks IFF sont alignés sur 16-bit */
|
||||||
|
|
||||||
|
if (strncmp(buf, "BMHD", 4) == 0) {
|
||||||
|
width = read_be16(f);
|
||||||
|
height = read_be16(f);
|
||||||
|
fseek(f, 4, SEEK_CUR); /* Skip x, y */
|
||||||
|
nPlanes = fgetc(f);
|
||||||
|
masking = fgetc(f);
|
||||||
|
compression = fgetc(f);
|
||||||
|
}
|
||||||
|
else if (strncmp(buf, "CMAP", 4) == 0 && pal_out) {
|
||||||
|
int num_colors = chunk_size / 3;
|
||||||
|
int i;
|
||||||
|
if (num_colors > 256) num_colors = 256;
|
||||||
|
for (i = 0; i < num_colors; i++) {
|
||||||
|
pal_out[i].r = (uint8_t)(fgetc(f) >> 2); /* Conversion 8-bit vers VGA DAC 6-bit */
|
||||||
|
pal_out[i].g = (uint8_t)(fgetc(f) >> 2);
|
||||||
|
pal_out[i].b = (uint8_t)(fgetc(f) >> 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strncmp(buf, "BODY", 4) == 0) {
|
||||||
|
body_offset = ftell(f);
|
||||||
|
break; /* Fin de l'en-tête, les données d'image commencent ici */
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(f, next_chunk, SEEK_SET);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!width || !height || !nPlanes || body_offset == 0) { fclose(f); return NULL; }
|
||||||
|
|
||||||
|
img = create_image(width, height);
|
||||||
|
if (!img) { fclose(f); return NULL; }
|
||||||
|
|
||||||
|
fseek(f, body_offset, SEEK_SET);
|
||||||
|
|
||||||
|
planes_to_read = is_ilbm ? (nPlanes + (masking == 1 ? 1 : 0)) : 1;
|
||||||
|
row_bytes = is_ilbm ? ((width + 15) / 16) * 2 : (width + 1) & ~1;
|
||||||
|
|
||||||
|
row_buf = (uint8_t *)malloc(row_bytes * planes_to_read);
|
||||||
|
if (!row_buf) { free_image(img); fclose(f); return NULL; }
|
||||||
|
|
||||||
|
for (y = 0; y < height; y++) {
|
||||||
|
for (p = 0; p < planes_to_read; p++) {
|
||||||
|
uint8_t *plane_dst = row_buf + p * row_bytes;
|
||||||
|
int bytes_to_read = row_bytes;
|
||||||
|
|
||||||
|
if (compression == 0) {
|
||||||
|
fread(plane_dst, 1, bytes_to_read, f);
|
||||||
|
} else if (compression == 1) {
|
||||||
|
while (bytes_to_read > 0 && !feof(f)) {
|
||||||
|
int n = (signed char)fgetc(f);
|
||||||
|
if (n >= 0 && n <= 127) { /* Copie littérale */
|
||||||
|
int count = n + 1;
|
||||||
|
int read_len = (count > bytes_to_read) ? bytes_to_read : count;
|
||||||
|
fread(plane_dst, 1, read_len, f);
|
||||||
|
if (count > read_len) fseek(f, count - read_len, SEEK_CUR);
|
||||||
|
plane_dst += read_len;
|
||||||
|
bytes_to_read -= read_len;
|
||||||
|
} else if (n >= -127 && n <= -1) { /* RLE (répétition) */
|
||||||
|
int count = -n + 1;
|
||||||
|
int val = fgetc(f);
|
||||||
|
int fill_len = (count > bytes_to_read) ? bytes_to_read : count;
|
||||||
|
memset(plane_dst, val, fill_len);
|
||||||
|
plane_dst += fill_len;
|
||||||
|
bytes_to_read -= fill_len;
|
||||||
|
} /* n == -128 est un no-op en PackBits */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_pbm) {
|
||||||
|
/* PBM est chunky : copie directe */
|
||||||
|
memcpy(img->data + y * width, row_buf, width);
|
||||||
|
} else if (is_ilbm) {
|
||||||
|
/* ILBM est planar : on recombine les bits en chunky */
|
||||||
|
uint8_t *dest_row = img->data + y * width;
|
||||||
|
int x;
|
||||||
|
memset(dest_row, 0, width);
|
||||||
|
for (p = 0; p < nPlanes; p++) {
|
||||||
|
uint8_t *plane_src = row_buf + p * row_bytes;
|
||||||
|
for (x = 0; x < width; x++) {
|
||||||
|
int byte_idx = x / 8;
|
||||||
|
int bit_idx = 7 - (x % 8);
|
||||||
|
if (plane_src[byte_idx] & (1 << bit_idx)) {
|
||||||
|
dest_row[x] |= (1 << p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(row_buf);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue