From 96b1e1b24211f453638e105b5971e10e35878e0e Mon Sep 17 00:00:00 2001 From: Shadow8t4 Date: Mon, 20 Feb 2017 18:32:06 -0600 Subject: [PATCH] Finished A2 --- A2/README.txt | 5 + A2/shadow8t4.zip | Bin 0 -> 35166 bytes A2/shadow8t4/shadow8t4/CMakeLists.txt | 126 ++ A2/shadow8t4/shadow8t4/README.txt | 5 + A2/shadow8t4/shadow8t4/resources/cube.obj | 29 + A2/shadow8t4/shadow8t4/resources/frag.glsl | 8 + A2/shadow8t4/shadow8t4/resources/vert.glsl | 13 + A2/shadow8t4/shadow8t4/src/.Component.cpp.swp | Bin 0 -> 12288 bytes A2/shadow8t4/shadow8t4/src/.Component.h.swp | Bin 0 -> 12288 bytes A2/shadow8t4/shadow8t4/src/.main.cpp.swp | Bin 0 -> 28672 bytes A2/shadow8t4/shadow8t4/src/Component.cpp | 120 + A2/shadow8t4/shadow8t4/src/Component.h | 28 + A2/shadow8t4/shadow8t4/src/GLSL.cpp | 152 ++ A2/shadow8t4/shadow8t4/src/GLSL.h | 40 + A2/shadow8t4/shadow8t4/src/MatrixStack.cpp | 114 + A2/shadow8t4/shadow8t4/src/MatrixStack.h | 50 + A2/shadow8t4/shadow8t4/src/Program.cpp | 126 ++ A2/shadow8t4/shadow8t4/src/Program.h | 44 + A2/shadow8t4/shadow8t4/src/Shape.cpp | 135 ++ A2/shadow8t4/shadow8t4/src/Shape.h | 36 + A2/shadow8t4/shadow8t4/src/main.cpp | 450 ++++ A2/shadow8t4/shadow8t4/src/tiny_obj_loader.h | 1922 +++++++++++++++++ A2/src/Body.h | 43 - A2/src/Component.cpp | 120 + A2/src/Component.h | 28 + A2/src/main.cpp | 483 ++++- 26 files changed, 3924 insertions(+), 153 deletions(-) create mode 100644 A2/README.txt create mode 100644 A2/shadow8t4.zip create mode 100644 A2/shadow8t4/shadow8t4/CMakeLists.txt create mode 100644 A2/shadow8t4/shadow8t4/README.txt create mode 100644 A2/shadow8t4/shadow8t4/resources/cube.obj create mode 100644 A2/shadow8t4/shadow8t4/resources/frag.glsl create mode 100644 A2/shadow8t4/shadow8t4/resources/vert.glsl create mode 100644 A2/shadow8t4/shadow8t4/src/.Component.cpp.swp create mode 100644 A2/shadow8t4/shadow8t4/src/.Component.h.swp create mode 100644 A2/shadow8t4/shadow8t4/src/.main.cpp.swp create mode 100644 A2/shadow8t4/shadow8t4/src/Component.cpp create mode 100644 A2/shadow8t4/shadow8t4/src/Component.h create mode 100644 A2/shadow8t4/shadow8t4/src/GLSL.cpp create mode 100644 A2/shadow8t4/shadow8t4/src/GLSL.h create mode 100644 A2/shadow8t4/shadow8t4/src/MatrixStack.cpp create mode 100644 A2/shadow8t4/shadow8t4/src/MatrixStack.h create mode 100644 A2/shadow8t4/shadow8t4/src/Program.cpp create mode 100644 A2/shadow8t4/shadow8t4/src/Program.h create mode 100644 A2/shadow8t4/shadow8t4/src/Shape.cpp create mode 100644 A2/shadow8t4/shadow8t4/src/Shape.h create mode 100644 A2/shadow8t4/shadow8t4/src/main.cpp create mode 100644 A2/shadow8t4/shadow8t4/src/tiny_obj_loader.h delete mode 100644 A2/src/Body.h create mode 100644 A2/src/Component.cpp create mode 100644 A2/src/Component.h diff --git a/A2/README.txt b/A2/README.txt new file mode 100644 index 0000000..e8183b3 --- /dev/null +++ b/A2/README.txt @@ -0,0 +1,5 @@ +Alexander Huddleston + +L00,L03, and L04 provided code. + +Thank you for the extra late day. I had an unexpected midterm this week. diff --git a/A2/shadow8t4.zip b/A2/shadow8t4.zip new file mode 100644 index 0000000000000000000000000000000000000000..05f62f9eb0ff501aec89510b0f1c0c29d05a1d6c GIT binary patch literal 35166 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≈bt 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 E0ZwkxrT_o{ literal 0 HcmV?d00001 diff --git a/A2/shadow8t4/shadow8t4/CMakeLists.txt b/A2/shadow8t4/shadow8t4/CMakeLists.txt new file mode 100644 index 0000000..e451276 --- /dev/null +++ b/A2/shadow8t4/shadow8t4/CMakeLists.txt @@ -0,0 +1,126 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) + +# Name of the project +PROJECT(A2) + +# FOR LAB MACHINES ONLY! +# DO NOT EDIT +SET(DEF_DIR_GLM "C:\\c++\\glm") +SET(DEF_DIR_GLFW "C:\\c++\\glfw-3.2.1") +SET(DEF_DIR_GLEW "C:\\c++\\glew-2.0.0") + +# Is this the solution? +# Override with `cmake -DSOL=ON ..` +OPTION(SOL "Solution" OFF) + +# Use glob to get the list of all source files. +# We don't really need to include header and resource files to build, but it's +# nice to have them also show up in IDEs. +IF(${SOL}) + FILE(GLOB_RECURSE SOURCES "src0/*.cpp") + FILE(GLOB_RECURSE HEADERS "src0/*.h") +ELSE() + FILE(GLOB_RECURSE SOURCES "src/*.cpp") + FILE(GLOB_RECURSE HEADERS "src/*.h") +ENDIF() +FILE(GLOB_RECURSE GLSL "resources/*.glsl") + +# Set the executable. +ADD_EXECUTABLE(${CMAKE_PROJECT_NAME} ${SOURCES} ${HEADERS} ${GLSL}) + +# Get the GLM environment variable. Since GLM is a header-only library, we +# just need to add it to the include directory. +SET(GLM_INCLUDE_DIR "$ENV{GLM_INCLUDE_DIR}") +IF(NOT GLM_INCLUDE_DIR) + # The environment variable was not set + SET(ERR_MSG "Please point the environment variable GLM_INCLUDE_DIR to the root directory of your GLM installation.") + IF(WIN32) + # On Windows, try the default location + MESSAGE(STATUS "Looking for GLM in ${DEF_DIR_GLM}") + IF(IS_DIRECTORY ${DEF_DIR_GLM}) + MESSAGE(STATUS "Found!") + SET(GLM_INCLUDE_DIR ${DEF_DIR_GLM}) + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() +ENDIF() +INCLUDE_DIRECTORIES(${GLM_INCLUDE_DIR}) + +# Get the GLFW environment variable. There should be a CMakeLists.txt in the +# specified directory. +SET(GLFW_DIR "$ENV{GLFW_DIR}") +IF(NOT GLFW_DIR) + # The environment variable was not set + SET(ERR_MSG "Please point the environment variable GLFW_DIR to the root directory of your GLFW installation.") + IF(WIN32) + # On Windows, try the default location + MESSAGE(STATUS "Looking for GLFW in ${DEF_DIR_GLFW}") + IF(IS_DIRECTORY ${DEF_DIR_GLFW}) + MESSAGE(STATUS "Found!") + SET(GLFW_DIR ${DEF_DIR_GLFW}) + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() +ENDIF() +OPTION(GLFW_BUILD_EXAMPLES "GLFW_BUILD_EXAMPLES" OFF) +OPTION(GLFW_BUILD_TESTS "GLFW_BUILD_TESTS" OFF) +OPTION(GLFW_BUILD_DOCS "GLFW_BUILD_DOCS" OFF) +IF(CMAKE_BUILD_TYPE MATCHES Release) + ADD_SUBDIRECTORY(${GLFW_DIR} ${GLFW_DIR}/release) +ELSE() + ADD_SUBDIRECTORY(${GLFW_DIR} ${GLFW_DIR}/debug) +ENDIF() +INCLUDE_DIRECTORIES(${GLFW_DIR}/include) +TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} glfw ${GLFW_LIBRARIES}) + +# Get the GLEW environment variable. +SET(GLEW_DIR "$ENV{GLEW_DIR}") +IF(NOT GLEW_DIR) + # The environment variable was not set + SET(ERR_MSG "Please point the environment variable GLEW_DIR to the root directory of your GLEW installation.") + IF(WIN32) + # On Windows, try the default location + MESSAGE(STATUS "Looking for GLEW in ${DEF_DIR_GLEW}") + IF(IS_DIRECTORY ${DEF_DIR_GLEW}) + MESSAGE(STATUS "Found!") + SET(GLEW_DIR ${DEF_DIR_GLEW}) + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() +ENDIF() +INCLUDE_DIRECTORIES(${GLEW_DIR}/include) +IF(WIN32) + # With prebuilt binaries + TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} ${GLEW_DIR}/lib/Release/Win32/glew32s.lib) +ELSE() + TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} ${GLEW_DIR}/lib/libGLEW.a) +ENDIF() + +# OS specific options and libraries +IF(WIN32) + # c++11 is enabled by default. + # -Wall produces way too many warnings. + # -pedantic is not supported. + # Disable warning 4996. + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4996") + TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} opengl32.lib) +ELSE() + # Enable all pedantic warnings. + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -pedantic") + IF(APPLE) + # Add required frameworks for GLFW. + TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} "-framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo") + ELSE() + #Link the Linux OpenGL library + TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} "GL") + ENDIF() +ENDIF() diff --git a/A2/shadow8t4/shadow8t4/README.txt b/A2/shadow8t4/shadow8t4/README.txt new file mode 100644 index 0000000..e8183b3 --- /dev/null +++ b/A2/shadow8t4/shadow8t4/README.txt @@ -0,0 +1,5 @@ +Alexander Huddleston + +L00,L03, and L04 provided code. + +Thank you for the extra late day. I had an unexpected midterm this week. diff --git a/A2/shadow8t4/shadow8t4/resources/cube.obj b/A2/shadow8t4/shadow8t4/resources/cube.obj new file mode 100644 index 0000000..e81edd5 --- /dev/null +++ b/A2/shadow8t4/shadow8t4/resources/cube.obj @@ -0,0 +1,29 @@ +# Blender v2.71 (sub 0) OBJ File: '' +# www.blender.org +v 0.500000 0.500000 -0.500000 +v 0.500000 -0.500000 -0.500000 +v -0.500000 -0.500000 -0.500000 +v -0.500000 0.500000 -0.500000 +v 0.500000 0.500000 0.500000 +v 0.500000 -0.500000 0.500000 +v -0.500000 -0.500000 0.500000 +v -0.500000 0.500000 0.500000 +vn 0.000000 0.000000 -1.000000 +vn 0.000000 0.000000 1.000000 +vn 1.000000 -0.000000 -0.000000 +vn -0.000000 -1.000000 -0.000000 +vn -1.000000 0.000000 -0.000000 +vn 0.000000 1.000000 0.000000 +s off +f 2//1 3//1 4//1 +f 8//2 7//2 6//2 +f 1//3 5//3 6//3 +f 2//4 6//4 7//4 +f 7//5 8//5 4//5 +f 1//6 4//6 8//6 +f 1//1 2//1 4//1 +f 5//2 8//2 6//2 +f 2//3 1//3 6//3 +f 3//4 2//4 7//4 +f 3//5 7//5 4//5 +f 5//6 1//6 8//6 diff --git a/A2/shadow8t4/shadow8t4/resources/frag.glsl b/A2/shadow8t4/shadow8t4/resources/frag.glsl new file mode 100644 index 0000000..9d07efa --- /dev/null +++ b/A2/shadow8t4/shadow8t4/resources/frag.glsl @@ -0,0 +1,8 @@ +#version 120 + +varying vec3 vCol; + +void main() +{ + gl_FragColor = vec4(vCol.r, vCol.g, vCol.b, 1.0); +} diff --git a/A2/shadow8t4/shadow8t4/resources/vert.glsl b/A2/shadow8t4/shadow8t4/resources/vert.glsl new file mode 100644 index 0000000..3ecb3f4 --- /dev/null +++ b/A2/shadow8t4/shadow8t4/resources/vert.glsl @@ -0,0 +1,13 @@ +#version 120 + +attribute vec4 aPos; +attribute vec3 aNor; +uniform mat4 P; +uniform mat4 MV; +varying vec3 vCol; + +void main() +{ + gl_Position = P * MV * aPos; + vCol = 0.5*(aNor + 1.0); +} diff --git a/A2/shadow8t4/shadow8t4/src/.Component.cpp.swp b/A2/shadow8t4/shadow8t4/src/.Component.cpp.swp new file mode 100644 index 0000000000000000000000000000000000000000..5212f55262f72975de5a7398d0bd07edc3603507 GIT binary patch literal 12288 zcmeI2O>7%Q6vw9&3NB44AR$o|G;u_sY(NFiQ7mfQIQ*!Wp`q)uyK2e@!RpjLc{6DN@P&+LbtIEg4Hie{Ui z$2;%sn>YVAJDV!|Tw(rLnU3lOf@2>cJHKB$Rqi{mbL<{Mg1TY3XGi&nux)cRT+?XO z-GJ-zo8>kQ+u6kbg(P79h-X03SHuX>cd_@LodR z1sA~u@H(gg29AOwU>NA&=iP+d1UJAZ;3M!BcoVz?+Moi;;21ax_JZBuj}#%_g0H}J za231(UIlFsfCVrIPJ*YvaWD+-2Yp}G7 zNVRZ4Iyp&C%+1VXXq&(gx`&_fSyuqFZZ|CCS+$3X3nGv>+C(-8s-c@s(AY~4>=mYE zGSVJ;!DlcwSM3Ecx?x#<=#tM%X}a8>7NQv>nf1peoi#mvF3en5k+sM&(TcQ5@^;`LO}>te)gt|qE_yJW z-WJ80_1Ti`wt}RlvF1^(;rtMF#t8V75MM*(|9$Yf1=O0I$ z?F~4)c|1zRNC937W?G;xX9N8lSdsV6DoJ&li+V8|Aofa?i)_fFgVjVlBFEk;zOjH67%p~E^NNOlBEUt zQ|vL}3YegFp~r-XqCYhC4Cu)bJvpQoNhDW5E2wvtK$|SNw$;7WNfq!qwa=_G9``3g z-wHR(=SxsOOSiH?wJuYoZg{LDbnNOBlKMuo6lyD0Wh%g?zr@T#nyHI|Qqf?}qLDgb zbB^tPX!k=qRFie(UdMyWNt-%a83U~h!n<6;AhHy24DIovfExymRtSm|*H-q&C+LqK zvG5MRj(0yf#>SF8LNi?_;2n7fsfh=exYOfky3gd(RF*dpqo^0KcqO9ji3o)({%x3c z+?Psbne@a{LH>&do(A2ii(d}5OdCnI0^6xk$7r&^GfYMUZsB*60oySfEsN1~GDp3h P?sQMscv;_Ps4@8)to0p9 literal 0 HcmV?d00001 diff --git a/A2/shadow8t4/shadow8t4/src/.Component.h.swp b/A2/shadow8t4/shadow8t4/src/.Component.h.swp new file mode 100644 index 0000000000000000000000000000000000000000..2f302be4244a74429fb01544626721ce8af6a5d7 GIT binary patch literal 12288 zcmeI2L2DC16o6mr#Y?Q#YY$@z8jEI|CWp|51>JfOj0A#3PcoSuvx~bs%gk)rBGrp{ z@dt?DUHTUk#Diz=#iJL&t3SZEA>AZxDipi~-onScy!SG*?+ZDEY;S$%ew#I`>wwo~ zfG!cWU)-FalEc~ zuhFPE!U&nKcQzcOh2yC>RS9-fgBd$fiVTo}a~a6&v)j!Q)HiCwulj2F8oRpu=v-S+ zGZ`QQWPl8i0Wv@a$N(821M_XbrVH>2M_3$fDDiU zGC&5%02v?yb7+A30HqSZdnEt=|M>U+?mWQZkY^_0Wv@a$N(8217v^r4B98|wvOI-^+B>({S+&kosT=TAx~w~u>}b{3Ja$e=P>HdVlZ#U= z!^A*}Iy1S5VWf-5rsFV=dP+si$Vdt+{ZYv(-6}M>OypLzO!8`xW@{;qpV&N^X1ypB zoA3fe#Els@0c0jj`YhqGG$|L7^`m&}RMJ>H8CJtYM42yHd8D8klqZrySyQQ2EMukj p-EmV3w|9_gkfsyq^2Fyey#va@VO?+>=4r{TWOtRn&%AsL_zTq72Uh?9 literal 0 HcmV?d00001 diff --git a/A2/shadow8t4/shadow8t4/src/.main.cpp.swp b/A2/shadow8t4/shadow8t4/src/.main.cpp.swp new file mode 100644 index 0000000000000000000000000000000000000000..64811a03b1a41f66d2f71ee779abb619b0d85683 GIT binary patch literal 28672 zcmeI43zQ^Pd4O95bQggL#{jZo?VwA~?o7`NEN0!u#MznI*$Fed!}iWD>jvAJ?&=5I z)74g2&w~{WY7&7g0y#N}0&zuwoZulZK|Dd?YNGLo4-%p=sJmd!K@W(Lmk*-J_upGp zUENc)5B0>8b860h+uir^-+TZ2clG`6{i|mBca2XP>oWZ*{(d8s`u%U;b@}^Wy5eQ) zUy({R%4WfyU+1osyrcY8?Yvnn+YL9P-WBXwvr>yF|IR>Q--w-W&RR9M(KnnO9$mY3 zpfBIZTk<+|QD4K!_lby1zFvJQ-F%-Smmvp?I;(b2gz4mqF zpX7b^9rpKh2o_AiI`}Pk zEt~@1K0TFs5IzM5;X`l$Trgn*E`hbM5)3#MUN|k4dLBLp?|}+T!FJdNzYVX4W$^SX zQ>i0x7(NI0!M*SycsE=Fm%&-^D){eHQ>ho>Nq7Rj2KT|Wa3vJsGMI#oumYZ4o=QCe zUxly0KfvF^U&4*>M=%c!n1QV@0>f}I^uhUX5~Scs^!o&S4IY5|;a<1{J`6X)95`?V z?18P2fz^-(nWK}5%lIzy^)K)+JOFpW&2SUAkb~cWap-|Gyb7LU6X$98GTaA$4!6M{ zfDM=|77##2s{X%g4^LBTn}%DS(t*0UK2@4qt?i!)oGVC`F*2~V>?F5 z;IFUGm^AlU#*Rv<>>AVcy5$%XR*5|R&De#-Ouk&H796XVsW%(t+>Dvum##LeR;haf zCd!}s5Lv3KOG%-W{6|?y%D9=Uj7>&=rhh|9r3T51B=_nvjm%=-MVPk+p9%od)>Y1QpYCLUX>n6H$>BuT2!0*ejJzKYH zlB33}lD&HVluTGf*O;*9gBj6U)cxqtp`WNVDASV(_0-P|x~W>yslM_&E%}LBb>0m5 ziMl=|L-pMbwRvrMN>diJv?p3)Ugkodp16?EmeQn*)>%knGCmSjg*I)q?3cWF>ouKO ztk>|&vfAWxv;pgasvR*lDc7O+R^eSaW`-^(7>*S`qGRts_zE3{zG*^Q14aTGczPufS+M^#@f% zQed?D>J*aM(pR+6(!x=Uc1SBK&S=Y)S@5s8^1f4(UYa&SPXS(<^jaxb^;IW!4BtcQx}%dejoi1F=2Wz@~o)yNeLqhVF8ylWMD2OX}Zz0&M}HXFXBj_sPRmC0l%x*x1+ z!!jzxbiQtE+GJe#mJ7Q{jFPkF=yF;ju2Lc*r7WIcZ}!CWX3;qA-Yg;_vM&oK*q6&= z`m%8ReOZX^i$7n?y6ZG8JyoH^RsQ?l!II@}vliU+w&{rpeeDd*wqFc6MU!a_=3HmQ z&Uq$sWFcwC(W@!Pnyc8&#xL2kmKF7AUFFNBV~A}UX?fe7-;mm$YGA^ZyfJ523WlWS zi0-YbCDGW#mfiD}8bQIvYW><{G;57Ysb&?73P1Dt?i62wo#jfyC^l<(w_?`}-irWA z%$Kd2VJexDTB+5WE-Pk#k+3>YHvL)U*tWYtq-DMDo00bmhU)Nz^NQ`@O{<7es@gMV z6+ePr(c@veSwq~cS>M=jol33LGd9sAZ_t=&7RN^#9a$=;S*yflnXc=oT3U)xckI&m z2p3<8nRcu~uI@S;vt_ex4H~4>F_uuq6r~+=c2HF#M|H^9F`C^zy<>PZH!{8h1$1Tl zx;Dtlb$8ivEW<5ZhGRACrjxfC25lHs+bp2eqGQjdmQIYSI!O?smx`N5e zl)FO7-U!WkdbiD7x<} zRg3c%XUgFg$0kU%=2c=KXLNTiyK`vg_;6SPRvE51$IpxHgi|WS);ks!6BOl)!d}=7E8t;#`9ttAxD7r4 zZwK-D-vsAF3ci95|7mytu7qy*20r>B_#5~jyc>4HI(Q{Kjn92Q+zh+n&G1H84oC2# zzX+d#55PO%a@Y)mum(IkS}-?sr=GZjv-&vGlPQcPpPIJui;;iPutkpg8jJUaVX0D5+hFBgoX^gi_07#<(Q+DTy+Ze# zPw{@plQlkWjEE37Ok5Tzs|B#}TCki@lRH#`!R?eaONz|1wQZ$WN<&%?*|OcN7KW>K z!}6Q!R+|+xH(}d#TspT>RUSu^MWT_Hk`47)_fDi%Y86*EO097|RLpASDy!A38kps7 zK~I+MaF+aG-<8yodc>z8IdCz3HD@h1)Sy>N`H@Nm(gUx7N!(&0WOeE>A@@ z?ky&kUoc!-S*vHDV-ushl?wb}u_+R2e&r_giI=whQvIEftkDGyj4E=wvRTD5_xEes z4PR>cQ!j^2!+d4gOB!xEax~(9(L|5bQ>Rhl((A9mg=~@N;znMV7fF$W6RYpI&@q6O zT8{3reosfG>@a?#Ywgw-z&Eb#?=jY{64!6;F=Su!L+`I=&)l`#dJz@dk3yC))?9)PIvWnse!iX+B*;m?0u?gnQY@W>Q=r| zTx{ElF$xt&x$BFWPNSl&ys^=^NXEH8CHqivPkUP4NLG*D2V1>b`qZ6DNe@EbWHsjW z*yzsOmhp+v+ypK?9i_}v?_k}o>x~orJ)hjQBncCn;zF)BI~Xg!8vI;PTQ;hC2b;AS z3_@xv|9^n9+SAwr5dYtg-+vMx{$cnMh~Iw`><2mj_s{+}@P0kK0bUNz;L|@1UxkO@ zUidS(8LomoFa&RgZa5QO#J~S3`~)6{&%oVqCtL%+2XBSFATa=&APuL(a(Ifp0NEe- zB-{@lfg4~E7T_%~3jNRr5)W`1yucoT>>>Os{4Mx<2-omlVgj-tu>c$3JU9uy&)&gP z@Ok(wd>9Ub!~$Fg*TNjQ@Vl@VWZ&T&_!;{NkHcdidk=TR)lh|fFb;CY|2_5_J^

