boarfds
This commit is contained in:
parent
80d8141b5a
commit
eae91de89d
8 changed files with 641 additions and 280 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,3 +1,4 @@
|
||||||
voyager.code-workspace
|
voyager.code-workspace
|
||||||
.vscode
|
.vscode
|
||||||
build
|
build
|
||||||
|
*.err
|
||||||
|
|
|
||||||
106
Makefile
106
Makefile
|
|
@ -1,50 +1,88 @@
|
||||||
# --- Détection de l'OS et Chemins ---
|
# --- Options de Build ---
|
||||||
ifeq ($(OS),Windows_NT)
|
# Valeurs possibles : causeway (recommandé), dos4g (classique)
|
||||||
# Chemins Windows pour les outils (utilisés par WSL)
|
EXTENDER = causeway
|
||||||
WATCOM := D:/WatCom
|
STACK_SIZE = 64k
|
||||||
NASM := C:/Program Files/NASM/nasm.exe
|
|
||||||
CC := $(WATCOM)/binnt64/wcc386.exe
|
WATCOM_WIN = D:\WatCom
|
||||||
AS := $(NASM)
|
WATCOM_WSL = /mnt/d/WatCom
|
||||||
LINK := $(WATCOM)/binnt64/wlink.exe
|
NASM_WIN = /mnt/c/Program\ Files/NASM/nasm.exe
|
||||||
FIX_PATH = $(subst /,\,$1)
|
|
||||||
|
# --- Configuration Dynamique du Linker ---
|
||||||
|
ifeq ($(EXTENDER), causeway)
|
||||||
|
# Configuration optimisée pour CauseWay
|
||||||
|
L_SYS = system causeway
|
||||||
|
L_OPTS = option osname='CauseWay' \
|
||||||
|
option stub=$(WATCOM_WIN)/binw/cwstub.exe \
|
||||||
|
option stack=$(STACK_SIZE)
|
||||||
else
|
else
|
||||||
# Chemins Debian (à adapter selon ton install Linux)
|
# Configuration classique pour DOS/4GW
|
||||||
WATCOM := /opt/watcom
|
L_SYS = system dos4g
|
||||||
CC := $(WATCOM)/binl64/wcc386
|
L_OPTS = option stack=$(STACK_SIZE)
|
||||||
AS := nasm
|
|
||||||
LINK := $(WATCOM)/binl64/wlink
|
|
||||||
FIX_PATH = $1
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# --- Configuration ---
|
# Binaires Windows exécutés par WSL
|
||||||
INC_DIRS := -i="$(WATCOM)/h" -i="$(WATCOM)/CustomH"
|
CC = $(WATCOM_WSL)/binnt64/wcc386.exe
|
||||||
LIB_DIRS := libpath "$(WATCOM)/lib386" libpath "$(WATCOM)/lib386/dos" libpath "$(WATCOM)/CustomLib"
|
CXX = $(WATCOM_WSL)/binnt64/wpp386.exe
|
||||||
CFLAGS := -bt=dos -6r -fp6 -ox -oh -ot -ei -zp8 $(INC_DIRS)
|
AS = $(NASM_WIN)
|
||||||
LFLAGS := system dos4g $(LIB_DIRS)
|
LINK = $(WATCOM_WSL)/binnt64/wlink.exe
|
||||||
|
|
||||||
# --- Détection AUTOMATIQUE des sources ---
|
# --- Flags de Performance ---
|
||||||
# Cherche récursivement tous les .cpp, .c et .asm dans src/
|
# On utilise wslpath pour que les outils Windows comprennent les chemins Linux
|
||||||
SRC_CPP := $(shell find src -name "*.cpp")
|
INC_FLAGS = -i="$(WATCOM_WIN)\h" -i="$(WATCOM_WIN)\CustomH"
|
||||||
SRC_ASM := $(shell find src -name "*.asm")
|
CFLAGS = -bt=dos -6s -fp6 -ox -od -oh -ot -ei -zp8 $(INC_FLAGS)
|
||||||
|
LFLAGS = $(L_SYS) $(L_OPTS) \
|
||||||
|
libpath "$(WATCOM_WIN)\lib386" \
|
||||||
|
libpath "$(WATCOM_WIN)\lib386\dos" \
|
||||||
|
libpath "$(WATCOM_WIN)\CustomLib"
|
||||||
|
|
||||||
# Génère la liste des objets correspondants dans build/
|
# --- Détection des Sources ---
|
||||||
OBJS := $(patsubst src/%.cpp, build/%.obj, $(SRC_CPP))
|
# On force le shell à trouver les fichiers
|
||||||
OBJS += $(patsubst src/%.asm, build/%.obj, $(SRC_ASM))
|
SRCS_CPP := $(shell find src -name "*.cpp")
|
||||||
|
SRCS_C := $(shell find src -name "*.c")
|
||||||
|
SRCS_ASM := $(shell find src -name "*.asm")
|
||||||
|
|
||||||
|
# Création de la liste des objets (src/main/main.cpp -> build/main.obj)
|
||||||
|
OBJS := $(patsubst src/%.cpp, build/%.obj, $(SRCS_CPP)) \
|
||||||
|
$(patsubst src/%.c, build/%.obj, $(SRCS_C)) \
|
||||||
|
$(patsubst src/%.asm, build/%.obj, $(SRCS_ASM))
|
||||||
|
|
||||||
# --- Règles ---
|
# --- Règles ---
|
||||||
all: build/app.exe
|
all: prepare build/app.exe
|
||||||
|
|
||||||
|
prepare:
|
||||||
|
@mkdir -p build
|
||||||
|
@# Crée les sous-dossiers dans build pour correspondre à src
|
||||||
|
@$(foreach dir, $(sort $(dir $(SRCS_CPP) $(SRCS_C) $(SRCS_ASM))), mkdir -p $(subst src,build,$(dir));)
|
||||||
|
|
||||||
# Création du dossier build miroir de src
|
|
||||||
build/%.obj: src/%.cpp
|
build/%.obj: src/%.cpp
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
$(CC) $(CFLAGS) $< -fo=$(call FIX_PATH,$@)
|
$(CXX) $(CFLAGS) $< -fo='$(shell wslpath -w $@)'
|
||||||
|
@rm -f $*.err
|
||||||
|
|
||||||
|
build/%.obj: src/%.c
|
||||||
|
@mkdir -p $(dir $@)
|
||||||
|
$(CC) $(CFLAGS) $< -fo='$(shell wslpath -w $@)'
|
||||||
|
@rm -f $*.err
|
||||||
|
|
||||||
build/%.obj: src/%.asm
|
build/%.obj: src/%.asm
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
$(AS) -f obj $< -o $(call FIX_PATH,$@)
|
$(AS) -f obj $< -o '$(shell wslpath -w $@)'
|
||||||
|
|
||||||
build/app.exe: $(OBJS)
|
# --- PARTIE LINK CORRIGÉE ---
|
||||||
$(LINK) $(LFLAGS) name $(call FIX_PATH,$@) file {$(foreach f,$(OBJS),$(call FIX_PATH,$f))}
|
build/app.exe: $(OBJS) MakeFile
|
||||||
|
@if [ -z "$(OBJS)" ]; then echo "ERREUR: Aucun objet trouvé!"; exit 1; fi
|
||||||
|
@echo "Generating linker file: build/link.lnk"
|
||||||
|
@printf '%s\n' '$(LFLAGS)' > build/link.lnk
|
||||||
|
@printf 'name %s\n' '$(shell wslpath -w $@)' >> build/link.lnk
|
||||||
|
@$(foreach f,$(OBJS),printf 'file %s\n' '$(shell wslpath -w $f)' >> build/link.lnk;)
|
||||||
|
@echo "Linking..."
|
||||||
|
$(LINK) @build/link.lnk
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf build/*
|
rm -rf build
|
||||||
|
# Nettoyage des logs d'erreurs
|
||||||
|
rm -f *.err src/**/*.err
|
||||||
|
|
||||||
|
cleanall:
|
||||||
|
clean
|
||||||
|
all
|
||||||
|
|
@ -1,25 +1,76 @@
|
||||||
#define MAIN_C
|
#include "../part3D/defines.h"
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
init_engine_math();
|
|
||||||
// Allocation initiale large pour accumulation
|
// Allocation initiale large pour accumulation
|
||||||
Mesh scene; scene.verts = (Vector3*)malloc(5000*sizeof(Vector3));
|
Mesh scene;
|
||||||
scene.v_normals = (Vector3*)malloc(5000*sizeof(Vector3));
|
Matrix3 rot, tmpX, tmpY;
|
||||||
scene.faces = (Face*)malloc(8000*sizeof(Face));
|
int angX = 0, angY = 0;
|
||||||
scene.num_verts = scene.num_faces = 0;
|
int key = 0;
|
||||||
|
|
||||||
|
printf("STARTING\n");
|
||||||
|
|
||||||
|
init_engine_math();
|
||||||
|
|
||||||
|
scene.verts = (Vector3*)malloc(MAX_VERTEX*sizeof(Vector3));
|
||||||
|
scene.v_normals = (Vector3*)malloc(MAX_VERTEX*sizeof(Vector3));
|
||||||
|
scene.faces = (Face*)malloc(MAX_FACES*sizeof(Face));
|
||||||
|
|
||||||
|
if (!scene.verts || !scene.v_normals || !scene.faces) {
|
||||||
|
printf("Erreur : Memoire insuffisante pour le Mesh.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
scene.num_verts = 0;
|
||||||
|
scene.num_faces = 0;
|
||||||
|
|
||||||
// Création d'objets mixtes
|
// Création d'objets mixtes
|
||||||
add_cylinder(&scene, int_to_f(-50), 0, int_to_f(300), int_to_f(20), int_to_f(80), 16, 2, 0); // Plein
|
add_cylinder(&scene, int_to_f(-50), 0, int_to_f(300), int_to_f(20), int_to_f(80), 16, 2, 0); // Plein
|
||||||
add_sphere(&scene, int_to_f(50), 0, int_to_f(300), int_to_f(30), 12, 4, 1); // Toujours filaire
|
add_sphere(&scene, int_to_f(50), 0, int_to_f(300), int_to_f(30), 12, 4, 1); // Toujours filaire
|
||||||
|
|
||||||
init_vga();
|
init_vga();
|
||||||
Matrix3 rot; mat3_identity(&rot);
|
mat3_identity(&rot);
|
||||||
|
|
||||||
while(!kbhit()) {
|
while (key != 27) { // 27 = Touche Echap pour quitter
|
||||||
clear_buffers();
|
if (kbhit()) {
|
||||||
render_scene(&scene, &rot, MODE_SOLID); // Mode global : Plein
|
key = getch();
|
||||||
flip();
|
// Gestion ZQSD (Sensibilité de 5 degrés)
|
||||||
}
|
if (key == 'z' || key == 'Z') angX = (angX + 5) % 360;
|
||||||
close_vga(); return 0;
|
if (key == 's' || key == 'S') angX = (angX + 355) % 360;
|
||||||
|
if (key == 'q' || key == 'Q') angY = (angY + 355) % 360;
|
||||||
|
if (key == 'd' || key == 'D') angY = (angY + 5) % 360;
|
||||||
|
|
||||||
|
// Reconstruction de la matrice de rotation combinée
|
||||||
|
mat3_rotate_x(&tmpX, angX);
|
||||||
|
mat3_rotate_y(&tmpY, angY);
|
||||||
|
mat3_mul(&rot, &tmpX, &tmpY);
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_buffers(0);
|
||||||
|
render_scene(&scene, &rot, MODE_WIRE);
|
||||||
|
flip();
|
||||||
|
}
|
||||||
|
close_vga();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
int main() {
|
||||||
|
init_engine_math();
|
||||||
|
init_vga(); // On alloue les buffers ici
|
||||||
|
|
||||||
|
// VÉRIFICATION MANUELLE ICI
|
||||||
|
if (backbuffer == NULL || zbuffer == NULL) {
|
||||||
|
printf("Erreur d'allocation des buffers video\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(!kbhit()) {
|
||||||
|
// Test ultra-basique : on remplit l'écran de rouge
|
||||||
|
// SANS utiliser le z-buffer pour l'instant
|
||||||
|
memset(backbuffer, 4, 64000);
|
||||||
|
flip();
|
||||||
|
}
|
||||||
|
close_vga();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
#ifndef DEFINE_H
|
||||||
|
#define DEFINE_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
@ -5,4 +8,99 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <conio.h>
|
#include <conio.h>
|
||||||
|
|
||||||
typedef int32_t fixed;
|
#define MODE_WIRE 0 // Transparent totalv_cache
|
||||||
|
#define MODE_HIDDEN 1 // Fil de fer avec surfaces cachées
|
||||||
|
#define MODE_SOLID 2 // Plein (Gouraud)
|
||||||
|
|
||||||
|
#define MAX_VERTEX 5000
|
||||||
|
#define MAX_FACES 8000
|
||||||
|
|
||||||
|
typedef int32_t fixed;
|
||||||
|
|
||||||
|
#define f_to_int(a) ((a) >> 16)
|
||||||
|
#define int_to_f(a) ((a) << 16)
|
||||||
|
// #define f_mul(a, b) ((fixed)(((int64_t)(a) * (b)) >> 16))
|
||||||
|
|
||||||
|
// --- Remplacement des inlines ---
|
||||||
|
static __inline fixed f_mul(fixed a, fixed b) { return (fixed)(((int64_t)a * b) >> 16); }
|
||||||
|
static __inline fixed f_div(fixed a, fixed b) { if (b == 0) return 0; return (fixed)(((int64_t)a << 16) / b); }
|
||||||
|
|
||||||
|
// Matrice 3x3 pour la rotation des normales et des sommets
|
||||||
|
typedef struct {
|
||||||
|
fixed m[3][3];
|
||||||
|
} Matrix3;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
fixed x, y, z;
|
||||||
|
} Vector3;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int a, b, c;
|
||||||
|
uint8_t color;
|
||||||
|
uint8_t force_wire;
|
||||||
|
} Face;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int x, y;
|
||||||
|
fixed z;
|
||||||
|
int intensity;
|
||||||
|
} Point2D;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Vector3 *verts;
|
||||||
|
Vector3 *v_normals;
|
||||||
|
Face *faces;
|
||||||
|
int num_verts, num_faces;
|
||||||
|
} Mesh;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Mesh *mesh; // Pointeur vers le modèle 3D (partagé si plusieurs sphères)
|
||||||
|
Vector3 position; // Position dans le monde
|
||||||
|
Matrix3 rotation; // Rotation locale de l'objet
|
||||||
|
} Object3D;
|
||||||
|
|
||||||
|
typedef struct { uint8_t r, g, b; } RGB;
|
||||||
|
|
||||||
|
// --- Ajout des déclarations de tables ---
|
||||||
|
extern fixed sintab[360];
|
||||||
|
extern fixed costab[360];
|
||||||
|
extern fixed inv_table[321];
|
||||||
|
extern Point2D v_cache[MAX_VERTEX];
|
||||||
|
extern uint8_t *backbuffer;
|
||||||
|
extern uint16_t *zbuffer;
|
||||||
|
extern uint8_t *vga;
|
||||||
|
|
||||||
|
// Engine.C
|
||||||
|
void init_engine_math();
|
||||||
|
void normalize(Vector3 *v);
|
||||||
|
void mat3_rotate_x(Matrix3 *m, int angle);
|
||||||
|
void mat3_rotate_y(Matrix3 *m, int angle);
|
||||||
|
void mat3_mul(Matrix3 *res, Matrix3 *a, Matrix3 *b);
|
||||||
|
|
||||||
|
// geometry.c
|
||||||
|
void add_face(Mesh *m, int a, int b, int c, uint8_t col, uint8_t wire);
|
||||||
|
void add_sphere(Mesh *m, fixed x, fixed y, fixed z, fixed r, int det, uint8_t col, uint8_t wire);
|
||||||
|
void add_cylinder(Mesh *m, fixed x, fixed y, fixed z, fixed r, fixed h, int det, uint8_t col, uint8_t wire);
|
||||||
|
void save_mesh(Mesh *m, const char *fn);
|
||||||
|
Mesh* load_mesh(const char *fname);
|
||||||
|
void free_mesh(Mesh *m);
|
||||||
|
void render_scene(Mesh *m, Matrix3 *rot, int global_mode);
|
||||||
|
|
||||||
|
// Raster.c
|
||||||
|
void draw_line_z(Point2D *p1, Point2D *p2, uint8_t col, int z_test);
|
||||||
|
void swap_pt(Point2D **a, Point2D **b);
|
||||||
|
void fill_triangle_gouraud(Point2D *p1, Point2D *p2, Point2D *p3, uint8_t base_color);
|
||||||
|
void fill_triangle_zonly(Point2D *p1, Point2D *p2, Point2D *p3);
|
||||||
|
|
||||||
|
// Graph.c
|
||||||
|
void init_vga();
|
||||||
|
void clear_buffers(uint8_t color);
|
||||||
|
void flip();
|
||||||
|
void close_vga();
|
||||||
|
|
||||||
|
// Math.c
|
||||||
|
void mat3_identity(Matrix3 *mat);
|
||||||
|
void init_engine_math();
|
||||||
|
void normalize(Vector3 *v);
|
||||||
|
|
||||||
|
#endif // DEFINE_H
|
||||||
|
|
|
||||||
|
|
@ -1,49 +1,25 @@
|
||||||
#ifndef ENGINE_H
|
|
||||||
#define ENGINE_H
|
|
||||||
|
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
|
|
||||||
#define f_to_int(a) ((a) >> 16)
|
fixed sintab[360], costab[360], inv_table[321];
|
||||||
#define int_to_f(a) ((a) << 16)
|
Point2D v_cache[MAX_VERTEX];
|
||||||
// #define f_mul(a, b) ((fixed)(((int64_t)(a) * (b)) >> 16))
|
|
||||||
inline fixed f_mul(fixed a, fixed b) { return (fixed)(((int64_t)a * b) >> 16); }
|
|
||||||
inline fixed f_div(fixed a, fixed b) {
|
|
||||||
if (b == 0) return 0; // Évite la division par zéro
|
|
||||||
return (fixed)(((int64_t)a << 16) / b);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Matrice 3x3 pour la rotation des normales et des sommets
|
|
||||||
typedef struct { fixed m[3][3]; } Matrix3;
|
|
||||||
|
|
||||||
void mat3_identity(Matrix3 *mat) {
|
void mat3_identity(Matrix3 *mat) {
|
||||||
memset(mat, 0, sizeof(Matrix3));
|
memset(mat, 0, sizeof(Matrix3));
|
||||||
mat->m[0][0] = mat->m[1][1] = mat->m[2][2] = int_to_f(1);
|
mat->m[0][0] = mat->m[1][1] = mat->m[2][2] = int_to_f(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static fixed sintab[360], costab[360], inv_table[321];
|
|
||||||
|
|
||||||
void init_engine_math() {
|
void init_engine_math() {
|
||||||
for (int i = 0; i < 360; i++) {
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 360; i++) {
|
||||||
double r = (double)i * 3.14159265 / 180.0;
|
double r = (double)i * 3.14159265 / 180.0;
|
||||||
sintab[i] = (fixed)(sin(r) * 65536.0);
|
sintab[i] = (fixed)(sin(r) * 65536.0);
|
||||||
costab[i] = (fixed)(cos(r) * 65536.0);
|
costab[i] = (fixed)(cos(r) * 65536.0);
|
||||||
}
|
}
|
||||||
inv_table[0] = 0;
|
inv_table[0] = 0;
|
||||||
for (int i = 1; i <= 320; i++) inv_table[i] = (int_to_f(1) / i);
|
for (i = 1; i <= 320; i++) inv_table[i] = (int_to_f(1) / i);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct { fixed x, y, z; } Vector3;
|
|
||||||
|
|
||||||
typedef struct { int a, b, c; uint8_t color; uint8_t force_wire; } Face;
|
|
||||||
typedef struct { int x, y; fixed z; int intensity; } Point2D;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
Vector3 *verts;
|
|
||||||
Vector3 *v_normals;
|
|
||||||
Face *faces;
|
|
||||||
int num_verts, num_faces;
|
|
||||||
} Mesh;
|
|
||||||
|
|
||||||
// Normalisation pour le Gouraud (à la création uniquement)
|
// Normalisation pour le Gouraud (à la création uniquement)
|
||||||
void normalize(Vector3 *v) {
|
void normalize(Vector3 *v) {
|
||||||
double dx = (double)v->x, dy = (double)v->y, dz = (double)v->z;
|
double dx = (double)v->x, dy = (double)v->y, dz = (double)v->z;
|
||||||
|
|
@ -53,4 +29,92 @@ void normalize(Vector3 *v) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
// Génère une matrice de rotation sur l'axe X
|
||||||
|
void mat3_rotate_x(Matrix3 *m, int angle) {
|
||||||
|
fixed c = costab[angle % 360];
|
||||||
|
fixed s = sintab[angle % 360];
|
||||||
|
mat3_identity(m);
|
||||||
|
m->m[1][1] = c; m->m[1][2] = -s;
|
||||||
|
m->m[2][1] = s; m->m[2][2] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Génère une matrice de rotation sur l'axe Y
|
||||||
|
void mat3_rotate_y(Matrix3 *m, int angle) {
|
||||||
|
fixed c = costab[angle % 360];
|
||||||
|
fixed s = sintab[angle % 360];
|
||||||
|
mat3_identity(m);
|
||||||
|
m->m[0][0] = c; m->m[0][2] = s;
|
||||||
|
m->m[2][0] = -s; m->m[2][2] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiplie deux matrices 3x3 : res = a * b
|
||||||
|
void mat3_mul(Matrix3 *res, Matrix3 *a, Matrix3 *b) {
|
||||||
|
int i, j;
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
for (j = 0; j < 3; j++) {
|
||||||
|
res->m[i][j] = f_mul(a->m[i][0], b->m[0][j]) +
|
||||||
|
f_mul(a->m[i][1], b->m[1][j]) +
|
||||||
|
f_mul(a->m[i][2], b->m[2][j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void render_scene(Mesh *m, Matrix3 *rot, int global_mode) {
|
||||||
|
int i;
|
||||||
|
fixed pz, rx, ry, rz;
|
||||||
|
Vector3 *v;
|
||||||
|
Vector3 *n;
|
||||||
|
fixed nz;
|
||||||
|
int intensity;
|
||||||
|
|
||||||
|
|
||||||
|
for (i = 0; i < m->num_verts; i++) {
|
||||||
|
v = &m->verts[i];
|
||||||
|
n = &m->v_normals[i];
|
||||||
|
|
||||||
|
// --- 1. Rotation de la normale (pour la lumière) ---
|
||||||
|
nz = f_mul(n->x, rot->m[0][2]) + f_mul(n->y, rot->m[1][2]) + f_mul(n->z, rot->m[2][2]);
|
||||||
|
intensity = f_to_int(nz * 15);
|
||||||
|
if (intensity < 0) intensity = 0;
|
||||||
|
|
||||||
|
// --- 2. Rotation du sommet (LA PIÈCE MANQUANTE) ---
|
||||||
|
// On applique la multiplication Matrice * Vecteur
|
||||||
|
rx = f_mul(v->x, rot->m[0][0]) + f_mul(v->y, rot->m[1][0]) + f_mul(v->z, rot->m[2][0]);
|
||||||
|
ry = f_mul(v->x, rot->m[0][1]) + f_mul(v->y, rot->m[1][1]) + f_mul(v->z, rot->m[2][1]);
|
||||||
|
rz = f_mul(v->x, rot->m[0][2]) + f_mul(v->y, rot->m[1][2]) + f_mul(v->z, rot->m[2][2]);
|
||||||
|
|
||||||
|
// --- 3. Projection avec les coordonnées tournées ---
|
||||||
|
pz = rz; // On utilise le Z tourné
|
||||||
|
if (pz < int_to_f(10)) pz = int_to_f(10);
|
||||||
|
|
||||||
|
v_cache[i].z = pz;
|
||||||
|
v_cache[i].intensity = intensity;
|
||||||
|
v_cache[i].x = 160 + f_to_int(f_div(rx << 8, pz)); // On utilise rx tourné
|
||||||
|
v_cache[i].y = 100 - f_to_int(f_div(ry << 8, pz)); // On utilise ry tourné
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < m->num_faces; i++) {
|
||||||
|
Face *f = &m->faces[i];
|
||||||
|
Point2D *p1 = &v_cache[f->a];
|
||||||
|
Point2D *p2 = &v_cache[f->b];
|
||||||
|
Point2D *p3 = &v_cache[f->c];
|
||||||
|
int back = (p2->x - p1->x) * (p3->y - p1->y) - (p2->y - p1->y) * (p3->x - p1->x);
|
||||||
|
|
||||||
|
if (global_mode == MODE_WIRE) {
|
||||||
|
draw_line_z(p1, p2, f->color, 0);
|
||||||
|
draw_line_z(p2, p3, f->color, 0);
|
||||||
|
draw_line_z(p3, p1, f->color, 0);
|
||||||
|
} else {
|
||||||
|
if (back < 0) {
|
||||||
|
if (f->force_wire || global_mode == MODE_HIDDEN) {
|
||||||
|
fill_triangle_zonly(p1, p2, p3);
|
||||||
|
draw_line_z(p1, p2, f->color, 1);
|
||||||
|
draw_line_z(p2, p3, f->color, 1);
|
||||||
|
draw_line_z(p3, p1, f->color, 1); // Ajouté pour fermer le triangle
|
||||||
|
} else {
|
||||||
|
fill_triangle_gouraud(p1, p2, p3, f->color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,112 +1,118 @@
|
||||||
#define GEOMETRY_H
|
#include "defines.h"
|
||||||
|
|
||||||
#define MODE_WIRE 0 // Transparent total
|
|
||||||
#define MODE_HIDDEN 1 // Fil de fer avec surfaces cachées
|
|
||||||
#define MODE_SOLID 2 // Plein (Gouraud)
|
|
||||||
|
|
||||||
Point2D v_cache[5000];
|
|
||||||
|
|
||||||
void add_face(Mesh *m, int a, int b, int c, uint8_t col, uint8_t wire) {
|
void add_face(Mesh *m, int a, int b, int c, uint8_t col, uint8_t wire) {
|
||||||
m->faces[m->num_faces++] = (Face){a, b, c, col, wire};
|
Face *f = &m->faces[m->num_faces++];
|
||||||
|
f->a = a;
|
||||||
|
f->b = b;
|
||||||
|
f->c = c;
|
||||||
|
f->color = col;
|
||||||
|
f->force_wire = wire;
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_sphere(Mesh *m, fixed x, fixed y, fixed z, fixed r, int det, uint8_t col, uint8_t wire) {
|
void add_sphere(Mesh *m, fixed x, fixed y, fixed z, fixed r, int det, uint8_t col, uint8_t wire) {
|
||||||
int v_base = m->num_verts;
|
int i, j, v_base;
|
||||||
for (int j = 0; j <= det; j++) {
|
v_base = m->num_verts;
|
||||||
|
|
||||||
|
for (j = 0; j <= det; j++) {
|
||||||
fixed sin_phi = sintab[(j * 180 / det) % 360];
|
fixed sin_phi = sintab[(j * 180 / det) % 360];
|
||||||
fixed cos_phi = costab[(j * 180 / det) % 360];
|
fixed cos_phi = costab[(j * 180 / det) % 360];
|
||||||
for (int i = 0; i < det; i++) {
|
for (i = 0; i < det; i++) {
|
||||||
|
Vector3 *v = &m->verts[m->num_verts];
|
||||||
|
Vector3 *n = &m->v_normals[m->num_verts];
|
||||||
fixed sin_th = sintab[(i * 360 / det) % 360];
|
fixed sin_th = sintab[(i * 360 / det) % 360];
|
||||||
fixed cos_th = costab[(i * 360 / det) % 360];
|
fixed cos_th = costab[(i * 360 / det) % 360];
|
||||||
m->verts[m->num_verts] = (Vector3){x + f_mul(r, f_mul(sin_phi, cos_th)), y + f_mul(r, cos_phi), z + f_mul(r, f_mul(sin_phi, sin_th))};
|
|
||||||
m->v_normals[m->num_verts] = (Vector3){f_mul(sin_phi, cos_th), cos_phi, f_mul(sin_phi, sin_th)};
|
v->x = x + f_mul(r, f_mul(sin_phi, cos_th));
|
||||||
|
v->y = y + f_mul(r, cos_phi);
|
||||||
|
v->z = z + f_mul(r, f_mul(sin_phi, sin_th));
|
||||||
|
|
||||||
|
n->x = f_mul(sin_phi, cos_th);
|
||||||
|
n->y = cos_phi;
|
||||||
|
n->z = f_mul(sin_phi, sin_th);
|
||||||
|
|
||||||
m->num_verts++;
|
m->num_verts++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int j = 0; j < det; j++) {
|
for (j = 0; j < det; j++) {
|
||||||
for (int i = 0; i < det; i++) {
|
for (i = 0; i < det; i++) {
|
||||||
int a = v_base + j * det + i, b = v_base + j * det + (i + 1) % det;
|
int a = v_base + j * det + i;
|
||||||
int c = v_base + (j + 1) * det + i, d = v_base + (j + 1) * det + (i + 1) % det;
|
int b = v_base + j * det + (i + 1) % det;
|
||||||
add_face(m, a, b, c, col, wire); add_face(m, b, d, c, col, wire);
|
int c = v_base + (j + 1) * det + i;
|
||||||
|
int d = v_base + (j + 1) * det + (i + 1) % det;
|
||||||
|
add_face(m, a, b, c, col, wire);
|
||||||
|
add_face(m, b, d, c, col, wire);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_cylinder(Mesh *m, fixed x, fixed y, fixed z, fixed r, fixed h, int det, uint8_t col, uint8_t wire) {
|
void add_cylinder(Mesh *m, fixed x, fixed y, fixed z, fixed r, fixed h, int det, uint8_t col, uint8_t wire) {
|
||||||
int v_base = m->num_verts;
|
int i, v_base;
|
||||||
for (int i = 0; i < det; i++) {
|
v_base = m->num_verts;
|
||||||
fixed s = sintab[(i * 360 / det) % 360], c = costab[(i * 360 / det) % 360];
|
|
||||||
m->verts[m->num_verts] = (Vector3){x + f_mul(r, c), y - h / 2, z + f_mul(r, s)};
|
for (i = 0; i < det; i++) {
|
||||||
m->v_normals[m->num_verts] = (Vector3){c, 0, s}; m->num_verts++;
|
Vector3 *v1 = &m->verts[m->num_verts];
|
||||||
m->verts[m->num_verts] = (Vector3){x + f_mul(r, c), y + h / 2, z + f_mul(r, s)};
|
Vector3 *n1 = &m->v_normals[m->num_verts];
|
||||||
m->v_normals[m->num_verts] = (Vector3){c, 0, s}; m->num_verts++;
|
fixed s = sintab[(i * 360 / det) % 360];
|
||||||
|
fixed c = costab[(i * 360 / det) % 360];
|
||||||
|
|
||||||
|
v1->x = x + f_mul(r, c); v1->y = y - h / 2; v1->z = z + f_mul(r, s);
|
||||||
|
n1->x = c; n1->y = 0; n1->z = s;
|
||||||
|
m->num_verts++;
|
||||||
|
|
||||||
|
{ // Bloc pour v2/n2
|
||||||
|
Vector3 *v2 = &m->verts[m->num_verts];
|
||||||
|
Vector3 *n2 = &m->v_normals[m->num_verts];
|
||||||
|
v2->x = x + f_mul(r, c); v2->y = y + h / 2; v2->z = z + f_mul(r, s);
|
||||||
|
n2->x = c; n2->y = 0; n2->z = s;
|
||||||
|
m->num_verts++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0; i < det; i++) {
|
for (i = 0; i < det; i++) {
|
||||||
int a = v_base + i * 2, b = v_base + ((i * 2 + 2) % (det * 2)), c = a + 1, d = b + 1;
|
int a = v_base + i * 2;
|
||||||
add_face(m, a, b, c, col, wire); add_face(m, b, d, c, col, wire);
|
int b = v_base + ((i * 2 + 2) % (det * 2));
|
||||||
|
int c = a + 1;
|
||||||
|
int d = b + 1;
|
||||||
|
add_face(m, a, b, c, col, wire);
|
||||||
|
add_face(m, b, d, c, col, wire);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void save_mesh(Mesh *m, const char *fn) {
|
void save_mesh(Mesh *m, const char *fn) {
|
||||||
FILE *f = fopen(fn, "wb");
|
FILE *f = fopen(fn, "wb");
|
||||||
fwrite(&m->num_verts, 4, 1, f);
|
if (!f) return;
|
||||||
fwrite(&m->num_faces, 4, 1, f);
|
fwrite(&m->num_verts, sizeof(int), 1, f);
|
||||||
fwrite(m->verts, sizeof(Vector3), m->num_verts, f);
|
fwrite(&m->num_faces, sizeof(int), 1, f);
|
||||||
fwrite(m->v_normals, sizeof(Vector3), m->num_verts, f);
|
fwrite(m->verts, sizeof(Vector3), m->num_verts, f);
|
||||||
fwrite(m->faces, sizeof(Face), m->num_faces, f);
|
fwrite(m->v_normals, sizeof(Vector3), m->num_verts, f);
|
||||||
fclose(f);
|
fwrite(m->faces, sizeof(Face), m->num_faces, f);
|
||||||
|
fclose(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh* load_mesh(const char *fname) {
|
Mesh* load_mesh(const char *fname) {
|
||||||
FILE *f = fopen(fname, "rb");
|
Mesh *m;
|
||||||
if (!f) return NULL;
|
FILE *f = fopen(fname, "rb");
|
||||||
Mesh *m = (Mesh*)malloc(sizeof(Mesh));
|
if (!f) return NULL;
|
||||||
fread(&m->num_verts, 4, 1, f);
|
|
||||||
fread(&m->num_faces, 4, 1, f);
|
m = (Mesh*)malloc(sizeof(Mesh));
|
||||||
fread(&m->is_wire_only, 1, 1, f);
|
fread(&m->num_verts, sizeof(int), 1, f);
|
||||||
m->verts = (Vector3*)malloc(sizeof(Vector3) * m->num_verts);
|
fread(&m->num_faces, sizeof(int), 1, f);
|
||||||
m->v_normals = (Vector3*)malloc(sizeof(Vector3) * m->num_verts);
|
// Suppression de is_wire_only car absent du .h
|
||||||
m->faces = (Face*)malloc(sizeof(Face) * m->num_faces);
|
|
||||||
fread(m->verts, sizeof(Vector3), m->num_verts, f);
|
m->verts = (Vector3*)malloc(sizeof(Vector3) * m->num_verts);
|
||||||
fread(m->v_normals, sizeof(Vector3), m->num_verts, f);
|
m->v_normals = (Vector3*)malloc(sizeof(Vector3) * m->num_verts);
|
||||||
fread(m->faces, sizeof(Face), m->num_faces, f);
|
m->faces = (Face*)malloc(sizeof(Face) * m->num_faces);
|
||||||
fclose(f);
|
|
||||||
return m;
|
fread(m->verts, sizeof(Vector3), m->num_verts, f);
|
||||||
|
fread(m->v_normals, sizeof(Vector3), m->num_verts, f);
|
||||||
|
fread(m->faces, sizeof(Face), m->num_faces, f);
|
||||||
|
fclose(f);
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_mesh(Mesh *m) {
|
void free_mesh(Mesh *m) {
|
||||||
if (!m) return;
|
if (!m) return;
|
||||||
if (m->verts) free(m->verts);
|
if (m->verts) free(m->verts);
|
||||||
if (m->faces) free(m->faces);
|
if (m->faces) free(m->faces);
|
||||||
if (m->v_normals) free(m->v_normals);
|
if (m->v_normals) free(m->v_normals);
|
||||||
free(m);
|
free(m);
|
||||||
}
|
|
||||||
|
|
||||||
void render_scene(Mesh *m, Matrix3 *rot, int global_mode) {
|
|
||||||
for (int i = 0; i < m->num_verts; i++) {
|
|
||||||
Vector3 *v = &m->verts[i]; Vector3 *n = &m->v_normals[i];
|
|
||||||
fixed nz = f_mul(n->x, rot->m[0][2]) + f_mul(n->y, rot->m[1][2]) + f_mul(n->z, rot->m[2][2]);
|
|
||||||
int intensity = f_to_int(nz * 15); if (intensity < 0) intensity = 0;
|
|
||||||
v_cache[i].z = v->z; v_cache[i].intensity = intensity;
|
|
||||||
v_cache[i].x = 160 + f_to_int(f_div(v->x << 8, v->z));
|
|
||||||
v_cache[i].y = 100 - f_to_int(f_div(v->y << 8, v->z));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < m->num_faces; i++) {
|
|
||||||
Face *f = &m->faces[i]; Point2D *p1 = &v_cache[f->a], *p2 = &v_cache[f->b], *p3 = &v_cache[f->c];
|
|
||||||
int back = (p2->x - p1->x) * (p3->y - p1->y) - (p2->y - p1->y) * (p3->x - p1->x);
|
|
||||||
|
|
||||||
if (global_mode == MODE_WIRE) {
|
|
||||||
draw_line_z(p1, p2, f->color, 0); draw_line_z(p2, p3, f->color, 0); draw_line_z(p3, p1, f->color, 0);
|
|
||||||
} else {
|
|
||||||
if (back < 0) {
|
|
||||||
if (f->force_wire || global_mode == MODE_HIDDEN) {
|
|
||||||
fill_triangle_zonly(p1, p2, p3); // Pas de couleur, juste Z
|
|
||||||
draw_line_z(p1, p2, f->color, 1); draw_line_z(p2, p3, f->color, 1);
|
|
||||||
} else {
|
|
||||||
fill_triangle_gouraud(p1, p2, p3, f->color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,57 +1,80 @@
|
||||||
#define GRAPH_H
|
#include "defines.h"
|
||||||
|
|
||||||
RGB my_palette[16] = {
|
RGB my_palette[16] = {
|
||||||
{0, 0, 0}, // 0: Noir
|
{0, 0, 0}, // 0: Noir
|
||||||
{63, 0, 0}, // 1: Rouge vif
|
{63, 0, 0}, // 1: Rouge vif
|
||||||
{0, 63, 0}, // 2: Vert vif
|
{0, 63, 0}, // 2: Vert vif
|
||||||
{0, 0, 63}, // 3: Bleu vif
|
{0, 0, 63}, // 3: Bleu vif
|
||||||
{63, 63, 0}, // 4: Jaune
|
{63, 63, 0}, // 4: Jaune
|
||||||
{63, 0, 63}, // 5: Magenta
|
{63, 0, 63}, // 5: Magenta
|
||||||
{0, 63, 63}, // 6: Cyan
|
{0, 63, 63}, // 6: Cyan
|
||||||
{63, 63, 63},// 7: Blanc
|
{63, 63, 63}, // 7: Blanc
|
||||||
{31, 0, 0}, // 8: Rouge sombre
|
{31, 0, 0}, // 8: Rouge sombre
|
||||||
{0, 31, 0}, // 9: Vert sombre
|
{0, 31, 0}, // 9: Vert sombre
|
||||||
{0, 0, 31}, // 10: Bleu sombre
|
{0, 0, 31}, // 10: Bleu sombre
|
||||||
{31, 31, 31},// 11: Gris
|
{31, 31, 31}, // 11: Gris
|
||||||
{63, 31, 0}, // 12: Orange
|
{63, 31, 0}, // 12: Orange
|
||||||
{31, 63, 0}, // 13: Citron vert
|
{31, 63, 0}, // 13: Citron vert
|
||||||
{40, 20, 0}, // 14: Marron
|
{40, 20, 0}, // 14: Marron
|
||||||
{20, 20, 40} // 15: Bleu nuit
|
{20, 20, 40} // 15: Bleu nuit
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
uint8_t *backbuffer = NULL;
|
||||||
uint8_t *screen;
|
uint16_t *zbuffer = NULL;
|
||||||
uint8_t *backbuffer;
|
uint8_t *vga = (uint8_t *)0xA0000;
|
||||||
uint16_t *zbuffer;
|
|
||||||
} VideoSystem;
|
|
||||||
|
|
||||||
VideoSystem vid;
|
void set_mode(int mode);
|
||||||
|
#pragma aux set_mode = "int 0x10" parm [ax];
|
||||||
|
|
||||||
void init_vga() {
|
void reset_mode(int mode);
|
||||||
// Mode 13h via interruption BIOS
|
#pragma aux reset_mode = "int 0x10" parm [ax];
|
||||||
union { struct { uint8_t al, ah; } b; uint16_t w; } r;
|
|
||||||
r.b.al = 0x13; r.b.ah = 0x00;
|
|
||||||
// Utilisation de l'inline assembly Watcom
|
|
||||||
#pragma aux set_mode = "int 0x10" parm [ax];
|
|
||||||
set_mode(0x0013);
|
|
||||||
|
|
||||||
vid.screen = (uint8_t *)0xA0000;
|
|
||||||
vid.backbuffer = (uint8_t *)malloc(64000);
|
|
||||||
vid.zbuffer = (uint16_t *)malloc(64000 * sizeof(uint16_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear_buffers(uint8_t color) {
|
void clear_buffers(uint8_t color) {
|
||||||
memset(vid.backbuffer, color, 64000);
|
memset(backbuffer, color, 64000);
|
||||||
memset(vid.zbuffer, 0xFF, 64000 * sizeof(uint16_t)); // Z-buffer à l'infini
|
memset(zbuffer, 0xFF, 64000 * sizeof(uint16_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
void flip() {
|
void flip() {
|
||||||
memcpy(vid.screen, vid.backbuffer, 64000);
|
memcpy(vga, backbuffer, 64000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void close_vga() {
|
void close_vga() {
|
||||||
#pragma aux reset_mode = "int 0x10" parm [ax];
|
reset_mode(0x0003); // Retour au mode texte
|
||||||
reset_mode(0x0003);
|
if (backbuffer) free(backbuffer);
|
||||||
free(vid.backbuffer);
|
if (zbuffer) free(zbuffer);
|
||||||
free(vid.zbuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prend 16 couleurs RGB (0-63) et remplit les 256 entrées du DAC
|
||||||
|
void setup_vga_palette(RGB *base_colors) {
|
||||||
|
int i, c;
|
||||||
|
// Port 0x3C8 : Index de départ (0)
|
||||||
|
outp(0x3C8, 0);
|
||||||
|
|
||||||
|
for (c = 0; c < 16; c++) {
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
// Interpolation linéaire vers le noir (0,0,0)
|
||||||
|
// On utilise l'arithmétique entière : (color * intensity) / 15
|
||||||
|
uint8_t r = (uint8_t)((base_colors[c].r * i) / 15);
|
||||||
|
uint8_t g = (uint8_t)((base_colors[c].g * i) / 15);
|
||||||
|
uint8_t b = (uint8_t)((base_colors[c].b * i) / 15);
|
||||||
|
|
||||||
|
// Port 0x3C9 : Envoi des composantes R, G, B
|
||||||
|
outp(0x3C9, r);
|
||||||
|
outp(0x3C9, g);
|
||||||
|
outp(0x3C9, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_vga() {
|
||||||
|
// On passe en mode 13h (320x200x256)
|
||||||
|
set_mode(0x0013);
|
||||||
|
|
||||||
|
// Allocations
|
||||||
|
backbuffer = (uint8_t *)malloc(64000);
|
||||||
|
zbuffer = (uint16_t *)malloc(64000 * sizeof(uint16_t));
|
||||||
|
|
||||||
|
// Note : Pense à ajouter ici une boucle pour envoyer my_palette
|
||||||
|
// aux ports 0x3C8/0x3C9 si tu veux tes couleurs personnalisées.
|
||||||
|
// setup_vga_palette(my_palette);
|
||||||
|
}
|
||||||
|
|
@ -1,42 +1,101 @@
|
||||||
#define RASTER_H
|
#include "defines.h"
|
||||||
|
|
||||||
uint8_t *backbuffer, *vga = (uint8_t*)0xA0000;
|
|
||||||
uint16_t *zbuffer;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Prototypes pour le compilateur C
|
// Prototypes pour le compilateur C
|
||||||
extern void scanline_gouraud_asm(int width, uint8_t *dest, uint16_t *zbuf, int z, int dz_step, int intensity, int di_step);
|
// extern void scanline_gouraud_asm(int width, uint8_t *dest, uint16_t *zbuf, int z, int dz_step, int intensity, int di_step);
|
||||||
extern void scanline_zonly_asm(int width, uint16_t *zbuf, int z, int dz_step);
|
|
||||||
|
|
||||||
|
extern void scanline_zonly_asm(int width, uint16_t *zbuf, int z, int dz_step);
|
||||||
|
/*
|
||||||
#pragma aux scanline_gouraud_asm = \
|
#pragma aux scanline_gouraud_asm = \
|
||||||
"test ecx, ecx" "jz d" \
|
"test ecx, ecx" \
|
||||||
"l:" "mov ax, dx" "cmp ax, [esi]" "jae s" "mov [esi], ax" "mov [edi], bh" \
|
"jz done" \
|
||||||
"s:" "add edx, ebp" "add ebx, eax" "inc edi" "add esi, 2" "dec ecx" "jnz l" "d:" \
|
"loop_l:" \
|
||||||
parm [ecx] [edi] [esi] [edx] [ebp] [ebx] [eax] modify [ax ecx edi esi edx ebx];
|
"mov eax, edx" \
|
||||||
|
"shr eax, 16" /* EAX = Z entier * / \
|
||||||
|
"cmp ax, [esi]" \
|
||||||
|
"jae skip_p" \
|
||||||
|
"mov [esi], ax" /* Z-Write * / \
|
||||||
|
"mov eax, ebx" \
|
||||||
|
"shr eax, 8" \
|
||||||
|
"mov [edi], al" /* Color-Write * / \
|
||||||
|
"skip_p:" \
|
||||||
|
"add edx, ebp" /* + dz_step (EBP) * / \
|
||||||
|
"add ebx, [esp+4]" /* + di_step (LU SUR LA PILE) * / \
|
||||||
|
"inc edi" \
|
||||||
|
"add esi, 2" \
|
||||||
|
"dec ecx" \
|
||||||
|
"jnz loop_l" \
|
||||||
|
"done:" \
|
||||||
|
parm [ecx] [edi] [esi] [edx] [ebp] [ebx] \
|
||||||
|
modify [eax ecx edi esi edx ebx];
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma aux scanline_zonly_asm = \
|
#pragma aux scanline_zonly_asm = \
|
||||||
"test ecx, ecx" "jz d" \
|
"test ecx, ecx" \
|
||||||
"l:" "mov ax, dx" "cmp ax, [esi]" "jae s" "mov [esi], ax" \
|
"jz done_z" \
|
||||||
"s:" "add edx, ebx" "add esi, 2" "dec ecx" "jnz l" "d:" \
|
"loop_z:" \
|
||||||
parm [ecx] [esi] [edx] [ebx] modify [ax ecx esi edx];
|
"mov eax, edx" \
|
||||||
|
"shr eax, 16" \
|
||||||
|
"cmp ax, [esi]" \
|
||||||
|
"jae skip_z" \
|
||||||
|
"mov [esi], ax" \
|
||||||
|
"skip_z:" \
|
||||||
|
"add edx, ebx" \
|
||||||
|
"add esi, 2" \
|
||||||
|
"dec ecx" \
|
||||||
|
"jnz loop_z" \
|
||||||
|
"done_z:" \
|
||||||
|
parm [ecx] [esi] [edx] [ebx] \
|
||||||
|
modify [eax ecx esi edx];
|
||||||
|
|
||||||
|
|
||||||
|
#include "defines.h"
|
||||||
|
|
||||||
|
// Ajout de base_color en paramètre
|
||||||
|
void scanline_gouraud_c(int width, uint8_t *dest, uint16_t *zbuf, int z, int dz_step, int intensity, int di_step, uint8_t base_color) {
|
||||||
|
int i;
|
||||||
|
uint8_t shade;
|
||||||
|
|
||||||
|
// On calcule le décalage de bloc (ex: couleur 1 commence à l'index 16)
|
||||||
|
uint8_t color_offset = (uint8_t)(base_color << 4);
|
||||||
|
|
||||||
|
for (i = 0; i < width; i++) {
|
||||||
|
uint16_t zv = (uint16_t)(z >> 16);
|
||||||
|
if (zv < zbuf[i]) {
|
||||||
|
zbuf[i] = zv;
|
||||||
|
// On extrait l'intensité (on travaille en 16.16 pour la précision)
|
||||||
|
shade = (uint8_t)(intensity >> 16);
|
||||||
|
if (shade > 15) shade = 15; // Sécurité pour ne pas déborder sur la couleur suivante
|
||||||
|
|
||||||
|
dest[i] = color_offset + shade;
|
||||||
|
}
|
||||||
|
z += dz_step;
|
||||||
|
intensity += di_step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void draw_line_z(Point2D *p1, Point2D *p2, uint8_t col, int z_test) {
|
void draw_line_z(Point2D *p1, Point2D *p2, uint8_t col, int z_test) {
|
||||||
int dx = abs(p2->x - p1->x), dy = abs(p2->y - p1->y);
|
int dx, dy, sx, sy, err, steps, x, y, e2;
|
||||||
int sx = (p1->x < p2->x) ? 1 : -1, sy = (p1->y < p2->y) ? 1 : -1;
|
fixed z_step, cz;
|
||||||
int err = dx - dy, steps = (dx > dy) ? dx : dy;
|
uint16_t zv;
|
||||||
fixed z_step = (steps > 0) ? (p2->z - p1->z) / steps : 0, cz = p1->z;
|
|
||||||
int x = p1->x, y = p1->y;
|
dx = abs(p2->x - p1->x); dy = abs(p2->y - p1->y);
|
||||||
|
sx = (p1->x < p2->x) ? 1 : -1; sy = (p1->y < p2->y) ? 1 : -1;
|
||||||
|
err = dx - dy;
|
||||||
|
steps = (dx > dy) ? dx : dy;
|
||||||
|
z_step = (steps > 0) ? (p2->z - p1->z) / steps : 0;
|
||||||
|
cz = p1->z;
|
||||||
|
x = p1->x; y = p1->y;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (x >= 0 && x < 320 && y >= 0 && y < 200) {
|
if (x >= 0 && x < 320 && y >= 0 && y < 200) {
|
||||||
uint16_t zv = (uint16_t)f_to_int(cz);
|
zv = (uint16_t)f_to_int(cz);
|
||||||
if (!z_test || zv <= zbuffer[y * 320 + x]) {
|
if (!z_test || zv <= zbuffer[y * 320 + x]) {
|
||||||
backbuffer[y * 320 + x] = col;
|
backbuffer[y * 320 + x] = col;
|
||||||
if (z_test) zbuffer[y * 320 + x] = zv;
|
if (z_test) zbuffer[y * 320 + x] = zv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (x == p2->x && y == p2->y) break;
|
if (x == p2->x && y == p2->y) break;
|
||||||
int e2 = 2 * err;
|
e2 = 2 * err;
|
||||||
if (e2 > -dy) { err -= dy; x += sx; }
|
if (e2 > -dy) { err -= dy; x += sx; }
|
||||||
if (e2 < dx) { err += dx; y += sy; }
|
if (e2 < dx) { err += dx; y += sy; }
|
||||||
cz += z_step;
|
cz += z_step;
|
||||||
|
|
@ -48,23 +107,27 @@ void swap_pt(Point2D **a, Point2D **b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void fill_triangle_gouraud(Point2D *p1, Point2D *p2, Point2D *p3, uint8_t base_color) {
|
void fill_triangle_gouraud(Point2D *p1, Point2D *p2, Point2D *p3, uint8_t base_color) {
|
||||||
|
int y, total_height, width, start_x, end_x, dz_step, intensity_1, intensity_2, di_step, clip_x, w, start_z, start_i, second_half;
|
||||||
|
fixed dx13, dz13, di13, xA, zA, iA, xB, zB, iB, dx12, dz12, di12, dx23, dz23, di23, cx1, cz1, ci1, cx2, cz2, ci2, tx, tz, ti;
|
||||||
|
uint8_t *dest;
|
||||||
|
uint16_t *zbuf;
|
||||||
|
|
||||||
if (p1->y > p2->y) swap_pt(&p1, &p2);
|
if (p1->y > p2->y) swap_pt(&p1, &p2);
|
||||||
if (p1->y > p3->y) swap_pt(&p1, &p3);
|
if (p1->y > p3->y) swap_pt(&p1, &p3);
|
||||||
if (p2->y > p3->y) swap_pt(&p2, &p3);
|
if (p2->y > p3->y) swap_pt(&p2, &p3);
|
||||||
|
|
||||||
int total_height = p3->y - p1->y;
|
total_height = p3->y - p1->y;
|
||||||
if (total_height == 0) return;
|
if (total_height == 0) return;
|
||||||
|
|
||||||
// Incréments pour l'arête principale (p1 -> p3)
|
dx13 = ((p3->x - p1->x) << 16) / total_height;
|
||||||
fixed dx13 = ((p3->x - p1->x) << 16) / total_height;
|
dz13 = (p3->z - p1->z) / total_height;
|
||||||
fixed dz13 = (p3->z - p1->z) / total_height;
|
di13 = ((p3->intensity - p1->intensity) << 16) / total_height;
|
||||||
fixed di13 = ((p3->intensity - p1->intensity) << 16) / total_height;
|
|
||||||
|
|
||||||
fixed xA = int_to_f(p1->x), zA = p1->z, iA = int_to_f(p1->intensity);
|
xA = int_to_f(p1->x); zA = p1->z; iA = int_to_f(p1->intensity);
|
||||||
fixed xB = xA, zB = zA, iB = iA;
|
xB = xA; zB = zA; iB = iA;
|
||||||
|
|
||||||
fixed dx12 = 0, dz12 = 0, di12 = 0;
|
dx12 = 0; dz12 = 0; di12 = 0;
|
||||||
fixed dx23 = 0, dz23 = 0, di23 = 0;
|
dx23 = 0; dz23 = 0; di23 = 0;
|
||||||
|
|
||||||
if (p2->y > p1->y) {
|
if (p2->y > p1->y) {
|
||||||
dx12 = ((p2->x - p1->x) << 16) / (p2->y - p1->y);
|
dx12 = ((p2->x - p1->x) << 16) / (p2->y - p1->y);
|
||||||
|
|
@ -77,37 +140,50 @@ void fill_triangle_gouraud(Point2D *p1, Point2D *p2, Point2D *p3, uint8_t base_c
|
||||||
di23 = ((p3->intensity - p2->intensity) << 16) / (p3->y - p2->y);
|
di23 = ((p3->intensity - p2->intensity) << 16) / (p3->y - p2->y);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int y = p1->y; y < p3->y; y++) {
|
for (y = p1->y; y < p3->y; y++) {
|
||||||
int second_half = (y >= p2->y);
|
second_half = (y >= p2->y);
|
||||||
fixed cx1 = xA, cz1 = zA, ci1 = iA;
|
cx1 = xA; cz1 = zA; ci1 = iA;
|
||||||
fixed cx2 = xB, cz2 = zB, ci2 = iB;
|
cx2 = xB; cz2 = zB; ci2 = iB;
|
||||||
|
|
||||||
if (cx1 > cx2) { // Tri horizontal pour tracer de gauche à droite
|
if (cx1 > cx2) {
|
||||||
fixed tx = cx1; cx1 = cx2; cx2 = tx;
|
tx = cx1; cx1 = cx2; cx2 = tx;
|
||||||
fixed tz = cz1; cz1 = cz2; cz2 = tz;
|
tz = cz1; cz1 = cz2; cz2 = tz;
|
||||||
fixed ti = ci1; ci1 = ci2; ci2 = ti;
|
ti = ci1; ci1 = ci2; ci2 = ti;
|
||||||
}
|
}
|
||||||
|
|
||||||
int start_x = f_to_int(cx1), end_x = f_to_int(cx2);
|
start_x = f_to_int(cx1); end_x = f_to_int(cx2);
|
||||||
int width = end_x - start_x;
|
width = end_x - start_x;
|
||||||
|
|
||||||
if (y >= 0 && y < 200 && width > 0) {
|
if (y >= 0 && y < 200 && width > 0) {
|
||||||
int dz_step = (cz2 - cz1) / width;
|
dz_step = (cz2 - cz1) / width;
|
||||||
int intensity_1 = f_to_int(ci1), intensity_2 = f_to_int(ci2);
|
// intensity_1 = f_to_int(ci1);
|
||||||
int di_step = ((intensity_2 - intensity_1) << 8) / width;
|
// intensity_2 = f_to_int(ci2);
|
||||||
|
|
||||||
|
intensity_1 = p1->intensity;
|
||||||
|
intensity_2 = p2->intensity;
|
||||||
|
|
||||||
|
// di_step = ((intensity_2 - intensity_1) << 8) / width;
|
||||||
|
di_step = (ci2 - ci1) / width;
|
||||||
|
|
||||||
|
clip_x = start_x < 0 ? 0 : start_x;
|
||||||
|
|
||||||
int clip_x = start_x < 0 ? 0 : start_x;
|
|
||||||
if (clip_x < 320) {
|
if (clip_x < 320) {
|
||||||
int w = width - (clip_x - start_x);
|
w = width - (clip_x - start_x);
|
||||||
if (clip_x + w > 320) w = 320 - clip_x;
|
if (clip_x + w > 320) w = 320 - clip_x;
|
||||||
|
|
||||||
if (w > 0) {
|
if (w > 0) {
|
||||||
int start_z = cz1 + (clip_x - start_x) * dz_step;
|
start_z = cz1 + (clip_x - start_x) * dz_step;
|
||||||
int start_i = ((base_color + intensity_1) << 8) + (clip_x - start_x) * di_step;
|
/*start_i = ((base_color + intensity_1) << 8) + (clip_x - start_x) * di_step;
|
||||||
|
dest = backbuffer + (y * 320) + clip_x;
|
||||||
|
zbuf = zbuffer + (y * 320) + clip_x;
|
||||||
|
//scanline_gouraud_asm(w, dest, zbuf, start_z, dz_step, start_i, di_step);
|
||||||
|
scanline_gouraud_c(w, dest, zbuf, start_z, dz_step, start_i, di_step);*/
|
||||||
|
|
||||||
uint8_t *dest = vid.backbuffer + (y * 320) + clip_x;
|
start_i = ci1 + (clip_x - start_x) * di_step;
|
||||||
uint16_t *zbuf = vid.zbuffer + (y * 320) + clip_x;
|
|
||||||
scanline_gouraud_asm(w, dest, zbuf, start_z, dz_step, start_i, di_step);
|
dest = backbuffer + (y * 320) + clip_x;
|
||||||
|
zbuf = zbuffer + (y * 320) + clip_x;
|
||||||
|
scanline_gouraud_c(w, dest, zbuf, start_z, dz_step, start_i, di_step, base_color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -123,20 +199,24 @@ void fill_triangle_gouraud(Point2D *p1, Point2D *p2, Point2D *p3, uint8_t base_c
|
||||||
}
|
}
|
||||||
|
|
||||||
void fill_triangle_zonly(Point2D *p1, Point2D *p2, Point2D *p3) {
|
void fill_triangle_zonly(Point2D *p1, Point2D *p2, Point2D *p3) {
|
||||||
|
int y, total_height, width, start_x, end_x, dz_step, clip_x, w, start_z, second_half;
|
||||||
|
fixed dx13, dz13, xA, zA, xB, zB, dx12, dz12, dx23, dz23, cx1, cz1, cx2, cz2, tx, tz;
|
||||||
|
uint16_t *zbuf;
|
||||||
|
|
||||||
if (p1->y > p2->y) swap_pt(&p1, &p2);
|
if (p1->y > p2->y) swap_pt(&p1, &p2);
|
||||||
if (p1->y > p3->y) swap_pt(&p1, &p3);
|
if (p1->y > p3->y) swap_pt(&p1, &p3);
|
||||||
if (p2->y > p3->y) swap_pt(&p2, &p3);
|
if (p2->y > p3->y) swap_pt(&p2, &p3);
|
||||||
|
|
||||||
int total_height = p3->y - p1->y;
|
total_height = p3->y - p1->y;
|
||||||
if (total_height == 0) return;
|
if (total_height == 0) return;
|
||||||
|
|
||||||
fixed dx13 = ((p3->x - p1->x) << 16) / total_height;
|
dx13 = ((p3->x - p1->x) << 16) / total_height;
|
||||||
fixed dz13 = (p3->z - p1->z) / total_height;
|
dz13 = (p3->z - p1->z) / total_height;
|
||||||
|
|
||||||
fixed xA = int_to_f(p1->x), zA = p1->z;
|
xA = int_to_f(p1->x); zA = p1->z;
|
||||||
fixed xB = xA, zB = zA;
|
xB = xA; zB = zA;
|
||||||
|
|
||||||
fixed dx12 = 0, dz12 = 0, dx23 = 0, dz23 = 0;
|
dx12 = 0; dz12 = 0; dx23 = 0; dz23 = 0;
|
||||||
|
|
||||||
if (p2->y > p1->y) {
|
if (p2->y > p1->y) {
|
||||||
dx12 = ((p2->x - p1->x) << 16) / (p2->y - p1->y);
|
dx12 = ((p2->x - p1->x) << 16) / (p2->y - p1->y);
|
||||||
|
|
@ -147,29 +227,29 @@ void fill_triangle_zonly(Point2D *p1, Point2D *p2, Point2D *p3) {
|
||||||
dz23 = (p3->z - p2->z) / (p3->y - p2->y);
|
dz23 = (p3->z - p2->z) / (p3->y - p2->y);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int y = p1->y; y < p3->y; y++) {
|
for (y = p1->y; y < p3->y; y++) {
|
||||||
int second_half = (y >= p2->y);
|
second_half = (y >= p2->y);
|
||||||
fixed cx1 = xA, cz1 = zA, cx2 = xB, cz2 = zB;
|
cx1 = xA; cz1 = zA; cx2 = xB; cz2 = zB;
|
||||||
|
|
||||||
if (cx1 > cx2) {
|
if (cx1 > cx2) {
|
||||||
fixed tx = cx1; cx1 = cx2; cx2 = tx;
|
tx = cx1; cx1 = cx2; cx2 = tx;
|
||||||
fixed tz = cz1; cz1 = cz2; cz2 = tz;
|
tz = cz1; cz1 = cz2; cz2 = tz;
|
||||||
}
|
}
|
||||||
|
|
||||||
int start_x = f_to_int(cx1), end_x = f_to_int(cx2);
|
start_x = f_to_int(cx1); end_x = f_to_int(cx2);
|
||||||
int width = end_x - start_x;
|
width = end_x - start_x;
|
||||||
|
|
||||||
if (y >= 0 && y < 200 && width > 0) {
|
if (y >= 0 && y < 200 && width > 0) {
|
||||||
int dz_step = (cz2 - cz1) / width;
|
dz_step = (cz2 - cz1) / width;
|
||||||
int clip_x = start_x < 0 ? 0 : start_x;
|
clip_x = start_x < 0 ? 0 : start_x;
|
||||||
|
|
||||||
if (clip_x < 320) {
|
if (clip_x < 320) {
|
||||||
int w = width - (clip_x - start_x);
|
w = width - (clip_x - start_x);
|
||||||
if (clip_x + w > 320) w = 320 - clip_x;
|
if (clip_x + w > 320) w = 320 - clip_x;
|
||||||
|
|
||||||
if (w > 0) {
|
if (w > 0) {
|
||||||
int start_z = cz1 + (clip_x - start_x) * dz_step;
|
start_z = cz1 + (clip_x - start_x) * dz_step;
|
||||||
uint16_t *zbuf = vid.zbuffer + (y * 320) + clip_x;
|
zbuf = zbuffer + (y * 320) + clip_x;
|
||||||
scanline_zonly_asm(w, zbuf, start_z, dz_step);
|
scanline_zonly_asm(w, zbuf, start_z, dz_step);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -183,4 +263,4 @@ void fill_triangle_zonly(Point2D *p1, Point2D *p2, Point2D *p3) {
|
||||||
xB += dx23; zB += dz23;
|
xB += dx23; zB += dz23;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue