From 7d08a2ffefa6b353fdceba059f0a8965562d71dd Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Fri, 18 Jun 2021 11:48:50 +0200 Subject: [PATCH] initial-with-some-changes --- .gitignore | 13 + CMakeLists - Kikoudx.txt | 86 ++ CMakeLists.txt | 61 + LEPHE.md | 45 + assets-cg/example.png | Bin 0 -> 3816 bytes assets-cg/fxconv-metadata.txt | 3 + assets-cg/icon-sel.png | Bin 0 -> 8388 bytes assets-cg/icon-uns.png | Bin 0 -> 4629 bytes assets-fx/.DS_Store | Bin 0 -> 6148 bytes assets-fx/example.png | Bin 0 -> 3569 bytes assets-fx/fxconv-metadata.txt | 7 + assets-fx/icon.png | Bin 0 -> 4070 bytes assets-fx/img/.DS_Store | Bin 0 -> 6148 bytes assets-fx/img/brique base.png | Bin 0 -> 318 bytes assets-fx/img/brique.png | Bin 0 -> 302 bytes assets-fx/img/epouvantail masque.png | Bin 0 -> 268 bytes assets-fx/img/epouvantail.png | Bin 0 -> 302 bytes assets-fx/img/fenetre simple.png | Bin 0 -> 172 bytes assets-fx/img/forgeron.png | Bin 0 -> 534 bytes assets-fx/img/fxconv-metadata.txt | 3 + assets-fx/img/haie.png | Bin 0 -> 176 bytes assets-fx/img/herbe.png | Bin 0 -> 211 bytes assets-fx/img/horloge.png | Bin 0 -> 387 bytes assets-fx/img/mask_forgeron.png | Bin 0 -> 315 bytes assets-fx/img/moulin mur.png | Bin 0 -> 361 bytes assets-fx/img/moulin pale.png | Bin 0 -> 314 bytes assets-fx/img/mur_int_maison.png | Bin 0 -> 242 bytes assets-fx/img/paille dessus.png | Bin 0 -> 182 bytes assets-fx/img/paille.png | Bin 0 -> 266 bytes assets-fx/img/panneau.png | Bin 0 -> 234 bytes assets-fx/img/pierre eglise.png | Bin 0 -> 212 bytes assets-fx/img/pierre eglise2.png | Bin 0 -> 214 bytes assets-fx/img/planche bois.png | Bin 0 -> 320 bytes assets-fx/img/porte eglise.png | Bin 0 -> 513 bytes assets-fx/img/porte simple.png | Bin 0 -> 271 bytes assets-fx/img/table.png | Bin 0 -> 225 bytes assets-fx/img/toit tuile.png | Bin 0 -> 416 bytes assets-fx/img/windmill.png | Bin 0 -> 531 bytes assets-fx/img/windmill2.png | Bin 0 -> 513 bytes src/Scene_Title.cpp | 87 ++ src/Scene_Title.hpp | 122 ++ src/camera.cpp | 196 +++ src/camera.hpp | 123 ++ src/game.cpp | 33 + src/game.hpp | 93 ++ src/main.cpp | 39 + src/main.hpp | 9 + src/map.cpp | 1427 ++++++++++++++++++++ src/player.cpp | 49 + src/player.hpp | 52 + src/scene_map.cpp | 849 ++++++++++++ src/scene_map.hpp | 101 ++ src/windmill.cpp | 1788 ++++++++++++++++++++++++++ src/windmill.hpp | 257 ++++ 54 files changed, 5443 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists - Kikoudx.txt create mode 100644 CMakeLists.txt create mode 100644 LEPHE.md create mode 100644 assets-cg/example.png create mode 100644 assets-cg/fxconv-metadata.txt create mode 100644 assets-cg/icon-sel.png create mode 100644 assets-cg/icon-uns.png create mode 100644 assets-fx/.DS_Store create mode 100644 assets-fx/example.png create mode 100644 assets-fx/fxconv-metadata.txt create mode 100644 assets-fx/icon.png create mode 100644 assets-fx/img/.DS_Store create mode 100644 assets-fx/img/brique base.png create mode 100644 assets-fx/img/brique.png create mode 100644 assets-fx/img/epouvantail masque.png create mode 100644 assets-fx/img/epouvantail.png create mode 100644 assets-fx/img/fenetre simple.png create mode 100644 assets-fx/img/forgeron.png create mode 100644 assets-fx/img/fxconv-metadata.txt create mode 100644 assets-fx/img/haie.png create mode 100644 assets-fx/img/herbe.png create mode 100644 assets-fx/img/horloge.png create mode 100644 assets-fx/img/mask_forgeron.png create mode 100644 assets-fx/img/moulin mur.png create mode 100644 assets-fx/img/moulin pale.png create mode 100644 assets-fx/img/mur_int_maison.png create mode 100644 assets-fx/img/paille dessus.png create mode 100644 assets-fx/img/paille.png create mode 100644 assets-fx/img/panneau.png create mode 100644 assets-fx/img/pierre eglise.png create mode 100644 assets-fx/img/pierre eglise2.png create mode 100644 assets-fx/img/planche bois.png create mode 100644 assets-fx/img/porte eglise.png create mode 100644 assets-fx/img/porte simple.png create mode 100644 assets-fx/img/table.png create mode 100644 assets-fx/img/toit tuile.png create mode 100644 assets-fx/img/windmill.png create mode 100644 assets-fx/img/windmill2.png create mode 100644 src/Scene_Title.cpp create mode 100644 src/Scene_Title.hpp create mode 100644 src/camera.cpp create mode 100644 src/camera.hpp create mode 100644 src/game.cpp create mode 100644 src/game.hpp create mode 100644 src/main.cpp create mode 100644 src/main.hpp create mode 100644 src/map.cpp create mode 100644 src/player.cpp create mode 100644 src/player.hpp create mode 100644 src/scene_map.cpp create mode 100644 src/scene_map.hpp create mode 100644 src/windmill.cpp create mode 100644 src/windmill.hpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2c4f84b --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +# Build files +/build-fx +/build-cg +/*.g1a +/*.g3a + +# Python bytecode + __pycache__/ + +# Common IDE files +*.sublime-project +*.sublime-workspace +.vscode diff --git a/CMakeLists - Kikoudx.txt b/CMakeLists - Kikoudx.txt new file mode 100644 index 0000000..2bfe772 --- /dev/null +++ b/CMakeLists - Kikoudx.txt @@ -0,0 +1,86 @@ +# Configure with [fxsdk build-fx] or [fxsdk build-cg], which provide the + # toolchain file and module path of the fxSDK + + cmake_minimum_required(VERSION 3.18) + # replace this with your project's name + project(Windmill) + + include(GenerateG1A) + include(GenerateG3A) + include(Fxconv) + find_package(Gint 2.1 REQUIRED) + + # include directories, put your .h files in those folders + include_directories(include) + + # source files + set(SOURCES + src/main.cpp + + # ... + ) + # shared assets + set(ASSETS + # ... + ) + # fx-9860G-only assets (monochrome) + set(ASSETS_fx + assets-fx/example.png + assets-fx/img/windmill.png + # ... + ) + # fx-CG-50-only assets (polychrome) + set(ASSETS_cg + assets-cg/example.png + # ... + ) + + # Compile flags + set(FLAGS + # C standard, other values: c89, c99 + -std=c11 + + # general warnings + -Wall -Wextra -pedantic + + # enable this flag to stop compilation on warnings + #-Werror + + # specific warnings + # variable shadowing + -Wshadow + # switch/case safety + -Wswitch-default -Wswitch-enum + # unreachable code, bad 99% of the time + -Wunreachable-code + # prototypes warnings + -Wstrict-prototypes -Wmissing-prototypes + # function declaration + -Werror-implicit-function-declaration + + # optimisation level + # -Os: like -O2 without space-expensive optimizations + # -O2: good speed/size tradeoff + # -O3: gotta go fast + -Os + ) + + fxconv_declare_assets(${ASSETS} ${ASSETS_fx} ${ASSETS_cg} WITH_METADATA) + + add_executable(${PROJECT_NAME} ${SOURCES} ${ASSETS} ${ASSETS_${FXSDK_PLATFORM}}) + target_compile_options(${PROJECT_NAME} PRIVATE ${FLAGS}) + target_link_libraries(${PROJECT_NAME} Gint::Gint) + + if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G) + generate_g1a( + TARGET ${PROJECT_NAME} + OUTPUT "${PROJECT_NAME}.g1a" + NAME "${PROJECT_NAME}" + ICON assets-fx/icon.png) + elseif("${FXSDK_PLATFORM_LONG}" STREQUAL fxCG50) + generate_g3a( + TARGET ${PROJECT_NAME} + OUTPUT "${PROJECT_NAME}.g3a" + NAME "${PROJECT_NAME}" + ICONS assets-cg/icon-uns.png assets-cg/icon-sel.png) + endif() \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..2308fd5 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,61 @@ +# Configure with [fxsdk build-fx] or [fxsdk build-cg], which provide the +# toolchain file and module path of the fxSDK + +cmake_minimum_required(VERSION 3.18) +project(Windmill) + +include(GenerateG1A) +include(GenerateG3A) +include(Fxconv) +find_package(Gint 2.1 REQUIRED) + +set(SOURCES + src/main.cpp + src/windmill.cpp + src/map.cpp + src/scene_map.cpp + src/camera.cpp + src/game.cpp + src/player.cpp + # ... +) +# Shared assets, fx-9860G-only assets and fx-CG-50-only assets +set(ASSETS + # ... +) +set(ASSETS_fx + assets-fx/example.png + assets-fx/img/windmill.png + # ... +) +set(ASSETS_cg + assets-cg/example.png + # ... +) + +fxconv_declare_assets(${ASSETS} ${ASSETS_fx} ${ASSETS_cg} WITH_METADATA) + +set_source_files_properties(src/map.cpp PROPERTIES + COMPILE_OPTIONS "-Wp,-w;-Wno-missing-field-initializers") + +add_executable(${PROJECT_NAME} ${SOURCES} ${ASSETS} ${ASSETS_${FXSDK_PLATFORM}}) + +target_include_directories(${PROJECT_NAME} PRIVATE "${FXSDK_COMPILER_INSTALL}/include/openlibm") + +target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Os -fno-use-cxa-atexit) + +target_link_libraries(${PROJECT_NAME} Gint::Gint -lopenlibm -lc -lsupc++) + +if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G) + generate_g1a( + TARGET ${PROJECT_NAME} + OUTPUT "${PROJECT_NAME}.g1a" + NAME "${PROJECT_NAME}" + ICON assets-fx/icon.png) + elseif("${FXSDK_PLATFORM_LONG}" STREQUAL fxCG50) + generate_g3a( + TARGET ${PROJECT_NAME} + OUTPUT "${PROJECT_NAME}.g3a" + NAME "${PROJECT_NAME}" + ICONS assets-cg/icon-uns.png assets-cg/icon-sel.png) + endif() diff --git a/LEPHE.md b/LEPHE.md new file mode 100644 index 0000000..1a4fb4e --- /dev/null +++ b/LEPHE.md @@ -0,0 +1,45 @@ +Changements faits par Lephe' pour que ça compile : + +## Dans CMakeLists.txt + +* Ajouté `-Wp,-w` à src/map.cpp ; ça indique à GCC de passer `-w` au préprocesseur, ce qui désactive (entre autres) les avertissements de redéfinition de macros pour ce fichier (normalement il faut `#undef` les macros avant de les redéfinir). + +Pour information: `-W,` passe les options (séparées par des virgules) au programme spécifié par la lettre dans la chaîne de compilation : `-Wp` passe des options au préprocesseur, `-Wa` à l'assembleur, et `-Wl` à l'éditeur de liens. + +* Ajouté `-Wno-missing-field-initializers` à src/map.cpp, ce qui désactive les avertissements pour les champs non initialisés dans les structures ; attention du coup, si tu en oublies des importants personne ne te le dira. + +## Dans src/map.cpp et src/windmill.cpp + +* Rendu les textures (`tex_white`, `tex_black`, etc) non-constantes + - Dans src/map.cpp: `Texture tex_white = {};` + - Dans src/windmill.cpp `extern Texture tex_white;` + +C'est parce qu'en C++ `const` implique *internal linkage* (comme `static`), et du coup la variable n'est visible que dans le fichier où elle est déclarée. Du coup `extern const` c'est un peu bizarre, et même si certains bouts m'échappent, le résultat c'est que ça ne marche pas. Il y a probablement une meilleure solution que de couper le `const`, à rechercher une autre fois. + +En déclarant les textures non-constantes les noms sont exportés comme il faut et se retrouvent bien. Du coup les 4 textures arrivent dans la section `.bss` (RAM initialisée à 0) au lieu de `.rodata` (ROM) ; si c'est un problème et à défaut d'une autre solution, tu peux mettre `GSECTION(".rodata")` (de ``) devant le `Texture` et ça les déplacera dans leur section d'origine. + +## Dans src/windmill.cpp + +* Décommenté la vieille fonction `render_triangle_white`. J'ai vu que `render_triangle_black` avait été redéfinie, celle-là je n'y ai pas touché. + +## Test + +À ce stade ça compile et le programme ne crashe pas ; l'écran titre a juste une image de titre, et ensuite quand j'appuie sur EXE, écran noir. Pas moyen de sortir, je RESET. Manifestement c'est normal vu la tête de src/main.cpp. + +## Dans src/windmill.cpp and src/windmill.hpp + +* Décommenté tout le code concernant la VRAM ; la VRAM est accessible par la variable `gint_vram` déclarée dans ``. Sur Graph mono ce n'est pas un tableau de char mais un tableau de `uint32_t` donc attention ! Quand tu écris `char *vram = ...` ça ne pose pas de problème, mais `gint_vram[i]` contrôle 32 pixels d'un coup. + +* Dans src/windmill.hpp, ajouté `#define get_vram_address() ((char *)gint_vram)`. + +* Dans `draw_ground()`, renommé `sol.x` et `sol.y` en `ground.x` et `ground.y` dans la ligne suivante. + +```c +vram[(ground.y << 4) + (ground.x>>3)] |= mask; +``` + +## Test + +Pareil. + + diff --git a/assets-cg/example.png b/assets-cg/example.png new file mode 100644 index 0000000000000000000000000000000000000000..8826800383eeae92dade9545feaeb68faf0720f2 GIT binary patch literal 3816 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 eRZ5JQiUR=bBzf^!G-(0=0000 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 ag#Q8hHNm}t`+-sb0000 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 LNkvXXu0mjfMjhGA literal 0 HcmV?d00001 diff --git a/assets-fx/.DS_Store b/assets-fx/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..14e5079fc25a62303ef2fc076a75bb641688d018 GIT binary patch literal 6148 zcmeHKPfrs;6rX{rEr=|IB1TO%HYO(YKtV+kjY}ypH6|cSumrH|c9*hocc$)cTcOtU zTNu6i8N3-2Ti z#Kafe(;GW=`b<2Lh$jXT8~QeF=%EqTf}G*6vC*OtZktkHrqtcj4Rgh@8zp6Aj*`%D zi0$)W$Fjj?{gFc~+Q`uwu>!u1E(|1UY)XD60E2B1NCMPoL^{Jb!Rw91> zYW7ZH)7#l?K5xBvCHTZ}{BRkR*n!ue$nu*Py;&9IeN~jb0{i;U4xAfQhLXcW zBSWdtRB|kJA$jpqNf|bc@{@|swmL^$>gU{=T~Y=ED85jpWYM?lP-ro^cztyKBI5w z2l|Nz@F>25$8iSVz|&a61$-Yrzz^{fUK8Oxoo{+sj5|HHK$G9ptz`8w^$uP((&Ev4 zUS3A=nf%J_cd3uF`*9w%{$j0eAGK;-_lZkM1y*9aley|a=!WoB2_-hno*0n?$NNvr zj-!o63`7hZ7X$2kP@yr@B(??eqXRnr1OSY|G#Aj>TY|-?5;ci!fnWi_A{0=BV)?|t zA{^#b>8D9-3l!l9%f|F1+%s{UgD(wEBKl=TDI4BxL z3`7k4R}A1-UeD*CBzd=X702#c71|~=Cd{ubkcU7guVb#Tt9T3=7qF>J0n{Y61;PwS P^hbcx5Oom)$I8Gjjxy@W literal 0 HcmV?d00001 diff --git a/assets-fx/example.png b/assets-fx/example.png new file mode 100644 index 0000000000000000000000000000000000000000..b26ba9ac37f37f0bbc06db263613c33184d47a12 GIT binary patch literal 3569 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 Tp{%#$=B;b1>#J3%*hT#ZGA&*V literal 0 HcmV?d00001 diff --git a/assets-fx/img/.DS_Store b/assets-fx/img/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0*~f|4b!5hcO-X(i=}MX3x0iJ5sNdU>fO3MP66dWJ^MEZJ{>igtUt zIEHw5zYV>}#~{e_`M>>J6`{oC+oqnhox?uS@b;~#Q}lY~6n6$atJ|YnTAsDuvrGC` z<&H*~J>PyXY}C21L)osS_5gd~Q>7SAhw_m5EfL3qHoS_@xBh3Puyfbi=Gvsz8A~qo zu?Vb~aKq}(x6N_;y+5Ac8pT+Z-XpuBIZ{xe-H>~$SIPOGX1P!O?EcQ}XAN^udR?^m zqv@ybjIt8Ot@g9H{XZ4xFFm>||DYJ>$$|~i%s%>Ce@rTkz9V;C@@xFm{WcmvZ!mbe L`njxgN@xNAYG`{@ literal 0 HcmV?d00001 diff --git a/assets-fx/img/brique.png b/assets-fx/img/brique.png new file mode 100644 index 0000000000000000000000000000000000000000..5c7e594db9f58a6cc954180b458dbf55026a3ea2 GIT binary patch literal 302 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1SJ1Ryj={WSkfJR9T^xl_H+M9WCij$3p^r= z85sBufiR<}hF1enP_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM&(O%3CHoCf(P~c@ z#}E(itJ5O+4k&QA?EJrUcgqph!j(Krer29XXs>itTI3yl;O}+^ZFap2b1i?F!`BA1;__8z=B1)@MK8qDQO&``Fs__ia1Y u@F!;xxA^lyh8gT9-%YiD=hT(!p7%R(`|8<$-qZt~&EVa~60+7BevL9R^{>I6ZD3je literal 0 HcmV?d00001 diff --git a/assets-fx/img/epouvantail.png b/assets-fx/img/epouvantail.png new file mode 100644 index 0000000000000000000000000000000000000000..7877be3a0e091040ef85d85d4047684031ea1993 GIT binary patch literal 302 zcmeAS@N?(olHy`uVBq!ia0vp^0zj<5!2~3yyw0Buq!^2X+?^QKos)S9a~60+7BevL9R^{>?ELAN&d$uz2rR{85edga%eZ#BW zRW1!T-W+37Z8&&`Ior&@+qSG&@9^hk8`&)0$;BSDbNI8u{N#lbX&cva2CqNlT<5hi zj&E*RO}OvP%eMjyYOGT7ook{#Gbjpr&+y)q%HqY9!tuf}qjCBFW$pft=e}e_C??c)I$ztaD0e0s!gDZ)^Yn literal 0 HcmV?d00001 diff --git a/assets-fx/img/fenetre simple.png b/assets-fx/img/fenetre simple.png new file mode 100644 index 0000000000000000000000000000000000000000..59c690044b2cbaeba5da12b2e583fdcc71b6bf56 GIT binary patch literal 172 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|Ea{HEjtmSN`?>!lvI6;>1s;*b z3=DjSK$uZf!>a)(C|TkfQ4*Y=R#Ki=l*&+$n3-3imzP?iV4`QBXK3WilKlp#NYm5B zF~q_@IYEK{k2|Y_^97fN7?H{B3)v>s+Pz{gSi)D~Gg+qaNHzn5wL<37hPTIJfSMRQ MUHx3vIVCg!0QO`pZvX%Q literal 0 HcmV?d00001 diff --git a/assets-fx/img/forgeron.png b/assets-fx/img/forgeron.png new file mode 100644 index 0000000000000000000000000000000000000000..b6ddf481d78b4e15cfb19d8781fdc6664b62b113 GIT binary patch literal 534 zcmV+x0_pvUP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02y>eSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E-^Ag1Z(U700D+cL_t(oN9|b462l+}%>Vy%+KdfRSRPWG z_FzsKqpZO0>f|^VKgZ(u=LT>qyh~J8qGNpAxHQ4i`-FFuPg9fu6z3pk=_o zY!-c$fltI69Q&1#f!0!)O&@xqL|Pzud?o?h;xH40th00gdFgsav_z~oZron~s?geT z7%Y8oGImpzW~3R~k`18s_8CuH7l;Lh6aP0rBPg@BJd5B;=?ZxOO;Fqtlv^IqK|*El zBmhUIF)uCVdNn{1`ISV`@iy0XB4ude`@%$AjKtah8*NBqf{Irtt#G+J&g2c?c61}|C5(N`I z13g0{XO`?YKt&3kE{-7@!N~~;2|xTz7_`*51#%D8ulTs-y2B>>jMpj*mRY}96*FGU Q0;*;3boFyt=akR{0E9*`{r~^~ literal 0 HcmV?d00001 diff --git a/assets-fx/img/herbe.png b/assets-fx/img/herbe.png new file mode 100644 index 0000000000000000000000000000000000000000..cb8156b69778008a329d2ac57a7218a07dcb1c76 GIT binary patch literal 211 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~c!2~4hMP3{LQjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn{1`ISV`@iy0XB4ude`@%$AjKtah8*NBqf{Irtt#G+J&g2c?c61}|C5(N`I z13g0{XO`?YKt;};E{-7@!O1`RStKMRChUy3sUTWVIzwthN5a*Hs~jB)UA#v!)WVn# z`E{JXaHru-$qH|UcLz(fH<@gTEGW#d5Xxs}c=Uw-|F7x08-d0#c)I$ztaD0e0s!l~ BLaYD) literal 0 HcmV?d00001 diff --git a/assets-fx/img/horloge.png b/assets-fx/img/horloge.png new file mode 100644 index 0000000000000000000000000000000000000000..024af58bcfe0e0a389dc219b8be8d3ced1ccbccc GIT binary patch literal 387 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1SJ1Ryj={W7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`0h7I;J!GcfQS24TkI`72U@f|4b!5hcO-X(i=}MX3x0iJ5sNdU>fO3MP66 zdWJ^MEZJ{>iavX~IEHw5-wpHRJEFkz`oI0%iEL^t!ZPVCRT=uZqQdElr%T_@_pX~U zDd3vPh_KD@OE`X_QrW|B9y8~c zBSlX(M11+h|LEODL5+i=nKj$8zQ?K z@1~oLo_@9-q1C}>UVOfr^tv%`K}SubY)9Pmg#MNn6}#IWuIRfNlp_B1o1g#y literal 0 HcmV?d00001 diff --git a/assets-fx/img/mask_forgeron.png b/assets-fx/img/mask_forgeron.png new file mode 100644 index 0000000000000000000000000000000000000000..58e2d03add7d40e27d52999bd14d5509eaf97489 GIT binary patch literal 315 zcmeAS@N?(olHy`uVBq!ia0vp^3P9|@!2~3~ym|B!NHG=%xjQkeJ16rJ$YDu$^mSxl z*x1kgCy^D%=PdAuEM{QfI}E~%$MaXD00kvWTq8 z4D<|*oLREp02QtFba4!caDO}fCSQXB56jR0^WB7npK9ocRa|^{Hlb|NTSw_f&xFlh zyE9x$)QL(9Jkft;Z~X;BjU|`Q3-&OSTv@MulA*yhB~YfK;9B^mFMmZht$89@y16o? zq4Mi2#sej$xd9O^uKO-!r(LXk82sjp(YKI?hiAMuX0Y^3x@fQaDKs)W)?gEd!@Ws% znHM)d3VXP3-7B3JIzfANH>JlG$<>T+;)7->ymnI-9}M)z4*} HQ$iB}J!pA- literal 0 HcmV?d00001 diff --git a/assets-fx/img/moulin mur.png b/assets-fx/img/moulin mur.png new file mode 100644 index 0000000000000000000000000000000000000000..0b265b338e0dcaf855fdf42ecf4a1763eed19ef6 GIT binary patch literal 361 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1SJ1Ryj={W7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`0h7I;J!GcfQS24TkI`72U@f|4b!5hcO-X(i=}MX3x0iJ5sNdU>fO3MP66 zdWJ^MEZJ{>if($kIEHw5znylQuR(#w`RD)nVZuTy)}G-#-ppw?qayn5HCc_NQ=Ivp z`&PZ(wZ^^ox}GtsLCJNGGYw96jSi(>R=vd(#b|WKr*qfsBNtwsZeXa5u{A%n;HjX% zhl+6ax9UtB%+*zCY-`<)7hkT(2}+-wKFN@!sQ0DYp3h&5Un!ZC+xc$HFkc$@oo9CY z>@}ZFyWZ){+J5pf!+oY*r-E-6dtFHpskdZOj$(<}a?15s(YI2*j?~pg1_6IenX7+p z6;EuFy>#cK>2FiD6?~^(vmN>=Z#diT-}TpS&sYisd5Wvj=5Yc&$>8bg=d#Wzp$Pzq C*o!Ox literal 0 HcmV?d00001 diff --git a/assets-fx/img/moulin pale.png b/assets-fx/img/moulin pale.png new file mode 100644 index 0000000000000000000000000000000000000000..f70cc5d2658769eaa504b68fcf0a5b7c8b502b63 GIT binary patch literal 314 zcmeAS@N?(olHy`uVBq!ia0vp^0zmA*!2~4d$R`{GQY`6?zK#qG8~eHcB(eheoCO|{ z#S9F52SAuH>slu#P*AeOHKHUqKdq!Zu_%?HATcwqL@zJ3M8QPQK+n*~nI-!TP|8kve2 z6B3@!IXc~-P>Z!U;6mWRu032*3tOMvU;lX5UjwF-Z_+RQem8B6f%L(onNrv>6iE~j0L6MZzrCR+79#rgQu&X J%Q~loCIG&RexLvV literal 0 HcmV?d00001 diff --git a/assets-fx/img/mur_int_maison.png b/assets-fx/img/mur_int_maison.png new file mode 100644 index 0000000000000000000000000000000000000000..cd48ba557dba551259629a46d7fc646d61edb332 GIT binary patch literal 242 zcmeAS@N?(olHy`uVBq!ia0vp^0zj<5!2~3yyw0Buq!^2X+?^QKos)S9a~60+7BevL9R^{>IUK3fmF^3Er@zNy0l9y11=V3*@$OKDf6rMry%EK})`VrIcnj g(+fHgo?Yn-pP3{Twg%QO2inHq>FVdQ&MBb@09n9D2><{9 literal 0 HcmV?d00001 diff --git a/assets-fx/img/paille dessus.png b/assets-fx/img/paille dessus.png new file mode 100644 index 0000000000000000000000000000000000000000..0e5c4f0a974cd13e230240917559f9f2295ff558 GIT binary patch literal 182 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucLCF%=h?3y^w370~qEv>0#LT=By}Z;C1rt33 zJwqdBmh3k`MQWZdjv*HQ$q5MwKlqtlHY#>?26355tth&})}&}A<#l9<_N{gyhNY8j V@2{|8D+20Z@O1TaS?83{1OQ88F;f5l literal 0 HcmV?d00001 diff --git a/assets-fx/img/paille.png b/assets-fx/img/paille.png new file mode 100644 index 0000000000000000000000000000000000000000..d729d003c1381a2d15db572da51404b85ecafe21 GIT binary patch literal 266 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucLCF%=h?3y^w370~qEv>0#LT=By}Z;C1rt33 zJwqdBmh3k`MOB_Ijv*HQQzv-~9Z=wK-uZuNrnSa=hmu`|TC*nEh=hs?M*ltB{j=om z%ckw0{3rarW1W(Gci~*I*E*Aaep#ViqSt%#(f0{LXKt8jFb1c6Qjs{hh=J)#U;tzA zycul!{$>@a&JdIOsuduYX5RO6GGnmW?iUW3ZxRpwu4Xv9y}fbP0 Hl+XkKX|G?x literal 0 HcmV?d00001 diff --git a/assets-fx/img/panneau.png b/assets-fx/img/panneau.png new file mode 100644 index 0000000000000000000000000000000000000000..3d3b639c6d151ba32b3897daddce0d5409502ee0 GIT binary patch literal 234 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucLCF%=h?3y^w370~qEv>0#LT=By}Z;C1rt33 zJwqdBmh3k`MNytEjv*HQ$q5R~f7GQMc-5o+)}JzAD0N=bWbi;GMn;K)sX#2ObjGiZ z5!1A9a8~$6cD_5(8IJ87sypN-92PfTvrwwzqoJ40g$QO(P8kLV W-G{m#CB;DQWAJqKb6Mw<&;$UII78q7 literal 0 HcmV?d00001 diff --git a/assets-fx/img/pierre eglise.png b/assets-fx/img/pierre eglise.png new file mode 100644 index 0000000000000000000000000000000000000000..d5ea93414a0df5e0a62202408c6b62230c919cc8 GIT binary patch literal 212 zcmeAS@N?(olHy`uVBq!ia0vp^3P3Et!2~3KB)#GTQjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn{1`ISV`@iy0XB4ude`@%$AjKtah8*NBqf{Irtt#G+J&g2c?c61}|C5(N`I z13g0{XO`?YKt(Q|E{-7<{>cdqjsHVf3z8)jjxqfVF_lkL*yVd=6Wh_4Ro3#BAr6Yp z(cEszlJ2V{dQ+Nirkbb=^C(sPTUzV4tTd33VgI9`FYSEUc|h|RJYD@<);T3K0RVN` BJ+1%% literal 0 HcmV?d00001 diff --git a/assets-fx/img/pierre eglise2.png b/assets-fx/img/pierre eglise2.png new file mode 100644 index 0000000000000000000000000000000000000000..b9cdc165a81d0c2353980746eb65b108fae52df2 GIT binary patch literal 214 zcmeAS@N?(olHy`uVBq!ia0vp^3P3Et!2~3KB)#GTQjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn{1`ISV`@iy0XB4ude`@%$AjKtah8*NBqf{Irtt#G+J&g2c?c61}|C5(N`I z13g0{XO`?YKt*nzE{-7<{>eZ7|F>smW}dLbszHMLnDcF>1)migb~&<`i)HEQ>NM<- zxT}`+llf@ODr@<7WxJLvy6ACiqL!QT%!D#YH%mzduNy&M{H9I10yL4q)78&qol`;+ E0G`u9?*IS* literal 0 HcmV?d00001 diff --git a/assets-fx/img/planche bois.png b/assets-fx/img/planche bois.png new file mode 100644 index 0000000000000000000000000000000000000000..be3db7c38ec77a576ffcc2294c1e06d02acc362f GIT binary patch literal 320 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1SJ1Ryj={WSkfJR9T^xl_H+M9WCij$3p^r= z85sBufiR<}hF1enP_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM&(O%3CHoCf(Oyp% z#}E(iw_(v-2NZZd|C@eKrpZJ4_7(BEGwT(1%`oX*Hs#Xdws|sf)65?!IxJ_{W_*I- zYs1szjV|gEJG!JzGd!JN#fsmw_Efd!KI^eWcg4{I4DZf4^Jw)X?w_6Iu&uk`c*sP_ z`ppamn;X)@ZYn=pG-1afOI^;7^EXYJnz2Uy|8IvWR@0VksQUJ#isAYf_n0f6LEideMW9C* NJYD@<);T3K0RTErdNu$6 literal 0 HcmV?d00001 diff --git a/assets-fx/img/porte eglise.png b/assets-fx/img/porte eglise.png new file mode 100644 index 0000000000000000000000000000000000000000..1dd14038e94bf8dc4d852c3e6440395ce7dc876d GIT binary patch literal 513 zcmV+c0{;DpP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02y>eSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E-^Ag1Z(U700D7HL_t(oN9|Wz4#F@D+x;&+G+NR$PX{^) zY2^d4DX~-M(QuqMe~z2+&rOgjyd~Nar3$15NfjNyC+2Vo8nSlQFFniVYeSeQm-UCT z{orP9Kq5u~Ay7;;IJ6NN_YrY<=ZIN_*O16m9KqsY8PfGsuzU(NwP@NUsD*w455*Im z-b+E|D(F?D&qc}rZQzF3VRf~U0thNn{1`ISV`@ ziy0XB4uLSEsD@VqP*AeOHKHUqKdq!Zu_%?HATcwqL@zJ3M8QPQK+n*~nI-!TP*IPk zi(`m||Jsm?LJbNWpa0k2+O^oZIf41}N*nd$LNU|H&YQEJe%ZUb z{>Az{y$C*mC#yY#7vxqLg|IgNZw`uAUCcPmROs!Ec8@Th%=d8_8|*Y*GC8yhNk8Ap zq&2f8Mbz$a3u7z8RCniA^UkflzZn=DOzy3@EO-8wK-h}CsZUl{GFC?mNiJVhVGDE@ NgQu&X%Q~loCIG>RVDJC{ literal 0 HcmV?d00001 diff --git a/assets-fx/img/table.png b/assets-fx/img/table.png new file mode 100644 index 0000000000000000000000000000000000000000..9b66e1b4be3b48016054742222cb74be92c145cd GIT binary patch literal 225 zcmeAS@N?(olHy`uVBq!ia0vp^3P3Et!2~3KB)#GTQjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn{1`ISV`@iy0XB4ude`@%$AjKtah8*NBqf{Irtt#G+J&g2c?c61}|C5(N`I z13g0{XO`?YKt+L`E{-7<{>cdon1A>iGnCq#J@emwh7Q9n*8T1qwIqD(6!hnv_{ey0 zgHsuorPzcgqHlnNTazLGre+oQiAyRPnmSa>FPU~2IM0rAbh*qV&9L>rjRc=}SxG>{ O89ZJ6T-G@yGywp4kwwh_ literal 0 HcmV?d00001 diff --git a/assets-fx/img/toit tuile.png b/assets-fx/img/toit tuile.png new file mode 100644 index 0000000000000000000000000000000000000000..a4c97c885058cd7589b9591ae889173b359d9d7b GIT binary patch literal 416 zcmV;R0bl-!P)N2bZe?^J zG%heMF)~90YwQ330Ub$1K~zXf)mB>)gdhy_{+Hg>K}woFsIpJLgeh%F(&)DR{qull zzl^LZ?|X0**76+a{7M07g<8IOgGT%cTne8|X^Zo+Spcl<KpNc{RtDLB%Y>WIDo8LdUp@hS!?U4x^}Kcf0000< KMNUMnLSTZgNUY)j literal 0 HcmV?d00001 diff --git a/assets-fx/img/windmill.png b/assets-fx/img/windmill.png new file mode 100644 index 0000000000000000000000000000000000000000..58062529eb5019cebd8006a6dba8e1f608418a84 GIT binary patch literal 531 zcmV+u0_^>XP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02y>eSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E-^Ag1Z(U700DzZL_t(oN99=262dSD+yDQxdd_tSA*3GD zdE1lgbreDpdM>xqKg;uJPjd}xBafB-!+NuisdvTydr-Q77;y+9k3DZp+4(cW*l#wo z3!Mp2)+0%gP~L8TqXl$@igEY~@RSS`zFq=4+vF|+a#FywRZy(5YV$m)`2nwNzpFUV%+a!Wl9Y(?pOBdGOm!J~MWtd+b^Ilth}VBAApc&Det ziNoYGfQXt>dSY=L1uGwN;MP#l<4VQFzQUDPv6(qTvA~S8=vkr)nVs)sCgMUVl8ls$ z9_Ky9iMDhWr!uABY)|YzH2zG>5XV`It(lUIhKyXZ8CWtBC(bx~5KVxmObJBnB-fWU zFWnlH25_Zhm8PI5T!6|d)dUlDP7E1THsG_!(fa`?4vuTSp8cPPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02y>eSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E-^Ag1Z(U700D7HL_t(oN9~u{4#OY}1oQtt-A1B{2(0Zf zM-Qoe>H$86^^zXPcfTIhYhk5z*z^4vc~hc=HNQgjrLW3Cp)~8tM^eN-#+xF`PIWE< zVcDg}Nor8EF&2a!tx4U{++ zY`#CtfzF*Rt45L-YMe_#=_jkd!{X2ko6N70Z=^C7+~au$lIv@m5jN>E?&im{G8RTY7fyWmpkt^SGP6xmRc?*I`PC-EGV>O`uP&ki&uBD#5*Tox|GBB5AiS;t7)@Ne`|29!w{ zN?wIiN^v^3yegC%?>6Mygd!#7ES9@NtucatTv%Zocrk?>oy#FMTFWw;@$;LR88Koy z3vp{AHDgN){mxH8S%|x~FcZ!H2lUrwVBmjiOQVA)Oa_n{^7wmR00000NkvXXu0mjf D9kJ8z literal 0 HcmV?d00001 diff --git a/src/Scene_Title.cpp b/src/Scene_Title.cpp new file mode 100644 index 0000000..7d7d578 --- /dev/null +++ b/src/Scene_Title.cpp @@ -0,0 +1,87 @@ +#include "Scene_Title.hpp" +//#include "Map.hpp" + + +extern Game game; +extern int scene; +extern Windmill windmill; + +extern Map map_menu; + + +//---------------------------------------------------------------------------------------------------- +// CONSTRUCTOR +//---------------------------------------------------------------------------------------------------- +Scene_Title::Scene_Title() +{ + // rien +} + + +//---------------------------------------------------------------------------------------------------- +// LAUNCH +//---------------------------------------------------------------------------------------------------- +void Scene_Title::launch() +{ + time_scene = 0; + + camera.set(-20, 110, 16, 301, 25); + windmill.load_map(&map_menu); + windmill.set_camera(&camera); +} + + +//---------------------------------------------------------------------------------------------------- +// UPDATE +//---------------------------------------------------------------------------------------------------- +void Scene_Title::update() +{ + time_scene += 0.02; + + map_menu.object[1]->angle += 1; + //camera.y = 40 * sinf(2*PI * time_scene / 10); + //camera.set_yaw(20 - 10 * sinf(2*PI * time_scene / 10)); + + if (time_scene > 0.2 and input_trigger(K_SHIFT)) + { + scene = SCENE_MAP; + } +} + + +//---------------------------------------------------------------------------------------------------- +// DRAW +//---------------------------------------------------------------------------------------------------- +void Scene_Title::draw() +{ + ML_clear_vram(); + + windmill.draw(); + + ML_bmp_and(sprite_titre_windmill2, 16, 0, 96, 21); + ML_bmp_or(sprite_titre_windmill, 16, 0, 96, 21); + + if (int(2*time_scene) % 2 == 0) + { + PrintMini(25, 58, "Appuyer sur [shift]", MINI_OVER); + } + + ML_display_vram(); +} + + +//---------------------------------------------------------------------------------------------------- +// TERMINATE +//---------------------------------------------------------------------------------------------------- +void Scene_Title::terminate() +{ + +} + +//---------------------------------------------------------------------------------------------------- +// DESTRUCTOR +//---------------------------------------------------------------------------------------------------- +Scene_Title::~Scene_Title() +{ + // rien +} \ No newline at end of file diff --git a/src/Scene_Title.hpp b/src/Scene_Title.hpp new file mode 100644 index 0000000..74caa04 --- /dev/null +++ b/src/Scene_Title.hpp @@ -0,0 +1,122 @@ +//---------------------------------------------------------------------------------------------------- +// +// WINDMILL v1.0 +// +// Scene_Title.hpp +// +//---------------------------------------------------------------------------------------------------- + +#ifndef DEF_SCENE_TITLE +#define DEF_SCENE_TITLE + + +extern "C" +{ + #include "Input.h" +} +#include "Game.hpp" +#include "Windmill.hpp" +#include "Camera.hpp" +#include "MonochromeLib.h" +#include "Debug.hpp" + + +#define EXIT 0 +#define SCENE_TITLE 1 +#define SCENE_MAP 2 +#define SCENE_MAP_DEBUG 3 + +#define PI 3.1415 + + +const unsigned char sprite_titre_windmill[]={ + 0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x1c,0x70, + 0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x1c,0x70, + 0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x38,0xe0, + 0x0f,0x80,0x03,0x80,0x00,0x00,0x0e,0x00,0x00,0x00,0x38,0xe0, + 0x03,0x81,0x83,0x98,0x00,0x00,0x0c,0x00,0x00,0x0c,0x30,0xc0, + 0x03,0x83,0x83,0x38,0x00,0x00,0x1c,0x00,0x00,0x1c,0x71,0xc0, + 0x03,0x87,0x87,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x61,0x80, + 0x03,0x87,0x06,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0xe3,0x80, + 0x03,0x8f,0x0c,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0xc3,0x00, + 0x03,0x9b,0x18,0x63,0x9e,0x03,0xf1,0xce,0x78,0x30,0xc3,0x00, + 0x03,0x1f,0x18,0xe1,0xb6,0x0e,0x30,0xff,0xd8,0x71,0xc7,0x00, + 0x03,0x37,0x30,0xc3,0xee,0x1c,0x61,0xe7,0x98,0x61,0x86,0x00, + 0x03,0x67,0x61,0xc3,0xcc,0x38,0xe1,0xef,0x38,0xe3,0x8e,0x00, + 0x07,0xc7,0xc1,0xc3,0x8c,0x71,0xe1,0xce,0x30,0xe3,0x8e,0x00, + 0x07,0xc7,0xc1,0x87,0x1c,0x73,0xc3,0x8e,0x70,0xc3,0x0c,0x00, + 0x07,0x87,0x83,0x86,0x18,0x66,0xc3,0x1c,0x61,0xc7,0x1c,0x00, + 0x07,0x07,0x03,0x8e,0x38,0x6d,0xc7,0x18,0x61,0xc7,0x1c,0x00, + 0x06,0x0e,0x03,0xcc,0x3c,0x79,0xe6,0x38,0xf1,0xe7,0x9e,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0x00, +}; + +const unsigned char sprite_titre_windmill2[]={ + 0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0x7f,0xff,0xff,0xc1,0x00, + 0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,0xc1,0x00, + 0xe0,0x3f,0xfc,0x3f,0xff,0xff,0xf0,0xff,0xff,0xff,0x80,0x00, + 0xe0,0x3e,0x3c,0x3f,0xff,0xff,0xe0,0xff,0xff,0xf1,0x82,0x00, + 0xe0,0x3c,0x38,0x27,0xff,0xff,0xe0,0xff,0xff,0xe1,0x86,0x10, + 0xf8,0x38,0x38,0x07,0xff,0xff,0xc1,0xff,0xff,0xc1,0x84,0x10, + 0xf8,0x38,0x30,0xff,0xff,0xff,0xc3,0xff,0xff,0xc1,0x0c,0x30, + 0xf8,0x30,0x21,0x0f,0xff,0xff,0x03,0xff,0xff,0xfe,0x08,0x30, + 0xf8,0x20,0x01,0x0c,0x20,0xf8,0x00,0x30,0x03,0x86,0x18,0x30, + 0xf8,0x00,0x02,0x0c,0x00,0xf0,0x04,0x00,0x03,0x86,0x18,0x70, + 0xf8,0x00,0x02,0x08,0x00,0xc0,0x06,0x00,0x03,0x86,0x30,0x70, + 0xf8,0x00,0x04,0x08,0x00,0x81,0x0e,0x00,0x03,0x04,0x30,0xf0, + 0xf0,0x00,0x0c,0x18,0x00,0x02,0x0c,0x00,0x02,0x0c,0x20,0xf0, + 0xf0,0x00,0x1c,0x10,0x01,0x04,0x1c,0x00,0x06,0x08,0x60,0xf0, + 0xf0,0x10,0x18,0x10,0x01,0x08,0x18,0x00,0x84,0x18,0x60,0xf0, + 0xf0,0x30,0x38,0x20,0x03,0x00,0x18,0x01,0x8c,0x10,0xc1,0xf0, + 0xf0,0x60,0x78,0x00,0x81,0x00,0x00,0x03,0x04,0x00,0x40,0xf0, + 0xf0,0xe0,0x78,0x01,0x81,0x00,0x00,0x82,0x04,0x00,0x00,0xf0, + 0xf1,0xe1,0xf8,0x01,0x81,0x00,0x00,0x86,0x04,0x00,0x00,0xf0, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xf0, +}; + + + + +class Scene_Title +{ +public: + Scene_Title(); + void launch(); + void update(); + void draw(); + void terminate(); + ~Scene_Title(); + + Camera camera; + float time_scene; + + // perso + +}; + +#endif + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/camera.cpp b/src/camera.cpp new file mode 100644 index 0000000..df79065 --- /dev/null +++ b/src/camera.cpp @@ -0,0 +1,196 @@ +#include "camera.hpp" + +//----------------------------------------------------------------------------- +// CAMERA +//----------------------------------------------------------------------------- +Camera::Camera() +{ + x = 0; + y = 0; + z = 0; + yaw = 0; + pitch = 0; + fov = 50; + near = 1; + far = 1000; + + float fov_rad = to_rad(fov); + scale_coef = 64 * near * tanf(fov_rad); + cos_fov = SCALE_AI * cosf(fov_rad); + //sin_fov = SCALE_AI * sinf(fov_rad); + sin_fov = sinf(fov_rad); + cos_fov_square = cosf(fov_rad) * cosf(fov_rad); + //near_coef = - far / float(far - near); + //far_coef = - far * near * 128 / (far - near); + +} + + +//----------------------------------------------------------------------------- +// SET +//----------------------------------------------------------------------------- +void Camera::set(float _x, float _y, float _z, float _yaw, float _pitch) +{ + x = _x; + y = _y; + z = _z; + yaw = to_rad(_yaw); + pitch = to_rad(_pitch); +} + +void Camera::set(Camera* _camera) +{ + x = _camera->x; + y = _camera->y; + z = _camera->z; + yaw = _camera->yaw; + pitch = _camera->pitch; +} + +//----------------------------------------------------------------------------- +// UPDATE_CAMERA +//----------------------------------------------------------------------------- +void Camera::update() +{ + if (look_at_duration) + { + yaw = (yaw * (look_at_duration - 1) + look_at_yaw) / look_at_duration; + look_at_duration -= 1; + } + + cos_yaw = cosf(yaw); + sin_yaw = sinf(yaw); + cos_pitch = cosf(pitch); + sin_pitch = sinf(pitch); + + //nx = SCALE_AI * cos_pitch * cos_yaw; + //ny = SCALE_AI * cos_pitch * sin_yaw; + //nz = SCALE_AI * sin_pitch; + + nx = cos_pitch * cos_yaw; + ny = cos_pitch * sin_yaw; + nz = sin_pitch; + + // a1 a2 a3 + // a4 a5 a6 + // a7 a8 a9 + + a1 = SCALE_AI * cos_pitch * cos_yaw; + a2 = SCALE_AI * cos_pitch * sin_yaw; + a3 = SCALE_AI * sin_pitch; + a4 = SCALE_AI * -sin_yaw; + a5 = SCALE_AI * cos_yaw; + a6 = SCALE_AI * 0; + a7 = SCALE_AI * -sin_pitch * cos_yaw; + a8 = SCALE_AI * sin_pitch * -sin_yaw; + a9 = SCALE_AI * cos_pitch; +} + + +//----------------------------------------------------------------------------- +// NORMAL_VECTOR +//----------------------------------------------------------------------------- +void Camera::direction_vector(float* _x, float* _y) +{ + *_x = cos_yaw; + *_y = sin_yaw; +} + + +//----------------------------------------------------------------------------- +// MOVE_FRONT (valeur positive signifie devant) +//----------------------------------------------------------------------------- +void Camera::move_front(float value) +{ + x += value * cosf(yaw); + y -= value * sinf(yaw); +} + + +//----------------------------------------------------------------------------- +// MOVE_SIDE (valeur positive signifie à droite) +//----------------------------------------------------------------------------- +void Camera::move_side(float value) +{ + x -= value * sinf(yaw); + y -= value * cosf(yaw); +} + +//----------------------------------------------------------------------------- +// MOVE_ALTITUDE (valeur positive signifie en haut) +//----------------------------------------------------------------------------- +void Camera::move_altitude(float value) +{ + z += value; +} + + +//----------------------------------------------------------------------------- +// TURN_YAW (valeur positive signifie a gauche) +//----------------------------------------------------------------------------- +void Camera::turn_yaw(float value) +{ + yaw += to_rad(value); +} + +//----------------------------------------------------------------------------- +// TURN_PITCH (valeur positive signifie en haut) +//----------------------------------------------------------------------------- +void Camera::turn_pitch(float value) +{ + pitch += to_rad(value); +} + + +//----------------------------------------------------------------------------- +// SET_YAW (valeur positive signifie a gauche) +//----------------------------------------------------------------------------- +void Camera::set_yaw(float value) +{ + yaw = to_rad(value); +} + +//----------------------------------------------------------------------------- +// SET_PITCH (valeur positive signifie en haut) +//----------------------------------------------------------------------------- +void Camera::set_pitch(float value) +{ + pitch = to_rad(value); +} + + +//----------------------------------------------------------------------------- +// LOOK_AT +//----------------------------------------------------------------------------- +void Camera::look_at(float look_at_x, float look_at_y, float look_at_z, float duration) +{ + look_at_yaw = 0;//atan2f(look_at_y - y, look_at_x - x); + + //look_at_pitch = atan2(look_at_z - z, look_at_x - x); + // calcule de sqrt ?? + look_at_duration = duration; +} + +/* +//----------------------------------------------------------------------------- +// MIN +//----------------------------------------------------------------------------- +int Camera::min(int a, int b) +{ + return (a < b) ? a : b; +} + + +//----------------------------------------------------------------------------- +// MAX +//----------------------------------------------------------------------------- +int Camera::max(int a, int b) +{ + return (a > b) ? a : b; +} +*/ + + + + + diff --git a/src/camera.hpp b/src/camera.hpp new file mode 100644 index 0000000..d42a672 --- /dev/null +++ b/src/camera.hpp @@ -0,0 +1,123 @@ +//----------------------------------------------------------------------------- +// +// CAMERA +// +// Repere monde Repere camera : z rentre dans l'ecran +// z O------ x +// | y | +// |/ | +// ☐☐◁ O---- x y +// +// rotation autour de z de x vers y : rotation droite vers gauche : yaw +// rotation autour de y' de x' vers z' : rotation de bas vers haut : pitch +// +// avec yaw = pitch = 0, la camera regarde vers x, avec y à gauche et z en haut +// +// les objets sont affiches dans le sens trigo +// +// texture : O----->w +// | +// | +// h +// +// sens trigonométrique pour afficher la face avant +// le 0 texture correspond au 0 triangle et 0 rectangle +// +// triangle : 0-----2 avec offset 0-----2 +// | / de 50% c'est | | +// | / le point 1 | | +// | / qui se décale | | +// | / | +// 1 1 +// +// rectangle : 0-----2 +// | /| +// | / | +// | / | +// | / | +// 1-----3 3 est automatiquement crée +//----------------------------------------------------------------------------- + +#ifndef DEF_CAMERA +#define DEF_CAMERA + +extern "C" +{ + #define __BSD_VISIBLE 1 + #include + #include +} + + +//#define PI 3.1415 +#define DEG 180.0 +#define to_rad(x) M_PI / DEG * x +#define to_deg(x) DEG / M_PI * x +#define SCALE_AI 128 + + +class Camera +{ +public: + Camera(); + void set(float _x, float _y, float _z, float _yaw, float _pitch); + void set(Camera* _camera); + void update(); + + void direction_vector(float* _x, float* _y); + + //void move(float _x, float _y, float _z); + void move_front(float value); + void move_side(float value); + void move_altitude(float value); + + void turn_yaw(float value); + void turn_pitch(float value); + void set_yaw(float value); + void set_pitch(float value); + + void look_at(float _x, float _y, float _z, float duration); + + + void turn(float _yaw, float _pitch); + + //int min(int a, int b); + //int max(int a, int b); + +public: + + float x, y, z; + float yaw, pitch; + +public: + int look_at_type; + float look_at_yaw; + float look_at_pitch; + float look_at_duration; + + + //int nx, ny, nz; + float nx, ny, nz; + float cos_yaw, sin_yaw; + float cos_pitch, sin_pitch; + + float fov; + int cos_fov; + //int sin_fov; + float sin_fov; + float cos_fov_square; + + int scale_coef; + int near; + int far; + float near_coef; + int far_coef; + + float normal_x, normal_y, normal_z; + + int a1, a2, a3, a4, a5, a6, a7, a8, a9; +}; + + + +#endif diff --git a/src/game.cpp b/src/game.cpp new file mode 100644 index 0000000..941bf19 --- /dev/null +++ b/src/game.cpp @@ -0,0 +1,33 @@ +#include "game.hpp" + +//----------------------------------------------------------------------------- +// GAME +//----------------------------------------------------------------------------- +Game::Game() +{ + time_game = 0; +} + + +//----------------------------------------------------------------------------- +// NEW_GAME +//----------------------------------------------------------------------------- +void Game::new_game() +{ + // pour exemple + //map = &map_exemple; + //map = &map_interieur_forgeron; // ICI LAUNCH GAME + player.teleport(0,0,0,0,0); + //player.dissociate_camera = true; + //scene_map.camera.set(-14,25,5,90,0); // de face + //player.teleport(25,-50,0,90,0); + //scene_map.camera.set(-14,1,5,-20,0); // de biais + + //map = &map_village; + + //scene_map.load_map(); + //player.teleport(-85.7, -77.5, 0, 40, 0); + //player.teleport(0, -5, 0, 0, 0); + //player.teleport(250.7, -110.7, 0, 26.8, 15.4); // bug chevauchement clip depth + //player.teleport(250.7, -110.7, 0, 319.6, 53.55); +} diff --git a/src/game.hpp b/src/game.hpp new file mode 100644 index 0000000..a593e49 --- /dev/null +++ b/src/game.hpp @@ -0,0 +1,93 @@ +#ifndef DEF_GAME +#define DEF_GAME + + +extern "C" +{ + #define __BSD_VISIBLE 1 + #include + //#include "MonochromeLib.h" +} + +//#include "camera.hpp" + +//#include "Structures.hpp" +#include "windmill.hpp" + +//#include "Scene_Map.hpp" +//#include "Debug.hpp" +//#include "Toolbox.h" + + + +#define MAP_EXTERIOR_LIMIT 1000 +#define COL_NO 0 +#define COL_GROUND 1 +#define COL_WALL 2 +#define COL_ON 3 +#define COL_CARA 4 +#define COL_BOUND 5 + + + +class Player +{ +public: + Player(); + void teleport(float _x, float _y, float _z, float _yaw, float _pitch); + + float x, y, z, yaw, pitch; + + bool moving, jumping, turning; + + float height; + float total_height; + float belly; + + float action_distance; + + float translation_speed; + float rotation_speed; + float jump_speed; + + float translation_speed_max; + float translation_acceleration; + float rotation_speed_max; + float jump_speed_max; + + bool dissociate_camera; + bool can_move; +}; + + + + + +class Game +{ +public: + Game(); + + void new_game(); + + // bool player_close_to(float x, float y); + // bool player_close_to(Object* object); + // bool player_contact_with(Object* object); + + //Object* get_object(int id); + + //Collision_flag collision(float* new_x, float* new_y, float* new_z); + //bool CollisionDroiteSeg(Vecteur wall, Vecteur player); + + + Map *map; + Player player; + float time_game; + bool* switchs[100]; + float* variables[100]; + //float time_map; +}; + + + +#endif diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..5345e67 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,39 @@ +#include "main.hpp" + + +Game game; +Windmill windmill; +Scene_Map scene_map; + +int main(void) +{ + + extern bopti_image_t img_windmill; + + dclear(C_WHITE); + dimage(16, 0, &img_windmill); + + int key = 0; + + while(key != KEY_EXE) + { + dupdate(); + + key = getkey().key; + } + + dclear(C_BLACK); + dupdate(); + + scene_map.launch(); + + while(1) + { + scene_map.draw(); + scene_map.update(); + } + scene_map.terminate(); + + getkey(); + return 1; +} diff --git a/src/main.hpp b/src/main.hpp new file mode 100644 index 0000000..04bdadd --- /dev/null +++ b/src/main.hpp @@ -0,0 +1,9 @@ +extern "C" +{ + #include + #include +} + +#include "game.hpp" +#include "windmill.hpp" +#include "scene_map.hpp" diff --git a/src/map.cpp b/src/map.cpp new file mode 100644 index 0000000..e679fca --- /dev/null +++ b/src/map.cpp @@ -0,0 +1,1427 @@ +//----------------------------------------------------------------------------- +// +// MAP +// +// fichier ou sont enregistres les sprites, les textures, et les objets +// +// +// Ce fichier est compilé avec -Wp,-w et -Wno-missing-field-initializers. +// +//----------------------------------------------------------------------------- + +#include "windmill.hpp" + +// SPRITES +const unsigned char sprite_brique_base[]={ + 0xff,0xff,0xff,0xff, + 0xa0,0x80,0x81,0x80, + 0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80, + 0xff,0xff,0xff,0xff, + 0x08,0x08,0x08,0x08, + 0x0c,0x08,0x08,0x08, + 0x0a,0x08,0x08,0x88, + 0xff,0xff,0xff,0xff, + 0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80, + 0xff,0xff,0xff,0xff, + 0x08,0x08,0x08,0x08, + 0x08,0x08,0x08,0x18, + 0x08,0x08,0x08,0x10, + 0xff,0xff,0xff,0xff, + 0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80, + 0x80,0x88,0x80,0x80, + 0xff,0xf7,0xff,0xff, + 0x08,0x08,0x08,0x08, + 0x08,0x08,0x08,0x0c, + 0x88,0x08,0x08,0x08, + 0xff,0xff,0xff,0xff, + 0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80, + 0xff,0xff,0xff,0xff, + 0xdd,0xdc,0xdd,0xfd, + 0xdd,0xdd,0xdd,0xdd, + 0xff,0xff,0xff,0xff, +}; + +const unsigned char sprite_brique[]={ + 0x80,0x80,0x80,0x80, + 0xa0,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80, + 0xff,0xff,0xff,0xff, + 0x08,0x08,0x08,0x18, + 0x08,0x08,0x08,0x08, + 0x08,0x08,0x08,0x08, + 0xff,0xff,0xff,0xff, + 0x80,0xc0,0x80,0x80, + 0x80,0x80,0x80,0x80, + 0x80,0x80,0x81,0x80, + 0xff,0xff,0xfe,0xff, + 0x08,0x08,0x08,0x08, + 0x08,0x08,0x08,0x18, + 0x08,0x08,0x08,0x28, + 0xff,0xff,0xff,0xff, + 0x81,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80, + 0xff,0xff,0xff,0xff, + 0x08,0x08,0x08,0x08, + 0x08,0x08,0x08,0x08, + 0x08,0x08,0x08,0x18, + 0xff,0xff,0xff,0xff, + 0x80,0x80,0x80,0x80, + 0x80,0x80,0xc0,0x80, + 0x88,0x80,0xa0,0x80, + 0xf7,0xff,0xff,0xff, + 0x08,0x08,0x08,0x08, + 0x08,0x08,0x08,0x18, + 0x08,0x08,0x48,0x08, + 0xff,0xff,0xff,0xff, +}; + +const unsigned char sprite_toit_tuile[]={ + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0x08,0x88,0x84,0x41, + 0x08,0x88,0x84,0x41, + 0x08,0x8c,0x8c,0x41, + 0x09,0x88,0x88,0x41, + 0x19,0x08,0x88,0x41, + 0x1d,0x18,0x8c,0x41, + 0xf7,0xb7,0xf6,0xe3, + 0x22,0xe6,0x33,0xbe, + 0x22,0x42,0x11,0x10, + 0x22,0x42,0x11,0x10, + 0x32,0x46,0x11,0x10, + 0x1e,0x65,0x39,0xd8, + 0xe5,0xdd,0xef,0x7d, + 0x84,0x84,0x44,0x27, + 0x84,0x84,0x44,0x21, + 0x8c,0x84,0x46,0x21, + 0xdc,0xcc,0x66,0x21, + 0x77,0xde,0xf7,0x73, + 0x42,0x73,0x9d,0xde, + 0x42,0x21,0x08,0x88, + 0x42,0x21,0x08,0x88, + 0x42,0x21,0x08,0x88, + 0x47,0x21,0x0d,0xdc, + 0xfd,0xf3,0x15,0x77, + 0x99,0x9e,0xf7,0x21, + 0x08,0x84,0x42,0x21, + 0x08,0x84,0x42,0x21, + 0x88,0x84,0x42,0x21, + 0x8d,0xcc,0xe6,0x73, + 0xff,0xff,0xff,0xff, +}; + +const unsigned char sprite_paille[]={ + 0x5a,0x95, + 0x58,0x95, + 0x5a,0x95, + 0x5e,0xd5, + 0xd2,0xd0, + 0xd3,0x59, + 0x93,0x59, + 0x37,0x49, + 0x36,0x49, + 0x26,0x49, + 0x24,0xcb, + 0xa4,0xeb, + 0xa9,0xaa, + 0xe9,0xaa, + 0x69,0xaa, + 0x49,0x8a, +}; + +const unsigned char sprite_paille_dessus[]={ + 0x88,0x88, + 0x22,0x22, + 0x88,0x88, + 0x22,0x22, + 0x88,0x88, + 0x22,0x22, + 0x88,0x88, + 0x22,0x22, + 0x88,0x88, + 0x22,0x22, + 0x88,0x88, + 0x22,0x22, + 0x88,0x88, + 0x22,0x22, + 0x88,0x88, + 0x22,0x22, +}; + +const unsigned char sprite_mur_moulin[]={ + 0x81,0x02,0x08,0x73, + 0x81,0x02,0x08,0x4d, + 0x81,0x02,0x08,0x41, + 0x81,0x02,0x08,0x41, + 0x81,0x02,0x08,0x41, + 0x81,0x02,0x08,0x41, + 0x81,0x02,0x09,0xc1, + 0x81,0x1e,0x0e,0x41, + 0x81,0xe2,0x08,0x41, + 0x81,0x02,0x08,0x41, + 0x81,0x02,0x08,0x41, + 0x81,0x02,0x48,0x41, + 0x81,0x02,0xa8,0x41, + 0x81,0x03,0x18,0x79, + 0x81,0x02,0x08,0x47, + 0x81,0x02,0x08,0x41, + 0xf9,0x02,0x08,0x41, + 0x87,0x04,0x08,0x21, + 0x81,0x04,0x08,0x21, + 0x81,0x04,0x08,0x21, + 0x81,0x04,0x08,0x21, + 0x81,0x04,0x0e,0x61, + 0x81,0x04,0x09,0xa1, + 0x81,0x04,0x08,0x21, + 0x81,0x04,0x08,0x21, + 0x81,0x3c,0x08,0x21, + 0x81,0xc4,0x08,0x21, + 0x81,0x04,0x08,0x21, + 0x81,0x04,0x08,0x31, + 0x99,0x04,0x08,0x2f, + 0xe7,0x04,0x08,0x21, + 0x81,0x07,0xf8,0x21, +}; + +const unsigned char sprite_pale_moulin[]={ + 0xff,0xff, + 0x87,0xe1, + 0x87,0xe1, + 0x8f,0xf1, + 0x8f,0xf1, + 0x9b,0xd9, + 0x9b,0xd9, + 0xb3,0xcd, + 0xb3,0xcd, + 0xe7,0xe7, + 0xe7,0xe7, + 0xc7,0xe3, + 0xff,0xff, + 0xc7,0xe3, + 0xc7,0xe3, + 0xc7,0xe3, + 0xc7,0xe3, + 0xc7,0xe3, + 0xc5,0xa3, + 0xcd,0xb3, + 0xcd,0xb3, + 0xff,0xff, + 0xcd,0xb3, + 0xcd,0xb3, + 0xcd,0xb3, + 0xcd,0xb3, + 0xcd,0xb3, + 0xd9,0x9b, + 0xff,0xff, + 0xd9,0x9b, + 0xd9,0x9b, + 0xd9,0x9b, + 0xd9,0x9b, + 0xd9,0x9b, + 0xd9,0x9b, + 0xd9,0x9b, + 0xd1,0x8b, + 0xff,0xff, + 0xf1,0x8f, + 0xf1,0x8f, + 0xf1,0x8f, + 0xf1,0x8f, + 0xf1,0x8f, + 0xf1,0x8f, + 0xf1,0x8f, + 0xff,0xff, + 0xe1,0x87, + 0xe1,0x87, + 0xe1,0x87, + 0xe1,0x87, + 0xe1,0x87, + 0xe1,0x87, + 0xe1,0x87, + 0xe1,0x87, + 0xff,0xff, + 0xc1,0x83, + 0xc1,0x83, + 0xc1,0x83, + 0xc1,0x83, + 0xc1,0x83, + 0xc1,0x83, + 0xff,0xff, + 0xff,0xff, + 0xff,0xff, +}; + +const unsigned char sprite_fenetre_simple[]={ + 0xff,0xff, + 0xc1,0x03, + 0xc1,0x03, + 0xc1,0x03, + 0xc1,0x03, + 0xff,0xff, + 0xc1,0x03, + 0xc1,0x03, + 0xc1,0x03, + 0xff,0xff, + 0xc1,0x03, + 0xc1,0x03, + 0xc1,0x03, + 0xc1,0x03, + 0xff,0xff, + 0xff,0xff, +}; + +const unsigned char sprite_porte_simple[]={ + 0xff,0xff, + 0x80,0x01, + 0x80,0x01, + 0xff,0xff, + 0xff,0xff, + 0xe0,0x07, + 0xc9,0x43, + 0xc9,0x4b, + 0xc9,0x4b, + 0xc1,0x0b, + 0xc9,0x0b, + 0xc9,0x4b, + 0xc9,0x43, + 0xc8,0x43, + 0xc8,0x4b, + 0xc9,0x4b, + 0xc1,0x03, + 0xc9,0x3b, + 0xc9,0x3b, + 0xc9,0x2b, + 0xc9,0x13, + 0xc9,0x03, + 0xc8,0x03, + 0xc8,0x43, + 0xc8,0x43, + 0xc9,0x4b, + 0xc1,0x4b, + 0xc9,0x4b, + 0xc9,0x4b, + 0xc9,0x0b, + 0xc0,0x03, + 0xff,0xff, +}; + +const unsigned char sprite_pierre_eglise[]={ + 0xe0,0x00,0x00,0x07, + 0x20,0x00,0x00,0x04, + 0xe0,0x00,0x00,0x07, + 0x40,0x00,0x00,0x02, + 0x40,0x00,0x00,0x02, + 0xe0,0x00,0x00,0x07, + 0x20,0x00,0x00,0x04, + 0xe0,0x00,0x00,0x07, + 0x40,0x00,0x00,0x02, + 0x40,0x00,0x00,0x02, + 0xe0,0x00,0x00,0x07, + 0x20,0x00,0x00,0x04, + 0xe0,0x00,0x00,0x07, + 0x40,0x00,0x00,0x02, + 0x40,0x00,0x00,0x02, + 0x40,0x00,0x00,0x02, +}; + +const unsigned char sprite_pierre_eglise2[]={ + 0x40,0x00,0x00,0x02, + 0x40,0x00,0x00,0x02, + 0x40,0x00,0x00,0x02, + 0xe0,0x00,0x00,0x07, + 0x20,0x00,0x00,0x04, + 0xe0,0x00,0x00,0x07, + 0x40,0x00,0x00,0x02, + 0x40,0x00,0x00,0x02, + 0xe0,0x00,0x00,0x07, + 0x20,0x00,0x00,0x04, + 0xe0,0x00,0x00,0x07, + 0x40,0x00,0x00,0x02, + 0x40,0x00,0x00,0x02, + 0xe0,0x00,0x00,0x07, + 0x20,0x00,0x00,0x04, + 0xe0,0x00,0x00,0x07, +}; + +const unsigned char sprite_horloge[]={ + 0x00,0x7f,0xfe,0x00, + 0x01,0x80,0x01,0x80, + 0x06,0x02,0xc0,0x60, + 0x08,0x82,0x41,0x10, + 0x10,0x02,0x80,0x08, + 0x24,0x02,0xc0,0x24, + 0x20,0x00,0x00,0x04, + 0x40,0x00,0x00,0x02, + 0x50,0x00,0x00,0x0a, + 0x80,0x00,0x00,0x01, + 0x80,0x00,0x00,0x01, + 0x80,0x00,0x00,0x01, + 0x80,0x00,0x00,0x01, + 0x90,0x00,0x00,0x0d, + 0xa8,0x01,0x80,0x05, + 0x98,0x01,0x80,0x0d, + 0x88,0x00,0x00,0x05, + 0x90,0x00,0x00,0x0d, + 0x80,0x00,0x00,0x01, + 0x80,0x00,0x00,0x01, + 0x80,0x00,0x00,0x01, + 0x80,0x00,0x00,0x01, + 0x80,0x00,0x00,0x01, + 0x50,0x00,0x00,0x12, + 0x40,0x00,0x00,0x02, + 0x20,0x01,0x00,0x04, + 0x24,0x02,0x00,0x24, + 0x10,0x03,0x00,0x08, + 0x08,0x82,0x81,0x10, + 0x06,0x01,0x00,0x60, + 0x01,0x80,0x01,0x80, + 0x00,0x7f,0xfe,0x00, +}; + +const unsigned char sprite_porte_eglise[]={ + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x3f,0xfc,0x00, + 0x00,0xc0,0x83,0x00, + 0x03,0x05,0x28,0xc0, + 0x04,0x90,0x03,0x20, + 0x0a,0x41,0x20,0x10, + 0x10,0x10,0x0a,0xa8, + 0x23,0x12,0x10,0x04, + 0x24,0x00,0x44,0x24, + 0x50,0xbf,0xfc,0x92, + 0x44,0xff,0xff,0x12, + 0x93,0xc1,0x83,0xc5, + 0xd7,0x01,0x80,0xe1, + 0x9c,0x01,0x80,0x35, + 0xf8,0x01,0x80,0x19, + 0xb0,0x01,0x80,0x0d, + 0xa0,0x01,0x80,0x05, + 0xe0,0x01,0x80,0x07, + 0xc0,0x01,0x80,0x83, + 0xc0,0x81,0x80,0x03, + 0x80,0x01,0x80,0x01, + 0x80,0x01,0x80,0x01, + 0x80,0x01,0x80,0x01, + 0x80,0x01,0x80,0x01, + 0x80,0x01,0x80,0x01, + 0x80,0x01,0x82,0x01, + 0x80,0x01,0x82,0x01, + 0xc0,0x01,0x82,0x03, + 0xc0,0x01,0x80,0x03, + 0x80,0x01,0x80,0x01, + 0x80,0x01,0x80,0x01, + 0x80,0x01,0x80,0x01, + 0x80,0x01,0x80,0x01, + 0x80,0x01,0x80,0x01, + 0x80,0x81,0x80,0x01, + 0x80,0x01,0x80,0x01, + 0x80,0x01,0x80,0x01, + 0x80,0x01,0x80,0x01, + 0x80,0x1d,0xb8,0x01, + 0x80,0x09,0x90,0x01, + 0x80,0x15,0xa8,0x01, + 0x80,0x09,0x90,0x01, + 0x80,0x01,0x80,0x01, + 0x80,0x01,0x80,0xf1, + 0x80,0x01,0x80,0x01, + 0x80,0x01,0x80,0x01, + 0x80,0x01,0x80,0x01, + 0xc0,0x01,0x80,0x03, + 0xc0,0x01,0x80,0x03, + 0x80,0x01,0x80,0x01, + 0x80,0x01,0x80,0x01, + 0x80,0x01,0x80,0x01, + 0x80,0x01,0x80,0x01, + 0xff,0xff,0xff,0xff, +}; + +const unsigned char sprite_planche_bois[]={ + 0x81,0x04,0x08,0x20, + 0xff,0x04,0x08,0x20, + 0x81,0x04,0x08,0x20, + 0xa5,0x04,0x08,0x20, + 0x81,0x04,0x08,0x20, + 0x81,0x04,0x0a,0xa0, + 0x81,0x54,0x08,0x20, + 0x81,0x04,0x0f,0xe0, + 0x81,0xfc,0x08,0x20, + 0x81,0x04,0x0a,0xa0, + 0x81,0x54,0x08,0x20, + 0x81,0x05,0x28,0x2a, + 0x81,0x04,0x08,0x20, + 0x81,0x07,0xf8,0x3f, + 0x81,0x04,0x08,0x20, + 0xa5,0x05,0x28,0x24, + 0x81,0x04,0x08,0x20, + 0xff,0x04,0x08,0x20, + 0x81,0x04,0x08,0x20, + 0xa5,0x04,0x0a,0x20, + 0x81,0x04,0x08,0x20, + 0x81,0x04,0x0f,0xe0, + 0x81,0x04,0x08,0x20, + 0x81,0x54,0x0a,0xaa, + 0x81,0x04,0x08,0x20, + 0x81,0xfc,0x08,0x3f, + 0x81,0x04,0x08,0x20, + 0x81,0x04,0x08,0x2a, + 0x81,0x04,0x08,0x20, + 0x81,0x05,0x28,0x20, + 0x81,0x04,0x08,0x20, + 0xa5,0x07,0xf8,0x20, +}; + +const unsigned char sprite_haie[]={ + 0x80,0x01, + 0xff,0xff, + 0x80,0x01, + 0x80,0x01, + 0x80,0x01, + 0xff,0xff, + 0x80,0x01, + 0x80,0x01, +}; + +const unsigned char sprite_epouvantail[]={ + 0x00,0x00, + 0x03,0x8c, + 0x06,0xd0, + 0x04,0x20, + 0x0f,0xf0, + 0x04,0x20, + 0x04,0x20, + 0x06,0x60, + 0x03,0xc0, + 0x01,0x80, + 0xe1,0x80, + 0xff,0xfc, + 0x3f,0xff, + 0x04,0x23, + 0x04,0xa0, + 0x04,0xa0, + 0x04,0x20, + 0x06,0x20, + 0x04,0x20, + 0x04,0x20, + 0x05,0x20, + 0x04,0x20, + 0x04,0x60, + 0x04,0xa0, + 0x07,0xe0, + 0x03,0xc0, + 0x03,0xc0, + 0x03,0xc0, + 0x01,0x80, + 0x01,0x80, + 0x01,0x80, + 0x01,0x80, +}; + +const unsigned char sprite_epouvantail_masque[]={ + 0x00,0x00, + 0x03,0x8c, + 0x07,0xd0, + 0x07,0xe0, + 0x0f,0xf0, + 0x07,0xe0, + 0x07,0xe0, + 0x07,0xe0, + 0x03,0xc0, + 0x01,0x80, + 0xe1,0x80, + 0xff,0xfc, + 0x3f,0xff, + 0x07,0xe3, + 0x07,0xe0, + 0x07,0xe0, + 0x07,0xe0, + 0x07,0xe0, + 0x07,0xe0, + 0x07,0xe0, + 0x07,0xe0, + 0x07,0xe0, + 0x07,0xe0, + 0x07,0xe0, + 0x07,0xe0, + 0x03,0xc0, + 0x03,0xc0, + 0x03,0xc0, + 0x01,0x80, + 0x01,0x80, + 0x01,0x80, + 0x01,0x80, +}; + +const unsigned char sprite_herbe[]={ + 0x08,0x00, + 0x48,0x20, + 0x49,0x22, + 0x44,0x92, + 0x44,0x94, + 0x25,0x15, + 0x25,0x15, + 0x25,0x15, +}; + +const unsigned char sprite_panneau[]={ + 0xff,0xff, + 0x80,0x01, + 0x80,0x01, + 0x80,0x01, + 0x92,0xb1, + 0xb5,0x95, + 0x94,0xb5, + 0x80,0x01, + 0x80,0x01, + 0x95,0x6d, + 0x95,0x45, + 0xa2,0x65, + 0x80,0x01, + 0x80,0x01, + 0x80,0x01, + 0xff,0xff, +}; + +const unsigned char sprite_mur_int_maison[]={ + 0xff,0xff, + 0x98,0x19, + 0xb0,0x0d, + 0xe0,0x07, + 0xc0,0x03, + 0x80,0x01, + 0x80,0x01, + 0x80,0x01, + 0x80,0x01, + 0x80,0x01, + 0x80,0x01, + 0x80,0x01, + 0x80,0x01, + 0x80,0x01, + 0x80,0x01, + 0x80,0x01, + 0x80,0x01, + 0x80,0x01, + 0x80,0x01, + 0x80,0x01, + 0xff,0xff, + 0xff,0xff, + 0x91,0x11, + 0x91,0x11, + 0x91,0x11, + 0x91,0x11, + 0x91,0x11, + 0x91,0x11, + 0x91,0x11, + 0x91,0x11, + 0x91,0x11, + 0xff,0xff, +}; + +const unsigned char sprite_planche[]={ + 0xff,0xff,0xff,0xff, + 0x80,0x00,0x00,0x01, + 0x80,0x00,0x00,0x01, + 0x80,0x00,0x00,0x01, + 0x80,0x04,0x00,0x81, + 0x80,0x00,0x00,0x01, + 0x80,0x00,0x00,0x01, + 0x80,0x00,0x80,0x01, + 0x80,0x00,0x00,0x01, + 0x82,0x00,0x00,0x01, + 0x80,0x00,0x00,0x01, + 0x80,0x00,0x00,0x01, + 0x80,0x00,0x00,0x01, + 0x80,0x00,0x00,0x41, + 0x80,0x00,0x00,0x01, + 0xff,0xff,0xff,0xff, +}; + + +const unsigned char sprite_exemple[]={ + 0xff,0xff,0xff,0xff, + 0x87,0xff,0xfc,0x01, + 0xb4,0x00,0x05,0xfd, + 0xb4,0x00,0x05,0xfd, + 0x84,0x00,0x04,0x01, + 0xfc,0x00,0x07,0xff, + 0xc0,0x00,0x00,0x01, + 0xc0,0xfc,0x00,0x01, + 0xc3,0x86,0x00,0x01, + 0xcc,0x03,0x00,0x01, + 0xc9,0x99,0x00,0x01, + 0xc9,0x99,0x07,0xff, + 0xc8,0x01,0x04,0x01, + 0xc8,0x01,0x04,0x01, + 0xc8,0xf1,0x04,0x01, + 0xcc,0x62,0xff,0xff, + 0xc6,0x06,0x80,0x21, + 0xc3,0xfc,0x80,0x21, + 0xc0,0x00,0x80,0x21, + 0xc0,0x00,0xff,0xff, + 0xc0,0x00,0x04,0x01, + 0xc0,0x00,0x04,0x01, + 0xc0,0x00,0x04,0x01, + 0xc0,0x00,0x07,0xff, + 0xc0,0x00,0x00,0x01, + 0xc0,0x00,0x80,0x01, + 0xfc,0x01,0xc0,0x3f, + 0xc4,0x03,0xe0,0x3f, + 0xa4,0x07,0x70,0x33, + 0x94,0x0e,0x38,0x33, + 0x8f,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, +}; + +/* +const unsigned char sprite_mur_colombage[]={ + 0xff,0xff,0xff,0xff, + 0xc0,0x00,0x00,0x03, + 0xc0,0x00,0x00,0x03, + 0xe0,0x00,0x00,0x07, + 0xe0,0x3f,0xfc,0x07, + 0xe0,0x20,0x84,0x07, + 0xb0,0x20,0x84,0x0d, + 0xb0,0x20,0x84,0x0d, + 0xb0,0x20,0x84,0x0d, + 0x98,0x20,0x84,0x19, + 0x98,0x3f,0xfc,0x19, + 0x98,0x20,0x84,0x19, + 0x8c,0x20,0x84,0x31, + 0x8c,0x20,0x84,0x31, + 0xff,0xe0,0x87,0xff, + 0xff,0xe0,0x87,0xff, + 0x86,0x20,0x84,0x61, + 0x83,0x3f,0xfc,0xe1, + 0x83,0x20,0x84,0xc1, + 0x83,0x20,0x84,0xc1, + 0x81,0xa0,0x85,0x81, + 0x81,0xa0,0x85,0x81, + 0x81,0xbf,0xfd,0x81, + 0x80,0xc0,0x03,0x01, + 0x80,0xc0,0x03,0x01, + 0x80,0xc0,0x03,0x01, + 0x80,0x60,0x06,0x01, + 0x80,0x60,0x06,0x01, + 0x80,0x60,0x06,0x01, + 0x80,0x30,0x0c,0x01, + 0x80,0x30,0x0c,0x01, + 0xff,0xff,0xff,0xff, +}; + +const unsigned char sprite_plaque_egout[]={ + 0x07,0xe0, + 0x18,0x18, + 0x21,0x04, + 0x40,0x02, + 0x48,0x82, + 0x80,0x01, + 0x80,0x11, + 0x82,0x21, + 0x84,0x81, + 0x80,0x21, + 0x90,0x01, + 0x41,0x02, + 0x40,0x02, + 0x20,0x04, + 0x18,0x18, + 0x07,0xe0, +}; + + + +const unsigned char sprite_pancarte_forgeron[]={ + 0xff,0xff, + 0x80,0x01, + 0x80,0x01, + 0x80,0x01, + 0xbf,0x81, + 0xbf,0xfd, + 0x9f,0xf9, + 0x87,0xe1, + 0x87,0xe1, + 0x83,0xc1, + 0x83,0xc1, + 0x8f,0xf1, + 0x9f,0xf9, + 0x80,0x01, + 0x80,0x01, + 0xff,0xff, +}; + + + +const unsigned char sprite_comptoire[]={ + 0x88,0x88, + 0x88,0x88, + 0x88,0x88, + 0x88,0x88, + 0xaa,0xaa, + 0x88,0x88, + 0x88,0x88, + 0x88,0x88, +}; + +const unsigned char sprite_trappe[]={ + 0xff,0xff, + 0x88,0x89, + 0x88,0x89, + 0x88,0x89, + 0x88,0x89, + 0x88,0x89, + 0x88,0x89, + 0x88,0x89, + 0x88,0x89, + 0x88,0x89, + 0x88,0x09, + 0x89,0xc9, + 0x89,0x49, + 0x89,0xc9, + 0x88,0x09, + 0xff,0xff, +}; + + + +const unsigned char sprite_arbre1[]={ + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x07,0x80,0x00, + 0x00,0x08,0x7c,0x00, + 0x00,0x10,0x04,0x00, + 0x03,0x60,0x0b,0x80, + 0x04,0x80,0x04,0x40, + 0x04,0x00,0x00,0x40, + 0x04,0x00,0x00,0x20, + 0x08,0x78,0x00,0x10, + 0x14,0x07,0xc0,0x08, + 0x12,0x00,0x00,0x04, + 0x20,0x00,0x00,0x04, + 0x40,0x00,0x00,0x06, + 0x40,0x00,0x00,0xc6, + 0x40,0x00,0x03,0x04, + 0xe0,0x01,0x3c,0x04, + 0xa0,0x01,0xc0,0x06, + 0x9e,0x80,0x00,0x02, + 0x83,0x80,0x00,0x02, + 0x80,0x00,0x00,0x02, + 0x80,0x00,0x00,0x02, + 0x80,0x00,0x00,0x03, + 0x80,0x00,0x00,0x05, + 0x80,0x00,0x0c,0x05, + 0x88,0x00,0x0c,0x1d, + 0x88,0x1f,0x00,0x01, + 0x4e,0x08,0x00,0x06, + 0x70,0x00,0x00,0x01, + 0x10,0x00,0x00,0x01, + 0x60,0x00,0x00,0x01, + 0x40,0x00,0x30,0x09, + 0x50,0x00,0xc0,0x05, + 0x50,0x00,0x00,0x0e, + 0x40,0x00,0x00,0x08, + 0x48,0x00,0x00,0x84, + 0x74,0x00,0x00,0x04, + 0x07,0x7f,0x80,0xf8, + 0x00,0x89,0xff,0x80, + 0x00,0x06,0x51,0x00, + 0x00,0x05,0x50,0x80, + 0x00,0x04,0x10,0x00, + 0x00,0x04,0xd0,0x00, + 0x00,0x04,0xd0,0x00, + 0x00,0x04,0x10,0x00, + 0x00,0x04,0x90,0x00, + 0x00,0x05,0x30,0x00, + 0x00,0x05,0x30,0x00, + 0x00,0x05,0x30,0x00, + 0x00,0x05,0x30,0x00, + 0x00,0x04,0x10,0x00, + 0x00,0x04,0x10,0x00, + 0x00,0x06,0x10,0x00, + 0x00,0x05,0x50,0x00, + 0x00,0x04,0x50,0x00, + 0x00,0x04,0x50,0x00, + 0x00,0x04,0x90,0x00, + 0x00,0x04,0x50,0x00, + 0x00,0x04,0x30,0x00, + 0x00,0x05,0x10,0x00, + 0x00,0x05,0x10,0x00, + 0x00,0x0f,0x78,0x00, + 0x00,0x31,0xc4,0x00, + 0x00,0x02,0x20,0x00, +}; + +const unsigned char mask_arbre1[]={ + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x07,0x80,0x00, + 0x00,0x0f,0xfc,0x00, + 0x00,0x1f,0xfc,0x00, + 0x03,0x7f,0xfb,0x80, + 0x07,0xff,0xff,0xc0, + 0x07,0xff,0xff,0xc0, + 0x07,0xff,0xff,0xe0, + 0x0f,0xff,0xff,0xf0, + 0x1f,0xff,0xff,0xf8, + 0x1f,0xff,0xff,0xfc, + 0x3f,0xff,0xff,0xfc, + 0x7f,0xff,0xff,0xfe, + 0x7f,0xff,0xff,0xfe, + 0x7f,0xff,0xff,0xfc, + 0xff,0xff,0xff,0xfc, + 0xff,0xff,0xff,0xfe, + 0xff,0xff,0xff,0xfe, + 0xff,0xff,0xff,0xfe, + 0xff,0xff,0xff,0xfe, + 0xff,0xff,0xff,0xfe, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0x7f,0xff,0xff,0xfe, + 0x7f,0xff,0xff,0xff, + 0x1f,0xff,0xff,0xff, + 0x7f,0xff,0xff,0xff, + 0x7f,0xff,0xff,0xff, + 0x7f,0xff,0xff,0xff, + 0x7f,0xff,0xff,0xfe, + 0x7f,0xff,0xff,0xf8, + 0x7f,0xff,0xff,0xfc, + 0x77,0xff,0xff,0xfc, + 0x07,0xff,0xff,0xf8, + 0x00,0x8f,0xff,0x80, + 0x00,0x07,0xf1,0x00, + 0x00,0x07,0xf0,0x80, + 0x00,0x07,0xf0,0x00, + 0x00,0x07,0xf0,0x00, + 0x00,0x07,0xf0,0x00, + 0x00,0x07,0xf0,0x00, + 0x00,0x07,0xf0,0x00, + 0x00,0x07,0xf0,0x00, + 0x00,0x07,0xf0,0x00, + 0x00,0x07,0xf0,0x00, + 0x00,0x07,0xf0,0x00, + 0x00,0x07,0xf0,0x00, + 0x00,0x07,0xf0,0x00, + 0x00,0x07,0xf0,0x00, + 0x00,0x07,0xf0,0x00, + 0x00,0x07,0xf0,0x00, + 0x00,0x07,0xf0,0x00, + 0x00,0x07,0xf0,0x00, + 0x00,0x07,0xf0,0x00, + 0x00,0x07,0xf0,0x00, + 0x00,0x07,0xf0,0x00, + 0x00,0x07,0xf0,0x00, + 0x00,0x0f,0xf8,0x00, + 0x00,0x31,0xc4,0x00, + 0x00,0x02,0x20,0x00, +}; +*/ +// Personnages +const unsigned char sprite_forgeron[]={ + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x07,0xc0,0x00, + 0x00,0x18,0x30,0x00, + 0x00,0x20,0x08,0x00, + 0x00,0x2f,0xe8,0x00, + 0x00,0x24,0x48,0x00, + 0x00,0x25,0x48,0x00, + 0x00,0x21,0x08,0x00, + 0x00,0x20,0x08,0x00, + 0x00,0x23,0x88,0x00, + 0x00,0x30,0x18,0x00, + 0x00,0x3f,0xf8,0x00, + 0x00,0x1f,0xf0,0x00, + 0x03,0xff,0xff,0xc0, + 0x04,0x6f,0xe6,0x20, + 0x08,0x63,0x86,0x10, + 0x08,0x50,0x09,0x10, + 0x08,0x90,0x09,0x10, + 0x08,0x8f,0xf1,0x10, + 0x08,0x80,0x03,0x90, + 0x08,0xe1,0xfe,0x50, + 0x08,0xfe,0x02,0x50, + 0x08,0x80,0x03,0xd0, + 0x08,0x01,0xfe,0x10, + 0x08,0x0f,0xf0,0x10, + 0x07,0xf0,0x0f,0xe0, + 0x01,0x00,0x00,0x80, + 0x01,0x00,0x00,0x80, + 0x01,0x00,0x00,0x80, + 0x01,0x00,0x00,0x80, + 0x01,0x00,0x70,0x80, + 0x01,0x00,0x70,0x80, + 0x01,0x00,0x24,0x80, + 0x01,0x10,0x28,0x80, + 0x01,0x0f,0xf0,0x80, + 0x02,0x00,0x00,0x40, + 0x02,0x00,0x00,0x40, + 0x02,0x00,0x10,0x40, + 0x02,0x0c,0x60,0x40, + 0x02,0x00,0x00,0x40, + 0x03,0xff,0xff,0xc0, + 0x00,0x42,0x42,0x00, + 0x00,0x5a,0x5a,0x00, + 0x00,0x42,0x42,0x00, + 0x00,0x42,0x42,0x00, + 0x00,0x42,0x42,0x00, + 0x00,0x42,0x42,0x00, + 0x00,0x42,0x42,0x00, + 0x00,0x42,0x42,0x00, + 0x00,0x42,0x42,0x00, + 0x00,0x42,0x42,0x00, + 0x00,0x7e,0x7e,0x00, + 0x00,0x42,0x42,0x00, + 0x00,0x5a,0x5a,0x00, + 0x00,0x66,0x66,0x00, + 0x00,0x66,0x66,0x00, + 0x00,0x7e,0x7e,0x00, +}; + +const unsigned char mask_forgeron[]={ + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x07,0xc0,0x00, + 0x00,0x1f,0xf0,0x00, + 0x00,0x3f,0xf8,0x00, + 0x00,0x3f,0xf8,0x00, + 0x00,0x3f,0xf8,0x00, + 0x00,0x3f,0xf8,0x00, + 0x00,0x3f,0xf8,0x00, + 0x00,0x3f,0xf8,0x00, + 0x00,0x3f,0xf8,0x00, + 0x00,0x3f,0xf8,0x00, + 0x00,0x3f,0xf8,0x00, + 0x00,0x1f,0xf0,0x00, + 0x03,0xff,0xff,0xc0, + 0x07,0xff,0xff,0xe0, + 0x0f,0xff,0xff,0xf0, + 0x0f,0xff,0xff,0xf0, + 0x0f,0xff,0xff,0xf0, + 0x0f,0xff,0xff,0xf0, + 0x0f,0xff,0xff,0xf0, + 0x0f,0xff,0xff,0xf0, + 0x0f,0xff,0xff,0xf0, + 0x0f,0xff,0xff,0xf0, + 0x0f,0xff,0xff,0xf0, + 0x0f,0xff,0xff,0xf0, + 0x07,0xff,0xff,0xe0, + 0x01,0xff,0xff,0x80, + 0x01,0xff,0xff,0x80, + 0x01,0xff,0xff,0x80, + 0x01,0xff,0xff,0x80, + 0x01,0xff,0xff,0x80, + 0x01,0xff,0xff,0x80, + 0x01,0xff,0xff,0x80, + 0x01,0xff,0xff,0x80, + 0x01,0xff,0xff,0x80, + 0x03,0xff,0xff,0xc0, + 0x03,0xff,0xff,0xc0, + 0x03,0xff,0xff,0xc0, + 0x03,0xff,0xff,0xc0, + 0x03,0xff,0xff,0xc0, + 0x03,0xff,0xff,0xc0, + 0x00,0x7e,0x7e,0x00, + 0x00,0x7e,0x7e,0x00, + 0x00,0x7e,0x7e,0x00, + 0x00,0x7e,0x7e,0x00, + 0x00,0x7e,0x7e,0x00, + 0x00,0x7e,0x7e,0x00, + 0x00,0x7e,0x7e,0x00, + 0x00,0x7e,0x7e,0x00, + 0x00,0x7e,0x7e,0x00, + 0x00,0x7e,0x7e,0x00, + 0x00,0x7e,0x7e,0x00, + 0x00,0x7e,0x7e,0x00, + 0x00,0x7e,0x7e,0x00, + 0x00,0x7e,0x7e,0x00, + 0x00,0x7e,0x7e,0x00, + 0x00,0x7e,0x7e,0x00, +}; + +// TEXTURE +Texture tex_white = {}; +Texture tex_light = {}; +Texture tex_dark = {}; +Texture tex_black = {}; + +const Texture tex_brique_base = {sprite_brique_base, NULL, 32, 32, 30, 30, 0.5, false, false}; +const Texture tex_brique = {sprite_brique, NULL, 32, 32, 30, 30, 0.5, false, false}; +const Texture tex_toit_tuile = {sprite_toit_tuile, NULL, 32, 32, 15, 15, 0.5, false, false}; +const Texture tex_paille = {sprite_paille, NULL, 16, 16, 10, 10, 0, false, false}; +const Texture tex_paille_dessus = {sprite_paille_dessus, NULL, 16, 16, 10, 10, 0, false, false}; +const Texture tex_mur_moulin = {sprite_planche_bois, NULL, 32, 32, 25, 25, 0.5, false, false}; +const Texture tex_pale_moulin = {sprite_pale_moulin, NULL, 16, 64, 0, 0, 0.5, false, false}; +const Texture tex_fenetre_simple = {sprite_fenetre_simple, NULL, 16, 16, 0, 0, 0, false, true}; +const Texture tex_porte_simple = {sprite_porte_simple, NULL, 16, 32, 0, 0, 0, false, true}; +const Texture tex_porte_entrepot = {sprite_planche_bois, NULL, 32, 32, 25, 25, 0, false, true}; +const Texture tex_pierre_eglise = {sprite_pierre_eglise, NULL, 32, 16, 0, 15, 0, false, false}; +const Texture tex_pierre_eglise2 = {sprite_pierre_eglise2, NULL, 32, 16, 0, 15, 0, false, false}; +const Texture tex_horloge = {sprite_horloge, NULL, 32, 32, 0, 0, 0, false, true, false}; +const Texture tex_porte_eglise = {sprite_porte_eglise, NULL, 32, 64, 0, 0, 0, false, true}; +const Texture tex_planche_bois = {sprite_planche_bois, NULL, 32, 32, 15, 15, 0.5, false, false}; +const Texture tex_haie = {sprite_haie, NULL, 16, 8, 20, 0, 0, true}; +const Texture tex_epouvantail = {sprite_epouvantail, sprite_epouvantail_masque, 16, 32, 0, 0, 0, false}; +const Texture tex_herbe = {sprite_herbe, NULL, 16, 8, 7, 0, 0, true}; +const Texture tex_panneau = {sprite_panneau, NULL, 16, 16, 0, 0, 0, false, true}; +const Texture tex_forgeron = {sprite_forgeron, mask_forgeron, 32, 64, 0, 0}; +const Texture tex_mur_int_maison = {sprite_mur_int_maison, NULL, 16, 32, 15, 0}; +const Texture tex_planche = {sprite_planche, NULL, 32, 16, 0, 0}; + + + + + +// MODELES +#define L1 20 // longueur extension X +#define W1 15 // largueur extension Y +#define H1 30 // hauteur mur Z +#define HT1 45 // hauteur toit nef Z +#define D 5 // decalage toit XY +#define L2 80 // longueur tour X +#define W2 20 // largeur tour X +#define H2 70 // hauteur mur tour Z +#define HT2 90 // hauteur toit tour Z +#define L3 (L1+(L2-L1)/2) // milieu toit tour X +const Modele modele_moulin[] = { + // les murs extension + {RECTANGLE, &tex_white, NULL, L1,W1,0, -L1,W1,0, L1,W1,H1}, + {RECTANGLE, &tex_brique, NULL, -L1,W1,0, -L1,-W1,0, -L1,W1,H1}, + {RECTANGLE, &tex_white, NULL, -L1,-W1,0, L1,-W1,0, -L1,-W1,H1}, + // la tour + {RECTANGLE, &tex_mur_moulin, NULL, L2,-W2,0, L2,W2,0, L2,-W2,H2}, + {RECTANGLE, &tex_mur_moulin, NULL, L2,W2,0, L1,W2,0, L2,W2,H2}, + {RECTANGLE, &tex_mur_moulin, NULL, L1,W2,0, L1,-W2,0, L1,W2,H2}, + {RECTANGLE, &tex_mur_moulin, NULL, L1,-W2,0, L2,-W2,0, L1,-W2,H2}, + // prolongement mur nef jusqu au toit + {TRIANGLE, &tex_brique, NULL, -L1,W1,H1, -L1,-W1,H1, -L1,0,HT1}, + // le toit de l extension + {RECTANGLE, &tex_paille, &tex_black, L1,W1+D,H1-3, -L1-D,W1+D,H1-3, L1,0,HT1}, + {RECTANGLE, &tex_paille, &tex_black, -L1-D,-W1-D,H1-3, L1,-W1-D,H1-3, -L1-D,0,HT1}, + // prolongement mur nef jusqu au toit + {TRIANGLE, &tex_mur_moulin, NULL, L2,W2,H2, L1,W2,H2, L3,W2,HT2}, + {TRIANGLE, &tex_mur_moulin, NULL, L1,-W2,H2, L2,-W2,H2, L3,-W2,HT2}, + // le toit de la tour + {RECTANGLE, &tex_toit_tuile, NULL, L2,-W2,H2, L2,W2,H2, L3,-W2,HT2}, + {RECTANGLE, &tex_toit_tuile, NULL, L1,W2,H2, L1,-W2,H2, L3,W2,HT2}, +}; + +#define A 3 // angle pale +const Modele modele_pale[] = { + {TRIANGLE, &tex_pale_moulin, &tex_pale_moulin, -21,-A,56, 21,A,56, 0,0,0}, + {TRIANGLE, &tex_pale_moulin, &tex_pale_moulin, 47,-A,36, 60,A,-2, 0,0,0}, + {TRIANGLE, &tex_pale_moulin, &tex_pale_moulin, 50,-A,-34, 17,A,-58, 0,0,0}, + {TRIANGLE, &tex_pale_moulin, &tex_pale_moulin, -17,-A,-58, -50,A,-34, 0,0,0}, + {TRIANGLE, &tex_pale_moulin, &tex_pale_moulin, -60,-A,-2, -47,A,37, 0,0,0}, +}; + + +#define L 40 // longueur X +#define W 20 // largueur Y +#define H 30 // hauteur mur Z +#define HT 55 // hauteur toit Z +#define D 5 // decalage toit XY +#define F1 10 // position X fenetre +#define F2 10 // position X fenetre +#define P -20 // position X fporte +const Modele modele_chaumiere[] = { + // les murs + {RECTANGLE, &tex_brique_base, NULL, L,-W,0, L,W,0, L,-W,H}, + {RECTANGLE, &tex_white, NULL, L,W,0, -L,W,0, L,W,H}, + {RECTANGLE, &tex_brique_base, NULL, -L,W,0, -L,-W,0, -L,W,H}, + {RECTANGLE, &tex_white, NULL, -L,-W,0, L,-W,0, -L,-W,H}, + // prolongement mur jusqu au toit + {TRIANGLE, &tex_brique, NULL, L,-W,H, L,W,H, L,0,HT}, + {TRIANGLE, &tex_brique, NULL, -L,W,H, -L,-W,H, -L,0,HT}, + // le toit + {RECTANGLE, &tex_paille, &tex_black, L+D,W+D,H-3, -L-D,W+D,H-3, L+D,0,HT}, + {RECTANGLE, &tex_paille, &tex_black, -L-D,-W-D,H-3, L+D,-W-D,H-3, -L-D,0,HT}, + // fenetre + {RECTANGLE, &tex_fenetre_simple, NULL, F1,W,8, F1-9,W,8, F1,W,25}, + {RECTANGLE, &tex_fenetre_simple, NULL, F2,-W,8, F2+9,-W,8, F2,-W,25}, + // porte + {RECTANGLE, &tex_porte_simple, NULL, P,W,0, P-12,W,0, P,W,25}, +}; + + +#define L 80 // longueur X +#define W 30 // largueur Y +#define H 35 // hauteur mur Z +#define HT 55 // hauteur toit Z +#define P -20 // position X fporte +const Modele modele_entrepot[] = { + // les murs + {RECTANGLE, &tex_brique, NULL, L,-W,0, L,W,0, L,-W,H}, + {RECTANGLE, &tex_white, NULL, L,W,0, -L,W,0, L,W,HT}, + {RECTANGLE, &tex_brique, NULL, -L,W,0, -L,-W,0, -L,W,H}, + {RECTANGLE, &tex_white, NULL, -L,-W,0, L,-W,0, -L,-W,H}, + // prolongement mur jusqu au toit + {TRIANGLE, &tex_white, NULL, L,-W,H, L,W,H, L,W,HT}, + {TRIANGLE, &tex_white, NULL, -L,W,H, -L,-W,H, -L,W,HT}, + // le toit + {RECTANGLE, &tex_paille, &tex_black, -L-D,-W-D,H-3, L+D,-W-D,H-3, -L-D,W+D,HT}, + // porte + {RECTANGLE, &tex_planche_bois, NULL, P,W+2,0, P-35,W+2,0, P,W+1,40}, + // glissiere + {RECTANGLE, &tex_black, NULL, P+35,W+2,0, P-40,W+2,0, P+35,W+1,1}, + {RECTANGLE, &tex_black, NULL, P+35,W+2,40, P-40,W+2,40, P+35,W+1,41}, +}; + + +#define LN 50 // longueur nef X +#define WN 22 // largueur nef Y +#define HN 60 // hauteur mur nef Z +#define HNT 80 // hauteur toit nef Z +#define D 5 // decalage toit XY +#define LT 90 // longueur tour X +#define WT 28 // largeur tour X +#define HT 100 // hauteur mur tour Z +#define HH 70 // hauteur horloge Z +#define HC 120 // hauteur clocher Z +#define HCT 150 // hauteur clocher max Z +const Modele modele_eglise[] = { + // les murs nefs + {RECTANGLE, &tex_white, NULL, LN,WN,0, -LN,WN,0, LN,WN,HN}, + {RECTANGLE, &tex_brique, NULL, -LN,WN,0, -LN,-WN,0, -LN,WN,HN}, + {RECTANGLE, &tex_white, NULL, -LN,-WN,0, LN,-WN,0, -LN,-WN,HN}, + // la tour + {RECTANGLE, &tex_pierre_eglise, NULL, LT,-WT,0, LT,WT,0, LT,-WT,HT}, + {RECTANGLE, &tex_pierre_eglise, NULL, LT,WT,0, LN,WT,0, LT,WT,HT}, + {RECTANGLE, &tex_pierre_eglise, NULL, LN,WT,0, LN,-WT,0, LN,WT,HT}, + {RECTANGLE, &tex_pierre_eglise, NULL, LN,-WT,0, LT,-WT,0, LN,-WT,HT}, + // prolongement mur nef jusqu au toit + {TRIANGLE, &tex_brique, NULL, -LN,WN,HN, -LN,-WN,HN, -LN,0,HNT}, + // le toit de la nef + {RECTANGLE, &tex_toit_tuile, &tex_black, LN,WN+D,HN-3, -LN-D,WN+D,HN-3, LN,0,HNT}, + {RECTANGLE, &tex_toit_tuile, &tex_black, -LN-D,-WN-D,HN-3, LN,-WN-D,HN-3, -LN-D,0,HNT}, + // horloge + {RECTANGLE, &tex_horloge, NULL, LT,-10,HH, LT,10,HH, LT,-10,HH+20}, + // porte + {RECTANGLE, &tex_porte_eglise, NULL, LT,-15,0, LT,15,0, LT,-15,60}, + // clocher + {TRIANGLE, &tex_toit_tuile, NULL, LT,-WT,HT, LT,WT,HT, 70,0,HCT}, + {TRIANGLE, &tex_toit_tuile, NULL, LT,WT,HT, LN,WT,HT, 70,0,HCT}, + {TRIANGLE, &tex_toit_tuile, NULL, LN,WT,HT, LN,-WT,HT, 70,0,HCT}, + {TRIANGLE, &tex_toit_tuile, NULL, LN,-WT,HT, LT,-WT,HT, 70,0,HCT}, +}; + + +#define L 30// longueur X +#define H 10// hauteur Z +const Modele modele_haie1[] = { + {RECTANGLE, &tex_haie, &tex_haie, -L,0,0, L,0,0, -L,0,H} +}; + +#define L 50// longueur X +#define H 10// hauteur Z +const Modele modele_haie2[] = { + {RECTANGLE, &tex_haie, &tex_haie, -L,0,0, L,0,0, -L,0,H} +}; + +#define L 10// longueur X +#define H 19// hauteur Z +const Modele modele_epouventail1[] = { + {RECTANGLE, &tex_epouvantail, &tex_epouvantail, -L,0,0, L,0,0, -L,0,H} +}; + +#define L 60// longueur X +#define H 9// hauteur Z +const Modele modele_herbe1[] = { + {RECTANGLE, &tex_herbe, &tex_herbe, -L,0,0, L,0,0, -L,0,H} +}; + +#define L 60// longueur X +#define H 9// hauteur Z +const Modele modele_herbe2[] = { + {RECTANGLE, &tex_herbe, &tex_herbe, -L,0,0, L,0,0, -L,0,H} +}; + +#define L 4// longueur X +#define H1 13// hauteur Z +#define H2 18// hauteur Z +const Modele modele_panneau1[] = { + {RECTANGLE, &tex_panneau, &tex_panneau, -L,0,H1, L,0,H1, -L,0,H2}, + {RECTANGLE, &tex_black, &tex_black, -L-1,0,0, -L,0,0, -L-1,0,H2}, + {RECTANGLE, &tex_black, &tex_black, L,0,0, L+1,0,0, L,0,H2} +}; + +#define L 7 // longueur X +#define W 7 // largueur Y +#define H 14 // hauteur Z +const Modele modele_botte_paille[] = { + // les cotes + {RECTANGLE, &tex_paille, NULL, L,-W,0, L,W,0, L,-W,H}, + {RECTANGLE, &tex_paille, NULL, L,W,0, -L,W,0, L,W,H}, + {RECTANGLE, &tex_paille, NULL, -L,W,0, -L,-W,0, -L,W,H}, + {RECTANGLE, &tex_paille, NULL, -L,-W,0, L,-W,0, -L,-W,H}, + // dessus + {RECTANGLE, &tex_paille_dessus, NULL, -L,-W,H, L,-W,H, -L,W,H}, +}; + +#define L 50 // longueur X +#define W 25 // largueur Y +#define H 25 // hauteur Z +const Modele modele_murs_maison_forgeron[] = { + // les cotes + {RECTANGLE, NULL, &tex_mur_int_maison, L,-W,0, L,W,0, L,-W,H}, + {RECTANGLE, NULL, &tex_mur_int_maison, L,W,0, -L,W,0, L,W,H}, + {RECTANGLE, NULL, &tex_mur_int_maison, -L,W,0, -L,-W,0, -L,W,H}, + {RECTANGLE, NULL, &tex_mur_int_maison, -L,-W,0, L,-W,0, -L,-W,H}, + //plafond + {RECTANGLE, NULL, &tex_black, -L,-W,H, L,-W,H, -L,W,H}, +}; + +#define L 10 // longueur X +#define W 4 // largueur Y +#define H 7 // hauteur Z +#define D 1 // decalage pied +#define E 1 // epaisseur pied +const Modele modele_table[] = { + // planche + {RECTANGLE, &tex_planche, &tex_black, -L,-W,H, L,-W,H, -L,W,H}, + // pieds + {RECTANGLE, &tex_black, &tex_black, -L+D,-W+D,0, -L+D+E,-W+D+E,0, -L+D,-W+D,H-1}, + {RECTANGLE, &tex_black, &tex_black, L-D,-W+D,0, L-D-E,-W+D+E,0, L-D,-W+D,H-1}, + {RECTANGLE, &tex_black, &tex_black, -L+D,W-D,0, -L+D+E,W-D-E,0, -L+D,W-D,H-1}, + {RECTANGLE, &tex_black, &tex_black, L-D,W-D,0, L-D-E,W-D-E,0, L-D,W-D,H-1}, +}; + +#define W 7 // largueur Y +#define H 20 // hauteur Z +const Modele modele_forgeron[] = { + {RECTANGLE, &tex_forgeron, NULL, 0,-W,0, 0,W,0, 0,-W,H}, +}; + + + +// MAP +// ECRAN TITRE +Object moulin_menu = {0,0,0, 0,N, modele_moulin,14, NONE}; +Object pale_menu = {50,27,70, 0,Y, modele_pale,5, NONE}; + +Object* list_menu[] = { + &moulin_menu, &pale_menu +}; + +Map map_menu = {list_menu, 2, true, true}; + + + + + +// VILLAGE +Object chaumiere1 = {-36,62,0, 0,N, modele_chaumiere,11, ALL}; +Object chaumiere2 = {-153,194,0, 251,Z, modele_chaumiere,11, ALL}; +Object chaumiere3 = {0,257,0, 143,Z, modele_chaumiere,11, ALL}; +Object entrepot = {319,-57,0, 80,Z, modele_entrepot,10, ALL}; +Object eglise1 = {153,253,0, -102,Z, modele_eglise,16, ALL}; +Object moulin1 = {21,-211,0, 0,N, modele_moulin,14, ALL}; +Object pale_moulin1 = {72,-183,70, 0,Y, modele_pale,5, NONE}; +Object haie1 = {0,-102,0, -5,Z, modele_haie1,1, ALL}; +Object haie2 = {-63,-105,0, 9,Z, modele_haie1,1, ALL}; +Object haie3 = {-132,-144,0, 46,Z, modele_haie2,1, ALL}; +Object haie4 = {144,-135,0, -14,Z, modele_haie2,1, ALL}; +Object haie5 = {-117,-264,0, -30,Z, modele_haie2,1, ALL}; +Object epouvantail1 = {-93,-210,0, -28,Z, modele_epouventail1,1, ALL}; +Object herbe1 = {-130,-200,0, 90,Z, modele_herbe1,1, NONE}; +Object herbe2 = {-109,-200,0, 90,Z, modele_herbe1,1, NONE}; +Object herbe3 = {-82,-191,0, 90,Z, modele_herbe1,1, NONE}; +Object herbe4 = {-61,-185,0, 90,Z, modele_herbe1,1, NONE}; +Object herbe5 = {-37,-179,0, 90,Z, modele_herbe1,1, NONE}; +Object herbe6 = {235,119,0, 131,Z, modele_herbe1,1, NONE}; +Object herbe7 = {292,51,0, 94,Z, modele_herbe1,1, NONE}; +Object panneau1 = {91,-117,0, 0,N, modele_panneau1,3, ALL}; +Object botte_paille1 = {269,42,0, 0,N, modele_botte_paille,5, ALL}; +Object botte_paille2 = {269,21,0, 0,N, modele_botte_paille,5, ALL}; +Object botte_paille3 = {272,30,14, 0,N, modele_botte_paille,5, ALL}; + +Object* list_village[] = { + &chaumiere1, &chaumiere2, &chaumiere3, &entrepot, &eglise1, &moulin1, + &pale_moulin1, &haie1, &haie2, &haie3, &haie4, &haie5, &epouvantail1, + &herbe1, &herbe2, &herbe3, &herbe4, &herbe5, &herbe6, &herbe7, &panneau1, + &botte_paille1, &botte_paille2, &botte_paille3 +}; + +Map map_village = {list_village, 24, true, true}; + + + + + +// CHEZ LE FORGERON +Object murs_maison_forgeron1 = {0,0,0, 0,N, modele_murs_maison_forgeron,5, INSIDE}; +Object table1 = {18,17,0, 0,N, modele_table,5, ALL}; +Object table2 = {-23,-7,0, 99,Z, modele_table,5, ALL}; +Object forgeron1 = {-34,-8,0, 0,Z_BILLBOARD, modele_forgeron,1, ALL}; + +Object* liste_interieur_forgeron[] = { + &murs_maison_forgeron1, &table1, &table2, &forgeron1 +}; +Map map_interieur_forgeron = {liste_interieur_forgeron, 4, false, false}; + + + + + +// EXEMPLE +const Texture tex_exemple = {sprite_exemple, NULL, 32, 32, 0, 0, 1, false, false, false}; +//const Texture tex_exemple_mask = {sprite_forgeron, mask_forgeron, 32, 64, 0, 0, 1, false, false, false}; + +#define L 50 // longueur X +#define W 25 // largueur Y +#define W2 12 // largeur divise par deux +#define H 30 // hauteur mur Z +#define HT 40 // hauteur toit +#define F 20 // fenetre +const Modele modele_maison[] = { + // les murs + {RECTANGLE, &tex_white, NULL, 0,0,0, L,0,0, 0,0,H}, + {RECTANGLE, &tex_brique_base, NULL, L,0,0, L,W,0, L,0,H}, + {RECTANGLE, &tex_white, NULL, L,W,0, 0,W,0, L,W,H}, + {RECTANGLE, &tex_brique_base, NULL, 0,W,0, 0,0,0, 0,W,H}, + // prolongement mur jusqu au toit + {TRIANGLE, &tex_brique, NULL, L,0,H, L,W,H, L,W2,HT}, + {TRIANGLE, &tex_brique, NULL, 0,W,H, 0,0,H, 0,W2,HT}, + // le toit + {RECTANGLE, &tex_paille, NULL, L,W,H, 0,W,H, L,W2,HT}, + {RECTANGLE, &tex_paille, NULL, 0,0,H, L,0,H, 0,W2,HT}, + // fenetre + {RECTANGLE, &tex_fenetre_simple, NULL, F,0,7, F+9,0,7, F,0,25}, + {RECTANGLE, &tex_fenetre_simple, NULL, F,W,7, F-9,W,7, F,W,25}, +}; + +Object maison1 = { 33,-50, 0, 0, N, modele_maison, 10, ALL}; +Object maison2 = {100, 12, 0, 90, Z, modele_maison, 10, ALL}; + +Object* liste_exemple[] = { + &maison1, &maison2 +}; + +Map map_exemple = {liste_exemple, 2, true, true}; diff --git a/src/player.cpp b/src/player.cpp new file mode 100644 index 0000000..7dbe43b --- /dev/null +++ b/src/player.cpp @@ -0,0 +1,49 @@ +#include "player.hpp" + +//----------------------------------------------------------------------------- +// PLAYER +//----------------------------------------------------------------------------- +Player::Player() +{ + x = 0; + y = 0; + z = 0; + yaw = 0; + pitch = 0; + + height = 16;//16 + total_height = 18; + belly = 5; + + action_distance = 20; + + moving = false; + jumping = false; + turning = false; + + translation_speed = 0; + rotation_speed = 0; + jump_speed = 0; + + translation_speed_max = 1.5; + translation_acceleration = 0.1; + rotation_speed_max = 7; + int hauteur_saut_max = 2; // en metre + jump_speed_max = sqrtf(hauteur_saut_max * 2 * 9.81); + + dissociate_camera = false; + can_move = true; +} + + +//----------------------------------------------------------------------------- +// TELEPORT +//----------------------------------------------------------------------------- +void Player::teleport(float _x, float _y, float _z, float _yaw, float _pitch) +{ + x = _x; + y = _y; + z = _z; + yaw = _yaw; + pitch = _pitch; +} diff --git a/src/player.hpp b/src/player.hpp new file mode 100644 index 0000000..b8121ab --- /dev/null +++ b/src/player.hpp @@ -0,0 +1,52 @@ +#ifndef DEF_PLAYER +#define DEF_PLAYER + +extern "C" +{ + #define __BSD_VISIBLE 1 + #include +} + + + +#define MAP_EXTERIOR_LIMIT 1000 +#define COL_NO 0 +#define COL_GROUND 1 +#define COL_WALL 2 +#define COL_ON 3 +#define COL_CARA 4 +#define COL_BOUND 5 + + + +class Player +{ +public: + Player(); + void teleport(float _x, float _y, float _z, float _yaw, float _pitch); + + float x, y, z, yaw, pitch; + + bool moving, jumping, turning; + + float height; + float total_height; + float belly; + + float action_distance; + + float translation_speed; + float rotation_speed; + float jump_speed; + + float translation_speed_max; + float translation_acceleration; + float rotation_speed_max; + float jump_speed_max; + + bool dissociate_camera; + bool can_move; +}; + + +#endif diff --git a/src/scene_map.cpp b/src/scene_map.cpp new file mode 100644 index 0000000..3774210 --- /dev/null +++ b/src/scene_map.cpp @@ -0,0 +1,849 @@ +#include "scene_map.hpp" + + +extern Game game; +extern Windmill windmill; + +// import des map +extern Map map_village; +extern Map map_interieur_forgeron; + +// import des objets +extern Object chaumiere1; +extern Object panneau1; +extern Object forgeron1; + +//---------------------------------------------------------------------------------------------------- +// CONSTRUCTOR +//---------------------------------------------------------------------------------------------------- +Scene_Map::Scene_Map() +{ + // debug + show_repere = false; + show_coordinates = false; + // histoire + vue_horloge = false; + vue_panneau_moulin = false; + parle_avec_forgeron = false; +} + +//---------------------------------------------------------------------------------------------------- +// LAUNCH +//---------------------------------------------------------------------------------------------------- +void Scene_Map::launch() +{ + time_scene = 0; + + load_map(); + windmill.set_camera(&camera); + + // histoire + // ... +} + + +void Scene_Map::load_map() +{ + // mise a jour de la map pour la scene + windmill.load_map(game.map); + + // creation des bouding box 3D + //delete bbox; + free(bbox); + //bbox = new Bbox3D[game.map->list_object_length]; + bbox = (Bbox3D*) malloc(game.map->list_object_length * sizeof(Bbox3D)); + //if (bbox == NULL) debug_pop("ERROR ptr bbox NULL"); + memset(bbox, 0, game.map->list_object_length * sizeof(Bbox3D)); + + for (int i=0; ilist_object_length; i++) + { + Object* current_object = game.map->object[i]; + Bbox3D* current_bbox = &bbox[i]; + + int nb_poly = (current_object->collision < 0) ? current_object->modele_size : current_object->collision; + if (nb_poly > current_object->modele_size) nb_poly = current_object->modele_size; + + for (int j=0; jmodele[j]; + + for (int k=0; ktype; k++) + { + Point point = windmill.get_point(current_modele, k); + current_bbox->x1 = min(current_bbox->x1, point.x); + current_bbox->y1 = min(current_bbox->y1, point.y); + current_bbox->z1 = min(current_bbox->z1, point.z); + current_bbox->x2 = max(current_bbox->x2, point.x); + current_bbox->y2 = max(current_bbox->y2, point.y); + current_bbox->z2 = max(current_bbox->z2, point.z); + } + } + if (current_object->axe == Z_BILLBOARD) + { + current_bbox->radius = max(current_bbox->y1, current_bbox->y2); + } + + } + + // mise a zero du temps sur la map + time_scene = 0; +} + + +//---------------------------------------------------------------------------------------------------- +// DRAW +//---------------------------------------------------------------------------------------------------- +void Scene_Map::draw() +{ + //ML_clear_vram(); + dclear(C_WHITE); + + windmill.draw(); + + // MAP VILLAGE + if (game.map == &map_village) + { + if (vue_panneau_moulin) + { + //ML_rectangle(34, 15, 95, 50, 0, ML_WHITE, ML_WHITE); + //PrintXY(34, 20, "MOULIN DES", 0); + //PrintXY(52, 30, "RIBES", 0); + //PrintMini(45, 45, "NineStars", 0); + } + } + + // MAP INTERIEUR FORGERON + if (game.map == &map_interieur_forgeron) + { + if (parle_avec_forgeron) + { + //Point point_ancrage = windmill.get_point(&forgeron1.modele, 0); + + //ML_rectangle(50, 10, 118, 54, 1, ML_BLACK, ML_WHITE); + } + } + + if (show_repere) windmill.show_repere(); + if (show_coordinates) windmill.show_coordinates(); + + //ML_display_vram(); + dupdate(); +} + + +//---------------------------------------------------------------------------------------------------- +// UPDATE +//---------------------------------------------------------------------------------------------------- +void Scene_Map::update() +{ + time_scene += 0.02; + + // gestion des touches + /*if (input_trigger(K_EXIT)) + { + scene = EXIT; + return; + } + if (input_trigger(K_MENU)) + { + scene = SCENE_TITLE; + return; + } + if (input_trigger(K_F1)) + { + scene = SCENE_MAP_DEBUG; + return; + } + if (input_trigger(K_F2)) + { + show_repere = !show_repere; + } + if (input_trigger(K_F3)) + { + show_coordinates = !show_coordinates; + }*/ + + // action du joueur sur la map + player_action(); + + // animation des objets sur la map + animation(); + + // mouvements du joueur + if (game.player.can_move) + { + player_move(); + player_turn(); + } + if (game.player.dissociate_camera == false) + { + camera.set(game.player.x, game.player.y, game.player.z + game.player.height, game.player.yaw, game.player.pitch); + } + + //debug_display(id(windmill.object_cursor), 3); + //debug_display(windmill.poly_cursor, 4); +} + + +void Scene_Map::player_action() +{ + // MAP VILLAGE + if (game.map == &map_village) + { + /*if (input_trigger(K_EXE)) + { + if (action_object(object(20))) + { + + if (vue_panneau_moulin) + { + game.player.can_move = true; + game.player.dissociate_camera = false; + windmill.set_camera(&camera); + } else { + game.player.can_move = false; + game.player.dissociate_camera = true; + look(&panneau1, 0, 8, 17, 270, -10); + windmill.set_camera(&camera_look); + } + vue_panneau_moulin = not vue_panneau_moulin; + } + }*/ + + } + + // MAP INTERIEUR FORGERON + if (game.map == &map_interieur_forgeron) + { + /*if (input_trigger(K_EXE)) + { + // interaction avec le forgeron + if (parle_avec_forgeron) + { + parle_avec_forgeron = false; + game.player.can_move = true; + game.player.dissociate_camera = false; + } else { + if (action_object(&forgeron1)) + { + parle_avec_forgeron = true; + game.player.can_move = false; + game.player.dissociate_camera = true; + camera.set(-23, 4, game.player.height, 198, 0); + } + } + }*/ + } +} + + +void Scene_Map::animation() +{ + // MAP VILLAGE + if (game.map == &map_village) + { + object(6)->angle -= 1; + } +} + + + + +void Scene_Map::player_move() +{ + /*///////////// METTRE DANS PLAYER ET RETURN LE FLAG + float new_x = game.player.x; + float new_y = game.player.y; + float new_z = game.player.z; + + // deplacement + float front, side; + input_move(&front, &side); + + // si des touches sont pressees + if (side != 0 or front != 0) + { + game.player.moving = true; + //game.player.translation_speed = min(game.player.translation_speed + 0.25, game.player.translation_speed_max); + if (game.player.translation_speed < game.player.translation_speed_max) + { + game.player.translation_speed += game.player.translation_acceleration; // acceleration + } else { + game.player.translation_speed = game.player.translation_speed_max; + } + // conversion dans le repere monde + float angle_rad = game.player.yaw * 3.1415 / 180.0; + float x = (front * cosf(angle_rad) - side * sinf(angle_rad)) * game.player.translation_speed; + float y = (front * sinf(angle_rad) + side * cosf(angle_rad)) * game.player.translation_speed; + new_x += x; + new_y += y; + } else { + game.player.moving = false; + game.player.translation_speed = 0; + } + + // saut + if (input_press(K_8) and not game.player.jumping) + { + game.player.jump_speed = game.player.jump_speed_max; + game.player.jumping = true; + } else { + game.player.jump_speed -= 0.981; // gravite + } + new_z += game.player.jump_speed; + + // collision + flag = collision(&new_x, &new_y, &new_z); + + // contact avec le sol ou un objet + if (flag.type == COLLISION_GROUND or flag.type == COLLISION_ON) + { + game.player.jumping = false; + game.player.jump_speed = 0; + } + + // hors terrain + if (flag.type == COLLISION_BOUND) + { + debug_display("trop loin", 2); + } + + game.player.x = new_x; + game.player.y = new_y; + game.player.z = new_z; + */ +} + + +void Scene_Map::player_turn() +{/* + float yaw = 0; + float pitch = 0; + + if (input_press(K_RIGHT)) yaw = -1; + if (input_press(K_LEFT)) yaw = 1; + if (input_press(K_DOWN)) pitch = -0.5; + if (input_press(K_UP)) pitch = 0.5; + + if (yaw != 0 or pitch != 0) + { + game.player.turning = true; + if (game.player.rotation_speed < game.player.rotation_speed_max) + { + game.player.rotation_speed += float(game.player.rotation_speed_max / 10.0); + } + } else { + game.player.turning = false; + game.player.rotation_speed = 0; + } + + yaw = game.player.yaw + yaw * game.player.rotation_speed; + pitch = game.player.pitch + pitch * game.player.rotation_speed; + if (yaw < 0) yaw += 360; + if (yaw >= 360) yaw -= 360; + if (pitch > 90) pitch = 90; + if (pitch < -90) pitch = -90; + + game.player.yaw = yaw; + game.player.pitch = pitch; + */ +} + + +//----------------------------------------------------------------------------- +// COLLISION +// renvoie le type de la derniere collision detectee +// 0 rien +// 1 sol +// 2 cote objet +// 3 dessus objet +// 4 z_billboard +// 5 hors terrain +//----------------------------------------------------------------------------- +Collision_flag Scene_Map::collision(float* new_x, float* new_y, float* new_z) +{ + Collision_flag flag; + + float belly = game.player.belly; + float total_height = game.player.total_height; + + flag.type = COLLISION_NONE; + flag.object = NULL; + + if (*new_z <= 0) + { + *new_z = 0; + flag.type = COLLISION_GROUND; + } + + for (int i = 0; ilist_object_length; i++) + { + Object* current_object = game.map->object[i]; + + // si une bbox a ete cree pour l objet + if (current_object->collision != 0) + { + Bbox3D* current_bbox = &bbox[i]; + + float cosinus, sinus; + float player_x, player_y, player_z; + float temp_new_x, temp_new_y, temp_new_z; + + // si objet.axe != N + if (current_object->axe == Z) + { + float angle = 3.1415 * current_object->angle / 180.0; + cosinus = cosf(angle); + sinus = sinf(angle); + + player_x = cosinus * (game.player.x-current_object->x) + sinus * (game.player.y-current_object->y); + player_y = - sinus * (game.player.x-current_object->x) + cosinus * (game.player.y-current_object->y); + player_z = game.player.z - current_object->z; + + temp_new_x = cosinus * (*new_x-current_object->x) + sinus * (*new_y-current_object->y); + temp_new_y = - sinus * (*new_x-current_object->x) + cosinus * (*new_y-current_object->y); + temp_new_z = *new_z - current_object->z; + } else { + cosinus = 1; + sinus = 0; + + player_x = game.player.x - current_object->x; + player_y = game.player.y - current_object->y; + player_z = game.player.z - current_object->z; + + temp_new_x = *new_x - current_object->x; + temp_new_y = *new_y - current_object->y; + temp_new_z = *new_z - current_object->z; + } + + if (temp_new_z > current_bbox->z2) + { + // player au dessus + + // si je mets rien ici, on pourra pas sauter sur une caisse... + } else if (temp_new_z + total_height < current_bbox->z1) + { + // player en dessous + + } else { + // détermine si INT ou EXT + //if (game.player.x > current_bbox->x1 and game.player.x < current_bbox->x2 and + // game.player.y > current_bbox->y1 and game.player.y < current_bbox->y2) + if (current_object->collision < 0) + { + // si player a l interieur de l objet + if (temp_new_x - belly < current_bbox->x1) + { + temp_new_x = current_bbox->x1 + belly; + } + if (temp_new_x + belly > current_bbox->x2) + { + temp_new_x = current_bbox->x2 - belly; + } + if (temp_new_y - belly < current_bbox->y1) + { + temp_new_y = current_bbox->y1 + belly; + } + if (temp_new_y + belly > current_bbox->y2) + { + temp_new_y = current_bbox->y2 - belly; + } + *new_x = cosinus * temp_new_x - sinus * temp_new_y + current_object->x; + *new_y = sinus * temp_new_x + cosinus * temp_new_y + current_object->y; + + if (flag.type <= COLLISION_WALL) + { + flag.type = COLLISION_WALL; + flag.object = current_object; + } + } else { + if (current_object->axe == Z_BILLBOARD) + { + bool inside_after = belly < current_bbox->radius; + if (inside_after) + { + //debug_pop("collsiosn"); + if (flag.type <= COLLISION_CARA) + { + flag.type = COLLISION_CARA; + flag.object = current_object; + } + } + } else { + bool inside_after = (temp_new_x + belly > current_bbox->x1 and temp_new_x - belly < current_bbox->x2 and + temp_new_y + belly > current_bbox->y1 and temp_new_y - belly < current_bbox->y2); + // si player a l exterieur de l objet + if (inside_after) + { + // player rentre dans objet par le haut + if (player_z >= current_bbox->z2 and temp_new_z < current_bbox->z2) + { + temp_new_z = current_object->z + current_bbox->z2; + *new_z = temp_new_z; + if (flag.type <= COLLISION_ON) + { + flag.type = COLLISION_ON; + flag.object = current_object; + } + } else { + // si on rentre dans l'objet + if (player_x < current_bbox->x1) + { + temp_new_x = current_bbox->x1 - belly; + } + if (player_x > current_bbox->x2) // modifier par un else ? + { + temp_new_x = current_bbox->x2 + belly; + } + if (player_y < current_bbox->y1) + { + temp_new_y = current_bbox->y1 - belly; + } + if (player_y > current_bbox->y2) + { + temp_new_y = current_bbox->y2 + belly; + } + // transformation inverse + *new_x = cosinus * temp_new_x - sinus * temp_new_y + current_object->x; + *new_y = sinus * temp_new_x + cosinus * temp_new_y + current_object->y; + + if (flag.type <= COLLISION_WALL) + { + flag.type = COLLISION_WALL; + flag.object = current_object; + } + } + } + } + } + } + } + } + + + if (*new_x * *new_x + *new_y * *new_y > MAP_EXTERIOR_LIMIT * MAP_EXTERIOR_LIMIT) + { + flag.type = COLLISION_BOUND; + *new_x = game.player.x; + *new_y = game.player.y; + } + + return flag; +} +/*Collision_flag Scene_Map::collision(float* new_x, float* new_y, float* new_z) +{ + Collision_flag flag; + + float belly = game.player.belly; + float total_height = game.player.total_height; + + flag.type = COLLISION_NONE; + flag.object = NULL; + + if (*new_z <= 0) + { + *new_z = 0; + flag.type = COLLISION_GROUND; + } + + for (int i = 0; ilist_object_length; i++) + { + Object* current_object = game.map->object[i]; + + // si une bbox a ete cree pour l objet + if (current_object->for_collision != 0) + { + Bbox3D* current_bbox = &bbox[i]; + + float cosinus, sinus; + float player_x, player_y, player_z; + float temp_new_x, temp_new_y, temp_new_z; + + // si objet.axe != N + if (current_object->axe == Z) + { + float angle = 3.1415 * current_object->angle / 180.0; + cosinus = cosf(angle); + sinus = sinf(angle); + + player_x = cosinus * (game.player.x-current_object->x) + sinus * (game.player.y-current_object->y); + player_y = - sinus * (game.player.x-current_object->x) + cosinus * (game.player.y-current_object->y); + player_z = game.player.z - current_object->z; + + temp_new_x = cosinus * (*new_x-current_object->x) + sinus * (*new_y-current_object->y); + temp_new_y = - sinus * (*new_x-current_object->x) + cosinus * (*new_y-current_object->y); + temp_new_z = *new_z - current_object->z; + } else { + cosinus = 1; + sinus = 0; + + player_x = game.player.x - current_object->x; + player_y = game.player.y - current_object->y; + player_z = game.player.z - current_object->z; + + temp_new_x = *new_x - current_object->x; + temp_new_y = *new_y - current_object->y; + temp_new_z = *new_z - current_object->z; + } + + if (temp_new_z > current_bbox->z2) + { + // player au dessus + + // si je mets rien ici, on pourra pas sauter sur une caisse... + } else if (temp_new_z + total_height < current_bbox->z1) + { + // player en dessous + + } else { + // détermine si INT ou EXT + //if (game.player.x > current_bbox->x1 and game.player.x < current_bbox->x2 and + // game.player.y > current_bbox->y1 and game.player.y < current_bbox->y2) + if (current_object->type_collision == OUT) + { + // si player a l interieur de l objet + if (temp_new_x - belly < current_bbox->x1) + { + temp_new_x = current_bbox->x1 + belly; + } + if (temp_new_x + belly > current_bbox->x2) + { + temp_new_x = current_bbox->x2 - belly; + } + if (temp_new_y - belly < current_bbox->y1) + { + temp_new_y = current_bbox->y1 + belly; + } + if (temp_new_y + belly > current_bbox->y2) + { + temp_new_y = current_bbox->y2 - belly; + } + *new_x = cosinus * temp_new_x - sinus * temp_new_y + current_object->x; + *new_y = sinus * temp_new_x + cosinus * temp_new_y + current_object->y; + + if (flag.type <= COLLISION_WALL) + { + flag.type = COLLISION_WALL; + flag.object = current_object; + } + } + + if (current_object->type_collision == IN) + { + if (current_object->axe == Z_BILLBOARD) + { + bool inside_after = belly < current_bbox->radius; + if (inside_after) + { + //debug_pop("collsiosn"); + if (flag.type <= COLLISION_CARA) + { + flag.type = COLLISION_CARA; + flag.object = current_object; + } + } + } else { + bool inside_after = (temp_new_x + belly > current_bbox->x1 and temp_new_x - belly < current_bbox->x2 and + temp_new_y + belly > current_bbox->y1 and temp_new_y - belly < current_bbox->y2); + // si player a l exterieur de l objet + if (inside_after) + { + // player rentre dans objet par le haut + if (player_z >= current_bbox->z2 and temp_new_z < current_bbox->z2) + { + temp_new_z = current_object->z + current_bbox->z2; + *new_z = temp_new_z; + if (flag.type <= COLLISION_ON) + { + flag.type = COLLISION_ON; + flag.object = current_object; + } + } else { + // si on rentre dans l'objet + if (player_x < current_bbox->x1) + { + temp_new_x = current_bbox->x1 - belly; + } + if (player_x > current_bbox->x2) // modifier par un else ? + { + temp_new_x = current_bbox->x2 + belly; + } + if (player_y < current_bbox->y1) + { + temp_new_y = current_bbox->y1 - belly; + } + if (player_y > current_bbox->y2) + { + temp_new_y = current_bbox->y2 + belly; + } + // transformation inverse + *new_x = cosinus * temp_new_x - sinus * temp_new_y + current_object->x; + *new_y = sinus * temp_new_x + cosinus * temp_new_y + current_object->y; + + if (flag.type <= COLLISION_WALL) + { + flag.type = COLLISION_WALL; + flag.object = current_object; + } + } + } + } + } + } + } + } + + + if (*new_x * *new_x + *new_y * *new_y > MAP_EXTERIOR_LIMIT * MAP_EXTERIOR_LIMIT) + { + flag.type = COLLISION_BOUND; + *new_x = game.player.x; + *new_y = game.player.y; + } + + return flag; +}*/ + + +void Scene_Map::look(Object* object, float x, float y, float z, float yaw, float pitch) +{ + Vertex vertex; + int cosinus, sinus; + + vertex.set_xyz(x, y, z); + windmill.compute_object_angle(object, &cosinus, &sinus); + windmill.transform_model_to_world(&vertex, 1, object, cosinus, sinus); + + camera_look.x = vertex.x; + camera_look.y = vertex.y; + camera_look.z = vertex.z; + camera_look.yaw = PI * (object->angle + yaw) / DEG; + camera_look.pitch = to_rad(pitch); +} + + +void Scene_Map::lerp_camera(Camera camera_start, Camera camera_end, float t) +{ + camera_temp.x = (1-t) * camera_start.x + t * camera_end.x; + camera_temp.y = (1-t) * camera_start.y + t * camera_end.y; + camera_temp.z = (1-t) * camera_start.z + t * camera_end.z; + camera_temp.yaw = (1-t) * camera_start.yaw + t * camera_end.yaw; + camera_temp.pitch = (1-t) * camera_start.pitch + t * camera_end.pitch; +} + + +Object* Scene_Map::object(int id) +{ + if (id < 0 or id >= game.map->list_object_length) + { + //debug_pop("ERROR id out of range"); + return NULL; + } + return game.map->object[id]; +} + + +int Scene_Map::id(Object* object) +{ + if (object == NULL) return -1; + for (int i = 0; ilist_object_length; i++) + { + if (game.map->object[i] == object) + { + return i; + } + } + //debug_pop("ERROR object not found"); + return -1; +} + + +bool Scene_Map::action_object(Object* object, int poly_id) +{ + if (look_object(object, poly_id) == false) return false; + + Point center_poly = windmill.get_center_poly(&object->modele[poly_id]); + + return action_object(object, center_poly.x, center_poly.y, center_poly.z); +} + + +bool Scene_Map::action_object(Object* object, float x, float y, float z) +{ + Vertex vertex; + int cosinus, sinus; + + vertex.set_xyz(x, y, z); + windmill.compute_object_angle(object, &cosinus, &sinus); + windmill.transform_model_to_world(&vertex, 1, object, cosinus, sinus); + + float dx = vertex.x - game.player.x; + float dy = vertex.y - game.player.y; + float dz = vertex.z - game.player.z; + if (dx < 0) dx = -dx; + if (dy < 0) dy = -dy; + if (dz < 0) dz = -dz; + + return (dx <= game.player.action_distance and dy <= game.player.action_distance); +} + + +bool Scene_Map::look_object(Object* object, int poly_id) +{ + if (poly_id == -1) + { + return (object == windmill.object_cursor); + } else { + return (object == windmill.object_cursor and poly_id == windmill.poly_cursor); + } + +} + + +//---------------------------------------------------------------------------------------------------- +// TERMINATE +//---------------------------------------------------------------------------------------------------- +void Scene_Map::terminate() +{ + +} +//---------------------------------------------------------------------------------------------------- +// DESTRUCTOR +//---------------------------------------------------------------------------------------------------- +Scene_Map::~Scene_Map() +{ + // rien +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/scene_map.hpp b/src/scene_map.hpp new file mode 100644 index 0000000..60aed71 --- /dev/null +++ b/src/scene_map.hpp @@ -0,0 +1,101 @@ +#ifndef DEF_SCENE_MAP +#define DEF_SCENE_MAP + +extern "C" +{ + #include + #include +} +#include "windmill.hpp" +#include "game.hpp" + + +#define EXIT 0 +#define SCENE_TITLE 1 +#define SCENE_MAP 2 +#define SCENE_MAP_DEBUG 3 + +#define PI 3.1415 +#define DEG 180.0 + +#define MAP_EXTERIOR_LIMIT 1000 +#define COLLISION_NONE 0 +#define COLLISION_GROUND 1 +#define COLLISION_WALL 2 +#define COLLISION_ON 3 +#define COLLISION_CARA 4 +#define COLLISION_BOUND 5 + +struct Collision_flag +{ + int type; + Object* object; +}; + + +struct Bbox3D +{ + short x1, y1, z1; + short x2, y2, z2; + short radius; +}; + +struct Location +{ + float x, y, z; + float yaw, pitch; +}; + + +class Scene_Map +{ +public: + Scene_Map(); + void launch(); + void update(); + void draw(); + void animation(); + void player_action(); + void load_map(); + //Object* object(int id); + void terminate(); + ~Scene_Map(); + + void player_move(); + void player_turn(); + Collision_flag collision(float* new_x, float* new_y, float* new_z); + + void look(Object* object, float x, float y, float z, float yaw, float pitch); + void lerp_camera(Camera camera_start, Camera camera_end, float t); + + // renvoie un pointeur vers l objet dont l id est connu + Object* object(int id); + // renvoie l id d un objet connu + int id(Object* object); + // retourne true si le joueur + bool action_object(Object* object, int poly_id = -1); + // retourne true si le joueur est proche du point (x,y,z) dans le repere de l'objet + bool action_object(Object* object, float x, float y, float z); + // retourne true le joueur regarde l objet [et le poly indique] + bool look_object(Object* object, int poly_id = -1); + + Camera camera; + float time_scene; + + // collision + Bbox3D* bbox; + Collision_flag flag; + + // histoire + bool show_repere; + bool show_coordinates; + + Camera camera_look; // camera ou regarder + Camera camera_temp; // camera temporaire pour les transitions + bool vue_horloge; + bool vue_panneau_moulin; + bool parle_avec_forgeron; + Location position_pancarte_entrepot; +}; + +#endif diff --git a/src/windmill.cpp b/src/windmill.cpp new file mode 100644 index 0000000..3b2a836 --- /dev/null +++ b/src/windmill.cpp @@ -0,0 +1,1788 @@ +//---------------------------------------------------------------------------------------------------- +// +// WINDMILL +// +// version : 2.0 +// Moteur de rendu 3D base sur la methode de rasterisation avec buffer de profondeur +// +// Cree par Olivier Lanneau, alias NineStars +// Planet-casio.fr +// +//---------------------------------------------------------------------------------------------------- + + +#include "windmill.hpp" + +//const Texture tex_black = {}; +//const Texture tex_white = {}; +extern Texture tex_white; +extern Texture tex_light; +extern Texture tex_dark; +extern Texture tex_black; + + +//---------------------------------------------------------------------------------------------------- +// INITIALISATION +//---------------------------------------------------------------------------------------------------- +Windmill::Windmill() +{ + camera2 = NULL; + map = NULL; + object = NULL; + z_buffer = NULL; + set_viewport(0, 0, 128, 64); + + nb_object_on_screen = 0; + temp_object_cursor = NULL; + temp_poly_cursor = -1; +} + + +void Windmill::set_camera(Camera* _camera) +{ + camera2 = _camera; +} + + +void Windmill::set_viewport(int viewport_x1, int viewport_y1, int viewport_x2, int viewport_y2) +{ + viewport.x1 = max(0, viewport_x1); + viewport.y1 = max(0, viewport_y1); + viewport.x2 = min(viewport_x2, DWIDTH); + viewport.y2 = min(viewport_y2, DHEIGHT); + + //if (z_buffer != NULL) free(z_buffer); + free(z_buffer); + shift_x = (viewport.x1 + viewport.x2) / 2; + shift_y = (viewport.y1 + viewport.y2) / 2; + + z_buffer_size = (viewport.x2 - viewport.x1) * (viewport.y2 - viewport.y1); + z_buffer = (unsigned short*) calloc(z_buffer_size, 2); + //if (z_buffer == NULL) debug_pop("ERROR ptr z_buffer NULL"); + z_buffer_width = viewport.x2 - viewport.x1; + z_buffer_offset = - viewport.x1 - viewport.y1 * DWIDTH; + clear_z_buffer(); + + cursor_x = shift_x; + cursor_y = shift_y; +} + + +void Windmill::load_map(Map* _map) +{ + loading = true; + + if (map != _map) + { + // attribution de la map + map = _map; + + // enregistrement des objets de la map dans un tableau + // ceci permet de trier les objets pour les afficher du plus + // pres au plus loin + list_object_length = map->list_object_length; + //delete[] object; + free(object); + //object = new Object* [list_object_length]; + object = (Object**) malloc(list_object_length * sizeof(Object)); + //if (object == NULL) debug_pop("ERROR ptr object NULL"); + for (int i = 0; iobject[i]; + } + + // generation des spheres englobantes + // pour chaque objet + for (int i = 0; ilist_object_length; i++) + { + Object* current_object = map->object[i]; + int nb_point = 0; + int center_x = 0; + int center_y = 0; + int center_z = 0; + + // pour chaque poly + for (int j = 0; jmodele_size; j++) + { + const Modele* current_poly = ¤t_object->modele[j]; + + // pour chaque point + for (int k = 0; ktype; k++) + { + Point point = get_point(current_poly, k); + center_x += point.x; + center_y += point.y; + center_z += point.z; + + nb_point++; + } + } + // barycentre + center_x /= nb_point; + center_y /= nb_point; + center_z /= nb_point; + + // recherche du point le plus eloigne du centre + int radius_max = 0; + for (int j = 0; jmodele_size; j++) + { + const Modele* current_poly = ¤t_object->modele[j]; + for (int k = 0; ktype; k++) + { + Point point = get_point(current_poly, k); + int dx = point.x - center_x; + int dy = point.y - center_y; + int dz = point.z - center_z; + int radius = dx*dx + dy*dy + dz*dz; + //int rr = sqrtf(radius); + if (radius > radius_max) + { + radius_max = radius; + } + } + } + radius_max = sqrtf(radius_max) + 1; + + current_object->sphere.x = center_x; + current_object->sphere.y = center_y; + current_object->sphere.z = center_z; + current_object->sphere.radius = radius_max; + } + } + + loading = false; +} + + + + + +//---------------------------------------------------------------------------------------------------- +// DESSIN +//---------------------------------------------------------------------------------------------------- +void Windmill::draw() +{ + // quitte si pas de camera, de map, d objet ou de z_buffer + if(camera2 == NULL or map == NULL or object == NULL or z_buffer == NULL) return; + + // mets a jour les variables de la camera + camera2->update(); + + // cree une camera temporaire pour eviter les problemes de desynchronisation + copy_camera(); + + // fonction principale, l'ordre d'appel des fonctions suivantes est important + clear_z_buffer(); + + // trie les objets pour optimiser l affichage + sort_object(); + + // affiche le trait d'horizon + if (map->horizon) draw_horizon(); + + // affiche le sol + if (map->ground) draw_ground(); + + // affiche les objets de la scene + draw_objects(); + + // post traitement pour afficher les angles vifs + draw_post_treatment(); + + // affiche le corps du personnage + draw_body(); + + // affiche des informations + //show_fps(); + //show_coordinates(); + //show_repere(); +} + + +void Windmill::draw_horizon() +{ + Vertex horizon; + char* vram = get_vram_address(); + int distance = 1000; + int hx = camera.x + distance * camera.cos_yaw; + int hy = camera.y + distance * camera.sin_yaw; + + horizon.set_xyz(hx, hy, 0); + + transform_world_to_camera(&horizon, 1); + transform_camera_to_screen(&horizon, 1); + if (inside_viewport(horizon.x, horizon.y)) + { + dline(viewport.x1, horizon.y, viewport.x2, horizon.y, C_BLACK); + //ML_line(viewport.x1, horizon.y, viewport.x2, horizon.y, ML_BLACK); + } +} + + +void Windmill::draw_ground() +{ + Vertex ground; + char* vram = get_vram_address(); + unsigned char mask; + int distance = 50; + int esp = 20; + int nb = 6; + int nb2 = nb * nb; + float cx = camera.x + distance * camera.cos_yaw; + float cy = camera.y + distance * camera.sin_yaw; + int dx = int(cx) - int(cx)%esp; + int dy = int(cy) - int(cy)%esp; + + for (int i=-nb; i 0) + { + transform_camera_to_screen(&ground, 1); + if (inside_viewport(ground.x, ground.y) == true) + { + mask = 128 >> (ground.x & 7); + vram[(ground.y << 4) + (ground.x>>3)] |= mask; + } + } + } + } + } +} + + +void Windmill::draw_objects() +{ + nb_object_on_screen = 0; + temp_object_cursor = NULL; + temp_poly_cursor = -1; + + Vertex vertex[10]; + int vertex_length; + int width, height; + int cosinus, sinus; + + for(i=0; ilist_object_length; i++) + { + //Object* current_object = map->object[i]; + Object* current_object = object[i]; + + if (current_object->hidden == false) + { + // angle de l objet + compute_object_angle(current_object, &cosinus, &sinus); + + // transforme la sphere dans le repere monde + Sphere current_sphere = transform_sphere_to_world(¤t_object->sphere, current_object, cosinus, sinus); + + // verifie si la sphere englobante est dans le champs de vision de la camera + if (sphere_in_cone(¤t_sphere)) + { + temp_nb_object_on_screen ++; + current_object->on_screen = true; + current_object->distance_to_camera = current_sphere.z; + + for(j=0; jmodele_size; j++) + { + const Modele* current_poly = ¤t_object->modele[j]; + + // creation des vertex a partir du poly + extract_vertex_from_poly(current_poly, vertex, &vertex_length, &width, &height); + + // calcul des coordonnees dans le repère monde apres rotation et translation de l objet + transform_model_to_world(vertex, vertex_length, current_object, cosinus, sinus); + + // calcul des coordonnees dans le repère camera apres rotation et translation de la camera + transform_world_to_camera(vertex, vertex_length); + + // verifie si au moins 1 point peut etre visible + if (fast_check(vertex, vertex_length)) + { + // calcul de l'aire du rectangle pour connaitre sa face visible + int visible = visible_face(&vertex[0], &vertex[1], &vertex[2]); + + // choisi la texture visible + const Texture* texture; + texture = (visible == FRONT) ? current_poly->texture_front : current_poly->texture_back; + + // si le rectangle est visible + if (texture != NULL) + { + // si le rectangle a une texture + if (texture != &tex_black && texture != &tex_white) + { + texture_coordinates(current_poly, vertex, texture, visible, width, height); + } + + // tronque le polygon devant le plan avant de la camera + clip_depth(vertex, &vertex_length); + + // calcul des coordonnes apres perspective et decalage au centre de l ecran + transform_camera_to_screen(vertex, vertex_length); + + // tronque le polygon sur les bords de l ecran + clip_viewport(vertex, &vertex_length); + + // calcul des coordonnees de profondeur + transform_camera_to_screen2(vertex, vertex_length); + + // affiche les triangles + if (visible == FRONT) + { + for (int k = 1; k1; k--) + { + render_triangle(&vertex[0], &vertex[k], &vertex[k-1], texture); + } + } + } + } + } + } else { + current_object->on_screen = false; + } + } + } + + nb_object_on_screen = temp_nb_object_on_screen; + object_cursor = temp_object_cursor; + poly_cursor = temp_poly_cursor; +} + + +void Windmill::draw_post_treatment() +{ + char* vram = get_vram_address(); + unsigned char mask; + int current, right, bottom, left; + + for (int y = viewport.y1; y> ((x+1) & 7); + vram[address<<3] |= mask; + + //ML_pixel(x+1, y, ML_BLACK); + } + if (bottom < MAX_DEPTH_Z_BUFFER) + { + dpixel(x, y+1, C_BLACK); + //ML_pixel(x, y+1, ML_BLACK); + } + } else { + if (right == MAX_DEPTH_Z_BUFFER or bottom == MAX_DEPTH_Z_BUFFER) + { + dpixel(x, y+1, C_BLACK); + //ML_pixel(x, y, ML_BLACK); + } + } + } + + } // 21 fps 21,5 fps*/ + + /*left = z_buffer[0]; + for (int i = 1; i> (i & 7); + vram[(i - z_buffer_offset)>>3] |= mask; + } + } else { + if (left < MAX_DEPTH_Z_BUFFER) + { + mask = 128 >> ((i-1) & 7); + vram[(i - 1 - z_buffer_offset)>>3] |= mask; + + } + } + } + // sans rien 28 fps + // avec le i+1 : 24 fps + // avec le i : 25 fps + // calculer left = Z_buffer[i-1] dans if : 24 fps + // avec les deux cote : 24 fps ! */ + + bool flag = false; + for (int i = 0; i> ((i-2) & 7); + vram[(i - 2 - z_buffer_offset)>>3] |= mask; + flag = false; + } else { + // l objet commencait en fait 1 pixel a gauche + mask = 128 >> ((i-1) & 7); + vram[(i - 1 - z_buffer_offset)>>3] |= mask; + flag = false; + } + } + } else { + if (flag == false) + { + if (z_buffer[i-1] == MAX_DEPTH_Z_BUFFER) + { + // il y avait rien juste a gauche + mask = 128 >> (i & 7); + vram[(i - z_buffer_offset)>>3] |= mask; + flag = true; + } else { + // l objet commencait en fait 1 pixel a gauche + mask = 128 >> ((i-1) & 7); + vram[(i - 1 - z_buffer_offset)>>3] |= mask; + flag = true; + } + } + } + } // 24 fps + // avec astuce +=2 : 25 fps + + /*bool flag = false; + char i_mod_8; + for (int i = 0; i> i_mod_8;//((i-1) & 7); + flag = false; + } + } else { + if (flag == false) + { + mask |= 128 >> i_mod_8; + flag = true; + } + } + if (i_mod_8 == 7) + { + //if (mask > 0) + vram[i>>3] |= mask; + mask = 0; + } + }*/ +} + + +void Windmill::draw_body() +{ + /*int x = camera.x; + int y = camera.y; + int z = camera.z; + + Vertex v0, v1, v2, v3; + set_vertex_xyz() + METTRE DIRECT LES VERTEX DANS LE REPERE SCREEN PUIS RENDER... +*/ +} + + + + + +//---------------------------------------------------------------------------------------------------- +// TRANSFORMATION 3D +//---------------------------------------------------------------------------------------------------- +void Windmill::transform_model_to_world(Vertex vertex[], int vertex_length, Object* object, int cosinus, int sinus) +{ + for (int k = 0; kaxe == N) + { + vertex[k].x = vertex_x + object->x; + vertex[k].y = vertex_y + object->y; + vertex[k].z = vertex_z + object->z; + } + if (object->axe == X) + { + vertex[k].x = vertex_x + object->x; + vertex[k].y = ((vertex_y * cosinus - vertex_z * sinus) >> 10) + object->y; + vertex[k].z = ((vertex_y * sinus + vertex_z * cosinus) >> 10) + object->z; + } + if (object->axe == Y) + { + vertex[k].x = ((vertex_x * cosinus - vertex_z * sinus) >> 10) + object->x; + vertex[k].y = vertex_y + object->y; + vertex[k].z = ((vertex_x * sinus + vertex_z * cosinus) >> 10) + object->z; + } + if (object->axe == Z or object->axe == Z_BILLBOARD) + { + vertex[k].x = ((vertex_x * cosinus - vertex_y * sinus) >> 10) + object->x; + vertex[k].y = ((vertex_x * sinus + vertex_y * cosinus) >> 10) + object->y; + vertex[k].z = vertex_z + object->z; + } + + } +} + + +void Windmill::transform_world_to_camera(Vertex vertex[], int vertex_length) +{ + for (int k = 0; kz_normalized = (1<<15) * (vertex->z * camera.far - SCALE_AI * camera.far * camera.near) / (vertex->z * (camera.far - camera.near)); + // precalcul de 1/z + vertex[k].z = (1<<20) / vertex[k].z; + } +} + + + + + +//---------------------------------------------------------------------------------------------------- +// TEST VISIBILITE +//---------------------------------------------------------------------------------------------------- +bool Windmill::fast_check(Vertex vertex[], int vertex_length) +{ + int near = camera.near * SCALE_AI; + int far = camera.far * SCALE_AI; + + for (int i = 0; i= near and vertex[i].z < far) return true; + } + + return false; +} + + +bool Windmill::inside_viewport(int x, int y) +{ + return (x < viewport.x2 and y >= viewport.y1 and x >= viewport.x1 and y < viewport.y2); +} + + +int Windmill::visible_face(Vertex* a, Vertex* b, Vertex* c) +{ + int nx = ((b->y - a->y) * (c->z - a->z) - (b->z - a->z) * (c->y - a->y)) >> 15; + int ny = ((b->z - a->z) * (c->x - a->x) - (b->x - a->x) * (c->z - a->z)) >> 15; + int nz = ((b->x - a->x) * (c->y - a->y) - (b->y - a->y) * (c->x - a->x)) >> 15; + return (nx*a->x + ny*a->y + nz*a->z > 0) ? BACK : FRONT; +} + + + +// Sutherland–Hodgman algorithm +void Windmill::clip_depth(Vertex vertex_input[], int* vertex_input_length) +{ + Vertex vertex_temp; + Vertex vertex_output[10]; + int vertex_output_length = 0; + + int S = *vertex_input_length-1; + + for (int E = 0; E<*vertex_input_length; E++) + { + if (clip_depth_inside_edge(&vertex_input[E]) == true) + { + if (clip_depth_inside_edge(&vertex_input[S]) == false) + { + clip_depth_edge(&vertex_input[E], &vertex_input[S], &vertex_temp); + copy_vertex(&vertex_temp, &vertex_output[vertex_output_length]); + vertex_output_length += 1; + } + copy_vertex(&vertex_input[E], &vertex_output[vertex_output_length]); + vertex_output_length += 1; + + } else if (clip_depth_inside_edge(&vertex_input[S]) == true) + { + clip_depth_edge(&vertex_input[S], &vertex_input[E], &vertex_temp); + copy_vertex(&vertex_temp, &vertex_output[vertex_output_length]); + vertex_output_length += 1; + } + S = E; + + } + + *vertex_input_length = vertex_output_length; + for (int i = 0; i<*vertex_input_length; i++) + { + copy_vertex(&vertex_output[i], &vertex_input[i]); + } +} + + +void Windmill::clip_depth_edge(Vertex* vertex_in, Vertex* vertex_out, Vertex* vertex_set) +{ + int near, x_near, y_near, z_near, w_near, h_near; + float t; + + near = camera.near * SCALE_AI; + t = float(near - vertex_in->z) / float(vertex_out->z - vertex_in->z); + + x_near = (vertex_out->x - vertex_in->x) * t + vertex_in->x; + y_near = (vertex_out->y - vertex_in->y) * t + vertex_in->y; + z_near = near; + + w_near = (vertex_out->w - vertex_in->w) * t + vertex_in->w; + h_near = (vertex_out->h - vertex_in->h) * t + vertex_in->h; + + vertex_set->set_xyz(x_near, y_near, z_near); + vertex_set->set_wh(w_near, h_near); +} + + +bool Windmill::clip_depth_inside_edge(Vertex* vertex) +{ + return (vertex->z >= camera.near * SCALE_AI) ? true : false; +} + + +// Sutherland–Hodgman algorithm +void Windmill::clip_viewport(Vertex vertex_input[], int* vertex_input_length) +{ + Vertex vertex_temp; + + Vertex vertex_output[10]; + int vertex_output_length = *vertex_input_length; + + for (int i = 0; i<*vertex_input_length; i++) + { + copy_vertex(&vertex_input[i], &vertex_output[i]); + } + + for (int edge = 0; edge < 4; edge++) + { + for (int i = 0; ix) / float(vertex_out->x - vertex_in->x); + x_set = viewport.x2-1; + y_set = (vertex_out->y - vertex_in->y) * t + vertex_in->y; + } + if (edge == 1) + { + t = float(viewport.y1 - vertex_in->y) / float(vertex_out->y - vertex_in->y); + x_set = (vertex_out->x - vertex_in->x) * t + vertex_in->x; + y_set = viewport.y1; + } + if (edge == 2) + { + t = float(viewport.x1 - vertex_in->x) / float(vertex_out->x - vertex_in->x); + x_set = viewport.x1; + y_set = (vertex_out->y - vertex_in->y) * t + vertex_in->y; + } + if (edge == 3) + { + t = float(viewport.y2 - 1 - vertex_in->y) / float(vertex_out->y - vertex_in->y); + x_set = (vertex_out->x - vertex_in->x) * t + vertex_in->x; + y_set = viewport.y2-1; + } + + z_set = 0.5 + float(1) / (float(1-t)/float(vertex_in->z) + float(t)/float(vertex_out->z)); + w_set = z_set * ( (1.0-t) * vertex_in->w / float(vertex_in->z) + t * vertex_out->w / float(vertex_out->z) ); + h_set = z_set * ( (1.0-t) * vertex_in->h / float(vertex_in->z) + t * vertex_out->h / float(vertex_out->z) ); + + + vertex_set->set_xyz(x_set, y_set, z_set); + vertex_set->set_wh(w_set, h_set); +} + + +bool Windmill::clip_viewport_inside_edge(Vertex* vertex, int edge) +{ + // 0 : RIGHT 1 : UP 2: LEFT 3 : DOWN + if (edge == 0 and vertex->x < viewport.x2-1) return true; + if (edge == 1 and vertex->y > viewport.y1) return true; + if (edge == 2 and vertex->x > viewport.x1) return true; + if (edge == 3 and vertex->y < viewport.y2-1) return true; + + return false; +} + + + + + +//---------------------------------------------------------------------------------------------------- +// DESSIN DES TRIANGLES +//---------------------------------------------------------------------------------------------------- +void Windmill::render_triangle(Vertex* vertexA, Vertex* vertexB, Vertex* vertexC, const Texture *texture)//, bool billboard) +{ + //render_triangle_black(vertexA, vertexB, vertexC); + if (texture == NULL) return; + if (texture == &tex_black) + { + render_triangle_black(vertexA, vertexB, vertexC); + } + else if (texture == &tex_white) + { + render_triangle_white(vertexA, vertexB, vertexC); + } + else if (texture->transparent == true) + { + render_triangle_transparent(vertexA, vertexB, vertexC, texture); + } + else + { + render_triangle_texture(vertexA, vertexB, vertexC, texture); + } +} + + +void Windmill::render_triangle_texture(Vertex* vertexA, Vertex* vertexB, Vertex* vertexC, const Texture* texture) +{ + // calcul du rectangle circonscrit au triangle + int min_x = max(viewport.x1, min(vertexA->x, min(vertexB->x, vertexC->x))); + int max_x = min(viewport.x2-1, max(vertexA->x, max(vertexB->x, vertexC->x))); + int min_y = max(viewport.y1, min(vertexA->y, min(vertexB->y, vertexC->y))); + int max_y = min(viewport.y2-1, max(vertexA->y, max(vertexB->y, vertexC->y))); + + // calcul de l'aire du triangle + int area = edge(vertexA, vertexB, vertexC); + // determine si la taille du triangle est trop petite + if (area <= MIN_AREA_CLIP) return; + + // pre-calcul des coordonnees de la texture + int w0 = vertexA->w * vertexA->z; int h0 = vertexA->h * vertexA->z; + int w1 = vertexB->w * vertexB->z; int h1 = vertexB->h * vertexB->z; + int w2 = vertexC->w * vertexC->z; int h2 = vertexC->h * vertexC->z; + + // calcul des produits vectoriels + int u0_start = edge_start(vertexB, vertexC, min_x, min_y); + int u0_step_x = edge_step_x(vertexB, vertexC); + int u0_step_y = edge_step_y(vertexB, vertexC); + int u1_start = edge_start(vertexC, vertexA, min_x, min_y); + int u1_step_x = edge_step_x(vertexC, vertexA); + int u1_step_y = edge_step_y(vertexC, vertexA); + int u2_start = edge_start(vertexA, vertexB, min_x, min_y); + int u2_step_x = edge_step_x(vertexA, vertexB); + int u2_step_y = edge_step_y(vertexA, vertexB); + + int z_num_start = (u0_start * vertexA->z_normalized + u1_start * vertexB->z_normalized + u2_start * vertexC->z_normalized) / area; + int z_num_step_x = (u0_step_x * vertexA->z_normalized + u1_step_x * vertexB->z_normalized + u2_step_x * vertexC->z_normalized) / area; + int z_num_step_y = (u0_step_y * vertexA->z_normalized + u1_step_y * vertexB->z_normalized + u2_step_y * vertexC->z_normalized) / area; + + int z_div_start = u0_start * vertexA->z + u1_start * vertexB->z + u2_start * vertexC->z; + int z_div_step_x = u0_step_x * vertexA->z + u1_step_x * vertexB->z + u2_step_x * vertexC->z; + int z_div_step_y = u0_step_y * vertexA->z + u1_step_y * vertexB->z + u2_step_y * vertexC->z; + + // rapprochement artificiel si texture de type decoration + int decoration = (texture->decoration ? DECORATION_OFFSET : 0); + + // acces a la vram + char* vram = get_vram_address(); + unsigned char mask_vram, mask_w; + int offset_vram; + int address; + + int u0, u1, u2; + int z_num, z_div; + int w, h; + + // pre-calcul largeur en octet des tableaux + int nbw_tex = ((texture->pixel_width - 1) >> 3) + 1; + char loop_w_tex = texture->pixel_width-1; + char loop_h_tex = texture->pixel_height-1; + + // parcours en ligne + for(int x=min_x; x<=max_x; x++) + { + u0 = u0_start; u1 = u1_start; u2 = u2_start; + z_num = z_num_start; + z_div = z_div_start; + offset_vram = x >> 3; + mask_vram = 128 >> (x & 7); + // parcours en colonne + for(int y=min_y; y<=max_y; y++) + { + // si le pixel (x;y) est dans le triangle + if ((u0 | u1 | u2) > 0) + { + // addresse du z-buffer + address = x + y * z_buffer_width + z_buffer_offset; + // si le pixel (x;y) est plus proche qu'avant + if (z_num <= z_buffer[address] + decoration) + { + // calcul des coordonnees pour la texture + w = ((u0 * w0 + u1 * w1 + u2 * w2) / z_div) & loop_w_tex; + h = ((u0 * h0 + u1 * h1 + u2 * h2) / z_div) & loop_h_tex; + // calcul du masque pour l'octet + mask_w = 128 >> (w & 7); + if (texture->mask == NULL) + { + // enregistre la profondeur du pixel dans le z buffer + z_buffer[address] = z_num; + if ((texture->sprite[(w >> 3) + (h * nbw_tex)] & mask_w)) + { + // afficher pixel noir + vram[(y << 4) + offset_vram] |= mask_vram; + }else{ + // afficher pixel blanc + vram[(y << 4) + offset_vram] &= ~mask_vram; + } + // curseur + pixel_on_cursor(x, y); + } else { + int alpha = (w >> 3) + (h * nbw_tex); + if ((texture->mask[alpha] & mask_w)) + { + // enregistre la profondeur du pixel dans le z buffer + z_buffer[address] = z_num; + if ((texture->sprite[alpha] & mask_w)) + { + // afficher pixel noir + vram[(y << 4) + offset_vram] |= mask_vram; + }else{ + // afficher pixel blanc + vram[(y << 4) + offset_vram] &= ~mask_vram; + } + // curseur + pixel_on_cursor(x, y); + } + } + + } + } + u0 += u0_step_y; u1 += u1_step_y; u2 += u2_step_y; + z_num += z_num_step_y; + z_div += z_div_step_y; + } + u0_start += u0_step_x; u1_start += u1_step_x; u2_start += u2_step_x; + z_num_start += z_num_step_x; + z_div_start += z_div_step_x; + } +} + + + + +void Windmill::render_triangle_black(Vertex* vertexA, Vertex* vertexB, Vertex* vertexC) +{ + // calcul du rectangle circonscrit au triangle + int min_x = max(viewport.x1, min(vertexA->x, min(vertexB->x, vertexC->x))); + int max_x = min(viewport.x2-1, max(vertexA->x, max(vertexB->x, vertexC->x))); + int min_y = max(viewport.y1, min(vertexA->y, min(vertexB->y, vertexC->y))); + int max_y = min(viewport.y2-1, max(vertexA->y, max(vertexB->y, vertexC->y))); + + // calcul de l'aire du triangle + int area = edge(vertexA, vertexB, vertexC); + // termine si la taille du triangle est trop petite + if (area <= MIN_AREA_CLIP) return; + + // calcul des produits vectoriels + int u0_start = edge_start(vertexB, vertexC, min_x, min_y); + int u0_step_x = edge_step_x(vertexB, vertexC); + int u0_step_y = edge_step_y(vertexB, vertexC); + int u1_start = edge_start(vertexC, vertexA, min_x, min_y); + int u1_step_x = edge_step_x(vertexC, vertexA); + int u1_step_y = edge_step_y(vertexC, vertexA); + int u2_start = edge_start(vertexA, vertexB, min_x, min_y); + int u2_step_x = edge_step_x(vertexA, vertexB); + int u2_step_y = edge_step_y(vertexA, vertexB); + + int z_num_start = (u0_start * vertexA->z_normalized + u1_start * vertexB->z_normalized + u2_start * vertexC->z_normalized) / area; + int z_num_step_x = (u0_step_x * vertexA->z_normalized + u1_step_x * vertexB->z_normalized + u2_step_x * vertexC->z_normalized) / area; + int z_num_step_y = (u0_step_y * vertexA->z_normalized + u1_step_y * vertexB->z_normalized + u2_step_y * vertexC->z_normalized) / area; + + // acces a la vram + char* vram = get_vram_address(); + unsigned char mask_vram; + int offset_vram; + int address; + + int u0, u1, u2; + int z_num; + + // parcours en ligne + for(int x=min_x; x<=max_x; x++) + { + u0 = u0_start; u1 = u1_start; u2 = u2_start; + z_num = z_num_start; + offset_vram = x >> 3; + mask_vram = 128 >> (x & 7); + // parcours en colonne + for(int y=min_y; y<=max_y; y++) + { + // si le pixel (x;y) est dans le triangle + if ((u0 | u1 | u2) > 0) + { + // addresse du z-buffer + address = x + y * z_buffer_width + z_buffer_offset; + // si le pixel (x;y) est plus proche qu'avant + if (z_num <= z_buffer[address]) + { + // enregistre la profondeur du pixel dans le z buffer + z_buffer[address] = z_num; + // afficher pixel noir + vram[(y << 4) + offset_vram] |= mask_vram; + // curseur + pixel_on_cursor(x, y); + } + } + u0 += u0_step_y; u1 += u1_step_y; u2 += u2_step_y; + z_num += z_num_step_y; + } + u0_start += u0_step_x; u1_start += u1_step_x; u2_start += u2_step_x; + z_num_start += z_num_step_x; + } +} + +/* +void Windmill::render_triangle_black(Vertex* vertexA, Vertex* vertexB, Vertex* vertexC) +{ + // calcul du rectangle circonscrit au triangle + int min_x = max(viewport.x1, min(vertexA->x, min(vertexB->x, vertexC->x))); + int max_x = min(viewport.x2-1, max(vertexA->x, max(vertexB->x, vertexC->x))); + int min_y = max(viewport.y1, min(vertexA->y, min(vertexB->y, vertexC->y))); + int max_y = min(viewport.y2-1, max(vertexA->y, max(vertexB->y, vertexC->y))); + + // calcul de l'aire du triangle + int area = edge(vertexA, vertexB, vertexC); + // termine si la taille du triangle est trop petite + if (area <= MIN_AREA_CLIP) return; + + // calcul des produits vectoriels + int u0_start = edge_start(vertexB, vertexC, min_x, min_y); + int u0_step_x = edge_step_x(vertexB, vertexC); + int u0_step_y = edge_step_y(vertexB, vertexC); + int u1_start = edge_start(vertexC, vertexA, min_x, min_y); + int u1_step_x = edge_step_x(vertexC, vertexA); + int u1_step_y = edge_step_y(vertexC, vertexA); + int u2_start = edge_start(vertexA, vertexB, min_x, min_y); + int u2_step_x = edge_step_x(vertexA, vertexB); + int u2_step_y = edge_step_y(vertexA, vertexB); + + int z_num_start = (u0_start * vertexA->z_normalized + u1_start * vertexB->z_normalized + u2_start * vertexC->z_normalized) / area; + int z_num_step_x = (u0_step_x * vertexA->z_normalized + u1_step_x * vertexB->z_normalized + u2_step_x * vertexC->z_normalized) / area; + int z_num_step_y = (u0_step_y * vertexA->z_normalized + u1_step_y * vertexB->z_normalized + u2_step_y * vertexC->z_normalized) / area; + + // acces a la vram +// char* vram = get_vram_address(); + unsigned char mask_vram; + int offset_vram; + int address; + + int u0, u1, u2; + int z_num; + + // parcours en ligne + for(int x=min_x; x<=max_x; x++) + { + u0 = u0_start; u1 = u1_start; u2 = u2_start; + z_num = z_num_start; + offset_vram = x >> 3; + mask_vram = 128 >> (x & 7); + // parcours en colonne + for(int y=min_y; y<=max_y; y++) + { + // si le pixel (x;y) est dans le triangle + if ((u0 | u1 | u2) > 0) + { + // addresse du z-buffer + address = x + y * z_buffer_width + z_buffer_offset; + // si le pixel (x;y) est plus proche qu'avant + if (z_num <= z_buffer[address]) + { + // enregistre la profondeur du pixel dans le z buffer + z_buffer[address] = z_num; + // afficher pixel noir +// vram[(y << 4) + offset_vram] |= mask_vram; + // curseur + pixel_on_cursor(x, y); + } + } + u0 += u0_step_y; u1 += u1_step_y; u2 += u2_step_y; + z_num += z_num_step_y; + } + u0_start += u0_step_x; u1_start += u1_step_x; u2_start += u2_step_x; + z_num_start += z_num_step_x; + } +} +*/ + +void Windmill::render_triangle_white(Vertex* vertexA, Vertex* vertexB, Vertex* vertexC) +{ + // calcul du rectangle circonscrit au triangle + int min_x = max(viewport.x1, min(vertexA->x, min(vertexB->x, vertexC->x))); + int max_x = min(viewport.x2-1, max(vertexA->x, max(vertexB->x, vertexC->x))); + int min_y = max(viewport.y1, min(vertexA->y, min(vertexB->y, vertexC->y))); + int max_y = min(viewport.y2-1, max(vertexA->y, max(vertexB->y, vertexC->y))); + + // calcul de l'aire du triangle + int area = edge(vertexA, vertexB, vertexC); + // termine si la taille du triangle est trop petite + if (area <= MIN_AREA_CLIP) return; + + // calcul des produits vectoriels + int u0_start = edge_start(vertexB, vertexC, min_x, min_y); + int u0_step_x = edge_step_x(vertexB, vertexC); + int u0_step_y = edge_step_y(vertexB, vertexC); + int u1_start = edge_start(vertexC, vertexA, min_x, min_y); + int u1_step_x = edge_step_x(vertexC, vertexA); + int u1_step_y = edge_step_y(vertexC, vertexA); + int u2_start = edge_start(vertexA, vertexB, min_x, min_y); + int u2_step_x = edge_step_x(vertexA, vertexB); + int u2_step_y = edge_step_y(vertexA, vertexB); + + int z_num_start = (u0_start * vertexA->z_normalized + u1_start * vertexB->z_normalized + u2_start * vertexC->z_normalized) / area; + int z_num_step_x = (u0_step_x * vertexA->z_normalized + u1_step_x * vertexB->z_normalized + u2_step_x * vertexC->z_normalized) / area; + int z_num_step_y = (u0_step_y * vertexA->z_normalized + u1_step_y * vertexB->z_normalized + u2_step_y * vertexC->z_normalized) / area; + + // acces a la vram + char* vram = get_vram_address(); + unsigned char mask_vram; + int offset_vram; + int address; + + int u0, u1, u2; + int z_num; + + // parcours en ligne + for(int x=min_x; x<=max_x; x++) + { + u0 = u0_start; u1 = u1_start; u2 = u2_start; + z_num = z_num_start; + offset_vram = x >> 3; + mask_vram = 128 >> (x & 7); + // parcours en colonne + for(int y=min_y; y<=max_y; y++) + { + // si le pixel (x;y) est dans le triangle + if ((u0 | u1 | u2) > 0) + { + // addresse du z-buffer + address = x + y * z_buffer_width + z_buffer_offset; + // si le pixel (x;y) est plus proche qu'avant + if (z_num <= z_buffer[address]) + { + // enregistre la profondeur du pixel dans le z buffer + z_buffer[address] = z_num; + // afficher pixel blanc + vram[(y << 4) + offset_vram] &= ~mask_vram; + // curseur + pixel_on_cursor(x, y); + } + } + u0 += u0_step_y; u1 += u1_step_y; u2 += u2_step_y; + z_num += z_num_step_y; + } + u0_start += u0_step_x; u1_start += u1_step_x; u2_start += u2_step_x; + z_num_start += z_num_step_x; + } +} + + +void Windmill::render_triangle_transparent(Vertex* vertexA, Vertex* vertexB, Vertex* vertexC, const Texture* texture) +{ + // calcul du rectangle circonscrit au triangle + int min_x = max(viewport.x1, min(vertexA->x, min(vertexB->x, vertexC->x))); + int max_x = min(viewport.x2-1, max(vertexA->x, max(vertexB->x, vertexC->x))); + int min_y = max(viewport.y1, min(vertexA->y, min(vertexB->y, vertexC->y))); + int max_y = min(viewport.y2-1, max(vertexA->y, max(vertexB->y, vertexC->y))); + + // calcul de l'aire du triangle + int area = edge(vertexA, vertexB, vertexC); + // termine si la taille du triangle est trop petite + if (area <= MIN_AREA_CLIP) return; + + // pre-calcul des coordonnees de la texture + int w0 = vertexA->w * vertexA->z; int h0 = vertexA->h * vertexA->z; + int w1 = vertexB->w * vertexB->z; int h1 = vertexB->h * vertexB->z; + int w2 = vertexC->w * vertexC->z; int h2 = vertexC->h * vertexC->z; + + // calcul des produits vectoriels + int u0_start = edge_start(vertexB, vertexC, min_x, min_y); + int u0_step_x = edge_step_x(vertexB, vertexC); + int u0_step_y = edge_step_y(vertexB, vertexC); + int u1_start = edge_start(vertexC, vertexA, min_x, min_y); + int u1_step_x = edge_step_x(vertexC, vertexA); + int u1_step_y = edge_step_y(vertexC, vertexA); + int u2_start = edge_start(vertexA, vertexB, min_x, min_y); + int u2_step_x = edge_step_x(vertexA, vertexB); + int u2_step_y = edge_step_y(vertexA, vertexB); + + int z_num_start = (u0_start * vertexA->z_normalized + u1_start * vertexB->z_normalized + u2_start * vertexC->z_normalized) / area; + int z_num_step_x = (u0_step_x * vertexA->z_normalized + u1_step_x * vertexB->z_normalized + u2_step_x * vertexC->z_normalized) / area; + int z_num_step_y = (u0_step_y * vertexA->z_normalized + u1_step_y * vertexB->z_normalized + u2_step_y * vertexC->z_normalized) / area; + + int z_div_start = u0_start * vertexA->z + u1_start * vertexB->z + u2_start * vertexC->z; + int z_div_step_x = u0_step_x * vertexA->z + u1_step_x * vertexB->z + u2_step_x * vertexC->z; + int z_div_step_y = u0_step_y * vertexA->z + u1_step_y * vertexB->z + u2_step_y * vertexC->z; + + // acces a la vram + char* vram = get_vram_address(); + + // pre-calcul largeur en octet des tableaux + int nbw_tex = ((texture->pixel_width - 1) >> 3) + 1; + char loop_w_tex = texture->pixel_width-1; + char loop_h_tex = texture->pixel_height-1; + + // parcours en ligne + for(int x=min_x; x<=max_x; x++) + { + int u0 = u0_start; int u1 = u1_start; int u2 = u2_start; + int z_num = z_num_start; + int z_div = z_div_start; + int offset_vram = x >> 3; + char mask_vram = 128 >> (x & 7); + // parcours en colonne + for(int y=min_y; y<=max_y; y++) + { + // si le pixel (x;y) est dans le triangle + if ((u0 | u1 | u2) > 0) + { + // addresse du z-buffer + int address = x + y * z_buffer_width + z_buffer_offset; + // si le pixel (x;y) est plus proche qu'avant + if (z_num <= z_buffer[address]) + { + // calcul des coordonnees pour la texture + unsigned int w = ((u0 * w0 + u1 * w1 + u2 * w2) / z_div) & loop_w_tex; + unsigned int h = ((u0 * h0 + u1 * h1 + u2 * h2) / z_div) & loop_h_tex; + // calcul du masque pour l'octet + unsigned char mask_w = 128 >> (w & 7); + if ((texture->sprite[(w >> 3) + (h * nbw_tex)] & mask_w)) + { + // afficher pixel noir + vram[(y << 4) + offset_vram] |= mask_vram; + // enregistre la profondeur du pixel dans le z buffer + z_buffer[address] = z_num; + } + } + } + u0 += u0_step_y; u1 += u1_step_y; u2 += u2_step_y; + z_num += z_num_step_y; + z_div += z_div_step_y; + } + u0_start += u0_step_x; u1_start += u1_step_x; u2_start += u2_step_x; + z_num_start += z_num_step_x; + z_div_start += z_div_step_x; + } +} + + + + +/* +//----------------------------------------------------------------------------- +// load_map +// Ritter's bounding sphere +//----------------------------------------------------------------------------- +void Windmill::load_map(Map* _map) +{ + if (map != _map) + { + map = _map; + delete[] sphere; + sphere = new Bounding_Sphere [map->list_object_length]; + for (int i = 0; ilist_object_length; i++) + { + Object* current_object = map->object[i]; + + int nb_point; + for (int j = 0; jmodele_size; j++) + { + nb_point += current_object->modele[j].type; + } + + Point* point = get_point(current_object, 0); + int min_x = point->x; + int min_y = point->y; + int min_z = point->z; + int max_x = min_x; + int max_y = min_y; + int max_z = min_z; + + for (int j = 0; jx < min_x) + min_x = point->x; + if(point->y < min_y) + min_y = point->y; + if(point->z < min_z) + min_z = point->z; + + if(point->x > max_x) + max_x = point->x; + if(point->y > max_y) + max_y = point->y; + if(point->z > max_z) + max_z = point->z; + } + int xdiff = max_x - min_x; + int ydiff = max_y - min_y; + int zdiff = max_z - min_y; + + int diameter = max(xdiff, max(ydiff, zdiff)); //take max as diameter + glm::vec3 centre = (vmax+vmin)*(0.5f); + float radius = diameter/2; + float sq_radius = radius*radius; + + for(int i=0; i sq_radius) + { + float distance = sqrt(sq_distance); + + float difference = distance - radius; + + float new_diameter = 2 * radius + difference; + sq_radius = radius * radius; + + difference /= 2; + + centre += difference * direction; + } + } + + + + } + } +}*/ + + + + + +//---------------------------------------------------------------------------------------------------- +// MANIPULATION +//---------------------------------------------------------------------------------------------------- +Point Windmill::get_point(const Modele* poly, int i) +{ + Point point; + if (i == 0) + { + point.x = poly->x0; point.y = poly->y0; point.z = poly->z0; + } + if (i == 1) + { + point.x = poly->x1; point.y = poly->y1; point.z = poly->z1; + } + if (i == 2) + { + point.x = poly->x2; point.y = poly->y2; point.z = poly->z2; + } + if (i == 3) + { + if (poly->option == PARA) + { + point.x = poly->x2 + poly->x1 - poly->x0; + point.y = poly->y2 + poly->y1 - poly->y0; + point.z = poly->z2 + poly->z1 - poly->z0; + } else if (poly->option == TRAP) + { + point.x = poly->x2 - poly->x1 + poly->x0; + point.y = poly->y2 - poly->y1 + poly->y0; + point.z = poly->z2 - poly->z1 + poly->z0; + } + } + return point; +} + + +Point Windmill::get_center_poly(const Modele* poly) +{ + Point point; + point.x = 0; point.y = 0; point.z = 0; + + for (int i = 0; i < poly->type; i++) + { + point.x += get_point(poly, i).x; + point.y += get_point(poly, i).y; + point.z += get_point(poly, i).z; + } + + point.x /= poly->type; + point.y /= poly->type; + point.z /= poly->type; + + return point; +} + + +void Windmill::compute_object_angle(Object* object, int* cosinus, int* sinus) +{ + if (object->axe == Z_BILLBOARD) + { + float angle_look_at_camera = atan2f(camera.y - object->y, camera.x - object->x); + float angle_rad = angle_look_at_camera + 3.1415 * object->angle / 180.0; + *cosinus = 1024 * cosf(angle_rad); + *sinus = 1024 * sinf(angle_rad); + } + if (object->axe == X or object->axe == Y or object->axe == Z) + { + float angle_rad = 3.1415 * object->angle / 180.0; + *cosinus = 1024 * cosf(angle_rad); + *sinus = 1024 * sinf(angle_rad); + } +} + + +void Windmill::extract_vertex_from_poly(const Modele* poly, Vertex* vertex, int* vertex_length, int* width, int* height) +{ + int x0, y0, z0, x1, y1, z1, x2, y2, z2, x3, y3, z3; + + if (poly->type == TRIANGLE) + { + *vertex_length = 3; + x0 = poly->x0; y0 = poly->y0; z0 = poly->z0; + x1 = poly->x1; y1 = poly->y1; z1 = poly->z1; + x2 = poly->x2; y2 = poly->y2; z2 = poly->z2; + vertex[0].set_xyz(x0, y0, z0); + vertex[1].set_xyz(x1, y1, z1); + vertex[2].set_xyz(x2, y2, z2); + *width = distance(x0-x1, y0-y1, z0-z1); + *height = distance(x0-x2, y0-y2, z0-z2); + } + if (poly->type == RECTANGLE) + { + *vertex_length = 4; + x0 = poly->x0; y0 = poly->y0; z0 = poly->z0; + x1 = poly->x1; y1 = poly->y1; z1 = poly->z1; + x3 = poly->x2; y3 = poly->y2; z3 = poly->z2; + if (poly->option == PARA) + { + x2 = x3 + x1 - x0; y2 = y3 + y1 - y0; z2 = z3 + z1 - z0; + } else if (poly->option == TRAP) + { + //x2 = x3 - x1 + x0; y2 = y3 - y1 + y0; z2 = z3 - z1 + z0; + } + vertex[0].set_xyz(x0, y0, z0); + vertex[1].set_xyz(x1, y1, z1); + vertex[2].set_xyz(x2, y2, z2); + vertex[3].set_xyz(x3, y3, z3); + *width = distance(x0-x1, y0-y1, z0-z1); + *height = distance(x0-x3, y0-y3, z0-z3); + } +} + + +void Windmill::texture_coordinates(const Modele* poly, Vertex* vertex, const Texture* texture, int visible, int width, int height) +{ + int w = (texture->real_width > 0) ? width * texture->pixel_width / texture->real_width : texture->pixel_width; + int h = (texture->real_height > 0) ? height * texture->pixel_height / texture->real_height : texture->pixel_height; + + if (poly->type == TRIANGLE) + { + int offset = w * texture->offset; + if (visible == FRONT or texture->mirror == true) + { + vertex[0].set_wh(0, texture->pixel_height); + vertex[1].set_wh(w, texture->pixel_height); + vertex[2].set_wh(offset, texture->pixel_height-h); + // vertex[0].set_wh(0, h); + // vertex[1].set_wh(w, h); + // vertex[2].set_wh(offset, 0); + } else { + vertex[0].set_wh(w, h); + vertex[1].set_wh(0, h); + vertex[2].set_wh(w-offset, 0); + } + } + else if (poly->type == RECTANGLE) + { + if (visible == FRONT or texture->mirror == true) + { + vertex[0].set_wh(0, texture->pixel_height); + vertex[1].set_wh(w, texture->pixel_height); + vertex[2].set_wh(w, texture->pixel_height-h); + vertex[3].set_wh(0, texture->pixel_height-h); + + // vertex[0].set_wh(0, h); + // vertex[1].set_wh(w, h); + // vertex[2].set_wh(w, 0); + // vertex[3].set_wh(0, 0); + } else { + vertex[0].set_wh(w, h); + vertex[1].set_wh(0, h); + vertex[2].set_wh(0, 0); + vertex[3].set_wh(w, 0); + } + } +} + + +void Windmill::swap_vertex(Vertex* vertexA, Vertex* vertexB) +{ + Vertex vertex_temp; + memcpy(&vertex_temp, vertexA, sizeof(Vertex)); + memcpy(vertexA, vertexB, sizeof(Vertex)); + memcpy(vertexB, &vertex_temp, sizeof(Vertex)); +} + + +void Windmill::copy_vertex(Vertex* vertex_source, Vertex* vertex_dest) +{ + memcpy(vertex_dest, vertex_source, sizeof(Vertex)); +} + + + +//---------------------------------------------------------------------------------------------------- +// SPHERE +//---------------------------------------------------------------------------------------------------- +Sphere Windmill::transform_sphere_to_world(Sphere* sphere_input, Object* object, int cosinus, int sinus) +{ + Vertex vertex; + vertex.set_xyz(sphere_input->x, sphere_input->y, sphere_input->z); + transform_model_to_world(&vertex, 1, object, cosinus, sinus); + transform_world_to_camera(&vertex, 1); + Sphere sphere_output; + sphere_output.x = vertex.x >> 7; + sphere_output.y = vertex.y >> 7; + sphere_output.z = vertex.z >> 7; + sphere_output.radius = sphere_input->radius; + + return sphere_output; +} + +/* +bool Windmill::sphere_in_cone(Sphere* sphere) +{ + //return true; + int cone_offset = sphere->radius * camera.sin_fov; + + int nx = camera.nx; + int ny = camera.ny; + int nz = camera.nz; + + Point cone; + cone.x = int(camera.x) - ((nx * cone_offset) >> 14); + cone.y = int(camera.y) - ((ny * cone_offset) >> 14); + cone.z = int(camera.z) - ((nz * cone_offset) >> 14); + + int sx = sphere->x - cone.x; + int sy = sphere->y - cone.y; + int sz = sphere->z - cone.z; + int ss = sx*sx + sy*sy + sz*sz; + + // si sommet du cone dans la sphere + if (ss <= sphere->radius * sphere->radius) + { + return true; + } + + // si sphere dans le cone + int ns = ((nx * sx) >> 7) + ((ny * sy) >> 7) + ((nz * sz) >> 7); + + if (ns > 0 and ns*ns > camera.cos_fov_square * ss) + { + return true; + } + return false; +}*/ + +bool Windmill::sphere_in_cone(Sphere* sphere) +{ + //return true; + sphere->z += sphere->radius; + if (sphere->z > 0) + { + int sphere_z = int(sphere->z * camera.scale_coef) >> 6; + int xr = 0; + if (sphere->x > 0) xr = sphere->x - sphere->radius; + if (sphere->x < 0) xr = - sphere->x - sphere->radius; + + if (xr <= sphere_z) return true; + } + return false; +} + + + +//---------------------------------------------------------------------------------------------------- +// DIVERS +//---------------------------------------------------------------------------------------------------- +void Windmill::copy_camera() +{ + memcpy(&camera, camera2, sizeof(Camera)); +} + + +void Windmill::sort_object() +{ + //qsort(object, list_object_length, sizeof(Object*), compare_object); +} + + +int compare_object(void const *a, void const *b) +{ + Object* object_a = *(Object **) a; + Object* object_b = *(Object **) b; + return (object_a->distance_to_camera - object_b->distance_to_camera); +} + + +void Windmill::clear_z_buffer() +{ + memset(z_buffer, MAX_DEPTH_Z_BUFFER, z_buffer_size * sizeof(short)); +} + + +int Windmill::edge(Vertex* a, Vertex* b, Vertex* c) +{ + return (c->x - a->x) * (b->y - a->y) - (c->y - a->y) * (b->x - a->x); +} + + +int Windmill::edge_start(Vertex* a, Vertex* b, int px, int py) +{ + return (b->y - a->y) * (px - a->x) - (b->x - a->x) * (py - a->y); +} + + +int Windmill::edge_step_x(Vertex* a, Vertex* b) +{ + return b->y - a->y; +} + + +int Windmill::edge_step_y(Vertex* a, Vertex* b) +{ + return a->x - b->x; +} + + + +//---------------------------------------------------------------------------------------------------- +// UTILITAIRE +//---------------------------------------------------------------------------------------------------- +void Windmill::pixel_on_cursor(int x, int y) +{ + if (x == cursor_x and y == cursor_y) + { + temp_object_cursor = object[i]; + temp_poly_cursor = j; + } +} + + +void Windmill::show_coordinates() +{ + // coordonnees + float tab_coordinates[5] = {camera.x, camera.y, camera.z, to_deg(camera.yaw), to_deg(camera.pitch)}; + for (int i = 0; i < 5; i++) + { + /* + char str[20]; + sprintf(str, "%f", tab_coordinates[i]); + int j; + for(j= 0; j < 16; j++) + { + if (str[j] == '.') + { + str[j+2] = '\0'; + break; + } + } + PrintMini(127-4*(j+2), 1+6*i, (unsigned char*)str, MINI_OVER);*/ + dprint(0, 1+6*i, C_BLACK, "%f", tab_coordinates[i]); // need Gint + } +} + + +void Windmill::show_repere() +{/* + // repere + int repere_x = 112; + int repere_y = 55; + int repere_size = 12; + + float camera_yaw_rad = -camera.yaw;//- 3.1415 * camera.yaw / 180.0; + float camera_pitch_rad = camera.pitch;//3.1415 * camera.pitch / 180.0; + float cos_yaw = cosf(camera_yaw_rad); + float sin_yaw = sinf(camera_yaw_rad); + float cos_pitch = cosf(camera_pitch_rad); + float sin_pitch = sinf(camera_pitch_rad); + float aa4 = sin_yaw; + float aa5 = cos_yaw; + float aa6 = 0; + float aa7 = -sin_pitch * cos_yaw; + float aa8 = sin_pitch * sin_yaw; + float aa9 = cos_pitch; + // repere + Vertex v[3]; + //const unsigned char* cx = "x"; + //const unsigned char* cy = "y"; + //const unsigned char* cz = "z"; + const char* letter[] = {"x", "y", "z"}; + v[0].set_xyz(repere_size, 0 , 0 ); + v[1].set_xyz(0 , repere_size, 0 ); + v[2].set_xyz(0 , 0 , repere_size); + for (int i = 0; i < 3; i++) + { + float y = (aa4 * v[i].x + aa5 * v[i].y + aa6 * v[i].z); + float z = (aa7 * v[i].x + aa8 * v[i].y + aa9 * v[i].z); + v[i].x = -y; + v[i].y = -z; + //ML_line(repere_x, repere_y, v[i].x + repere_x, v[i].y + repere_y, ML_BLACK); + //PrintMini(v[i].x + repere_x, v[i].y + repere_y-2, letter[i], MINI_OVER); + } + */ +} + + +/*void Windmill::show_fps() +{ + char str[20]; + sprintf(str, "%i", time_get_fps()); + PrintMini(1, 58, (unsigned char*)str, MINI_OVER); +}*/ + + + + +//---------------------------------------------------------------------------------------------------- +// DESTRUCTEUR +//---------------------------------------------------------------------------------------------------- +Windmill::~Windmill() +{ + free(z_buffer); + free(object); + //delete[] object; +} + + + + + +float distance(float dx, float dy, float dz) +{ + return sqrtf(dx*dx + dy*dy + dz*dz); +} + +Vertex::Vertex(){} + +void Vertex::set_xyz(int _x, int _y, int _z) +{ + x = _x; + y = _y; + z = _z; +} + +void Vertex::set_wh(float _w, float _h) +{ + w = _w; + h = _h; +} + +float Vertex::length(int x, int y, int z) +{ + return sqrtf(x*x + y*y + z*z); +} diff --git a/src/windmill.hpp b/src/windmill.hpp new file mode 100644 index 0000000..56fc9b3 --- /dev/null +++ b/src/windmill.hpp @@ -0,0 +1,257 @@ +#ifndef DEF_WINDMILL +#define DEF_WINDMILL + + +extern "C" +{ + #define __BSD_VISIBLE 1 + #include + #include // pour affichage des coordonnées + #include + #include + #include +} +#include "camera.hpp" + +#define get_vram_address() ((char *)gint_vram) + +// parametrage de Windmill +#define MIN_AREA_CLIP 5 +#define DECORATION_OFFSET 50 +#define MAX_DEPTH_Z_BUFFER 0xffff + +enum {N, X, Y, Z, Z_BILLBOARD}; +#define FRONT 1 +#define BACK -1 +#define RIEN 0 +#define TRIANGLE 3 +#define RECTANGLE 4 +#define PARA 0 +#define TRAP 1 + +#define INTERIEUR true +#define EXTERIEUR false + +// pour la collision +#define INSIDE -1 +#define ALL 127 +#define NONE 0 +//#define OUT 1 +//#define IN 0 + + + +// definition des structures +struct Point +{ + int x, y, z; +}; + +class Vecteur +{ +public: + float x1, y1, x2, y2; +}; + +struct Sphere +{ + int x, y, z; + int radius; +}; + +class Vertex +{ +public: + int x, y, z; + float w, h; + unsigned short z_normalized; + + Vertex(); + void set_xyz(int _x, int _y, int _z); + void set_wh(float _w, float _h); + float length(int x, int y, int z); +}; + + +struct Texture +{ + const unsigned char* sprite; + const unsigned char* mask; + const char pixel_width; + const char pixel_height; + const char real_width; + const char real_height; + const float offset; + const bool transparent; + const bool decoration; + const bool mirror; +}; + + +struct Modele +{ + const int type; + const Texture* texture_front; + const Texture* texture_back; + const short x0, y0, z0; + const short x1, y1, z1; + const short x2, y2, z2; + const char option; +}; + + +struct Object +{ + short x, y, z; + float angle; + char axe; + const Modele* modele; + const int modele_size; + // ajouter ici + const char collision; + //const char for_collision; + //const char type_collision; + bool hidden; + Sphere sphere; + int distance_to_camera; + bool on_screen; +}; + + +struct Map +{ + Object** object; + int list_object_length; + bool horizon; + bool ground; + // ajouter ici +}; + +struct Viewport +{ + int x1, y1, x2, y2; +}; + + +float distance(float dx, float dy, float dz); +int compare_object(void const *a, void const *b); + + +class Windmill +{ +public: + // initialisation et parametrage + Windmill(); + void set_camera(Camera* _camera); + void set_viewport(int viewport_x1, int viewport_y1, int viewport_x2, int viewport_y2); + void load_map(Map* _map); + + // dessin + void draw(); + void draw_horizon(); + void draw_ground(); + void draw_objects(); + void draw_post_treatment(); + void draw_body(); + + // transformation 3D des vertex + void transform_model_to_world(Vertex vertex[], int vertex_length, Object* object, int cosinus, int sinus); + void transform_world_to_camera(Vertex vertex[], int vertex_length); + void transform_camera_to_screen(Vertex vertex[], int vertex_length); + void transform_camera_to_screen2(Vertex vertex[], int vertex_length); + + // text visiblilite + bool fast_check(Vertex vertex_list[], int vertex_list_length); + bool inside_viewport(int x, int y); + int visible_face(Vertex* a, Vertex* b, Vertex* c); + + void clip_depth(Vertex vertex_list_input[], int* vertex_list_input_length); + void clip_depth_edge(Vertex* vertex_in, Vertex* vertex_out, Vertex* vertex_set); + bool clip_depth_inside_edge(Vertex* vertex); + + void clip_viewport(Vertex vertex_list_input[], int* vertex_list_input_length); + void clip_viewport_edge(Vertex* vertex_in, Vertex* vertex_out, Vertex* vertex_set, int edge); + bool clip_viewport_inside_edge(Vertex* vertex, int edge); + + // dessin des triangles + void render_triangle(Vertex* vertex1, Vertex* vertex2, Vertex* vertex3, const Texture *texture); + void render_triangle_texture(Vertex* vertex1, Vertex* vertex2, Vertex* vertex3, const Texture* texture); + void render_triangle_black(Vertex* vertex0, Vertex* vertex1, Vertex* vertex2); + void render_triangle_white(Vertex* vertex0, Vertex* vertex1, Vertex* vertex2); + void render_triangle_transparent(Vertex* vertex1, Vertex* vertex2, Vertex* vertex3, const Texture* texture); + + // manipulation + Point get_point(const Modele* poly, int i); + Point get_center_poly(const Modele* poly); + void compute_object_angle(Object* object, int* cosinus, int* sinus); + void extract_vertex_from_poly(const Modele* poly, Vertex* vertex, int* vertex_length, int* width, int* height); + void texture_coordinates(const Modele* poly, Vertex* vertex, const Texture* texture, int visible, int width, int height); + void swap_vertex(Vertex* vertexA, Vertex* vertexB); + void copy_vertex(Vertex* vertex_source, Vertex* vertex_dest); + + // sphere + Sphere transform_sphere_to_world(Sphere* sphere, Object* object, int cosinus, int sinus); + bool sphere_in_cone(Sphere* sphere); + + // divers + void copy_camera(); + void sort_object(); + void clear_z_buffer(); + int edge(Vertex* a, Vertex* b, Vertex* c); + int edge_start(Vertex* a, Vertex* b, int px, int py); + int edge_step_x(Vertex* a, Vertex* b); + int edge_step_y(Vertex* a, Vertex* b); + + // utilitaires + void pixel_on_cursor(int x, int y); + void show_coordinates(); + void show_repere(); + //void show_fps(); + + // destructeurr + ~Windmill(); + +private: + // camera + Camera* camera2; // camera a suivre + Camera camera; // camera_temporaire + + // carte + Map* map; + + // liste objets triee + Object** object; + int list_object_length; + + // z_buffer + int shift_x, shift_y; + unsigned short* z_buffer; + int z_buffer_size; + int z_buffer_offset; + int z_buffer_width; + + // en cours + int i; + int j; + + // variables temporaire pour eviter de lire la valeur en cours de calcul + int temp_nb_object_on_screen; + Object* temp_object_cursor; + int temp_poly_cursor; + +public: + // fenetre de visualisation + Viewport viewport; + + // utilitaires + bool loading; + int nb_object_on_screen; + Object* object_cursor; + int poly_cursor; + int cursor_x; + int cursor_y; +}; + + + +#endif