rP^!s 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 literal 0 HcmV?d00001 diff --git a/A2/shadow8t4/shadow8t4/src/Component.cpp b/A2/shadow8t4/shadow8t4/src/Component.cpp new file mode 100644 index 0000000..f2ef94b --- /dev/null +++ b/A2/shadow8t4/shadow8t4/src/Component.cpp @@ -0,0 +1,120 @@ +#include +#include "Component.h" + +using namespace std; + +Component::Component() +{ + parent = NULL; + selected = false; + t = vec3(0,0,0); + tp = vec3(0,0,0); + r = vec3(0,0,0); + s = vec3(1.0,1.0,1.0); + children.resize(0); +} + +Component::Component(const Component& c) +{ + parent = c.parent; + children = c.children; + selected = c.selected; + t = vec3(c.t.x, c.t.y, c.t.z); + tp = vec3(c.tp.x, c.tp.y, c.tp.z); + r = vec3(c.r.x, c.r.y, c.r.z); + s = vec3(c.s.x, c.s.y, c.s.z); +} + +void Component::draw(shared_ptr MV, shared_ptr P, shared_ptr S, shared_ptr Prog) +{ + MV->pushMatrix(); + MV->translate(tp.x, tp.y, tp.z); + MV->rotate(r.x, 1, 0, 0); + MV->rotate(r.y, 0, 1, 0); + MV->rotate(r.z, 0, 0, 1); + MV->translate(t.x, t.y, t.z); + for(unsigned int i = 0; i < children.size(); i++) + { + children[i].draw(MV, P, S, Prog); + } + if(selected) + { + MV->scale(1.1,1.1,1.1); + } + MV->scale(s.x,s.y,s.z); + glUniformMatrix4fv(Prog->getUniform("P"), 1, GL_FALSE, &P->topMatrix()[0][0]); + glUniformMatrix4fv(Prog->getUniform("MV"), 1, GL_FALSE, &MV->topMatrix()[0][0]); + S->draw(Prog); + MV->popMatrix(); +} + +Component& Component::getLastChild() +{ + if(this->children.empty()) + { + return *this; + } + return this->children[this->children.size() - 1].getLastChild(); +} + +Component& Component::getPrevious(Component *addr) +{ + if(children.empty()) + { + if(parent != NULL) + { + return parent->getPrevious(this); + } + } + + for(unsigned int i = 0; i < this->children.size(); i++) + { + //return *this; + if(&children[i] == addr) + { + if(i > 0) + { + return children[i-1].getLastChild(); + } + else + { + return *this; + } + } + } + + if (parent == NULL) { + return this->getLastChild(); + } + + return parent->getPrevious(this); +} + +Component& Component::getNext(Component *addr) +{ + if(addr == NULL) + { + if(!children.empty()) + { + return children[0]; + } + } + + for(unsigned int i = 0; i < this->children.size(); i++) + { + //return *this; + if(&children[i] == addr) + { + if(i+1 < children.size()) + { + return children[i+1]; + } + } + } + + if (parent == NULL) { + return *this; + } + + return parent->getNext(this); +} diff --git a/A2/shadow8t4/shadow8t4/src/Component.h b/A2/shadow8t4/shadow8t4/src/Component.h new file mode 100644 index 0000000..b416cb4 --- /dev/null +++ b/A2/shadow8t4/shadow8t4/src/Component.h @@ -0,0 +1,28 @@ +// Create Body Class +#include +#include "MatrixStack.h" +#include +#include +#include "Shape.h" +#include "Program.h" + +using namespace std; +using namespace glm; + +class Component +{ + public: + Component *parent; + vector children; + bool selected; + vec3 t; + vec3 tp; + vec3 r; + vec3 s; + Component(); + Component(const Component& c); + void draw(shared_ptr MV, shared_ptr P, shared_ptr S, shared_ptr Prog); + Component& getNext(Component *addr); + Component& getPrevious(Component *addr); + Component& getLastChild(); +}; diff --git a/A2/shadow8t4/shadow8t4/src/GLSL.cpp b/A2/shadow8t4/shadow8t4/src/GLSL.cpp new file mode 100644 index 0000000..2969872 --- /dev/null +++ b/A2/shadow8t4/shadow8t4/src/GLSL.cpp @@ -0,0 +1,152 @@ +// +// Many useful helper functions for GLSL shaders - gleaned from various sources including orange book +// Created by zwood on 2/21/10. +// Modified by sueda 10/15/15. +// + +#include "GLSL.h" +#include +#include +#include +#include + +using namespace std; + +namespace GLSL { + +const char * errorString(GLenum err) +{ + switch(err) { + case GL_NO_ERROR: + return "No error"; + case GL_INVALID_ENUM: + return "Invalid enum"; + case GL_INVALID_VALUE: + return "Invalid value"; + case GL_INVALID_OPERATION: + return "Invalid operation"; + case GL_STACK_OVERFLOW: + return "Stack overflow"; + case GL_STACK_UNDERFLOW: + return "Stack underflow"; + case GL_OUT_OF_MEMORY: + return "Out of memory"; + default: + return "No error"; + } +} + +void checkVersion() +{ + int major, minor; + major = minor = 0; + const char *verstr = (const char *)glGetString(GL_VERSION); + + if((verstr == NULL) || (sscanf(verstr, "%d.%d", &major, &minor) != 2)) { + printf("Invalid GL_VERSION format %d.%d\n", major, minor); + } + if(major < 2) { + printf("This shader example will not work due to the installed Opengl version, which is %d.%d.\n", major, minor); + exit(0); + } +} + +void checkError(const char *str) +{ + GLenum glErr = glGetError(); + if(glErr != GL_NO_ERROR) { + if(str) { + printf("%s: ", str); + } + printf("GL_ERROR = %s.\n", errorString(glErr)); + assert(false); + } +} + +void printShaderInfoLog(GLuint shader) +{ + GLint infologLength = 0; + GLint charsWritten = 0; + GLchar *infoLog = 0; + + checkError(GET_FILE_LINE); + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infologLength); + checkError(GET_FILE_LINE); + + if(infologLength > 0) { + infoLog = (GLchar *)malloc(infologLength); + if(infoLog == NULL) { + puts("ERROR: Could not allocate InfoLog buffer"); + exit(1); + } + glGetShaderInfoLog(shader, infologLength, &charsWritten, infoLog); + checkError(GET_FILE_LINE); + printf("Shader InfoLog:\n%s\n\n", infoLog); + free(infoLog); + } +} + +void printProgramInfoLog(GLuint program) +{ + GLint infologLength = 0; + GLint charsWritten = 0; + GLchar *infoLog = 0; + + checkError(GET_FILE_LINE); + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infologLength); + checkError(GET_FILE_LINE); + + if(infologLength > 0) { + infoLog = (GLchar *)malloc(infologLength); + if(infoLog == NULL) { + puts("ERROR: Could not allocate InfoLog buffer"); + exit(1); + } + glGetProgramInfoLog(program, infologLength, &charsWritten, infoLog); + checkError(GET_FILE_LINE); + printf("Program InfoLog:\n%s\n\n", infoLog); + free(infoLog); + } +} + +char *textFileRead(const char *fn) +{ + FILE *fp; + char *content = NULL; + int count = 0; + if(fn != NULL) { + fp = fopen(fn,"rt"); + if(fp != NULL) { + fseek(fp, 0, SEEK_END); + count = (int)ftell(fp); + rewind(fp); + if(count > 0) { + content = (char *)malloc(sizeof(char) * (count+1)); + count = (int)fread(content,sizeof(char),count,fp); + content[count] = '\0'; + } + fclose(fp); + } else { + printf("error loading %s\n", fn); + } + } + return content; +} + +int textFileWrite(const char *fn, const char *s) +{ + FILE *fp; + int status = 0; + if(fn != NULL) { + fp = fopen(fn,"w"); + if(fp != NULL) { + if(fwrite(s,sizeof(char),strlen(s),fp) == strlen(s)) { + status = 1; + } + fclose(fp); + } + } + return(status); +} + +} diff --git a/A2/shadow8t4/shadow8t4/src/GLSL.h b/A2/shadow8t4/shadow8t4/src/GLSL.h new file mode 100644 index 0000000..f945fdd --- /dev/null +++ b/A2/shadow8t4/shadow8t4/src/GLSL.h @@ -0,0 +1,40 @@ +// +// Many useful helper functions for GLSL shaders - gleaned from various sources including orange book +// Created by zwood on 2/21/10. +// Modified by sueda 10/15/15. +// + +#pragma once +#ifndef __GLSL__ +#define __GLSL__ + +#define GLEW_STATIC +#include + +/////////////////////////////////////////////////////////////////////////////// +// For printing out the current file and line number // +/////////////////////////////////////////////////////////////////////////////// +#include + +template +std::string NumberToString(T x) +{ + std::ostringstream ss; + ss << x; + return ss.str(); +} + +#define GET_FILE_LINE (std::string(__FILE__) + ":" + NumberToString(__LINE__)).c_str() +/////////////////////////////////////////////////////////////////////////////// + +namespace GLSL { + + void checkVersion(); + void checkError(const char *str = 0); + void printProgramInfoLog(GLuint program); + void printShaderInfoLog(GLuint shader); + int textFileWrite(const char *filename, const char *s); + char *textFileRead(const char *filename); +} + +#endif diff --git a/A2/shadow8t4/shadow8t4/src/MatrixStack.cpp b/A2/shadow8t4/shadow8t4/src/MatrixStack.cpp new file mode 100644 index 0000000..eaa6e6c --- /dev/null +++ b/A2/shadow8t4/shadow8t4/src/MatrixStack.cpp @@ -0,0 +1,114 @@ +#include "MatrixStack.h" + +#include +#include +#include + +#define GLM_FORCE_RADIANS +#include +#include + +using namespace std; + +MatrixStack::MatrixStack() +{ + mstack = make_shared< stack >(); + mstack->push(glm::mat4(1.0)); +} + +MatrixStack::~MatrixStack() +{ +} + +void MatrixStack::pushMatrix() +{ + const glm::mat4 &top = mstack->top(); + mstack->push(top); + assert(mstack->size() < 100); +} + +void MatrixStack::popMatrix() +{ + assert(!mstack->empty()); + mstack->pop(); + // There should always be one matrix left. + assert(!mstack->empty()); +} + +void MatrixStack::loadIdentity() +{ + glm::mat4 &top = mstack->top(); + top = glm::mat4(1.0); +} + +void MatrixStack::translate(const glm::vec3 &t) +{ + glm::mat4 &top = mstack->top(); + top *= glm::translate(t); +} + +void MatrixStack::translate(float x, float y, float z) +{ + translate(glm::vec3(x, y, z)); +} + +void MatrixStack::scale(const glm::vec3 &s) +{ + glm::mat4 &top = mstack->top(); + top *= glm::scale(s); +} + +void MatrixStack::scale(float x, float y, float z) +{ + scale(glm::vec3(x, y, z)); +} + +void MatrixStack::scale(float s) +{ + scale(glm::vec3(s, s, s)); +} + +void MatrixStack::rotate(float angle, const glm::vec3 &axis) +{ + glm::mat4 &top = mstack->top(); + top *= glm::rotate(angle, axis); +} + +void MatrixStack::rotate(float angle, float x, float y, float z) +{ + rotate(angle, glm::vec3(x, y, z)); +} + +void MatrixStack::multMatrix(const glm::mat4 &matrix) +{ + glm::mat4 &top = mstack->top(); + top *= matrix; +} + +const glm::mat4 &MatrixStack::topMatrix() const +{ + return mstack->top(); +} + +void MatrixStack::print(const glm::mat4 &mat, const char *name) +{ + if(name) { + printf("%s = [\n", name); + } + for(int i = 0; i < 4; ++i) { + for(int j = 0; j < 4; ++j) { + // mat[j] returns the jth column + printf("%- 5.2f ", mat[j][i]); + } + printf("\n"); + } + if(name) { + printf("];"); + } + printf("\n"); +} + +void MatrixStack::print(const char *name) const +{ + print(mstack->top(), name); +} diff --git a/A2/shadow8t4/shadow8t4/src/MatrixStack.h b/A2/shadow8t4/shadow8t4/src/MatrixStack.h new file mode 100644 index 0000000..66278ce --- /dev/null +++ b/A2/shadow8t4/shadow8t4/src/MatrixStack.h @@ -0,0 +1,50 @@ +#pragma once +#ifndef _MatrixStack_H_ +#define _MatrixStack_H_ + +#include +#include +#include + +class MatrixStack +{ +public: + MatrixStack(); + virtual ~MatrixStack(); + + // glPushMatrix(): Copies the current matrix and adds it to the top of the stack + void pushMatrix(); + // glPopMatrix(): Removes the top of the stack and sets the current matrix to be the matrix that is now on top + void popMatrix(); + + // glLoadIdentity(): Sets the top matrix to be the identity + void loadIdentity(); + // glMultMatrix(): Right multiplies the top matrix + void multMatrix(const glm::mat4 &matrix); + + // glTranslate(): Right multiplies the top matrix by a translation matrix + void translate(const glm::vec3 &trans); + void translate(float x, float y, float z); + // glScale(): Right multiplies the top matrix by a scaling matrix + void scale(const glm::vec3 &scale); + void scale(float x, float y, float z); + // glScale(): Right multiplies the top matrix by a scaling matrix + void scale(float size); + // glRotate(): Right multiplies the top matrix by a rotation matrix (angle in radians) + void rotate(float angle, const glm::vec3 &axis); + void rotate(float angle, float x, float y, float z); + + // glGet(GL_MODELVIEW_MATRIX): Gets the top matrix + const glm::mat4 &topMatrix() const; + + // Prints out the specified matrix + static void print(const glm::mat4 &mat, const char *name = 0); + // Prints out the top matrix + void print(const char *name = 0) const; + +private: + std::shared_ptr< std::stack > mstack; + +}; + +#endif diff --git a/A2/shadow8t4/shadow8t4/src/Program.cpp b/A2/shadow8t4/shadow8t4/src/Program.cpp new file mode 100644 index 0000000..1e85538 --- /dev/null +++ b/A2/shadow8t4/shadow8t4/src/Program.cpp @@ -0,0 +1,126 @@ +#include "Program.h" + +#include +#include + +#include "GLSL.h" + +using namespace std; + +Program::Program() : + vShaderName(""), + fShaderName(""), + pid(0), + verbose(true) +{ + +} + +Program::~Program() +{ + +} + +void Program::setShaderNames(const string &v, const string &f) +{ + vShaderName = v; + fShaderName = f; +} + +bool Program::init() +{ + GLint rc; + + // Create shader handles + GLuint VS = glCreateShader(GL_VERTEX_SHADER); + GLuint FS = glCreateShader(GL_FRAGMENT_SHADER); + + // Read shader sources + const char *vshader = GLSL::textFileRead(vShaderName.c_str()); + const char *fshader = GLSL::textFileRead(fShaderName.c_str()); + glShaderSource(VS, 1, &vshader, NULL); + glShaderSource(FS, 1, &fshader, NULL); + + // Compile vertex shader + glCompileShader(VS); + glGetShaderiv(VS, GL_COMPILE_STATUS, &rc); + if(!rc) { + if(isVerbose()) { + GLSL::printShaderInfoLog(VS); + cout << "Error compiling vertex shader " << vShaderName << endl; + } + return false; + } + + // Compile fragment shader + glCompileShader(FS); + glGetShaderiv(FS, GL_COMPILE_STATUS, &rc); + if(!rc) { + if(isVerbose()) { + GLSL::printShaderInfoLog(FS); + cout << "Error compiling fragment shader " << fShaderName << endl; + } + return false; + } + + // Create the program and link + pid = glCreateProgram(); + glAttachShader(pid, VS); + glAttachShader(pid, FS); + glLinkProgram(pid); + glGetProgramiv(pid, GL_LINK_STATUS, &rc); + if(!rc) { + if(isVerbose()) { + GLSL::printProgramInfoLog(pid); + cout << "Error linking shaders " << vShaderName << " and " << fShaderName << endl; + } + return false; + } + + GLSL::checkError(GET_FILE_LINE); + return true; +} + +void Program::bind() +{ + glUseProgram(pid); +} + +void Program::unbind() +{ + glUseProgram(0); +} + +void Program::addAttribute(const string &name) +{ + attributes[name] = glGetAttribLocation(pid, name.c_str()); +} + +void Program::addUniform(const string &name) +{ + uniforms[name] = glGetUniformLocation(pid, name.c_str()); +} + +GLint Program::getAttribute(const string &name) const +{ + map::const_iterator attribute = attributes.find(name.c_str()); + if(attribute == attributes.end()) { + if(isVerbose()) { + cout << name << " is not an attribute variable" << endl; + } + return -1; + } + return attribute->second; +} + +GLint Program::getUniform(const string &name) const +{ + map::const_iterator uniform = uniforms.find(name.c_str()); + if(uniform == uniforms.end()) { + if(isVerbose()) { + cout << name << " is not a uniform variable" << endl; + } + return -1; + } + return uniform->second; +} diff --git a/A2/shadow8t4/shadow8t4/src/Program.h b/A2/shadow8t4/shadow8t4/src/Program.h new file mode 100644 index 0000000..51e58bb --- /dev/null +++ b/A2/shadow8t4/shadow8t4/src/Program.h @@ -0,0 +1,44 @@ +#pragma once +#ifndef __Program__ +#define __Program__ + +#include +#include + +#define GLEW_STATIC +#include + +/** + * An OpenGL Program (vertex and fragment shaders) + */ +class Program +{ +public: + Program(); + virtual ~Program(); + + void setVerbose(bool v) { verbose = v; } + bool isVerbose() const { return verbose; } + + void setShaderNames(const std::string &v, const std::string &f); + virtual bool init(); + virtual void bind(); + virtual void unbind(); + + void addAttribute(const std::string &name); + void addUniform(const std::string &name); + GLint getAttribute(const std::string &name) const; + GLint getUniform(const std::string &name) const; + +protected: + std::string vShaderName; + std::string fShaderName; + +private: + GLuint pid; + std::map attributes; + std::map uniforms; + bool verbose; +}; + +#endif diff --git a/A2/shadow8t4/shadow8t4/src/Shape.cpp b/A2/shadow8t4/shadow8t4/src/Shape.cpp new file mode 100644 index 0000000..cf80379 --- /dev/null +++ b/A2/shadow8t4/shadow8t4/src/Shape.cpp @@ -0,0 +1,135 @@ +#include "Shape.h" +#include + +#include "GLSL.h" +#include "Program.h" + +#define TINYOBJLOADER_IMPLEMENTATION +#include "tiny_obj_loader.h" + +using namespace std; + +Shape::Shape() : + posBufID(0), + norBufID(0), + texBufID(0) +{ +} + +Shape::~Shape() +{ +} + +void Shape::loadMesh(const string &meshName) +{ + // Load geometry + tinyobj::attrib_t attrib; + std::vector shapes; + std::vector materials; + string errStr; + bool rc = tinyobj::LoadObj(&attrib, &shapes, &materials, &errStr, meshName.c_str()); + if(!rc) { + cerr << errStr << endl; + } else { + // Some OBJ files have different indices for vertex positions, normals, + // and texture coordinates. For example, a cube corner vertex may have + // three different normals. Here, we are going to duplicate all such + // vertices. + // Loop over shapes + for(size_t s = 0; s < shapes.size(); s++) { + // Loop over faces (polygons) + size_t index_offset = 0; + for(size_t f = 0; f < shapes[s].mesh.num_face_vertices.size(); f++) { + size_t fv = shapes[s].mesh.num_face_vertices[f]; + // Loop over vertices in the face. + for(size_t v = 0; v < fv; v++) { + // access to vertex + tinyobj::index_t idx = shapes[s].mesh.indices[index_offset + v]; + posBuf.push_back(attrib.vertices[3*idx.vertex_index+0]); + posBuf.push_back(attrib.vertices[3*idx.vertex_index+1]); + posBuf.push_back(attrib.vertices[3*idx.vertex_index+2]); + if(!attrib.normals.empty()) { + norBuf.push_back(attrib.normals[3*idx.normal_index+0]); + norBuf.push_back(attrib.normals[3*idx.normal_index+1]); + norBuf.push_back(attrib.normals[3*idx.normal_index+2]); + } + if(!attrib.texcoords.empty()) { + texBuf.push_back(attrib.texcoords[2*idx.texcoord_index+0]); + texBuf.push_back(attrib.texcoords[2*idx.texcoord_index+1]); + } + } + index_offset += fv; + // per-face material (IGNORE) + shapes[s].mesh.material_ids[f]; + } + } + } +} + +void Shape::init() +{ + // Send the position array to the GPU + glGenBuffers(1, &posBufID); + glBindBuffer(GL_ARRAY_BUFFER, posBufID); + glBufferData(GL_ARRAY_BUFFER, posBuf.size()*sizeof(float), &posBuf[0], GL_STATIC_DRAW); + + // Send the normal array to the GPU + if(!norBuf.empty()) { + glGenBuffers(1, &norBufID); + glBindBuffer(GL_ARRAY_BUFFER, norBufID); + glBufferData(GL_ARRAY_BUFFER, norBuf.size()*sizeof(float), &norBuf[0], GL_STATIC_DRAW); + } + + // Send the texture array to the GPU + if(!texBuf.empty()) { + glGenBuffers(1, &texBufID); + glBindBuffer(GL_ARRAY_BUFFER, texBufID); + glBufferData(GL_ARRAY_BUFFER, texBuf.size()*sizeof(float), &texBuf[0], GL_STATIC_DRAW); + } + + // Unbind the arrays + glBindBuffer(GL_ARRAY_BUFFER, 0); + + GLSL::checkError(GET_FILE_LINE); +} + +void Shape::draw(const shared_ptr prog) const +{ + // Bind position buffer + int h_pos = prog->getAttribute("aPos"); + glEnableVertexAttribArray(h_pos); + glBindBuffer(GL_ARRAY_BUFFER, posBufID); + glVertexAttribPointer(h_pos, 3, GL_FLOAT, GL_FALSE, 0, (const void *)0); + + // Bind normal buffer + int h_nor = prog->getAttribute("aNor"); + if(h_nor != -1 && norBufID != 0) { + glEnableVertexAttribArray(h_nor); + glBindBuffer(GL_ARRAY_BUFFER, norBufID); + glVertexAttribPointer(h_nor, 3, GL_FLOAT, GL_FALSE, 0, (const void *)0); + } + + // Bind texcoords buffer + int h_tex = prog->getAttribute("aTex"); + if(h_tex != -1 && texBufID != 0) { + glEnableVertexAttribArray(h_tex); + glBindBuffer(GL_ARRAY_BUFFER, texBufID); + glVertexAttribPointer(h_tex, 2, GL_FLOAT, GL_FALSE, 0, (const void *)0); + } + + // Draw + int count = posBuf.size()/3; // number of indices to be rendered + glDrawArrays(GL_TRIANGLES, 0, count); + + // Disable and unbind + if(h_tex != -1) { + glDisableVertexAttribArray(h_tex); + } + if(h_nor != -1) { + glDisableVertexAttribArray(h_nor); + } + glDisableVertexAttribArray(h_pos); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + GLSL::checkError(GET_FILE_LINE); +} diff --git a/A2/shadow8t4/shadow8t4/src/Shape.h b/A2/shadow8t4/shadow8t4/src/Shape.h new file mode 100644 index 0000000..df2aea3 --- /dev/null +++ b/A2/shadow8t4/shadow8t4/src/Shape.h @@ -0,0 +1,36 @@ +#pragma once +#ifndef _SHAPE_H_ +#define _SHAPE_H_ + +#include +#include +#include + +class Program; + +/** + * A shape defined by a list of triangles + * - posBuf should be of length 3*ntris + * - norBuf should be of length 3*ntris (if normals are available) + * - texBuf should be of length 2*ntris (if texture coords are available) + * posBufID, norBufID, and texBufID are OpenGL buffer identifiers. + */ +class Shape +{ +public: + Shape(); + virtual ~Shape(); + void loadMesh(const std::string &meshName); + void init(); + void draw(const std::shared_ptr prog) const; + +private: + std::vector posBuf; + std::vector norBuf; + std::vector texBuf; + unsigned posBufID; + unsigned norBufID; + unsigned texBufID; +}; + +#endif diff --git a/A2/shadow8t4/shadow8t4/src/main.cpp b/A2/shadow8t4/shadow8t4/src/main.cpp new file mode 100644 index 0000000..1afc646 --- /dev/null +++ b/A2/shadow8t4/shadow8t4/src/main.cpp @@ -0,0 +1,450 @@ +#include +#include +#define _USE_MATH_DEFINES +#include +#include +#include +#include + +#define GLEW_STATIC +#include +#include + +#define GLM_FORCE_RADIANS +#include +#include +#include + +#include "tiny_obj_loader.h" + +#include "GLSL.h" +#include "MatrixStack.h" +#include "Shape.h" +#include "Program.h" +#include "Component.h" + +#define PI 3.14159 + +using namespace std; +using namespace glm; + +GLFWwindow *window; // Main application window +string RESOURCE_DIR = "./"; // Where the resources are loaded from +shared_ptr prog; +shared_ptr shape; + + +GLuint progID; +map attrIDs; +map unifIDs; +map bufIDs; +int indCount; + +// Root component global +Component root; + +// Selected component +Component* selected = &root; + +// This function is called when a char is input +static void char_callback(GLFWwindow *window, unsigned int c) +{ + char cp = (char)c; + + if(cp == ',') + { + // select... + selected->selected = false; + selected = &selected->getPrevious(NULL); + selected->selected = true; + } + else if(cp == '.') + { + // select... + selected->selected = false; + selected = &selected->getNext(NULL); + selected->selected = true; + } + + if(cp == 'x') + { + // rotate... + selected->r.x += 0.1; + } + else if(cp == 'X') + { + // rotate... + selected->r.x -= 0.1; + } + + if(cp == 'y') + { + // rotate... + selected->r.y += 0.1; + } + else if(cp == 'Y') + { + // rotate... + selected->r.y -= 0.1; + } + + if(cp == 'z') + { + // rotate... + selected->r.z += 0.1; + } + else if(cp == 'Z') + { + // rotate... + selected->r.z -= 0.1; + } +} + +// This function is called when a GLFW error occurs +static void error_callback(int error, const char *description) +{ + cerr << description << endl; +} + +// This function is called when a key is pressed +static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) +{ + if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { + glfwSetWindowShouldClose(window, GL_TRUE); + } +} + +// This function is called when the mouse is clicked +static void mouse_callback(GLFWwindow *window, int button, int action, int mods) +{ + // Do nothing +} + +// If the window is resized, capture the new size and reset the viewport +static void resize_callback(GLFWwindow *window, int width, int height) +{ + glViewport(0, 0, width, height); +} + +static void setParents(Component& elem) +{ + for (unsigned int i = 0; i < elem.children.size(); ++i) + { + setParents(elem.children[i]); + elem.children[i].parent = &elem; + } +} + +void createRobot(Component& body) +{ + + body.selected = true; + + //Make Body + + body.s.x = 1.5; + body.s.y = 2.0; + body.s.z = 1.0; + + + // Make Head + + Component head; + head.parent = &body; + + head.tp.x = 0.0; + head.tp.y = body.s.y/2; + head.tp.z = 0.0; + + head.t.x = 0.0; + head.t.y = 0.5; + head.t.z = 0.0; + + body.children.push_back(head); + + // Make Left Upper Arm + + Component luarm; + luarm.parent = &body; + + luarm.tp.x = body.s.x/2; + luarm.tp.y = body.s.y/4; + luarm.tp.z = 0.0; + + luarm.s.x = 1.0; + luarm.s.y = 0.5; + luarm.s.z = 0.5; + + luarm.t.x = luarm.s.x/2; + luarm.t.y = 0.0; + luarm.t.z = 0.0; + + // Make Left Lower Arm + + Component llarm; + llarm.parent = &luarm; + + llarm.tp.x = luarm.s.x/2; + llarm.tp.y = 0.0; + llarm.tp.z = 0.0; + + llarm.s.x = 1.5; + llarm.s.y = 0.4; + llarm.s.z = 0.4; + + llarm.t.x = llarm.s.x/2; + llarm.t.y = 0.0; + llarm.t.z = 0.0; + + luarm.children.push_back(llarm); + + body.children.push_back(luarm); + + // Make Left Upper Leg + + Component luleg; + luleg.parent = &body; + + luleg.tp.x = body.s.x/4; + luleg.tp.y = -body.s.y/2; + luleg.tp.z = 0.0; + + luleg.s.x = 0.5; + luleg.s.y = 1.0; + luleg.s.z = 0.5; + + luleg.t.x = 0.0; + luleg.t.y = -luleg.s.y/2; + luleg.t.z = 0.0; + + // Make Left Lower Leg + + Component llleg; + llleg.parent = &luleg; + + llleg.tp.x = 0.0; + llleg.tp.y = -luleg.s.y/2; + llleg.tp.z = 0.0; + + llleg.s.x = 0.4; + llleg.s.y = 1.5; + llleg.s.z = 0.4; + + + llleg.t.x = 0.0; + llleg.t.y = -llleg.s.y/2; + llleg.t.z = 0.0; + + luleg.children.push_back(llleg); + + body.children.push_back(luleg); + + // Make Right Upper Leg + + Component ruleg; + ruleg.parent = &body; + + ruleg.tp.x = -body.s.x/4; + ruleg.tp.y = -body.s.y/2; + ruleg.tp.z = 0.0; + + ruleg.s.x = 0.5; + ruleg.s.y = 1.0; + ruleg.s.z = 0.5; + + ruleg.t.x = 0.0; + ruleg.t.y = -ruleg.s.y/2; + ruleg.t.z = 0.0; + + // Make Right Lower Leg + + Component rlleg; + rlleg.parent = &ruleg; + + rlleg.tp.x = 0.0; + rlleg.tp.y = -ruleg.s.y/2; + rlleg.tp.z = 0.0; + + rlleg.s.x = 0.4; + rlleg.s.y = 1.5; + rlleg.s.z = 0.4; + + + rlleg.t.x = 0.0; + rlleg.t.y = -rlleg.s.y/2; + rlleg.t.z = 0.0; + + ruleg.children.push_back(rlleg); + + body.children.push_back(ruleg); + + // Make Right Upper Arm + + Component ruarm; + ruarm.parent = &body; + + ruarm.tp.x = -body.s.x/2; + ruarm.tp.y = body.s.y/4; + ruarm.tp.z = 0.0; + + ruarm.s.x = 1.0; + ruarm.s.y = 0.5; + ruarm.s.z = 0.5; + + ruarm.t.x = -ruarm.s.x/2; + ruarm.t.y = 0.0; + ruarm.t.z = 0.0; + + // Make Right Lower Arm + + Component rlarm; + rlarm.parent = &ruarm; + + rlarm.tp.x = -ruarm.s.x/2; + rlarm.tp.y = 0.0; + rlarm.tp.z = 0.0; + + rlarm.s.x = 1.5; + rlarm.s.y = 0.4; + rlarm.s.z = 0.4; + + rlarm.t.x = -rlarm.s.x/2; + rlarm.t.y = 0.0; + rlarm.t.z = 0.0; + + ruarm.children.push_back(rlarm); + + body.children.push_back(ruarm); + + setParents(body); +} + +static void init() +{ + GLSL::checkVersion(); + + // Set background color. + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + // Enable z-buffer test. + glEnable(GL_DEPTH_TEST); + + // Initialize mesh. + shape = make_shared(); + shape->loadMesh(RESOURCE_DIR + "cube.obj"); + shape->init(); + + // Initialize the GLSL program. + prog = make_shared(); + prog->setVerbose(false); // Set this to true when debugging. + prog->setShaderNames(RESOURCE_DIR + "vert.glsl", RESOURCE_DIR + "frag.glsl"); + prog->init(); + prog->addUniform("P"); + prog->addUniform("MV"); + prog->addAttribute("aPos"); + prog->addAttribute("aNor"); + + createRobot(root); + selected = &root; + + // If there were any OpenGL errors, this will print something. + // You can intersperse this line in your code to find the exact location + // of your OpenGL error. + GLSL::checkError(GET_FILE_LINE); +} + +static void render() +{ + // Get current frame buffer size. + int width, height; + glfwGetFramebufferSize(window, &width, &height); + float aspect = width/(float)height; + glViewport(0, 0, width, height); + + // Clear framebuffer. + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // Create matrix stacks. + auto P = make_shared(); + auto MV = make_shared(); + // Apply projection. + P->pushMatrix(); + P->multMatrix(glm::perspective((float)(45.0*M_PI/180.0), aspect, 0.01f, 100.0f)); + // Apply camera transform. + MV->pushMatrix(); + MV->translate(glm::vec3(0, -0.5, -10)); + + // Draw mesh using GLSL. + prog->bind(); + // glUniformMatrix4fv(prog->getUniform("P"), 1, GL_FALSE, &P->topMatrix()[0][0]); + // glUniformMatrix4fv(prog->getUniform("MV"), 1, GL_FALSE, &MV->topMatrix()[0][0]); + // shape->draw(prog); + + root.draw(MV, P, shape, prog); + + prog->unbind(); + + // Pop matrix stacks. + MV->popMatrix(); + P->popMatrix(); + + GLSL::checkError(GET_FILE_LINE); +} + +int main(int argc, char **argv) +{ + if(argc < 2) { + cout << "Please specify the resource directory." << endl; + return 0; + } + RESOURCE_DIR = argv[1] + string("/"); + + // Set error callback. + glfwSetErrorCallback(error_callback); + // Initialize the library. + if(!glfwInit()) { + return -1; + } + // Create a windowed mode window and its OpenGL context. + window = glfwCreateWindow(640, 480, "Alexander Huddleston", NULL, NULL); + if(!window) { + glfwTerminate(); + return -1; + } + // Make the window's context current. + glfwMakeContextCurrent(window); + // Initialize GLEW. + glewExperimental = true; + if(glewInit() != GLEW_OK) { + cerr << "Failed to initialize GLEW" << endl; + return -1; + } + glGetError(); // A bug in glewInit() causes an error that we can safely ignore. + cout << "OpenGL version: " << glGetString(GL_VERSION) << endl; + cout << "GLSL version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << endl; + GLSL::checkVersion(); + // Set vsync. + glfwSwapInterval(1); + // Set char callback. + glfwSetCharCallback(window, char_callback); + // Set keyboard callback. + glfwSetKeyCallback(window, key_callback); + // Set the mouse call back. + glfwSetMouseButtonCallback(window, mouse_callback); + // Set the window resize call back. + glfwSetFramebufferSizeCallback(window, resize_callback); + // Initialize scene. + init(); + // Loop until the user closes the window. + while(!glfwWindowShouldClose(window)) { + // Render scene. + render(); + // Swap front and back buffers. + glfwSwapBuffers(window); + // Poll for and process events. + glfwPollEvents(); + } + // Quit program. + glfwDestroyWindow(window); + glfwTerminate(); + return 0; +} diff --git a/A2/shadow8t4/shadow8t4/src/tiny_obj_loader.h b/A2/shadow8t4/shadow8t4/src/tiny_obj_loader.h new file mode 100644 index 0000000..b975601 --- /dev/null +++ b/A2/shadow8t4/shadow8t4/src/tiny_obj_loader.h @@ -0,0 +1,1922 @@ +/* +The MIT License (MIT) + +Copyright (c) 2012-2016 Syoyo Fujita and many contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +// +// version 1.0.3 : Support parsing texture options(#85) +// version 1.0.2 : Improve parsing speed by about a factor of 2 for large +// files(#105) +// version 1.0.1 : Fixes a shape is lost if obj ends with a 'usemtl'(#104) +// version 1.0.0 : Change data structure. Change license from BSD to MIT. +// + +// +// Use this in *one* .cc +// #define TINYOBJLOADER_IMPLEMENTATION +// #include "tiny_obj_loader.h" +// + +#ifndef TINY_OBJ_LOADER_H_ +#define TINY_OBJ_LOADER_H_ + +#include +#include +#include + +namespace tinyobj { + +// https://en.wikipedia.org/wiki/Wavefront_.obj_file says ... +// +// -blendu on | off # set horizontal texture blending +// (default on) +// -blendv on | off # set vertical texture blending +// (default on) +// -boost float_value # boost mip-map sharpness +// -mm base_value gain_value # modify texture map values (default +// 0 1) +// # base_value = brightness, +// gain_value = contrast +// -o u [v [w]] # Origin offset (default +// 0 0 0) +// -s u [v [w]] # Scale (default +// 1 1 1) +// -t u [v [w]] # Turbulence (default +// 0 0 0) +// -texres resolution # texture resolution to create +// -clamp on | off # only render texels in the clamped +// 0-1 range (default off) +// # When unclamped, textures are +// repeated across a surface, +// # when clamped, only texels which +// fall within the 0-1 +// # range are rendered. +// -bm mult_value # bump multiplier (for bump maps +// only) +// +// -imfchan r | g | b | m | l | z # specifies which channel of the file +// is used to +// # create a scalar or bump texture. +// r:red, g:green, +// # b:blue, m:matte, l:luminance, +// z:z-depth.. +// # (the default for bump is 'l' and +// for decal is 'm') +// bump -imfchan r bumpmap.tga # says to use the red channel of +// bumpmap.tga as the bumpmap +// +// For reflection maps... +// +// -type sphere # specifies a sphere for a "refl" +// reflection map +// -type cube_top | cube_bottom | # when using a cube map, the texture +// file for each +// cube_front | cube_back | # side of the cube is specified +// separately +// cube_left | cube_right + +typedef enum { + TEXTURE_TYPE_NONE, // default + TEXTURE_TYPE_SPHERE, + TEXTURE_TYPE_CUBE_TOP, + TEXTURE_TYPE_CUBE_BOTTOM, + TEXTURE_TYPE_CUBE_FRONT, + TEXTURE_TYPE_CUBE_BACK, + TEXTURE_TYPE_CUBE_LEFT, + TEXTURE_TYPE_CUBE_RIGHT +} texture_type_t; + +typedef struct { + texture_type_t type; // -type (default TEXTURE_TYPE_NONE) + float sharpness; // -boost (default 1.0?) + float brightness; // base_value in -mm option (default 0) + float contrast; // gain_value in -mm option (default 1) + float origin_offset[3]; // -o u [v [w]] (default 0 0 0) + float scale[3]; // -s u [v [w]] (default 1 1 1) + float turbulence[3]; // -t u [v [w]] (default 0 0 0) + // int texture_resolution; // -texres resolution (default = ?) TODO + bool clamp; // -clamp (default false) + char imfchan; // -imfchan (the default for bump is 'l' and for decal is 'm') + bool blendu; // -blendu (default on) + bool blendv; // -blendv (default on) + float bump_multiplier; // -bm (for bump maps only, default 1.0) +} texture_option_t; + +typedef struct { + std::string name; + + float ambient[3]; + float diffuse[3]; + float specular[3]; + float transmittance[3]; + float emission[3]; + float shininess; + float ior; // index of refraction + float dissolve; // 1 == opaque; 0 == fully transparent + // illumination model (see http://www.fileformat.info/format/material/) + int illum; + + int dummy; // Suppress padding warning. + + std::string ambient_texname; // map_Ka + std::string diffuse_texname; // map_Kd + std::string specular_texname; // map_Ks + std::string specular_highlight_texname; // map_Ns + std::string bump_texname; // map_bump, bump + std::string displacement_texname; // disp + std::string alpha_texname; // map_d + + texture_option_t ambient_texopt; + texture_option_t diffuse_texopt; + texture_option_t specular_texopt; + texture_option_t specular_highlight_texopt; + texture_option_t bump_texopt; + texture_option_t displacement_texopt; + texture_option_t alpha_texopt; + + // PBR extension + // http://exocortex.com/blog/extending_wavefront_mtl_to_support_pbr + float roughness; // [0, 1] default 0 + float metallic; // [0, 1] default 0 + float sheen; // [0, 1] default 0 + float clearcoat_thickness; // [0, 1] default 0 + float clearcoat_roughness; // [0, 1] default 0 + float anisotropy; // aniso. [0, 1] default 0 + float anisotropy_rotation; // anisor. [0, 1] default 0 + float pad0; + float pad1; + std::string roughness_texname; // map_Pr + std::string metallic_texname; // map_Pm + std::string sheen_texname; // map_Ps + std::string emissive_texname; // map_Ke + std::string normal_texname; // norm. For normal mapping. + + texture_option_t roughness_texopt; + texture_option_t metallic_texopt; + texture_option_t sheen_texopt; + texture_option_t emissive_texopt; + texture_option_t normal_texopt; + + int pad2; + + std::map unknown_parameter; +} material_t; + +typedef struct { + std::string name; + + std::vector intValues; + std::vector floatValues; + std::vector stringValues; +} tag_t; + +// Index struct to support different indices for vtx/normal/texcoord. +// -1 means not used. +typedef struct { + int vertex_index; + int normal_index; + int texcoord_index; +} index_t; + +typedef struct { + std::vector indices; + std::vector num_face_vertices; // The number of vertices per + // face. 3 = polygon, 4 = quad, + // ... Up to 255. + std::vector material_ids; // per-face material ID + std::vector tags; // SubD tag +} mesh_t; + +typedef struct { + std::string name; + mesh_t mesh; +} shape_t; + +// Vertex attributes +typedef struct { + std::vector vertices; // 'v' + std::vector normals; // 'vn' + std::vector texcoords; // 'vt' +} attrib_t; + +typedef struct callback_t_ { + // W is optional and set to 1 if there is no `w` item in `v` line + void (*vertex_cb)(void *user_data, float x, float y, float z, float w); + void (*normal_cb)(void *user_data, float x, float y, float z); + + // y and z are optional and set to 0 if there is no `y` and/or `z` item(s) in + // `vt` line. + void (*texcoord_cb)(void *user_data, float x, float y, float z); + + // called per 'f' line. num_indices is the number of face indices(e.g. 3 for + // triangle, 4 for quad) + // 0 will be passed for undefined index in index_t members. + void (*index_cb)(void *user_data, index_t *indices, int num_indices); + // `name` material name, `material_id` = the array index of material_t[]. -1 + // if + // a material not found in .mtl + void (*usemtl_cb)(void *user_data, const char *name, int material_id); + // `materials` = parsed material data. + void (*mtllib_cb)(void *user_data, const material_t *materials, + int num_materials); + // There may be multiple group names + void (*group_cb)(void *user_data, const char **names, int num_names); + void (*object_cb)(void *user_data, const char *name); + + callback_t_() + : vertex_cb(NULL), + normal_cb(NULL), + texcoord_cb(NULL), + index_cb(NULL), + usemtl_cb(NULL), + mtllib_cb(NULL), + group_cb(NULL), + object_cb(NULL) {} +} callback_t; + +class MaterialReader { + public: + MaterialReader() {} + virtual ~MaterialReader(); + + virtual bool operator()(const std::string &matId, + std::vector *materials, + std::map *matMap, + std::string *err) = 0; +}; + +class MaterialFileReader : public MaterialReader { + public: + explicit MaterialFileReader(const std::string &mtl_basedir) + : m_mtlBaseDir(mtl_basedir) {} + virtual ~MaterialFileReader() {} + virtual bool operator()(const std::string &matId, + std::vector *materials, + std::map *matMap, std::string *err); + + private: + std::string m_mtlBaseDir; +}; + +class MaterialStreamReader : public MaterialReader { + public: + explicit MaterialStreamReader(std::istream &inStream) + : m_inStream(inStream) {} + virtual ~MaterialStreamReader() {} + virtual bool operator()(const std::string &matId, + std::vector *materials, + std::map *matMap, std::string *err); + + private: + std::istream &m_inStream; +}; + +/// Loads .obj from a file. +/// 'attrib', 'shapes' and 'materials' will be filled with parsed shape data +/// 'shapes' will be filled with parsed shape data +/// Returns true when loading .obj become success. +/// Returns warning and error message into `err` +/// 'mtl_basedir' is optional, and used for base directory for .mtl file. +/// In default(`NULL'), .mtl file is searched from an application's working directory. +/// 'triangulate' is optional, and used whether triangulate polygon face in .obj +/// or not. +bool LoadObj(attrib_t *attrib, std::vector *shapes, + std::vector *materials, std::string *err, + const char *filename, const char *mtl_basedir = NULL, + bool triangulate = true); + +/// Loads .obj from a file with custom user callback. +/// .mtl is loaded as usual and parsed material_t data will be passed to +/// `callback.mtllib_cb`. +/// Returns true when loading .obj/.mtl become success. +/// Returns warning and error message into `err` +/// See `examples/callback_api/` for how to use this function. +bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback, + void *user_data = NULL, + MaterialReader *readMatFn = NULL, + std::string *err = NULL); + +/// Loads object from a std::istream, uses GetMtlIStreamFn to retrieve +/// std::istream for materials. +/// Returns true when loading .obj become success. +/// Returns warning and error message into `err` +bool LoadObj(attrib_t *attrib, std::vector *shapes, + std::vector *materials, std::string *err, + std::istream *inStream, MaterialReader *readMatFn = NULL, + bool triangulate = true); + +/// Loads materials into std::map +void LoadMtl(std::map *material_map, + std::vector *materials, std::istream *inStream); + +} // namespace tinyobj + +#ifdef TINYOBJLOADER_IMPLEMENTATION +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace tinyobj { + +MaterialReader::~MaterialReader() {} + +#define TINYOBJ_SSCANF_BUFFER_SIZE (4096) + +struct vertex_index { + int v_idx, vt_idx, vn_idx; + vertex_index() : v_idx(-1), vt_idx(-1), vn_idx(-1) {} + explicit vertex_index(int idx) : v_idx(idx), vt_idx(idx), vn_idx(idx) {} + vertex_index(int vidx, int vtidx, int vnidx) + : v_idx(vidx), vt_idx(vtidx), vn_idx(vnidx) {} +}; + +struct tag_sizes { + tag_sizes() : num_ints(0), num_floats(0), num_strings(0) {} + int num_ints; + int num_floats; + int num_strings; +}; + +struct obj_shape { + std::vector v; + std::vector vn; + std::vector vt; +}; + +// See +// http://stackoverflow.com/questions/6089231/getting-std-ifstream-to-handle-lf-cr-and-crlf +static std::istream &safeGetline(std::istream &is, std::string &t) { + t.clear(); + + // The characters in the stream are read one-by-one using a std::streambuf. + // That is faster than reading them one-by-one using the std::istream. + // Code that uses streambuf this way must be guarded by a sentry object. + // The sentry object performs various tasks, + // such as thread synchronization and updating the stream state. + + std::istream::sentry se(is, true); + std::streambuf *sb = is.rdbuf(); + + for (;;) { + int c = sb->sbumpc(); + switch (c) { + case '\n': + return is; + case '\r': + if (sb->sgetc() == '\n') sb->sbumpc(); + return is; + case EOF: + // Also handle the case when the last line has no line ending + if (t.empty()) is.setstate(std::ios::eofbit); + return is; + default: + t += static_cast(c); + } + } +} + +#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t')) +#define IS_DIGIT(x) \ + (static_cast((x) - '0') < static_cast(10)) +#define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0')) + +// Make index zero-base, and also support relative index. +static inline int fixIndex(int idx, int n) { + if (idx > 0) return idx - 1; + if (idx == 0) return 0; + return n + idx; // negative value = relative +} + +static inline std::string parseString(const char **token) { + std::string s; + (*token) += strspn((*token), " \t"); + size_t e = strcspn((*token), " \t\r"); + s = std::string((*token), &(*token)[e]); + (*token) += e; + return s; +} + +static inline int parseInt(const char **token) { + (*token) += strspn((*token), " \t"); + int i = atoi((*token)); + (*token) += strcspn((*token), " \t\r"); + return i; +} + +// Tries to parse a floating point number located at s. +// +// s_end should be a location in the string where reading should absolutely +// stop. For example at the end of the string, to prevent buffer overflows. +// +// Parses the following EBNF grammar: +// sign = "+" | "-" ; +// END = ? anything not in digit ? +// digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ; +// integer = [sign] , digit , {digit} ; +// decimal = integer , ["." , integer] ; +// float = ( decimal , END ) | ( decimal , ("E" | "e") , integer , END ) ; +// +// Valid strings are for example: +// -0 +3.1417e+2 -0.0E-3 1.0324 -1.41 11e2 +// +// If the parsing is a success, result is set to the parsed value and true +// is returned. +// +// The function is greedy and will parse until any of the following happens: +// - a non-conforming character is encountered. +// - s_end is reached. +// +// The following situations triggers a failure: +// - s >= s_end. +// - parse failure. +// +static bool tryParseDouble(const char *s, const char *s_end, double *result) { + if (s >= s_end) { + return false; + } + + double mantissa = 0.0; + // This exponent is base 2 rather than 10. + // However the exponent we parse is supposed to be one of ten, + // thus we must take care to convert the exponent/and or the + // mantissa to a * 2^E, where a is the mantissa and E is the + // exponent. + // To get the final double we will use ldexp, it requires the + // exponent to be in base 2. + int exponent = 0; + + // NOTE: THESE MUST BE DECLARED HERE SINCE WE ARE NOT ALLOWED + // TO JUMP OVER DEFINITIONS. + char sign = '+'; + char exp_sign = '+'; + char const *curr = s; + + // How many characters were read in a loop. + int read = 0; + // Tells whether a loop terminated due to reaching s_end. + bool end_not_reached = false; + + /* + BEGIN PARSING. + */ + + // Find out what sign we've got. + if (*curr == '+' || *curr == '-') { + sign = *curr; + curr++; + } else if (IS_DIGIT(*curr)) { /* Pass through. */ + } else { + goto fail; + } + + // Read the integer part. + end_not_reached = (curr != s_end); + while (end_not_reached && IS_DIGIT(*curr)) { + mantissa *= 10; + mantissa += static_cast(*curr - 0x30); + curr++; + read++; + end_not_reached = (curr != s_end); + } + + // We must make sure we actually got something. + if (read == 0) goto fail; + // We allow numbers of form "#", "###" etc. + if (!end_not_reached) goto assemble; + + // Read the decimal part. + if (*curr == '.') { + curr++; + read = 1; + end_not_reached = (curr != s_end); + while (end_not_reached && IS_DIGIT(*curr)) { + static const double pow_lut[] = { + 1.0, 0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001, + }; + const int lut_entries = sizeof pow_lut / sizeof pow_lut[0]; + + // NOTE: Don't use powf here, it will absolutely murder precision. + mantissa += static_cast(*curr - 0x30) * + (read < lut_entries ? pow_lut[read] : pow(10.0, -read)); + read++; + curr++; + end_not_reached = (curr != s_end); + } + } else if (*curr == 'e' || *curr == 'E') { + } else { + goto assemble; + } + + if (!end_not_reached) goto assemble; + + // Read the exponent part. + if (*curr == 'e' || *curr == 'E') { + curr++; + // Figure out if a sign is present and if it is. + end_not_reached = (curr != s_end); + if (end_not_reached && (*curr == '+' || *curr == '-')) { + exp_sign = *curr; + curr++; + } else if (IS_DIGIT(*curr)) { /* Pass through. */ + } else { + // Empty E is not allowed. + goto fail; + } + + read = 0; + end_not_reached = (curr != s_end); + while (end_not_reached && IS_DIGIT(*curr)) { + exponent *= 10; + exponent += static_cast(*curr - 0x30); + curr++; + read++; + end_not_reached = (curr != s_end); + } + exponent *= (exp_sign == '+' ? 1 : -1); + if (read == 0) goto fail; + } + +assemble: + *result = + (sign == '+' ? 1 : -1) * + (exponent ? ldexp(mantissa * pow(5.0, exponent), exponent) : mantissa); + return true; +fail: + return false; +} + +static inline float parseFloat(const char **token, double default_value = 0.0) { + (*token) += strspn((*token), " \t"); + const char *end = (*token) + strcspn((*token), " \t\r"); + double val = default_value; + tryParseDouble((*token), end, &val); + float f = static_cast(val); + (*token) = end; + return f; +} + +static inline void parseFloat2(float *x, float *y, const char **token, + const double default_x = 0.0, + const double default_y = 0.0) { + (*x) = parseFloat(token, default_x); + (*y) = parseFloat(token, default_y); +} + +static inline void parseFloat3(float *x, float *y, float *z, const char **token, + const double default_x = 0.0, + const double default_y = 0.0, + const double default_z = 0.0) { + (*x) = parseFloat(token, default_x); + (*y) = parseFloat(token, default_y); + (*z) = parseFloat(token, default_z); +} + +static inline void parseV(float *x, float *y, float *z, float *w, + const char **token, const double default_x = 0.0, + const double default_y = 0.0, + const double default_z = 0.0, + const double default_w = 1.0) { + (*x) = parseFloat(token, default_x); + (*y) = parseFloat(token, default_y); + (*z) = parseFloat(token, default_z); + (*w) = parseFloat(token, default_w); +} + +static inline bool parseOnOff(const char **token, bool default_value = true) { + (*token) += strspn((*token), " \t"); + const char *end = (*token) + strcspn((*token), " \t\r"); + + bool ret = default_value; + if ((0 == strncmp((*token), "on", 2))) { + ret = true; + } else if ((0 == strncmp((*token), "off", 3))) { + ret = false; + } + + (*token) = end; + return ret; +} + +static inline texture_type_t parseTextureType( + const char **token, texture_type_t default_value = TEXTURE_TYPE_NONE) { + (*token) += strspn((*token), " \t"); + const char *end = (*token) + strcspn((*token), " \t\r"); + texture_type_t ty = default_value; + + if ((0 == strncmp((*token), "cube_top", strlen("cube_top")))) { + ty = TEXTURE_TYPE_CUBE_TOP; + } else if ((0 == strncmp((*token), "cube_bottom", strlen("cube_bottom")))) { + ty = TEXTURE_TYPE_CUBE_BOTTOM; + } else if ((0 == strncmp((*token), "cube_left", strlen("cube_left")))) { + ty = TEXTURE_TYPE_CUBE_LEFT; + } else if ((0 == strncmp((*token), "cube_right", strlen("cube_right")))) { + ty = TEXTURE_TYPE_CUBE_RIGHT; + } else if ((0 == strncmp((*token), "cube_front", strlen("cube_front")))) { + ty = TEXTURE_TYPE_CUBE_FRONT; + } else if ((0 == strncmp((*token), "cube_back", strlen("cube_back")))) { + ty = TEXTURE_TYPE_CUBE_BACK; + } else if ((0 == strncmp((*token), "sphere", strlen("sphere")))) { + ty = TEXTURE_TYPE_SPHERE; + } + + (*token) = end; + return ty; +} + +static tag_sizes parseTagTriple(const char **token) { + tag_sizes ts; + + ts.num_ints = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return ts; + } + (*token)++; + + ts.num_floats = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return ts; + } + (*token)++; + + ts.num_strings = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r") + 1; + + return ts; +} + +// Parse triples with index offsets: i, i/j/k, i//k, i/j +static vertex_index parseTriple(const char **token, int vsize, int vnsize, + int vtsize) { + vertex_index vi(-1); + + vi.v_idx = fixIndex(atoi((*token)), vsize); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return vi; + } + (*token)++; + + // i//k + if ((*token)[0] == '/') { + (*token)++; + vi.vn_idx = fixIndex(atoi((*token)), vnsize); + (*token) += strcspn((*token), "/ \t\r"); + return vi; + } + + // i/j/k or i/j + vi.vt_idx = fixIndex(atoi((*token)), vtsize); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return vi; + } + + // i/j/k + (*token)++; // skip '/' + vi.vn_idx = fixIndex(atoi((*token)), vnsize); + (*token) += strcspn((*token), "/ \t\r"); + return vi; +} + +// Parse raw triples: i, i/j/k, i//k, i/j +static vertex_index parseRawTriple(const char **token) { + vertex_index vi(static_cast(0)); // 0 is an invalid index in OBJ + + vi.v_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return vi; + } + (*token)++; + + // i//k + if ((*token)[0] == '/') { + (*token)++; + vi.vn_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + return vi; + } + + // i/j/k or i/j + vi.vt_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return vi; + } + + // i/j/k + (*token)++; // skip '/' + vi.vn_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + return vi; +} + +static bool ParseTextureNameAndOption(std::string *texname, + texture_option_t *texopt, + const char *linebuf, const bool is_bump) { + // @todo { write more robust lexer and parser. } + bool found_texname = false; + std::string texture_name; + + // Fill with default value for texopt. + if (is_bump) { + texopt->imfchan = 'l'; + } else { + texopt->imfchan = 'm'; + } + texopt->bump_multiplier = 1.0f; + texopt->clamp = false; + texopt->blendu = true; + texopt->blendv = true; + texopt->sharpness = 1.0f; + texopt->brightness = 0.0f; + texopt->contrast = 1.0f; + texopt->origin_offset[0] = 0.0f; + texopt->origin_offset[1] = 0.0f; + texopt->origin_offset[2] = 0.0f; + texopt->scale[0] = 1.0f; + texopt->scale[1] = 1.0f; + texopt->scale[2] = 1.0f; + texopt->turbulence[0] = 0.0f; + texopt->turbulence[1] = 0.0f; + texopt->turbulence[2] = 0.0f; + texopt->type = TEXTURE_TYPE_NONE; + + const char *token = linebuf; // Assume line ends with NULL + + while (!IS_NEW_LINE((*token))) { + if ((0 == strncmp(token, "-blendu", 7)) && IS_SPACE((token[7]))) { + token += 8; + texopt->blendu = parseOnOff(&token, /* default */ true); + } else if ((0 == strncmp(token, "-blendv", 7)) && IS_SPACE((token[7]))) { + token += 8; + texopt->blendv = parseOnOff(&token, /* default */ true); + } else if ((0 == strncmp(token, "-clamp", 6)) && IS_SPACE((token[6]))) { + token += 7; + texopt->clamp = parseOnOff(&token, /* default */ true); + } else if ((0 == strncmp(token, "-boost", 6)) && IS_SPACE((token[6]))) { + token += 7; + texopt->sharpness = parseFloat(&token, 1.0); + } else if ((0 == strncmp(token, "-bm", 3)) && IS_SPACE((token[3]))) { + token += 4; + texopt->bump_multiplier = parseFloat(&token, 1.0); + } else if ((0 == strncmp(token, "-o", 2)) && IS_SPACE((token[2]))) { + token += 3; + parseFloat3(&(texopt->origin_offset[0]), &(texopt->origin_offset[1]), + &(texopt->origin_offset[2]), &token); + } else if ((0 == strncmp(token, "-s", 2)) && IS_SPACE((token[2]))) { + token += 3; + parseFloat3(&(texopt->scale[0]), &(texopt->scale[1]), &(texopt->scale[2]), + &token, 1.0, 1.0, 1.0); + } else if ((0 == strncmp(token, "-t", 2)) && IS_SPACE((token[2]))) { + token += 3; + parseFloat3(&(texopt->turbulence[0]), &(texopt->turbulence[1]), + &(texopt->turbulence[2]), &token); + } else if ((0 == strncmp(token, "-type", 5)) && IS_SPACE((token[5]))) { + token += 5; + texopt->type = parseTextureType((&token), TEXTURE_TYPE_NONE); + } else if ((0 == strncmp(token, "-imfchan", 8)) && IS_SPACE((token[8]))) { + token += 9; + token += strspn(token, " \t"); + const char *end = token + strcspn(token, " \t\r"); + if ((end - token) == 1) { // Assume one char for -imfchan + texopt->imfchan = (*token); + } + token = end; + } else if ((0 == strncmp(token, "-mm", 3)) && IS_SPACE((token[3]))) { + token += 4; + parseFloat2(&(texopt->brightness), &(texopt->contrast), &token, 0.0, 1.0); + } else { + // Assume texture filename + token += strspn(token, " \t"); // skip space + size_t len = strcspn(token, " \t\r"); // untile next space + texture_name = std::string(token, token + len); + token += len; + + token += strspn(token, " \t"); // skip space + + found_texname = true; + } + } + + if (found_texname) { + (*texname) = texture_name; + return true; + } else { + return false; + } +} + +static void InitMaterial(material_t *material) { + material->name = ""; + material->ambient_texname = ""; + material->diffuse_texname = ""; + material->specular_texname = ""; + material->specular_highlight_texname = ""; + material->bump_texname = ""; + material->displacement_texname = ""; + material->alpha_texname = ""; + for (int i = 0; i < 3; i++) { + material->ambient[i] = 0.f; + material->diffuse[i] = 0.f; + material->specular[i] = 0.f; + material->transmittance[i] = 0.f; + material->emission[i] = 0.f; + } + material->illum = 0; + material->dissolve = 1.f; + material->shininess = 1.f; + material->ior = 1.f; + + material->roughness = 0.f; + material->metallic = 0.f; + material->sheen = 0.f; + material->clearcoat_thickness = 0.f; + material->clearcoat_roughness = 0.f; + material->anisotropy_rotation = 0.f; + material->anisotropy = 0.f; + material->roughness_texname = ""; + material->metallic_texname = ""; + material->sheen_texname = ""; + material->emissive_texname = ""; + material->normal_texname = ""; + + material->unknown_parameter.clear(); +} + +static bool exportFaceGroupToShape( + shape_t *shape, const std::vector > &faceGroup, + const std::vector &tags, const int material_id, + const std::string &name, bool triangulate) { + if (faceGroup.empty()) { + return false; + } + + // Flatten vertices and indices + for (size_t i = 0; i < faceGroup.size(); i++) { + const std::vector &face = faceGroup[i]; + + vertex_index i0 = face[0]; + vertex_index i1(-1); + vertex_index i2 = face[1]; + + size_t npolys = face.size(); + + if (triangulate) { + // Polygon -> triangle fan conversion + for (size_t k = 2; k < npolys; k++) { + i1 = i2; + i2 = face[k]; + + index_t idx0, idx1, idx2; + idx0.vertex_index = i0.v_idx; + idx0.normal_index = i0.vn_idx; + idx0.texcoord_index = i0.vt_idx; + idx1.vertex_index = i1.v_idx; + idx1.normal_index = i1.vn_idx; + idx1.texcoord_index = i1.vt_idx; + idx2.vertex_index = i2.v_idx; + idx2.normal_index = i2.vn_idx; + idx2.texcoord_index = i2.vt_idx; + + shape->mesh.indices.push_back(idx0); + shape->mesh.indices.push_back(idx1); + shape->mesh.indices.push_back(idx2); + + shape->mesh.num_face_vertices.push_back(3); + shape->mesh.material_ids.push_back(material_id); + } + } else { + for (size_t k = 0; k < npolys; k++) { + index_t idx; + idx.vertex_index = face[k].v_idx; + idx.normal_index = face[k].vn_idx; + idx.texcoord_index = face[k].vt_idx; + shape->mesh.indices.push_back(idx); + } + + shape->mesh.num_face_vertices.push_back( + static_cast(npolys)); + shape->mesh.material_ids.push_back(material_id); // per face + } + } + + shape->name = name; + shape->mesh.tags = tags; + + return true; +} + +void LoadMtl(std::map *material_map, + std::vector *materials, std::istream *inStream) { + // Create a default material anyway. + material_t material; + InitMaterial(&material); + + std::string linebuf; + while (inStream->peek() != -1) { + safeGetline(*inStream, linebuf); + + // Trim trailing whitespace. + if (linebuf.size() > 0) { + linebuf = linebuf.substr(0, linebuf.find_last_not_of(" \t") + 1); + } + + // Trim newline '\r\n' or '\n' + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\n') + linebuf.erase(linebuf.size() - 1); + } + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\r') + linebuf.erase(linebuf.size() - 1); + } + + // Skip if empty line. + if (linebuf.empty()) { + continue; + } + + // Skip leading space. + const char *token = linebuf.c_str(); + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') continue; // empty line + + if (token[0] == '#') continue; // comment line + + // new mtl + if ((0 == strncmp(token, "newmtl", 6)) && IS_SPACE((token[6]))) { + // flush previous material. + if (!material.name.empty()) { + material_map->insert(std::pair( + material.name, static_cast(materials->size()))); + materials->push_back(material); + } + + // initial temporary material + InitMaterial(&material); + + // set new mtl name + char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE]; + token += 7; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + material.name = namebuf; + continue; + } + + // ambient + if (token[0] == 'K' && token[1] == 'a' && IS_SPACE((token[2]))) { + token += 2; + float r, g, b; + parseFloat3(&r, &g, &b, &token); + material.ambient[0] = r; + material.ambient[1] = g; + material.ambient[2] = b; + continue; + } + + // diffuse + if (token[0] == 'K' && token[1] == 'd' && IS_SPACE((token[2]))) { + token += 2; + float r, g, b; + parseFloat3(&r, &g, &b, &token); + material.diffuse[0] = r; + material.diffuse[1] = g; + material.diffuse[2] = b; + continue; + } + + // specular + if (token[0] == 'K' && token[1] == 's' && IS_SPACE((token[2]))) { + token += 2; + float r, g, b; + parseFloat3(&r, &g, &b, &token); + material.specular[0] = r; + material.specular[1] = g; + material.specular[2] = b; + continue; + } + + // transmittance + if ((token[0] == 'K' && token[1] == 't' && IS_SPACE((token[2]))) || + (token[0] == 'T' && token[1] == 'f' && IS_SPACE((token[2])))) { + token += 2; + float r, g, b; + parseFloat3(&r, &g, &b, &token); + material.transmittance[0] = r; + material.transmittance[1] = g; + material.transmittance[2] = b; + continue; + } + + // ior(index of refraction) + if (token[0] == 'N' && token[1] == 'i' && IS_SPACE((token[2]))) { + token += 2; + material.ior = parseFloat(&token); + continue; + } + + // emission + if (token[0] == 'K' && token[1] == 'e' && IS_SPACE(token[2])) { + token += 2; + float r, g, b; + parseFloat3(&r, &g, &b, &token); + material.emission[0] = r; + material.emission[1] = g; + material.emission[2] = b; + continue; + } + + // shininess + if (token[0] == 'N' && token[1] == 's' && IS_SPACE(token[2])) { + token += 2; + material.shininess = parseFloat(&token); + continue; + } + + // illum model + if (0 == strncmp(token, "illum", 5) && IS_SPACE(token[5])) { + token += 6; + material.illum = parseInt(&token); + continue; + } + + // dissolve + if ((token[0] == 'd' && IS_SPACE(token[1]))) { + token += 1; + material.dissolve = parseFloat(&token); + continue; + } + if (token[0] == 'T' && token[1] == 'r' && IS_SPACE(token[2])) { + token += 2; + // Invert value of Tr(assume Tr is in range [0, 1]) + material.dissolve = 1.0f - parseFloat(&token); + continue; + } + + // PBR: roughness + if (token[0] == 'P' && token[1] == 'r' && IS_SPACE(token[2])) { + token += 2; + material.roughness = parseFloat(&token); + continue; + } + + // PBR: metallic + if (token[0] == 'P' && token[1] == 'm' && IS_SPACE(token[2])) { + token += 2; + material.metallic = parseFloat(&token); + continue; + } + + // PBR: sheen + if (token[0] == 'P' && token[1] == 's' && IS_SPACE(token[2])) { + token += 2; + material.sheen = parseFloat(&token); + continue; + } + + // PBR: clearcoat thickness + if (token[0] == 'P' && token[1] == 'c' && IS_SPACE(token[2])) { + token += 2; + material.clearcoat_thickness = parseFloat(&token); + continue; + } + + // PBR: clearcoat roughness + if ((0 == strncmp(token, "Pcr", 3)) && IS_SPACE(token[3])) { + token += 4; + material.clearcoat_roughness = parseFloat(&token); + continue; + } + + // PBR: anisotropy + if ((0 == strncmp(token, "aniso", 5)) && IS_SPACE(token[5])) { + token += 6; + material.anisotropy = parseFloat(&token); + continue; + } + + // PBR: anisotropy rotation + if ((0 == strncmp(token, "anisor", 6)) && IS_SPACE(token[6])) { + token += 7; + material.anisotropy_rotation = parseFloat(&token); + continue; + } + + // ambient texture + if ((0 == strncmp(token, "map_Ka", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.ambient_texname), + &(material.ambient_texopt), token, + /* is_bump */ false); + continue; + } + + // diffuse texture + if ((0 == strncmp(token, "map_Kd", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.diffuse_texname), + &(material.diffuse_texopt), token, + /* is_bump */ false); + continue; + } + + // specular texture + if ((0 == strncmp(token, "map_Ks", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.specular_texname), + &(material.specular_texopt), token, + /* is_bump */ false); + continue; + } + + // specular highlight texture + if ((0 == strncmp(token, "map_Ns", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.specular_highlight_texname), + &(material.specular_highlight_texopt), token, + /* is_bump */ false); + continue; + } + + // bump texture + if ((0 == strncmp(token, "map_bump", 8)) && IS_SPACE(token[8])) { + token += 9; + ParseTextureNameAndOption(&(material.bump_texname), + &(material.bump_texopt), token, + /* is_bump */ true); + continue; + } + + // bump texture + if ((0 == strncmp(token, "bump", 4)) && IS_SPACE(token[4])) { + token += 5; + ParseTextureNameAndOption(&(material.bump_texname), + &(material.bump_texopt), token, + /* is_bump */ true); + continue; + } + + // alpha texture + if ((0 == strncmp(token, "map_d", 5)) && IS_SPACE(token[5])) { + token += 6; + material.alpha_texname = token; + ParseTextureNameAndOption(&(material.alpha_texname), + &(material.alpha_texopt), token, + /* is_bump */ false); + continue; + } + + // displacement texture + if ((0 == strncmp(token, "disp", 4)) && IS_SPACE(token[4])) { + token += 5; + ParseTextureNameAndOption(&(material.displacement_texname), + &(material.displacement_texopt), token, + /* is_bump */ false); + continue; + } + + // PBR: roughness texture + if ((0 == strncmp(token, "map_Pr", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.roughness_texname), + &(material.roughness_texopt), token, + /* is_bump */ false); + continue; + } + + // PBR: metallic texture + if ((0 == strncmp(token, "map_Pm", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.metallic_texname), + &(material.metallic_texopt), token, + /* is_bump */ false); + continue; + } + + // PBR: sheen texture + if ((0 == strncmp(token, "map_Ps", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.sheen_texname), + &(material.sheen_texopt), token, + /* is_bump */ false); + continue; + } + + // PBR: emissive texture + if ((0 == strncmp(token, "map_Ke", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.emissive_texname), + &(material.emissive_texopt), token, + /* is_bump */ false); + continue; + } + + // PBR: normal map texture + if ((0 == strncmp(token, "norm", 4)) && IS_SPACE(token[4])) { + token += 5; + ParseTextureNameAndOption( + &(material.normal_texname), &(material.normal_texopt), token, + /* is_bump */ false); // @fixme { is_bump will be true? } + continue; + } + + // unknown parameter + const char *_space = strchr(token, ' '); + if (!_space) { + _space = strchr(token, '\t'); + } + if (_space) { + std::ptrdiff_t len = _space - token; + std::string key(token, static_cast(len)); + std::string value = _space + 1; + material.unknown_parameter.insert( + std::pair(key, value)); + } + } + // flush last material. + material_map->insert(std::pair( + material.name, static_cast(materials->size()))); + materials->push_back(material); +} + +bool MaterialFileReader::operator()(const std::string &matId, + std::vector *materials, + std::map *matMap, + std::string *err) { + std::string filepath; + + if (!m_mtlBaseDir.empty()) { + filepath = std::string(m_mtlBaseDir) + matId; + } else { + filepath = matId; + } + + std::ifstream matIStream(filepath.c_str()); + LoadMtl(matMap, materials, &matIStream); + if (!matIStream) { + std::stringstream ss; + ss << "WARN: Material file [ " << filepath + << " ] not found. Created a default material."; + if (err) { + (*err) += ss.str(); + } + } + return true; +} + +bool MaterialStreamReader::operator()(const std::string &matId, + std::vector *materials, + std::map *matMap, + std::string *err) { + (void)matId; + LoadMtl(matMap, materials, &m_inStream); + if (!m_inStream) { + std::stringstream ss; + ss << "WARN: Material stream in error state." + << " Created a default material."; + if (err) { + (*err) += ss.str(); + } + } + return true; +} + +bool LoadObj(attrib_t *attrib, std::vector *shapes, + std::vector *materials, std::string *err, + const char *filename, const char *mtl_basedir, + bool trianglulate) { + attrib->vertices.clear(); + attrib->normals.clear(); + attrib->texcoords.clear(); + shapes->clear(); + + std::stringstream errss; + + std::ifstream ifs(filename); + if (!ifs) { + errss << "Cannot open file [" << filename << "]" << std::endl; + if (err) { + (*err) = errss.str(); + } + return false; + } + + std::string baseDir; + if (mtl_basedir) { + baseDir = mtl_basedir; + } + MaterialFileReader matFileReader(baseDir); + + return LoadObj(attrib, shapes, materials, err, &ifs, &matFileReader, + trianglulate); +} + +bool LoadObj(attrib_t *attrib, std::vector *shapes, + std::vector *materials, std::string *err, + std::istream *inStream, MaterialReader *readMatFn /*= NULL*/, + bool triangulate) { + std::stringstream errss; + + std::vector v; + std::vector vn; + std::vector vt; + std::vector tags; + std::vector > faceGroup; + std::string name; + + // material + std::map material_map; + int material = -1; + + shape_t shape; + + std::string linebuf; + while (inStream->peek() != -1) { + safeGetline(*inStream, linebuf); + + // Trim newline '\r\n' or '\n' + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\n') + linebuf.erase(linebuf.size() - 1); + } + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\r') + linebuf.erase(linebuf.size() - 1); + } + + // Skip if empty line. + if (linebuf.empty()) { + continue; + } + + // Skip leading space. + const char *token = linebuf.c_str(); + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') continue; // empty line + + if (token[0] == '#') continue; // comment line + + // vertex + if (token[0] == 'v' && IS_SPACE((token[1]))) { + token += 2; + float x, y, z; + parseFloat3(&x, &y, &z, &token); + v.push_back(x); + v.push_back(y); + v.push_back(z); + continue; + } + + // normal + if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) { + token += 3; + float x, y, z; + parseFloat3(&x, &y, &z, &token); + vn.push_back(x); + vn.push_back(y); + vn.push_back(z); + continue; + } + + // texcoord + if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) { + token += 3; + float x, y; + parseFloat2(&x, &y, &token); + vt.push_back(x); + vt.push_back(y); + continue; + } + + // face + if (token[0] == 'f' && IS_SPACE((token[1]))) { + token += 2; + token += strspn(token, " \t"); + + std::vector face; + face.reserve(3); + + while (!IS_NEW_LINE(token[0])) { + vertex_index vi = parseTriple(&token, static_cast(v.size() / 3), + static_cast(vn.size() / 3), + static_cast(vt.size() / 2)); + face.push_back(vi); + size_t n = strspn(token, " \t\r"); + token += n; + } + + // replace with emplace_back + std::move on C++11 + faceGroup.push_back(std::vector()); + faceGroup[faceGroup.size() - 1].swap(face); + + continue; + } + + // use mtl + if ((0 == strncmp(token, "usemtl", 6)) && IS_SPACE((token[6]))) { + char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE]; + token += 7; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + + int newMaterialId = -1; + if (material_map.find(namebuf) != material_map.end()) { + newMaterialId = material_map[namebuf]; + } else { + // { error!! material not found } + } + + if (newMaterialId != material) { + // Create per-face material. Thus we don't add `shape` to `shapes` at + // this time. + // just clear `faceGroup` after `exportFaceGroupToShape()` call. + exportFaceGroupToShape(&shape, faceGroup, tags, material, name, + triangulate); + faceGroup.clear(); + material = newMaterialId; + } + + continue; + } + + // load mtl + if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) { + if (readMatFn) { + char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE]; + token += 7; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + + std::string err_mtl; + bool ok = (*readMatFn)(namebuf, materials, &material_map, &err_mtl); + if (err) { + (*err) += err_mtl; + } + + if (!ok) { + faceGroup.clear(); // for safety + return false; + } + } + + continue; + } + + // group name + if (token[0] == 'g' && IS_SPACE((token[1]))) { + // flush previous face group. + bool ret = exportFaceGroupToShape(&shape, faceGroup, tags, material, name, + triangulate); + if (ret) { + shapes->push_back(shape); + } + + shape = shape_t(); + + // material = -1; + faceGroup.clear(); + + std::vector names; + names.reserve(2); + + while (!IS_NEW_LINE(token[0])) { + std::string str = parseString(&token); + names.push_back(str); + token += strspn(token, " \t\r"); // skip tag + } + + assert(names.size() > 0); + + // names[0] must be 'g', so skip the 0th element. + if (names.size() > 1) { + name = names[1]; + } else { + name = ""; + } + + continue; + } + + // object name + if (token[0] == 'o' && IS_SPACE((token[1]))) { + // flush previous face group. + bool ret = exportFaceGroupToShape(&shape, faceGroup, tags, material, name, + triangulate); + if (ret) { + shapes->push_back(shape); + } + + // material = -1; + faceGroup.clear(); + shape = shape_t(); + + // @todo { multiple object name? } + char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE]; + token += 2; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + name = std::string(namebuf); + + continue; + } + + if (token[0] == 't' && IS_SPACE(token[1])) { + tag_t tag; + + char namebuf[4096]; + token += 2; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + tag.name = std::string(namebuf); + + token += tag.name.size() + 1; + + tag_sizes ts = parseTagTriple(&token); + + tag.intValues.resize(static_cast(ts.num_ints)); + + for (size_t i = 0; i < static_cast(ts.num_ints); ++i) { + tag.intValues[i] = atoi(token); + token += strcspn(token, "/ \t\r") + 1; + } + + tag.floatValues.resize(static_cast(ts.num_floats)); + for (size_t i = 0; i < static_cast(ts.num_floats); ++i) { + tag.floatValues[i] = parseFloat(&token); + token += strcspn(token, "/ \t\r") + 1; + } + + tag.stringValues.resize(static_cast(ts.num_strings)); + for (size_t i = 0; i < static_cast(ts.num_strings); ++i) { + char stringValueBuffer[4096]; + +#ifdef _MSC_VER + sscanf_s(token, "%s", stringValueBuffer, + (unsigned)_countof(stringValueBuffer)); +#else + sscanf(token, "%s", stringValueBuffer); +#endif + tag.stringValues[i] = stringValueBuffer; + token += tag.stringValues[i].size() + 1; + } + + tags.push_back(tag); + } + + // Ignore unknown command. + } + + bool ret = exportFaceGroupToShape(&shape, faceGroup, tags, material, name, + triangulate); + // exportFaceGroupToShape return false when `usemtl` is called in the last + // line. + // we also add `shape` to `shapes` when `shape.mesh` has already some + // faces(indices) + if (ret || shape.mesh.indices.size()) { + shapes->push_back(shape); + } + faceGroup.clear(); // for safety + + if (err) { + (*err) += errss.str(); + } + + attrib->vertices.swap(v); + attrib->normals.swap(vn); + attrib->texcoords.swap(vt); + + return true; +} + +bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback, + void *user_data /*= NULL*/, + MaterialReader *readMatFn /*= NULL*/, + std::string *err /*= NULL*/) { + std::stringstream errss; + + // material + std::map material_map; + int material_id = -1; // -1 = invalid + + std::vector indices; + std::vector materials; + std::vector names; + names.reserve(2); + std::string name; + std::vector names_out; + + std::string linebuf; + while (inStream.peek() != -1) { + safeGetline(inStream, linebuf); + + // Trim newline '\r\n' or '\n' + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\n') + linebuf.erase(linebuf.size() - 1); + } + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\r') + linebuf.erase(linebuf.size() - 1); + } + + // Skip if empty line. + if (linebuf.empty()) { + continue; + } + + // Skip leading space. + const char *token = linebuf.c_str(); + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') continue; // empty line + + if (token[0] == '#') continue; // comment line + + // vertex + if (token[0] == 'v' && IS_SPACE((token[1]))) { + token += 2; + float x, y, z, w; // w is optional. default = 1.0 + parseV(&x, &y, &z, &w, &token); + if (callback.vertex_cb) { + callback.vertex_cb(user_data, x, y, z, w); + } + continue; + } + + // normal + if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) { + token += 3; + float x, y, z; + parseFloat3(&x, &y, &z, &token); + if (callback.normal_cb) { + callback.normal_cb(user_data, x, y, z); + } + continue; + } + + // texcoord + if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) { + token += 3; + float x, y, z; // y and z are optional. default = 0.0 + parseFloat3(&x, &y, &z, &token); + if (callback.texcoord_cb) { + callback.texcoord_cb(user_data, x, y, z); + } + continue; + } + + // face + if (token[0] == 'f' && IS_SPACE((token[1]))) { + token += 2; + token += strspn(token, " \t"); + + indices.clear(); + while (!IS_NEW_LINE(token[0])) { + vertex_index vi = parseRawTriple(&token); + + index_t idx; + idx.vertex_index = vi.v_idx; + idx.normal_index = vi.vn_idx; + idx.texcoord_index = vi.vt_idx; + + indices.push_back(idx); + size_t n = strspn(token, " \t\r"); + token += n; + } + + if (callback.index_cb && indices.size() > 0) { + callback.index_cb(user_data, &indices.at(0), + static_cast(indices.size())); + } + + continue; + } + + // use mtl + if ((0 == strncmp(token, "usemtl", 6)) && IS_SPACE((token[6]))) { + char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE]; + token += 7; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, + static_cast(_countof(namebuf))); +#else + sscanf(token, "%s", namebuf); +#endif + + int newMaterialId = -1; + if (material_map.find(namebuf) != material_map.end()) { + newMaterialId = material_map[namebuf]; + } else { + // { error!! material not found } + } + + if (newMaterialId != material_id) { + material_id = newMaterialId; + } + + if (callback.usemtl_cb) { + callback.usemtl_cb(user_data, namebuf, material_id); + } + + continue; + } + + // load mtl + if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) { + if (readMatFn) { + char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE]; + token += 7; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + + std::string err_mtl; + materials.clear(); + bool ok = (*readMatFn)(namebuf, &materials, &material_map, &err_mtl); + if (err) { + (*err) += err_mtl; + } + + if (!ok) { + return false; + } + + if (callback.mtllib_cb) { + callback.mtllib_cb(user_data, &materials.at(0), + static_cast(materials.size())); + } + } + + continue; + } + + // group name + if (token[0] == 'g' && IS_SPACE((token[1]))) { + names.clear(); + + while (!IS_NEW_LINE(token[0])) { + std::string str = parseString(&token); + names.push_back(str); + token += strspn(token, " \t\r"); // skip tag + } + + assert(names.size() > 0); + + // names[0] must be 'g', so skip the 0th element. + if (names.size() > 1) { + name = names[1]; + } else { + name.clear(); + } + + if (callback.group_cb) { + if (names.size() > 1) { + // create const char* array. + names_out.resize(names.size() - 1); + for (size_t j = 0; j < names_out.size(); j++) { + names_out[j] = names[j + 1].c_str(); + } + callback.group_cb(user_data, &names_out.at(0), + static_cast(names_out.size())); + + } else { + callback.group_cb(user_data, NULL, 0); + } + } + + continue; + } + + // object name + if (token[0] == 'o' && IS_SPACE((token[1]))) { + // @todo { multiple object name? } + char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE]; + token += 2; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + std::string object_name = std::string(namebuf); + + if (callback.object_cb) { + callback.object_cb(user_data, object_name.c_str()); + } + + continue; + } + +#if 0 // @todo + if (token[0] == 't' && IS_SPACE(token[1])) { + tag_t tag; + + char namebuf[4096]; + token += 2; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + tag.name = std::string(namebuf); + + token += tag.name.size() + 1; + + tag_sizes ts = parseTagTriple(&token); + + tag.intValues.resize(static_cast(ts.num_ints)); + + for (size_t i = 0; i < static_cast(ts.num_ints); ++i) { + tag.intValues[i] = atoi(token); + token += strcspn(token, "/ \t\r") + 1; + } + + tag.floatValues.resize(static_cast(ts.num_floats)); + for (size_t i = 0; i < static_cast(ts.num_floats); ++i) { + tag.floatValues[i] = parseFloat(&token); + token += strcspn(token, "/ \t\r") + 1; + } + + tag.stringValues.resize(static_cast(ts.num_strings)); + for (size_t i = 0; i < static_cast(ts.num_strings); ++i) { + char stringValueBuffer[4096]; + +#ifdef _MSC_VER + sscanf_s(token, "%s", stringValueBuffer, + (unsigned)_countof(stringValueBuffer)); +#else + sscanf(token, "%s", stringValueBuffer); +#endif + tag.stringValues[i] = stringValueBuffer; + token += tag.stringValues[i].size() + 1; + } + + tags.push_back(tag); + } +#endif + + // Ignore unknown command. + } + + if (err) { + (*err) += errss.str(); + } + + return true; +} +} // namespace tinyobj + +#endif + +#endif // TINY_OBJ_LOADER_H_ diff --git a/A2/src/Body.h b/A2/src/Body.h deleted file mode 100644 index 9d0f5a8..0000000 --- a/A2/src/Body.h +++ /dev/null @@ -1,43 +0,0 @@ -// Create Body Class - -/* -Class Body -{ - Head h; - Shoulder sl; - Shoulder sr; - Leg ull; - Leg ulr; - bool selected = true; - - draw(MatrixStack MV); -} -*/ - -/* - -static void renderA(MatrixStack MV) -{ - MV.pushMatrix(); - MV.translate(-1, 0, 0); - MV.rotate(-(2*PI)/16, 0, 0, 1); - MV.scale(0.5, 4, 0.5); - glUniformMatrix4fv(unifIDs["MV"], 1, GL_FALSE, value_ptr(MV.topMatrix())); - glDrawArrays(GL_TRIANGLES, 0, indCount); - MV.popMatrix(); // This line undoes the transformation applied to #1 - MV.pushMatrix(); - MV.scale(2, 0.5, 0.5); - glUniformMatrix4fv(unifIDs["MV"], 1, GL_FALSE, value_ptr(MV.topMatrix())); - glDrawArrays(GL_TRIANGLES, 0, indCount); - MV.popMatrix(); // This line undoes the transformation applied to #2 - MV.pushMatrix(); - MV.translate(1, 0, 0); - MV.rotate((2*PI)/16, 0, 0, 1); - MV.scale(0.5, 4, 0.5); - glUniformMatrix4fv(unifIDs["MV"], 1, GL_FALSE, value_ptr(MV.topMatrix())); - glDrawArrays(GL_TRIANGLES, 0, indCount); - MV.popMatrix(); // This line undoes the transformation applied to #3 -} - - -*/ diff --git a/A2/src/Component.cpp b/A2/src/Component.cpp new file mode 100644 index 0000000..f2ef94b --- /dev/null +++ b/A2/src/Component.cpp @@ -0,0 +1,120 @@ +#include +#include "Component.h" + +using namespace std; + +Component::Component() +{ + parent = NULL; + selected = false; + t = vec3(0,0,0); + tp = vec3(0,0,0); + r = vec3(0,0,0); + s = vec3(1.0,1.0,1.0); + children.resize(0); +} + +Component::Component(const Component& c) +{ + parent = c.parent; + children = c.children; + selected = c.selected; + t = vec3(c.t.x, c.t.y, c.t.z); + tp = vec3(c.tp.x, c.tp.y, c.tp.z); + r = vec3(c.r.x, c.r.y, c.r.z); + s = vec3(c.s.x, c.s.y, c.s.z); +} + +void Component::draw(shared_ptr MV, shared_ptr P, shared_ptr S, shared_ptr Prog) +{ + MV->pushMatrix(); + MV->translate(tp.x, tp.y, tp.z); + MV->rotate(r.x, 1, 0, 0); + MV->rotate(r.y, 0, 1, 0); + MV->rotate(r.z, 0, 0, 1); + MV->translate(t.x, t.y, t.z); + for(unsigned int i = 0; i < children.size(); i++) + { + children[i].draw(MV, P, S, Prog); + } + if(selected) + { + MV->scale(1.1,1.1,1.1); + } + MV->scale(s.x,s.y,s.z); + glUniformMatrix4fv(Prog->getUniform("P"), 1, GL_FALSE, &P->topMatrix()[0][0]); + glUniformMatrix4fv(Prog->getUniform("MV"), 1, GL_FALSE, &MV->topMatrix()[0][0]); + S->draw(Prog); + MV->popMatrix(); +} + +Component& Component::getLastChild() +{ + if(this->children.empty()) + { + return *this; + } + return this->children[this->children.size() - 1].getLastChild(); +} + +Component& Component::getPrevious(Component *addr) +{ + if(children.empty()) + { + if(parent != NULL) + { + return parent->getPrevious(this); + } + } + + for(unsigned int i = 0; i < this->children.size(); i++) + { + //return *this; + if(&children[i] == addr) + { + if(i > 0) + { + return children[i-1].getLastChild(); + } + else + { + return *this; + } + } + } + + if (parent == NULL) { + return this->getLastChild(); + } + + return parent->getPrevious(this); +} + +Component& Component::getNext(Component *addr) +{ + if(addr == NULL) + { + if(!children.empty()) + { + return children[0]; + } + } + + for(unsigned int i = 0; i < this->children.size(); i++) + { + //return *this; + if(&children[i] == addr) + { + if(i+1 < children.size()) + { + return children[i+1]; + } + } + } + + if (parent == NULL) { + return *this; + } + + return parent->getNext(this); +} diff --git a/A2/src/Component.h b/A2/src/Component.h new file mode 100644 index 0000000..b416cb4 --- /dev/null +++ b/A2/src/Component.h @@ -0,0 +1,28 @@ +// Create Body Class +#include +#include "MatrixStack.h" +#include +#include +#include "Shape.h" +#include "Program.h" + +using namespace std; +using namespace glm; + +class Component +{ + public: + Component *parent; + vector children; + bool selected; + vec3 t; + vec3 tp; + vec3 r; + vec3 s; + Component(); + Component(const Component& c); + void draw(shared_ptr MV, shared_ptr P, shared_ptr S, shared_ptr Prog); + Component& getNext(Component *addr); + Component& getPrevious(Component *addr); + Component& getLastChild(); +}; diff --git a/A2/src/main.cpp b/A2/src/main.cpp index 0985a74..1afc646 100644 --- a/A2/src/main.cpp +++ b/A2/src/main.cpp @@ -21,6 +21,7 @@ #include "MatrixStack.h" #include "Shape.h" #include "Program.h" +#include "Component.h" #define PI 3.14159 @@ -38,150 +39,412 @@ map attrIDs; map unifIDs; map bufIDs; int indCount; + +// Root component global +Component root; + +// Selected component +Component* selected = &root; + +// This function is called when a char is input +static void char_callback(GLFWwindow *window, unsigned int c) +{ + char cp = (char)c; + + if(cp == ',') + { + // select... + selected->selected = false; + selected = &selected->getPrevious(NULL); + selected->selected = true; + } + else if(cp == '.') + { + // select... + selected->selected = false; + selected = &selected->getNext(NULL); + selected->selected = true; + } + + if(cp == 'x') + { + // rotate... + selected->r.x += 0.1; + } + else if(cp == 'X') + { + // rotate... + selected->r.x -= 0.1; + } + + if(cp == 'y') + { + // rotate... + selected->r.y += 0.1; + } + else if(cp == 'Y') + { + // rotate... + selected->r.y -= 0.1; + } + + if(cp == 'z') + { + // rotate... + selected->r.z += 0.1; + } + else if(cp == 'Z') + { + // rotate... + selected->r.z -= 0.1; + } +} + // This function is called when a GLFW error occurs static void error_callback(int error, const char *description) { - cerr << description << endl; + cerr << description << endl; } // This function is called when a key is pressed static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) { - if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { - glfwSetWindowShouldClose(window, GL_TRUE); - } + if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { + glfwSetWindowShouldClose(window, GL_TRUE); + } } // This function is called when the mouse is clicked static void mouse_callback(GLFWwindow *window, int button, int action, int mods) { - // Do nothing + // Do nothing } // If the window is resized, capture the new size and reset the viewport static void resize_callback(GLFWwindow *window, int width, int height) { - glViewport(0, 0, width, height); + glViewport(0, 0, width, height); +} + +static void setParents(Component& elem) +{ + for (unsigned int i = 0; i < elem.children.size(); ++i) + { + setParents(elem.children[i]); + elem.children[i].parent = &elem; + } +} + +void createRobot(Component& body) +{ + + body.selected = true; + + //Make Body + + body.s.x = 1.5; + body.s.y = 2.0; + body.s.z = 1.0; + + + // Make Head + + Component head; + head.parent = &body; + + head.tp.x = 0.0; + head.tp.y = body.s.y/2; + head.tp.z = 0.0; + + head.t.x = 0.0; + head.t.y = 0.5; + head.t.z = 0.0; + + body.children.push_back(head); + + // Make Left Upper Arm + + Component luarm; + luarm.parent = &body; + + luarm.tp.x = body.s.x/2; + luarm.tp.y = body.s.y/4; + luarm.tp.z = 0.0; + + luarm.s.x = 1.0; + luarm.s.y = 0.5; + luarm.s.z = 0.5; + + luarm.t.x = luarm.s.x/2; + luarm.t.y = 0.0; + luarm.t.z = 0.0; + + // Make Left Lower Arm + + Component llarm; + llarm.parent = &luarm; + + llarm.tp.x = luarm.s.x/2; + llarm.tp.y = 0.0; + llarm.tp.z = 0.0; + + llarm.s.x = 1.5; + llarm.s.y = 0.4; + llarm.s.z = 0.4; + + llarm.t.x = llarm.s.x/2; + llarm.t.y = 0.0; + llarm.t.z = 0.0; + + luarm.children.push_back(llarm); + + body.children.push_back(luarm); + + // Make Left Upper Leg + + Component luleg; + luleg.parent = &body; + + luleg.tp.x = body.s.x/4; + luleg.tp.y = -body.s.y/2; + luleg.tp.z = 0.0; + + luleg.s.x = 0.5; + luleg.s.y = 1.0; + luleg.s.z = 0.5; + + luleg.t.x = 0.0; + luleg.t.y = -luleg.s.y/2; + luleg.t.z = 0.0; + + // Make Left Lower Leg + + Component llleg; + llleg.parent = &luleg; + + llleg.tp.x = 0.0; + llleg.tp.y = -luleg.s.y/2; + llleg.tp.z = 0.0; + + llleg.s.x = 0.4; + llleg.s.y = 1.5; + llleg.s.z = 0.4; + + + llleg.t.x = 0.0; + llleg.t.y = -llleg.s.y/2; + llleg.t.z = 0.0; + + luleg.children.push_back(llleg); + + body.children.push_back(luleg); + + // Make Right Upper Leg + + Component ruleg; + ruleg.parent = &body; + + ruleg.tp.x = -body.s.x/4; + ruleg.tp.y = -body.s.y/2; + ruleg.tp.z = 0.0; + + ruleg.s.x = 0.5; + ruleg.s.y = 1.0; + ruleg.s.z = 0.5; + + ruleg.t.x = 0.0; + ruleg.t.y = -ruleg.s.y/2; + ruleg.t.z = 0.0; + + // Make Right Lower Leg + + Component rlleg; + rlleg.parent = &ruleg; + + rlleg.tp.x = 0.0; + rlleg.tp.y = -ruleg.s.y/2; + rlleg.tp.z = 0.0; + + rlleg.s.x = 0.4; + rlleg.s.y = 1.5; + rlleg.s.z = 0.4; + + + rlleg.t.x = 0.0; + rlleg.t.y = -rlleg.s.y/2; + rlleg.t.z = 0.0; + + ruleg.children.push_back(rlleg); + + body.children.push_back(ruleg); + + // Make Right Upper Arm + + Component ruarm; + ruarm.parent = &body; + + ruarm.tp.x = -body.s.x/2; + ruarm.tp.y = body.s.y/4; + ruarm.tp.z = 0.0; + + ruarm.s.x = 1.0; + ruarm.s.y = 0.5; + ruarm.s.z = 0.5; + + ruarm.t.x = -ruarm.s.x/2; + ruarm.t.y = 0.0; + ruarm.t.z = 0.0; + + // Make Right Lower Arm + + Component rlarm; + rlarm.parent = &ruarm; + + rlarm.tp.x = -ruarm.s.x/2; + rlarm.tp.y = 0.0; + rlarm.tp.z = 0.0; + + rlarm.s.x = 1.5; + rlarm.s.y = 0.4; + rlarm.s.z = 0.4; + + rlarm.t.x = -rlarm.s.x/2; + rlarm.t.y = 0.0; + rlarm.t.z = 0.0; + + ruarm.children.push_back(rlarm); + + body.children.push_back(ruarm); + + setParents(body); } static void init() { - GLSL::checkVersion(); + GLSL::checkVersion(); - // Set background color. - glClearColor(1.0f, 1.0f, 1.0f, 1.0f); - // Enable z-buffer test. - glEnable(GL_DEPTH_TEST); + // Set background color. + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + // Enable z-buffer test. + glEnable(GL_DEPTH_TEST); - // Initialize mesh. - shape = make_shared(); - shape->loadMesh(RESOURCE_DIR + "teapot.obj"); - shape->init(); - - // Initialize the GLSL program. - prog = make_shared(); - prog->setVerbose(false); // Set this to true when debugging. - prog->setShaderNames(RESOURCE_DIR + "simple_vert.glsl", RESOURCE_DIR + "simple_frag.glsl"); - prog->init(); - prog->addUniform("P"); - prog->addUniform("MV"); - prog->addAttribute("aPos"); - prog->addAttribute("aNor"); - - // If there were any OpenGL errors, this will print something. - // You can intersperse this line in your code to find the exact location - // of your OpenGL error. - GLSL::checkError(GET_FILE_LINE); + // Initialize mesh. + shape = make_shared(); + shape->loadMesh(RESOURCE_DIR + "cube.obj"); + shape->init(); + + // Initialize the GLSL program. + prog = make_shared(); + prog->setVerbose(false); // Set this to true when debugging. + prog->setShaderNames(RESOURCE_DIR + "vert.glsl", RESOURCE_DIR + "frag.glsl"); + prog->init(); + prog->addUniform("P"); + prog->addUniform("MV"); + prog->addAttribute("aPos"); + prog->addAttribute("aNor"); + + createRobot(root); + selected = &root; + + // If there were any OpenGL errors, this will print something. + // You can intersperse this line in your code to find the exact location + // of your OpenGL error. + GLSL::checkError(GET_FILE_LINE); } static void render() { - // Get current frame buffer size. - int width, height; - glfwGetFramebufferSize(window, &width, &height); - float aspect = width/(float)height; - glViewport(0, 0, width, height); + // Get current frame buffer size. + int width, height; + glfwGetFramebufferSize(window, &width, &height); + float aspect = width/(float)height; + glViewport(0, 0, width, height); - // Clear framebuffer. - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + // Clear framebuffer. + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // Create matrix stacks. - auto P = make_shared(); - auto MV = make_shared(); - // Apply projection. - P->pushMatrix(); - P->multMatrix(glm::perspective((float)(45.0*M_PI/180.0), aspect, 0.01f, 100.0f)); - // Apply camera transform. - MV->pushMatrix(); - MV->translate(glm::vec3(0, -0.5, -3)); - - // Draw mesh using GLSL. - prog->bind(); - glUniformMatrix4fv(prog->getUniform("P"), 1, GL_FALSE, &P->topMatrix()[0][0]); - glUniformMatrix4fv(prog->getUniform("MV"), 1, GL_FALSE, &MV->topMatrix()[0][0]); - shape->draw(prog); - prog->unbind(); + // Create matrix stacks. + auto P = make_shared(); + auto MV = make_shared(); + // Apply projection. + P->pushMatrix(); + P->multMatrix(glm::perspective((float)(45.0*M_PI/180.0), aspect, 0.01f, 100.0f)); + // Apply camera transform. + MV->pushMatrix(); + MV->translate(glm::vec3(0, -0.5, -10)); - // Pop matrix stacks. - MV->popMatrix(); - P->popMatrix(); - - GLSL::checkError(GET_FILE_LINE); + // Draw mesh using GLSL. + prog->bind(); + // glUniformMatrix4fv(prog->getUniform("P"), 1, GL_FALSE, &P->topMatrix()[0][0]); + // glUniformMatrix4fv(prog->getUniform("MV"), 1, GL_FALSE, &MV->topMatrix()[0][0]); + // shape->draw(prog); + + root.draw(MV, P, shape, prog); + + prog->unbind(); + + // Pop matrix stacks. + MV->popMatrix(); + P->popMatrix(); + + GLSL::checkError(GET_FILE_LINE); } int main(int argc, char **argv) { - if(argc < 2) { - cout << "Please specify the resource directory." << endl; - return 0; - } - RESOURCE_DIR = argv[1] + string("/"); + if(argc < 2) { + cout << "Please specify the resource directory." << endl; + return 0; + } + RESOURCE_DIR = argv[1] + string("/"); - // Set error callback. - glfwSetErrorCallback(error_callback); - // Initialize the library. - if(!glfwInit()) { - return -1; - } - // Create a windowed mode window and its OpenGL context. - window = glfwCreateWindow(640, 480, "Alexander Huddleston", NULL, NULL); - if(!window) { - glfwTerminate(); - return -1; - } - // Make the window's context current. - glfwMakeContextCurrent(window); - // Initialize GLEW. - glewExperimental = true; - if(glewInit() != GLEW_OK) { - cerr << "Failed to initialize GLEW" << endl; - return -1; - } - glGetError(); // A bug in glewInit() causes an error that we can safely ignore. - cout << "OpenGL version: " << glGetString(GL_VERSION) << endl; - cout << "GLSL version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << endl; - GLSL::checkVersion(); - // Set vsync. - glfwSwapInterval(1); - // Set keyboard callback. - glfwSetKeyCallback(window, key_callback); - // Set the mouse call back. - glfwSetMouseButtonCallback(window, mouse_callback); - // Set the window resize call back. - glfwSetFramebufferSizeCallback(window, resize_callback); - // Initialize scene. - init(); - // Loop until the user closes the window. - while(!glfwWindowShouldClose(window)) { - // Render scene. - render(); - // Swap front and back buffers. - glfwSwapBuffers(window); - // Poll for and process events. - glfwPollEvents(); - } - // Quit program. - glfwDestroyWindow(window); - glfwTerminate(); - return 0; + // Set error callback. + glfwSetErrorCallback(error_callback); + // Initialize the library. + if(!glfwInit()) { + return -1; + } + // Create a windowed mode window and its OpenGL context. + window = glfwCreateWindow(640, 480, "Alexander Huddleston", NULL, NULL); + if(!window) { + glfwTerminate(); + return -1; + } + // Make the window's context current. + glfwMakeContextCurrent(window); + // Initialize GLEW. + glewExperimental = true; + if(glewInit() != GLEW_OK) { + cerr << "Failed to initialize GLEW" << endl; + return -1; + } + glGetError(); // A bug in glewInit() causes an error that we can safely ignore. + cout << "OpenGL version: " << glGetString(GL_VERSION) << endl; + cout << "GLSL version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << endl; + GLSL::checkVersion(); + // Set vsync. + glfwSwapInterval(1); + // Set char callback. + glfwSetCharCallback(window, char_callback); + // Set keyboard callback. + glfwSetKeyCallback(window, key_callback); + // Set the mouse call back. + glfwSetMouseButtonCallback(window, mouse_callback); + // Set the window resize call back. + glfwSetFramebufferSizeCallback(window, resize_callback); + // Initialize scene. + init(); + // Loop until the user closes the window. + while(!glfwWindowShouldClose(window)) { + // Render scene. + render(); + // Swap front and back buffers. + glfwSwapBuffers(window); + // Poll for and process events. + glfwPollEvents(); + } + // Quit program. + glfwDestroyWindow(window); + glfwTerminate(); + return 0; }