From 3965505b15c8c11b859595ff40068539f080f9f2 Mon Sep 17 00:00:00 2001 From: "wagic.the.homebrew@gmail.com" Date: Thu, 16 Sep 2010 13:12:05 +0000 Subject: [PATCH] wololo - Adding DJardin's port to N900 --- JGE/include/JRenderer.h | 30 + JGE/include/JSoundSystem.h | 26 +- JGE/include/JTypes.h | 14 +- JGE/lib/win/jge.lib | Bin 2502836 -> 2631718 bytes JGE/src/JMD2Model.cpp | 113 +- JGE/src/Qtmain.cpp | 272 +++++ JGE/src/main.cpp | 2 +- JGE/src/pc/JGfx.cpp | 1650 +++++++++++++++++++++++++--- JGE/src/pc/JSfx.cpp | 83 +- projects/mtg/include/MTGPack.h | 2 +- projects/mtg/include/config.h | 6 + projects/mtg/src/GameStateShop.cpp | 5 +- projects/mtg/src/MTGAbility.cpp | 11 +- projects/mtg/src/MTGPack.cpp | 24 +- projects/mtg/wagic.pro | 321 ++++++ 15 files changed, 2379 insertions(+), 180 deletions(-) create mode 100644 JGE/src/Qtmain.cpp create mode 100644 projects/mtg/wagic.pro diff --git a/JGE/include/JRenderer.h b/JGE/include/JRenderer.h index e2bda765e..d8feda767 100644 --- a/JGE/include/JRenderer.h +++ b/JGE/include/JRenderer.h @@ -53,6 +53,12 @@ #define COSF(x) cosf(x*DEG2RAD) #endif +#if (defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) || (defined WIN32) +typedef struct +{ + GLfloat m[4][4]; +} ESMatrix; +#endif // (defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) ////////////////////////////////////////////////////////////////////////// /// A collection of core rendering functions. @@ -541,8 +547,32 @@ private: #if defined (WIN32) || defined (LINUX) GLuint mCurrentTex; +#if (defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) || (defined WIN32) + // MVP matrix + ESMatrix theMvpMatrix; + // Handle to a program object + GLuint prog1; + // Attribute locations + GLint prog1_positionLoc; + GLint prog1_colorLoc; + // Uniform locations + GLint prog1_mvpLoc; + // Handle to a program object + GLuint prog2; + // Sampler location + GLint prog2_samplerLoc; + // Attribute locations + GLint prog2_positionLoc; + GLint prog2_texCoordLoc; + GLint prog2_colorLoc; + // MVP matrix + ESMatrix prog2_mvpMatrix; + // Uniform locations + GLint prog2_mvpLoc; + +#endif // (defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) #else void *fbp0, *fbp1, *zbp; PIXEL_TYPE* mVRAM; diff --git a/JGE/include/JSoundSystem.h b/JGE/include/JSoundSystem.h index 5ce12db70..b9c2ab1ff 100644 --- a/JGE/include/JSoundSystem.h +++ b/JGE/include/JSoundSystem.h @@ -19,6 +19,10 @@ #include "JTypes.h" +#ifdef USE_PHONON +#include +#include +#else #ifdef WIN32 #include @@ -43,16 +47,31 @@ #ifdef WITH_FMOD #include "../Dependencies/include/fmod.h" #endif +#endif //------------------------------------------------------------------------------------------------ +#ifdef USE_PHONON +class JMusic : public QObject +{ + Q_OBJECT +#else class JMusic { +#endif public: JMusic(); - ~JMusic(); + ~JMusic(); void Update(); int getPlayTime(); +#ifdef USE_PHONON + Phonon::AudioOutput* mOutput; + Phonon::MediaObject* mMediaObject; + public slots: + void seekAtTheBegining(); + +#else + #if defined (WIN32) || defined (LINUX) #ifdef WITH_FMOD FSOUND_SAMPLE* mTrack; // MP3 needed to be of "sample" type for FMOD, FMUSIC_MODULE is for MODs @@ -62,6 +81,7 @@ public: #else JMP3* mTrack; #endif +#endif }; @@ -80,6 +100,10 @@ class JSample #ifdef WITH_FMOD FSOUND_SAMPLE *mSample; #else +#ifdef USE_PHONON + Phonon::AudioOutput* mOutput; + Phonon::MediaObject* mMediaObject; +#endif void* mSample; #endif #else diff --git a/JGE/include/JTypes.h b/JGE/include/JTypes.h index 767c9009e..86a35469c 100644 --- a/JGE/include/JTypes.h +++ b/JGE/include/JTypes.h @@ -39,11 +39,11 @@ #define MAX_CHANNEL 128 -enum { - JGE_ERR_CANT_OPEN_FILE = -1, - JGE_ERR_PNG = -2, - JGE_ERR_MALLOC_FAILED = -4, - JGE_ERR_GENERIC = -5, +enum { + JGE_ERR_CANT_OPEN_FILE = -1, + JGE_ERR_PNG = -2, + JGE_ERR_MALLOC_FAILED = -4, + JGE_ERR_GENERIC = -5, }; @@ -88,10 +88,14 @@ enum { typedef bool BOOL; #endif +#ifndef QT_CONFIG #if defined (WIN32) || defined (LINUX) #include #include #endif +#else +# include +#endif #if defined (WIN32) || defined (LINUX) diff --git a/JGE/lib/win/jge.lib b/JGE/lib/win/jge.lib index e88f29f18a12c740bb053fce699bf9cfe593ef94..8550724e113f3dafd08c2bd82efef61b582f6d8f 100644 GIT binary patch delta 121279 zcmeEv2YeL87ys^F?vh-RE4f_DCAmu@bP^yyXt{*m6HufRnka$%i{prv4`TzgF)6Ks5&YL%H-n^Zioq4;g zJMo0Pa&L)T7#Y|sxk;l&X-($FI`Wz{N^YFu!7oQINg1@ivk{;sOPp*Zyap}0SHeBM(E`LB<>KU4TGD4X|RYyKBhj=J;yd(-_T z3ZVc0RSW#z-v43uoRt3XQIaWzsYhNp@t2>Egi2xT_&V;ljy#chsk;>R2M>d8rgYt5 zm?s(j(2?g?AgQfn_@|G&f4ahI_2vCzEzX}T8LmI_ZUp{1_GWL%@Mn&zZ%BqJM_yIH zXy`8eqetG~QQ?@@lJR#Qc~ux6`cN|dlgE+pJjr+@{9ios{>{o!ciz9+`fw@l-!=dL z`u}(Izv;+2>F+x7{w~44Q*Peh*0SHHK;C~gt@(6U>2Evo{!Zb)Lw4TZ)-u1!!ymsO z{mPN|YZ?C?esG->{)Z0q{~s&x7xU-+A#MNS%29XTzuNkP>(KxIss;Yn|NpA_|9|Lz zTSGGXH_RykFJq@2LEIAIVnr$g2+g!|A;1H2P;1$g66OzpZlnnPTZiN8XLV ze-O*Np;muJ0mqnC((ga={s=R8S5NRgSvz{^I`p z4+=yE#z<9;yz0P>(oeo9MgGy_RHzjB8;2`qrNoZBa^f#J508*sf9%NnqXqtA{=7e| z@n5Sz-XAm9AF4d6!>7`JI`aM#!{3~r_a8OAyYV%m<|#9(li(@mJx!E=qB~ape70=0A{^_nX@N{R-s$wt4<`1@eBQZ~pemQTPA) zpF3dUJsqVR9*;gRCH|*lbz3R%zdiE)+k$^lxxD{c^S?%cy#L;Ge~AKlf1>aH3I+b{ z{vY;t_kU9M^R)GvE^c06-2C*wMh`Em_vo^EvTs>E#oMpw{MmGx)+;WRURt5c@O|{C za!pHRGqrkZGe>S6eAk5GUT@!wtPJp_QR`XSSaP;=kESOIwH8K=q}{WX429>XSLF^! z_GV;I#w=|VtD|aOFw4uz=$(>G%jan`eTF$ov%sR#sdgGOMK%__bhS10S*?Uo<{UZ0 z=;ca?zfgtbZ#^v)h|YEfyNX`E+NzS3o@||Hr}P!tkQ>OMC!f-`{H?j;sH#sAtcY4B*(WA!>8!}<+crJ$=pK49y zQM3`ikNvX%XDsFPQG$HlQf0KF@p2t+sCOW%F|&6H&DF>ezW1(bvt{1{I^D~%&-aRA z)1WhH>j_N;6~3<2Q?fiC)M4j)eE;tgQK9zoJEQ!pqI+olv)o^bj)wusy)*)ZXV2X z2ag#$am3&WLq>YxLYYE4IhnGrm?LO&pnDcY#_9CDp5j1veYFN+>iZ6ERPr@+WTO&F zw@#65RlO`obgtU7a-chfZgvLStNK?Ut5m%hlw>dU*rI&NyQiYpGyKfeu(P`{4cw|E z1PmLSdmjy%BD<>AS?<~C2@^*QL&q1by_#O>%ppRfP8scBo$PE^3mQ5_j;t!d=}qw_ z!_Ey;yxx9NdV0d(o0)w?=cfn#PQd|80_{uHC33@=)Xp4n?*wt}b5u^DoPmn9sBn&z zr;XsM?zNdzbC^4fXVaFt3U}QMdb5Yl>YKe)X)M#;9y%TEJEqCJap`x1+)DWP7r=6Z3u6 zkJY& zn7QE%Op@tqvRjFgsl{$3?zhZqd&6yD`BrY+8%yf;zVeD92D83Oapb_L{_NI)VVv~yY9toiyjoj@R0haV&<|iV5 z?i8JkIz6ikE&fsIO`${FS1Gwn6G7glfdi=IqFYa&oN+fL&nJqWdbnjXl>`NjWEn}t zk0>>0%TXnW+!x%7Y12!(!<1X5yiVRDN-&wy-2Eu)U0nv1#mNrxwAS?Zl^s*^1L)2J zx}c(*;%fIRI+7j8hBk4{zIj1zSoNB{F25EPexwVi#?*X++b&G>^av%KN)E*YkvBzS zr?QKRmfR%~fs}hz6HCcoDi(pAJ)?=>ENuMZoC0;Lteia(fhV`Ducjlr}H;DFj2@JhnXgKZd z9;owqt|=WAx|S~Apk9;jHd*sP4DH+&SZ#!(CvU_3^$WMgBa`=LIii~Q!?$QcY4Xo< zurDxHGhU{$-f~FM;GL$b<2JpX8y`ZRVSxcfB|EFn87lI~bOZ*N6sMV0Wd5cVCH0pL zboVcTCW?&LOtSav(A(R&Lp!fGJEL7X8#`_^W(SHfyAR1fyBqo5iq|aBSo{n2>6ne% zM_bysEGCxjOVZpyOB-tS)!OuCj-2Al>F17>34afedsI*&^T%7MYzl60Ti%Q_QtrtZ zE7iU|$WxK=h_7{BO``xBG}`Sb+WTxEy*|QR%?x^>U3O->EE;lmKufs~rSuAjqq6wm zez^WL5BWx=Xfm~QY<`frs!pL5_oDK7jdO;(CchTwlSM&wediViy{J&>y}{>cOTPdM zl@cx*)BVBs`wq9zm;&kEJZm+P)Nrslv1&I3U?}QD87_SWEf^Kx=6d;{S5hO&DhM`I zRf+DMs4-GZjI-M1=YQM8kd#LGcLoF)*dW5jCY*4iq|G13;X-% zhF)9|97LPjD%Hi~A_^{^r_qt;7PGmk0jRXCQf*#B@Ni>M?(RSu;0&(TpR}i?)>%#Y z;KmqSSY!-W^D1Pm_Q#=Uj|Tzhc&j!mQY@SM$22`iHZx5 zd;9iH(cBb3$9DNQx00!BUqB3IHSWj13To?%$k5l8eb2AdY|&KMEr_z7*Q}@9cG~b8^ny?Kf@Y|Oq6g~( zDgW*px&bag?(Gvlaj&5dN9&`gtbTBRDtklLlIN#@XgW7qf8Py6KWZ!0_-v&Cg-`gu zMx5HTQNvX68gVU2k|ru4Qrw{sspsb*(#d@v8-~P5agqi9;Y_iewJkJA()rGK z-puW+?J828wDkg2J{s3mYboxc4Jgk^q}pAywRx&MOUrq=5LA`dMe7V^bucuJ7Ie|Z za_-o!D#0oP-`OtOS~wMS(b|P<0cU^>@Q|)rE3NE;hqNhOwRKfKoVIt>rsDKdS8Y14 z#4h1KitVNfnbbquqe5B*fdad`Y1<$jN5<~jUX1V!>8=ftk#k26?GT)H_0Xo^1k~+| z%+i*ytPR=PM4XOgYa95<^0|9z4vdI^R$0qLLokP@3LDn@qXgK=mG| z4X1aqv^LWB*Uqj`f)o4tYptq;?ftc>^kaW*CNknEZGbi!@@^i$yMDm{Z3EgdKwF=_ z8=!5?85#`Kt_8#Kf!YyV(xm=c7t(_V;aN3~)(p~iKx=*&q+JnJ^c`lkmFpLCAJFzS z-(cwikE5N~vxM)XncDS1tWebjiQm6i(Y9#mD@%N9-f+JxQ-fmdgLG`3l0ln`wb$sm zmoua`NxR1RA+^@rZ0J^*5_b@;*B0& zh_8aY^^V3|^q#LZ<)kOJpqwEtgD?47z)f;d&SMtJvg;Z#Y;sZVFTosX;Ls&=F3No| zVw^AQHSL`Zd9PJGNUL{N%Lf{>Z_{b*lOa6&?^-p9E4sEmg7*HXtx02hnRULBAGPhY z@RA$0xP1MjX!7eVe8#KVLJPflLgT&RdWpri)U10pgfslrizMx7)@E%O6azHMy|qC6cQv9i`H5BhRy=)P6{-&$zVS1z>BxM0~r#yYwn%GGKE zDJLiK8tutRH29X)(bd*4>;B$_mq4*}lU$U$DW6}0XX2cCs#g~s`amD6mtM;SInQ3f#Pi>oUn8f6eN> z;LFd@T{Zj-Yd3^d8;e-KS#Q>E!+1DYd5?1YSzjm52$z=f&&uzxKViPHy>-FNvaSA- z^&OM%p1!()!iYCE&hJ{_@fHPdu1S+_GC$(WAF8V#_-o@uO9?8beXmwg_@Z%5^H2lL*U6PG54N?r9_LUd^swP9kqZC5=j3nw$Ab zcgYiEU*2-vAO*aw{nwSA(na}>KBc=@hus1z*JrO^$6;$hl-u2Wv(FT*jg#qICsP=C z$13%yY>cZJm0iH{(cV`g>QiZw+<}sRk{dEAm=^BF{SnN=1&eomM6$?8t_c=o1XFTj z9|4qV9pUxPT(lj@p#t)<)CPT5=S5 z?1|Bo^_gN|82m9DyC1toC>|<&C)nvLJFM#%D7y03)~Jdm`3!XXSxpope1lKu;v%bQ z!rJ|x*Q&^KQP%tNf6>iuEGlFRR@`ICY6Yh9l`F!^m4U_->0DHHLKjTuE-9G*q+spr z$BW7%R6j7hT85rpoTnQ_rl^2WDr^Y84ZGxaw0Ad*$IAMeHw+vab-lJ&1jFK(4<>7) zzfta%TLJ@p$NB^g9$PJU|MZ9kMSI_AMuj)YxQo9NXr-K8ftmDvcH(gM$H5$_aZ%Zl zP?7T1wbr6@8mp0t%j{9UD?0=452z-xV$n>jsKH}sZ$z+;w$#)H`(AuMaEPv2fyyPa z{0{=L~&m55wnbklP>U+zOeXKYpNb=_(iuHqBvilb=o zd#!v67X(@BR^|WgrLc*4R!lbrn;-Di+7WbmQ?;Ue6^yNpu_o1{+-BO#v}H=L#h3L+ z@cwE&a>J#uQ2(Vd8rKZZfWI`>H7Uw{-{c$lSnyMtY8CR;v5KWLTGqtez}IYM@SDcU zOS)oV4DH@B3!Aj;Dh^y6Jfiyg)o-lB{L!T_wsJ;CbIi3Ue>@(ll5a8B_Iljz8D-{l)tATCAZQB`6iVHPqI~NU%Af37Q>X@jVR+`F%r?8=YkDB>)XLQ{2E)y zZg~t2!bUE}Ry25Tpzq4T;Ni|2N#^TeyFZSI@a3Efe&!FD<&Q0cz4DztF}+&<{f5nd zW$lXwt;hO0meJm`RJ0|CEmB4D)~1!kL{s!hY*IYewW;1b- zvg{jeFx+pVteFW0Ig~P9HzeV*bQ$|2=$&jgC~s@%{1QuJcuw4+z??$_+dy*lDw#9rbdP})i9bIPV?c!cV7h()Gg-=cM^Qq@5 zeTs_R;8^;R$snH;ZWTaTgJESi&3yp9)q=))48oa)`#IBWKWBQ)&zVjMXEIalqp(zq z;vtYURCv*JKQDU4&x?-ud67(}Lt&|M5)COtKix$89)pwzh5I}s+~)&7_qkl@K1yvZ z$*JKrxc{K1#wDPO&gG%g9~M5eO8C%+!iTO@`Ve+y@)E(!y$FFrZ-VAtbhn=uE%NiC zt-_1G;9evf$#g3k*@Chkg1K;oR`s8`e*Uvw_|FkP|B-yXwi&*^egwJqn4x!E)xQ4r zn&|6CuU#|XFyb)zu3a;)=~b0)cdu~a6UTdn#}sp)(8!WRXUOF7z4vwau^0W_t>65F zhI*fCwdH(Cb*J;qtYMoK?AyCI<^lQ9_Bj#0_Bqz|-Tf=GM>cMj){uXd6rUySDo4l| z;kuf#Bq>xwrB}itmBw`_YmK#rva>Fgxgu*QL+Vj!A7c$Aw;q)Z@zl_bt0zf!V@A@- z9;f8tL1U<=hLT^8yrn2pfb){bB)J})dk{sY)uTec>jL{IYk}BU4Ew_r7|R#66I`n0%% zA&yE;+XLiO8rQ>_r1jR9q$~vBx!iP)!Tkh05bzj3_#Oe@4|uwO3%>>TJOR%Kyh6Zb z3|=GPR{_5xU|!{Z0UrbWt$_2-fcp}Mb(#i}WNAQq3-vLy7q}ALfXeO+siA9tjC3`_ za~2t$)QoIo3{f+3k)gW-z#|Qcr$Iv5cStWldPM{B&I7Q8F}wxfBLI&8C_M+@8vudH z(@Gt|72^U$aZfLyGz&xVlMpqHwd=a8v9 zn?j~>#w0E9O)Ad%L3ukxnCcy594gOX7WfoEMnm$>VHUVIN~>*%k)R>vt|&LrW&pby z((IAY^DEF+EHW_radXvbBuT9riPo0f5*47!1~3)?GuM5fr(wySnX3r&VqP*%R|@*Q zMwE|!)S0lwSk{Pgr=c6q0hbz6{=_f@-!+z`#KxkLZ9w;GEUZ&@8I2j(STyDiWIWKA zN;=u&bdP|31qJkmINdSO-jV4`b}=@AXU8l8|TNy({x-QFF*&{R6N1gcI1 zJs+8@3ClpQNu?6j%Ns!N;DzFJCqYY1sEl=FL=#C$Xd=|E54uwmq4r47_cRgO6@Xp~ zoN0F$^jA$-bK;cmA%l7FMPRz7l-t1`C!26zH7DtuO(m(83N;c?OF&(l3PZ5o#$AlF z_6L54iZlP0?-uwZ;IlZ6Wh4PD1oXVh%514y2jI=7lw5$8ya)QInwd2lz417t^>GNcDtHhoHUrcV5W66`u$};NRQ^$*?^iRqQd2~snZOsTIB&#CfxiI! zbrmlyMdjN8{HzKKNRy<9G-00@GEYY3Nr0NBiORFsz?32I4#00waXthM5%^Hx<5is3 z`=G!JfX^+LGX?c70&ppf-oM`*r>oUmlG2(}_q*Zz-9YzkPG@pKj{!YRrI&!-&|LV! zZqUb?Q(>_oPX2Y1=;JX&IrC1-QO=!t3ragu5c|P>DM!HW+D$^O_13*3~vUoR7MY^;l z?`G|5px>p1kCSH3k19v@G1fGd(L_RZw9U6P{GMJu^J zH2^eA7p=?$-BZovCKv!zTHb( z=HimP3-lx}nMfb61xacd-lNL_yzZs4vj(1bK;-E=N|JOOSxFhiQy`&5h9q^#5LJ0) zM}Y2T0FPx*={ytz`DA(CaX8Q_08KJ!&^_?|shJomGU@7A`1^j)pJuXwKY~2(TJijq zNy+b8Yv=;oNK&IVbd?q80Q#0Tw3J;ScY~hWMqDf_KyPg$E|3GDPqh)+ocjg+dltY= zZN>e^I}c`>+7{Ker8j;GMYW)>wiPAA+euO!mPq+vgF#(a7eKpqyp4T9-md0xkG>1Q zl6JzJ&w%!+nfwO26~O0e<~h((dm)u~p}sxl675CFPN4g?7acJS^cWSt2lS)`K#vqzT(xmXFH-YX zfPO{fam_X(eNxRk1Nth@)87tr1$C07ah>>0j=G+;Cz$sFd=B7!ok8FiLPJj5UD_{@ zyhL)b%gu|)T_kB#7hX*J80aS`*NaPaz%FgC-A0;D2fljFdfu2j+ub)q{JWb_?jeWL{W4G<}Tp=^o_8 zh^hst%c7in!`Arb^s~2>Y48E-=<6S?3bp!?3a)4zl7@1M%{Jf0bKz$d8PC3jW?RTe z852QidfSA6$0%8jc7%-PK%*^b84lX=q}f5GO%noXYHYNLO0If>l!-F!35fR4<`MRI zO1u(Y7ppb$0-J}DHPHw_S1h6O42lh~I8npgE1u}$i{XJ(<4SlPWxh=3QBqz=Im^s3 z@-iwtX>ASW^z}xk^0Z7DbIq~xbJU~6=BE5-j5^Y~qOJ1FoLhNSrjiWD@LF#|y$H#R z*6hKdli1a?6_`%y3F>{0-GaYwkvYTR47tF8Q2gCNDJ5oW$WG211mHc&E-@#D9N-)d z{5{VB3iT%F<=s?JVslqc3JpGG?S|y)Q&uPDcqR8aU93SV8^aJG8W63gkF~L(wCr=M zU5Ugkwr;dbabtN6y`Us0lvQGj!K&XrZLF2^-~o_J_(n)j8YwjHOKa1hL2o6%cE3na z(BY7qU9U*1DvBtX3U7+iL7_%pTH~TbheCuD$^Q8Ly7C&bLVf`jAz^MN{X*}3X>}^u z3VrdVwS}v)D4WN#pGKUd-n9I*-by{cvQF;6++T;NIXueozQ+txx|L%YpoVdZd5j*p z5z+uqLpjC<1^^Mte37Bz$r4;LaDDM@(J<3Cvn z=H2+JTJI)O&RH8p&EQ?ZIBE+%bap7W%bQgze47@WvyQh4{`%k*6dNdZljl6Hh4-lW zdF$akfiv?73Ufl0!muqJ;O!h(fsLx5CWHEr=Pm>#nz8~^e~xVe^#P~0Rq%n3_ToSj za9CKUO8b9Z%_Ce*!3S)BHjMzK8y0H1T`ulo~?oz6{5~g-YxO26ouS z#*KKYs%^fe+b&qMtb!j;fRd1nnJ8rMz5v;0>5B{2L#k~ufs0yjw^6Afpe}NaZUglL zr|zxDeWZe#59$=peXasqUqON312`C95e;)y=>igg(x_{YOD((!A>>_TbkLQ~u}SpU zMXTGxu5O)V2B)}?>wpqN0A>ObMhjD4OC8%LUZ)j^4d#yEql!jD*?ldo6R#mpC$Y)` zxGWG7>(>BANHv)<(q+2ilGUYLRw%T2f7MXlS`rZ1gzAno zn0wV#}n~K}Z}kQ=tio9Ver0A&uEpj^AX-L(9&Z(&#(J@+Bf29=G>J zbVT;cmP}e1Y_q|ovyR!?ko6~{Enz$%C3%OniUAwa(UFwg6 zT}QZuEpk{$x7%#1F-g4@ECS9uMVeo6b0}}qlaVy;1&f20K8s6I!F)vmB z-r++g3`tll`D28+?fxUs;6L)6=i%B&9;Sv(*P^}-1)It zM<)$2Hf6Mn_S!@(Zk zqhfen((~7u<9TH0XsaWnDb26tvPC?ra;~cA(6?hmht_n4)TUPg(IKa?Lit%VEPW7t zFu+ZB9z!3@UxXfA=cbrQ=*c^Al7~Jy$=Gb@(NiAEdCrN4ES4A=OQFY6W`_ldeX+FV z7gHvsE{A|cakPcyaA|kNQ{ez~Jof@`0#;$b#=YRd1bXlVNaJM=B+%w9um_h`JCTxC zIWrw>2}{PYIb{AF8JU<6c4F&M}AI1kR4AOK;%kJ*T#siN@_TDt%jM?W^4;&%jxQib6te9h!?O;j0mIH`i$6cx*89a=i4!|eO#Be zp1}n>A|k@3T&_#5vq;Q0BY}OHNi$>N;8F0vwEE;p!X?HXwSRp|nH4L%ops`duys$D zcc&!1RG(%bS4eE$fR3Fjm-s^iN}r8#Y^KV7EB5awtSpzCOmokJ_0t&CcO;p?is&)Z>vqFSeva`mdYc`F?x=?U~`BH6B|Qs z{4{d8ux^b-g=;RL!nlzbVee>6=P#g{4}gy;wJK*QE)by}b{iT~mmi@24hu$y%vAc} zaTpJ)5^S0vtmwf-O?9HKQZ*Vw07W zX1*akJ&y(YMTcNpwPtdpzCmi^hU`VG@?T0r^9RZc3(!O-VIrR?k-T>{QRu>N!?DC#vUK>bahJPEpUP z>N!n4w^Gj;>baeI?xdc(spo9-Bj^wvqQF=$BfGo!5<^x3=Uvui9OpkBF@h)=J$eq|dkHE4ls~9DGTX zZE&=0B{uhlf*!B#VW_)Fd{?9Z_*@m|Mqea$OBMrPRgSYQ$n^lMt^L-$JG90UMQgu} z*CGJRT8oX>O`yMO?YHrI1%Nr-Z{sx)I|^+8u*P-+JuqEtyp9B&n=Y(11$0Te*m#Y? z(6la{Z@kjV{>B6{ufd`9iYCT;v9z!5H?ZA3xfK;m#l}w;;QhT~UvmWL`QT^! znwvoHF6U@b>r7YZK&70o4Ay?&DwSomqI6G^zBw$gs_HT0;1e| zYzf2-H3gZzZsK;g74$w;0vjWhBdUa>$T$reSEF*V8<|EMlLETKlf*tv{tQ^IKFQ-@ ztyIA6{NNq}?hW`>0rMds7wMAjl>80$yg|Muvb>K(Arz2_*$MEl%0CFwKjScMT;NjG zma)>-xQFP()}XtK?H?1aBoP!G(*?coAHd~TXXzL|-UVb4i{A|%D8Gy3|oHY#_d;O6fku4M$3p!8a@maz&q!+1q zD?q;@^0>V>BmJG4cNugjt^E;I@ohg_Pf7Cj6f!%5?kDoN%;88+RP*vd7xFwkI!0QE zmsG;O~N&MBjeVa#71r| z==;?IQ$WuX1^Bl4Qlvk>iM#pFAoVvhS#e4P&LeOOxEUiNhhl^wQvme8S=2oO^xbME zpDpA8cv{VT5%e1(lkG1{?;vgHEgI_RjkQkN_lw=FhwDfUkt|TNW`JJAvuMjt7}QoE zeMHSW1^Ne(2RmrBNH)AhNNjlv)?dkd#U8KpzJ(ir^7C;aavRS^<{K*GJD?BIxXb88 zZsSh{xAtq`KMS1OH~^2cP5TJp8KARi?G=>aChp%ybn*Sbrwg3#qt8QnXCLnB$3T87 zvhuH>S1$D-@B6sP^~D}7WnYCPZm^n2ck3%^xdrq{o~Os)Cyhh$^}amPft5NSN^zSU zN7~v?lydizqy`i#JK}X|AV;h4M9@=d?zM823;PL`*8txv*mr`wtg`F+W2~cbvcpY# z6~s$;kiNG+eKHAGbTQ}+{ly*Y1n95*Y3d-bez=hrd>5&73R^vby_~p$& z+Nb7i1-(z?ZTSf0jv#Fr$jj-X2f~{N3UB5nZ32Mul{~0Ko!lfN%CM zv=hKpwNTI?NpcM067?%#);Of!86?K4fWcUvA1v~2MP3ZjQ;?pDTlnD7A@TZI0G|bz zn!~S;PB|FubA)!R$?`BdaUed4-kFNs_Ge`T1b`uXC@n33*>(=aI6IVbgADFqWPOHY z%i(l}Wj#L}8#Kd(MSlUEG(uRk#R!D0(7q=;Zarpt(#=Q~kKj{0?K;rgMAkZFy^rKW zxAInK-+=1xQ|tniVjGBuko1~wt3@+$dw~2YpTwt4S;}z=mfj)7Y zXwW%Crf9zbkVSJX@TTFnW3%vfVH_jmPDXmxsNyC17=Ek&U=-F3M)5XiWA9)yihWBw z@wy=($K64tkL%qg4I&khTy`fE#t$)UH61Qx*Vy6_o;dQ%bZOgVgcmowGD|fiW>elyw099JhA>-*FBG{6OacKv>4N;ZDgm~dOISk7w(uZL5$LAg2Q1r@`o_Mq^#=z++3ZXwzR zARbxx2W~*s;7lG+aV)69if!ET#y8^>vt@faKhl{R63GD*fFzQ?3y%)1R{aM8fFlhKo`+*0j@2TvMYhw4@4^!hx4`r> zpjZZ{?4V%JwZ&$KjL5e0;Yo6PntQu5%~PF|HC&h=9#oKwHP>(lCeP=eGRKA3AuK{N zBBK{;o7LQ#OK18H=Ts0~n{TsH;Vyk>NMDXHLkytoi=LWjcFrEXQy$EU+N?t>ii$=v z6P~5)ClHV#O0q@|psja1opRQHY!wCk!867N@>8_-8Mxq+wDu{Jjq;C0+T>>`_F3cY9a!&);0581325f49IFrN z6;8DUC2Wlc8fhKJFxilLaSHc9=?xZ)QO_-Ux2m&lAvx%}-n4IQq9AG{0w&0~bX^v>hkB=?yM%Ec$vgjbEKr8)nuLvTlyx4b|2X@tACr5A?-tswF4zwunQ;`ZCPo$@g;bOvwOf4Mjru6%6PaSKgxeJK7>-%HoxnuUmKfMD14O^Fpsi4uH;#2#G~$vbIwJx-oH>YfOs&vQ zks*e^WV{r3kJEvd>-OoRW0b@{TpbI)Qfez?UTljC5q-jJiub=TC@T5+R-!B>$EnzYIk zq}+sfs?Ek`idUiYjVunOFP9uG4=N6fj#h>#w0xzxLfmc8$8Kq=j8SOiQrqh8ccbwU zQVjHB;X@G;rt;EL+(h?QP*XwO#d8-|@PUw4us{5#i(semsA`#QS`ATt9FPZiDVA5j z{@|xb0Ty&on$hP&@HCA>gl(W&86}p;V5^U75DpZmN5xd}Q0~1`z zJ_TPGb2Mbv(AKAI4&|VTpvyoy@f!qOd0?9l>Ij%74!g{==#1<#o*H24jp zPC?Mk@~y_!z*1V_D)?G>3sZIO&;$oUY?zxU7b;t}r46e8iMPx_?&H=VkKjua5$AP4ShT!p#kpv-c82(73$hGwEJ0GPiW(L z4o(_HTYEav%XN#@(6wHca@UhSViCw#UPcNlLZn@|cD@ql`W*PjSVxJZr39AGZ;FsDFBVnW2Idd$J32Q;*Hovo8i zC>jq$P|Oivchf7lW*^hgi2}>UMj|Jzf(K9C(%q08A>CGiv3?VLOBh9aAHroltHM?u zx^=y+tS6gi`kRV*&jK!~O$F5lR4T__XOhr(9glJo)G1(h@Z2+?ax~m5NjEaf5^(7x zZWhSk12@e*pic>z&oh{LmQvkUZB7MIW&5UB#)OC(ureXdqS!qchwR z>dfSY3KiGV#@8_5JnK97nysEDZxgfeLTdzhGNM(7f+-F>|x-9Kf zhVB&t26F*qI%U$)%~qF99#31RV;yh(0>pwprYE!66+@4FX|Z8Jq}~i<*iM;ju1%_( zp4U~>i-ugax?D$926hXBCcG&L4&2qoWe@lggBEdZ9 zJp|J1_}pZ(yri=9tzg+h=4p2PTN|?+wdp`ELJ*IJ(4Di;yDY*~K22LbH@2bAzcAT4 z{j8Q9%**-*;pCtZl`&;uUyo`s7*hoC>&c!i@XJ9dxIcayDSHVfokMu1_cw-#P9K6C zVThVQ%6|gsa2?VQ2y>@Osc%&9l$&oq?b~g3b{Yz{s)1^i%6*GM>|vDi@H%@M_(?_l zdv=&`!dF#>Vc@Ikgu}^nSFB6fZ=fx695LM8lrshz@Pso)_?ym1ooCsFzcq?siyQcj z#35Rlt|FBVFvt(NU2a-DAvQXk-Agrc6f25fY}m`ksrdqD0zH}uhsa&vjIvBpOO2}N z<0t6+*Cr>uTY`|}#@`@<^%TBAHy3?uJAmM{kFe#KIoJP|ewwxtOM zWs5}wjgNTEVjE^;H-G#d=Y{+))*_&l7wfFq!xR1&>9m>?3#|foI@z--Rokokje7XM8@C z#m}>NbNPN6d=y+wHo);;aFWRhS&tlrtnf$?3eR4KkaKCwF>vv4^*xay68_=+xVLtq zV<)5A@KF4E&#E%Dm}14L30j>60Jv ztjk^&P%cMNy`K;#&t4!=T+y`W5y&`r1w%`IG@W2MmZKJ1#Bnxx$8S3q$f)J&I|ZM( zqcEJXS2$G`$A4;DX@fT8ex zi_M^nPZSa3%=?sei6Ua0`(@Z#h;!4vR6_)abJJd`!2`r;eh}i%KTHzw z;M|(u)a3Et)cY8^V^%G{@NZ*n5&m5iVzRjh)P@c4`-L~S{5^(_9AQq>{Ck89cbOX- zu3W)CHPYA>sXSL(#E2_9@HS9z9jd!2K@GURxem2LY&Ja=4rR92A!3OO$8jx2*X2>$ zbkPK5?yf6>wAY_N&c(VsNL%<*`+6cKn>X#zdUOX1(B@4$fo~gy;;u9GB+4wUPX+T} z;e&^fxTgV&V9uoTF{t#N1{4zpwt1(JV@jrbS%L?H4^E~%KSEmXFOc(YGSxL8hpQ8Z z0GMJ3SWy!Kmf#CDEC-_P_~K)8BWPad%to|_z*Pfb(|HXVbDK$tvWJc2ey@zMeX*)x z-iZ}q-uI}bYM_*c3)lyQ4Uq!z9}kka9JY|he3T8Wm2wheQbjS�A|Cg#9=|v!94{ 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

3^m5poE{yR*;q7V&FP$>NMfuxOHqf+ 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 KF4d0xPW(SY#wck3 delta 91576 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%0AVe9(N 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 diff --git a/JGE/src/JMD2Model.cpp b/JGE/src/JMD2Model.cpp index cb1879117..7d1f7cedd 100644 --- a/JGE/src/JMD2Model.cpp +++ b/JGE/src/JMD2Model.cpp @@ -245,7 +245,11 @@ void JMD2Model::CalculateNormal(ScePspFVector3 *normal, float *p1, float *p2, fl #if defined (WIN32) || defined (LINUX) // normalize and specify the normal +#if (!defined GL_ES_VERSION_2_0) && (!defined GL_VERSION_2_0) glNormal3f(result[0]/length, result[1]/length, result[2]/length); +#else + // FIXME +#endif //(!defined GL_ES_VERSION_2_0) && (!defined GL_VERSION_2_0) #else if (length == 0.0f) @@ -275,15 +279,45 @@ void JMD2Model::Render(int frameNum) #if defined (WIN32) || defined (LINUX) - // display the textured model with proper lighting normals - glBegin(GL_TRIANGLES); +#if (defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) + +#elif (defined GL_ES_VERSION_1_1) || (defined GL_VERSION_1_1) + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + +#else + glBegin(GL_TRIANGLES); +#endif //(defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) + for(i = 0; i < mModel->numTriangles; i++) { CalculateNormal(pointList[mModel->triIndex[i].meshIndex[0]].v, pointList[mModel->triIndex[i].meshIndex[2]].v, pointList[mModel->triIndex[i].meshIndex[1]].v); - glTexCoord2f(mModel->st[mModel->triIndex[i].stIndex[0]].s, + +#if (defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) + +#elif (defined GL_ES_VERSION_1_1) || (defined GL_VERSION_1_1) + float vertex_data[]={ + pointList[mModel->triIndex[i].meshIndex[0]].x, pointList[mModel->triIndex[i].meshIndex[0]].y, pointList[mModel->triIndex[i].meshIndex[0]].z, + pointList[mModel->triIndex[i].meshIndex[2]].x, pointList[mModel->triIndex[i].meshIndex[2]].y, pointList[mModel->triIndex[i].meshIndex[2]].z, + pointList[mModel->triIndex[i].meshIndex[1]].x, pointList[mModel->triIndex[i].meshIndex[1]].y, pointList[mModel->triIndex[i].meshIndex[1]].z, + }; + float texcoord_data[] = { + mModel->st[mModel->triIndex[i].stIndex[0]].s, + mModel->st[mModel->triIndex[i].stIndex[0]].t, + mModel->st[mModel->triIndex[i].stIndex[2]].s, + mModel->st[mModel->triIndex[i].stIndex[2]].t, + mModel->st[mModel->triIndex[i].stIndex[1]].s, + mModel->st[mModel->triIndex[i].stIndex[1]].t, + }; + + glVertexPointer(3,GL_FLOAT,0,vertex_data); + glTexCoordPointer(2,GL_FLOAT,0,texcoord_data); + +#else + glTexCoord2f(mModel->st[mModel->triIndex[i].stIndex[0]].s, mModel->st[mModel->triIndex[i].stIndex[0]].t); glVertex3fv(pointList[mModel->triIndex[i].meshIndex[0]].v); @@ -294,8 +328,15 @@ void JMD2Model::Render(int frameNum) glTexCoord2f(mModel->st[mModel->triIndex[i].stIndex[1]].s, mModel->st[mModel->triIndex[i].stIndex[1]].t); glVertex3fv(pointList[mModel->triIndex[i].meshIndex[1]].v); - } - glEnd(); +#endif //#if (!defined GL_ES_VERSION_2_0) && (!defined GL_VERSION_2_0) + } +#if (defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) + +#elif (defined GL_ES_VERSION_1_1) || (defined GL_VERSION_1_1) + glDrawArrays(GL_TRIANGLES,0,3); // seems suspicious to put that here, should probably be in the loop +#else + glEnd(); +#endif //(defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) #else @@ -442,9 +483,16 @@ void JMD2Model::Render() #if defined (WIN32) || defined (LINUX) +#if (defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) + // FIXME +#elif (defined GL_ES_VERSION_1_1) || (defined GL_VERSION_1_1) + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); +#else + glBegin(GL_TRIANGLES); +#endif //(defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) - glBegin(GL_TRIANGLES); - for (i = 0; i < mModel->numTriangles; i++) + for (i = 0; i < mModel->numTriangles; i++) { // get first points of each frame x1 = pointList[mModel->triIndex[i].meshIndex[0]].x; @@ -489,19 +537,48 @@ void JMD2Model::Render() //CalculateNormal(vertex[0].v, vertex[2].v, vertex[1].v); // render properly textured triangle - glTexCoord2f(mModel->st[mModel->triIndex[i].stIndex[0]].s, - mModel->st[mModel->triIndex[i].stIndex[0]].t); - glVertex3fv(vertex[0].v); - glTexCoord2f(mModel->st[mModel->triIndex[i].stIndex[2]].s , - mModel->st[mModel->triIndex[i].stIndex[2]].t); - glVertex3fv(vertex[2].v); +#if (defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) + // FIXME +#elif (defined GL_ES_VERSION_1_1) || (defined GL_VERSION_1_1) + float vertex_data[]={ + vertex[0].x, vertex[0].y, vertex[0].z, + vertex[2].x, vertex[2].y, vertex[2].z, + vertex[1].x, vertex[1].y, vertex[1].z, + }; + float texcoord_data[] = { + mModel->st[mModel->triIndex[i].stIndex[0]].s, + mModel->st[mModel->triIndex[i].stIndex[0]].t, + mModel->st[mModel->triIndex[i].stIndex[2]].s, + mModel->st[mModel->triIndex[i].stIndex[2]].t, + mModel->st[mModel->triIndex[i].stIndex[1]].s, + mModel->st[mModel->triIndex[i].stIndex[1]].t, + }; - glTexCoord2f(mModel->st[mModel->triIndex[i].stIndex[1]].s, - mModel->st[mModel->triIndex[i].stIndex[1]].t); - glVertex3fv(vertex[1].v); - } - glEnd(); + glVertexPointer(3,GL_FLOAT,0,vertex_data); + glTexCoordPointer(2,GL_FLOAT,0,texcoord_data); +#else + glTexCoord2f(mModel->st[mModel->triIndex[i].stIndex[0]].s, + mModel->st[mModel->triIndex[i].stIndex[0]].t); + glVertex3fv(vertex[0].v); + + glTexCoord2f(mModel->st[mModel->triIndex[i].stIndex[2]].s , + mModel->st[mModel->triIndex[i].stIndex[2]].t); + glVertex3fv(vertex[2].v); + + glTexCoord2f(mModel->st[mModel->triIndex[i].stIndex[1]].s, + mModel->st[mModel->triIndex[i].stIndex[1]].t); + glVertex3fv(vertex[1].v); +#endif //(defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) + + } +#if (defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) + // FIXME +#elif (defined GL_ES_VERSION_1_1) || (defined GL_VERSION_1_1) + glDrawArrays(GL_TRIANGLES,0,3); // seems suspicious to put that here, should probably be in the loop +#else + glEnd(); +#endif //(defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) #else diff --git a/JGE/src/Qtmain.cpp b/JGE/src/Qtmain.cpp new file mode 100644 index 000000000..3f15186e0 --- /dev/null +++ b/JGE/src/Qtmain.cpp @@ -0,0 +1,272 @@ +#define GL_GLEXT_PROTOTYPES +#include +#include +#include "../include/JGE.h" +#include "../include/JTypes.h" +#include "../include/JApp.h" +#include "../include/JFileSystem.h" +#include "../include/JRenderer.h" +#include "../include/JGameLauncher.h" + +#define ACTUAL_SCREEN_WIDTH (SCREEN_WIDTH) +#define ACTUAL_SCREEN_HEIGHT (SCREEN_HEIGHT) +#define ACTUAL_RATIO ((GLfloat)ACTUAL_SCREEN_WIDTH / (GLfloat)ACTUAL_SCREEN_HEIGHT) + +class JGEQtRenderer : public QGLWidget +{ +// Q_OBJECT // must include this if you use Qt signals/slots + +public: + JGEQtRenderer(QWidget *parent); + +protected: + + void initializeGL(); + + void resizeGL(int w, int h); + + void paintGL(); + + void timerEvent( QTimerEvent* ); + + void keyPressEvent(QKeyEvent *event); + + void keyReleaseEvent(QKeyEvent *event); +}; + +uint64_t lastTickCount; +JGE* g_engine = NULL; +JApp* g_app = NULL; +JGameLauncher* g_launcher = NULL; +JGEQtRenderer *g_glwidget = NULL; + +static const struct { LocalKeySym keysym; JButton keycode; } gDefaultBindings[] = + { + { Qt::Key_Enter, JGE_BTN_MENU }, + { Qt::Key_Backspace, JGE_BTN_CTRL }, + { Qt::Key_Up, JGE_BTN_UP }, + { Qt::Key_Down, JGE_BTN_DOWN }, + { Qt::Key_Left, JGE_BTN_LEFT }, + { Qt::Key_Right, JGE_BTN_RIGHT }, + { Qt::Key_Space, JGE_BTN_OK }, + { Qt::Key_Tab, JGE_BTN_CANCEL }, + { Qt::Key_J, JGE_BTN_PRI }, + { Qt::Key_K, JGE_BTN_SEC }, + { Qt::Key_Q, JGE_BTN_PREV }, + { Qt::Key_A, JGE_BTN_NEXT }, +// fullscreen management seems somehow broken in JGE, it works fine with Qt directly +// { Qt::Key_F, JGE_BTN_FULLSCREEN }, + }; + + +void JGECreateDefaultBindings() +{ + for (signed int i = sizeof(gDefaultBindings)/sizeof(gDefaultBindings[0]) - 1; i >= 0; --i) + g_engine->BindKey(gDefaultBindings[i].keysym, gDefaultBindings[i].keycode); +} + +int JGEGetTime() +{ + QTime theTime = QTime::currentTime(); + return theTime.second() * 1000 + theTime.msec(); +} + +bool JGEToggleFullscreen() +{ + if(g_glwidget->isFullScreen()) + { + g_glwidget->showNormal(); + } + else + { + g_glwidget->showFullScreen(); + } + return true; +} + +bool InitGame(void) +{ + g_engine = JGE::GetInstance(); + g_app = g_launcher->GetGameApp(); + g_app->Create(); + g_engine->SetApp(g_app); + + JRenderer::GetInstance()->Enable2D(); + QTime theTime = QTime::currentTime(); + lastTickCount = theTime.second() * 1000 + theTime.msec(); + + return true; +} + +void DestroyGame(void) +{ + g_engine->SetApp(NULL); + if (g_app) + { + g_app->Destroy(); + delete g_app; + g_app = NULL; + } + + JGE::Destroy(); + + g_engine = NULL; +} + + +JGEQtRenderer::JGEQtRenderer(QWidget *parent) + : QGLWidget(QGLFormat(QGL::SampleBuffers), parent) +{ + startTimer( 5 ); + setWindowTitle(g_launcher->GetName()); +#ifdef Q_WS_MAEMO_5 + setAttribute(Qt::WA_Maemo5AutoOrientation); + setAttribute(Qt::WA_Maemo5NonComposited); +#endif +} + + +void JGEQtRenderer::initializeGL() +{ + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Black Background (yes that's the way fuckers) +#if (defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) +#if (defined GL_ES_VERSION_2_0) + glClearDepthf(1.0f); // Depth Buffer Setup +#else + glClearDepth(1.0f); // Depth Buffer Setup +#endif// (defined GL_ES_VERSION_2_0) + + glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing (Less Or Equal) + glEnable(GL_DEPTH_TEST); // Enable Depth Testing + +#else + glClearDepth(1.0f); // Depth Buffer Setup + + glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing (Less Or Equal) + glEnable(GL_DEPTH_TEST); // Enable Depth Testing + glShadeModel(GL_SMOOTH); // Select Smooth Shading + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Set Perspective Calculations To Most Accurate + + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); // Set Line Antialiasing + glEnable(GL_LINE_SMOOTH); // Enable it! + #endif + + glEnable(GL_CULL_FACE); // do not calculate inside of poly's + glFrontFace(GL_CCW); // counter clock-wise polygons are out + + glEnable(GL_TEXTURE_2D); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glEnable(GL_SCISSOR_TEST); // Enable Clipping +} + +int actualWidth; +int actualHeight; + +GLvoid ReSizeGLScene(GLsizei width, GLsizei height) // Resize The GL Window +{ + actualWidth = width; + actualHeight = height; + + if ((GLfloat)width / (GLfloat)height < ACTUAL_RATIO) + glViewport(0, -((width/ACTUAL_RATIO)-height)/2, width, width / ACTUAL_RATIO); // Reset The Current Viewport + else + glViewport(-(height*ACTUAL_RATIO-width)/2, 0, height * ACTUAL_RATIO, height); + glScissor(0, 0, width, height); +} + +void JGEQtRenderer::resizeGL(int width, int height) +{ + ReSizeGLScene(width, height); +} + +void JGEQtRenderer::paintGL() +{ + g_engine->Render(); +} + +void JGEQtRenderer::timerEvent( QTimerEvent* ) +{ + QTime theTime = QTime::currentTime(); + static uint64_t tickCount; + quint32 dt; + tickCount = theTime.second() * 1000 + theTime.msec(); + dt = (tickCount - lastTickCount); + lastTickCount = tickCount; + + if(g_engine->IsDone()) close(); + + //gPrevControllerState = gControllerState; + g_engine->SetDelta((float)dt / 1000.0f); + g_engine->Update((float)dt / 1000.0f); + + updateGL(); +} + + +void JGEQtRenderer::keyPressEvent(QKeyEvent *event) +{ + if(event->key() == Qt::Key_F) + { + JGEToggleFullscreen(); + } + g_engine->HoldKey_NoRepeat(event->key()); + event->accept(); + QWidget::keyPressEvent(event); + return; +} + +void JGEQtRenderer::keyReleaseEvent(QKeyEvent *event) +{ + g_engine->ReleaseKey(event->key()); + event->accept(); + QWidget::keyReleaseEvent(event); + return; +} + + +int main(int argc, char* argv[]) +{ + char* path = argv[0]; + while (*path) ++path; + while ((*path != '/') && (path > argv[0])) --path; + if ('/' == *path) *path = 0; + if (strlen(argv[0]) != 0) QDir::current().cd(argv[0]); + + QApplication a( argc, argv ); + + g_launcher = new JGameLauncher(); + + u32 flags = g_launcher->GetInitFlags(); + + if ((flags&JINIT_FLAG_ENABLE3D)!=0) + JRenderer::Set3DFlag(true); + + g_glwidget = new JGEQtRenderer(NULL); + + g_glwidget->resize(ACTUAL_SCREEN_WIDTH, ACTUAL_SCREEN_HEIGHT); + + g_glwidget->show(); + + if (!InitGame()) + { + printf("Could not init the game\n"); + return 1; + } + + JGECreateDefaultBindings(); + + a.exec(); + + if (g_launcher) + delete g_launcher; + + if(g_glwidget) + delete g_glwidget; + + // Shutdown + DestroyGame(); + return 0; +} diff --git a/JGE/src/main.cpp b/JGE/src/main.cpp index 4bf8e1a44..59d2dc704 100644 --- a/JGE/src/main.cpp +++ b/JGE/src/main.cpp @@ -112,7 +112,7 @@ int SetupCallbacks(void) #ifdef DEVHOOK //code by sakya, crazyc, samuraiX -//http://forums.ps2dev.org/viewtopic.php?t=9591&sid=2056889f6b9531194cab9b2d487df844 +//http://forums.ps2dev.org/viewtopic.php?t=9591 PspDebugRegBlock exception_regs; extern int _ftext; diff --git a/JGE/src/pc/JGfx.cpp b/JGE/src/pc/JGfx.cpp index 0836e7aa4..c17435938 100644 --- a/JGE/src/pc/JGfx.cpp +++ b/JGE/src/pc/JGfx.cpp @@ -7,6 +7,7 @@ // Copyright (c) 2007 James Hui (a.k.a. Dr.Watson) // //------------------------------------------------------------------------------------- +#define GL_GLEXT_PROTOTYPES #ifdef WIN32 #pragma warning(disable : 4786) @@ -15,8 +16,7 @@ #pragma comment( lib, "giflib.lib" ) #endif - -#include "../../Dependencies/include/png.h" +#include #ifdef __cplusplus extern "C" { @@ -42,6 +42,237 @@ extern "C" { #endif #endif +#ifdef FORCE_GL2 +// This code is to force the windows code to use GL_VERSION_2_0 even if it's not defined in the header files +// It's mostly to try to debug the shaders on Windows. +typedef GLuint (APIENTRY *_glCreateShader) (GLenum); +typedef void (APIENTRY *_glShaderSource) (GLuint, GLsizei, const char **, const GLint *); +typedef void (APIENTRY *_glShaderBinary) (GLint, const GLuint*, GLenum, const void*, GLint); +typedef void (APIENTRY *_glCompileShader) (GLuint); +typedef void (APIENTRY *_glDeleteShader) (GLuint); +typedef GLboolean (APIENTRY *_glIsShader) (GLuint); + +typedef GLuint (APIENTRY *_glCreateProgram) (); +typedef void (APIENTRY *_glAttachShader) (GLuint, GLuint); +typedef void (APIENTRY *_glDetachShader) (GLuint, GLuint); +typedef void (APIENTRY *_glLinkProgram) (GLuint); +typedef void (APIENTRY *_glUseProgram) (GLuint); +typedef void (APIENTRY *_glDeleteProgram) (GLuint); +typedef GLboolean (APIENTRY *_glIsProgram) (GLuint); + +typedef void (APIENTRY *_glGetShaderInfoLog) (GLuint, GLsizei, GLsizei *, char *); +typedef void (APIENTRY *_glGetShaderiv) (GLuint, GLenum, GLint *); +typedef void (APIENTRY *_glGetShaderSource) (GLuint, GLsizei, GLsizei *, char *); +typedef void (APIENTRY *_glGetProgramiv) (GLuint, GLenum, GLint *); +typedef void (APIENTRY *_glGetProgramInfoLog) (GLuint, GLsizei, GLsizei *, char *); + +typedef GLuint (APIENTRY *_glGetUniformLocation) (GLuint, const char*); +typedef void (APIENTRY *_glUniform4fv) (GLint, GLsizei, const GLfloat *); +typedef void (APIENTRY *_glUniform3fv) (GLint, GLsizei, const GLfloat *); +typedef void (APIENTRY *_glUniform2fv) (GLint, GLsizei, const GLfloat *); +typedef void (APIENTRY *_glUniform1fv) (GLint, GLsizei, const GLfloat *); +typedef void (APIENTRY *_glUniform1i) (GLint, GLint); +typedef void (APIENTRY *_glUniform1iv) (GLint, GLsizei, const GLint *); +typedef void (APIENTRY *_glUniformMatrix2fv) (GLint, GLsizei, GLboolean, const GLfloat *); +typedef void (APIENTRY *_glUniformMatrix3fv) (GLint, GLsizei, GLboolean, const GLfloat *); +typedef void (APIENTRY *_glUniformMatrix4fv) (GLint, GLsizei, GLboolean, const GLfloat *); +typedef void (APIENTRY *_glUniformMatrix2x3fv) (GLint, GLsizei, GLboolean, const GLfloat *); +typedef void (APIENTRY *_glUniformMatrix2x4fv) (GLint, GLsizei, GLboolean, const GLfloat *); +typedef void (APIENTRY *_glUniformMatrix3x2fv) (GLint, GLsizei, GLboolean, const GLfloat *); +typedef void (APIENTRY *_glUniformMatrix3x4fv) (GLint, GLsizei, GLboolean, const GLfloat *); +typedef void (APIENTRY *_glUniformMatrix4x2fv) (GLint, GLsizei, GLboolean, const GLfloat *); +typedef void (APIENTRY *_glUniformMatrix4x3fv) (GLint, GLsizei, GLboolean, const GLfloat *); + +typedef void (APIENTRY *_glBindAttribLocation) (GLuint, GLuint, const char *); +typedef GLint (APIENTRY *_glGetAttribLocation) (GLuint, const char *); +typedef void (APIENTRY *_glVertexAttrib1fv) (GLuint, const GLfloat *); +typedef void (APIENTRY *_glVertexAttrib2fv) (GLuint, const GLfloat *); +typedef void (APIENTRY *_glVertexAttrib3fv) (GLuint, const GLfloat *); +typedef void (APIENTRY *_glVertexAttrib4fv) (GLuint, const GLfloat *); +typedef void (APIENTRY *_glVertexAttribPointer) (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *); +typedef void (APIENTRY *_glDisableVertexAttribArray) (GLuint); +typedef void (APIENTRY *_glEnableVertexAttribArray) (GLuint); + +typedef void (APIENTRY *_glGetProgramBinaryOES) (GLuint, GLsizei, GLsizei *, GLenum *, void *); +typedef void (APIENTRY *_glProgramBinaryOES) (GLuint, GLenum, const void *, GLint); + + +typedef void (APIENTRY *_glMultiTexCoord4f) (GLenum, GLfloat, GLfloat, GLfloat, GLfloat); +typedef void (APIENTRY *_glActiveStencilFaceEXT) (GLenum ); + +typedef void (APIENTRY *_glStencilOpSeparate) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +typedef void (APIENTRY *_glActiveTexture) (GLenum); +typedef void (APIENTRY *_glBlendColor) (GLclampf, GLclampf, GLclampf, GLclampf); + +#define GLSLGETPROC(func) a ## func = (_ ## func)wglGetProcAddress(#func); + +struct glslFunctions +{ + void load(){ + GLSLGETPROC(glCreateShader); + GLSLGETPROC(glShaderSource); + GLSLGETPROC(glShaderBinary); + GLSLGETPROC(glCompileShader); + GLSLGETPROC(glDeleteShader); + GLSLGETPROC(glIsShader); + GLSLGETPROC(glCreateProgram); + GLSLGETPROC(glAttachShader); + GLSLGETPROC(glDetachShader); + GLSLGETPROC(glLinkProgram); + GLSLGETPROC(glUseProgram); + GLSLGETPROC(glDeleteProgram); + GLSLGETPROC(glIsProgram); + GLSLGETPROC(glGetShaderInfoLog); + GLSLGETPROC(glGetShaderiv); + GLSLGETPROC(glGetShaderSource); + GLSLGETPROC(glGetProgramiv); + GLSLGETPROC(glGetProgramInfoLog); + GLSLGETPROC(glGetUniformLocation); + GLSLGETPROC(glUniform4fv); + GLSLGETPROC(glUniform3fv); + GLSLGETPROC(glUniform2fv); + GLSLGETPROC(glUniform1fv); + GLSLGETPROC(glUniform1i); + GLSLGETPROC(glUniform1iv); + GLSLGETPROC(glUniformMatrix2fv); + GLSLGETPROC(glUniformMatrix3fv); + GLSLGETPROC(glUniformMatrix4fv); + GLSLGETPROC(glUniformMatrix2x3fv); + GLSLGETPROC(glUniformMatrix2x4fv); + GLSLGETPROC(glUniformMatrix3x2fv); + GLSLGETPROC(glUniformMatrix3x4fv); + GLSLGETPROC(glUniformMatrix4x2fv); + GLSLGETPROC(glUniformMatrix4x3fv); + GLSLGETPROC(glBindAttribLocation); + GLSLGETPROC(glGetAttribLocation); + GLSLGETPROC(glVertexAttrib1fv); + GLSLGETPROC(glVertexAttrib2fv); + GLSLGETPROC(glVertexAttrib3fv); + GLSLGETPROC(glVertexAttrib4fv); + GLSLGETPROC(glVertexAttribPointer); + GLSLGETPROC(glDisableVertexAttribArray); + GLSLGETPROC(glEnableVertexAttribArray); + GLSLGETPROC(glGetProgramBinaryOES); + GLSLGETPROC(glProgramBinaryOES); + GLSLGETPROC(glMultiTexCoord4f); + GLSLGETPROC(glActiveStencilFaceEXT); + GLSLGETPROC(glStencilOpSeparate); + GLSLGETPROC(glActiveTexture); + GLSLGETPROC(glBlendColor); + }; + + _glCreateShader aglCreateShader; + _glShaderSource aglShaderSource; + _glShaderBinary aglShaderBinary; + _glCompileShader aglCompileShader; + _glDeleteShader aglDeleteShader; + _glIsShader aglIsShader; + _glCreateProgram aglCreateProgram; + _glAttachShader aglAttachShader; + _glDetachShader aglDetachShader; + _glLinkProgram aglLinkProgram; + _glUseProgram aglUseProgram; + _glDeleteProgram aglDeleteProgram; + _glIsProgram aglIsProgram; + _glGetShaderInfoLog aglGetShaderInfoLog; + _glGetShaderiv aglGetShaderiv; + _glGetShaderSource aglGetShaderSource; + _glGetProgramiv aglGetProgramiv; + _glGetProgramInfoLog aglGetProgramInfoLog; + + _glGetUniformLocation aglGetUniformLocation; + _glUniform4fv aglUniform4fv; + _glUniform3fv aglUniform3fv; + _glUniform2fv aglUniform2fv; + _glUniform1fv aglUniform1fv; + _glUniform1i aglUniform1i; + _glUniform1iv aglUniform1iv; + _glUniformMatrix2fv aglUniformMatrix2fv; + _glUniformMatrix3fv aglUniformMatrix3fv; + _glUniformMatrix4fv aglUniformMatrix4fv; + _glUniformMatrix2x3fv aglUniformMatrix2x3fv; + _glUniformMatrix2x4fv aglUniformMatrix2x4fv; + _glUniformMatrix3x2fv aglUniformMatrix3x2fv; + _glUniformMatrix3x4fv aglUniformMatrix3x4fv; + _glUniformMatrix4x2fv aglUniformMatrix4x2fv; + _glUniformMatrix4x3fv aglUniformMatrix4x3fv; + + _glBindAttribLocation aglBindAttribLocation; + _glGetAttribLocation aglGetAttribLocation; + _glVertexAttrib1fv aglVertexAttrib1fv; + _glVertexAttrib2fv aglVertexAttrib2fv; + _glVertexAttrib3fv aglVertexAttrib3fv; + _glVertexAttrib4fv aglVertexAttrib4fv; + _glVertexAttribPointer aglVertexAttribPointer; + _glDisableVertexAttribArray aglDisableVertexAttribArray; + _glEnableVertexAttribArray aglEnableVertexAttribArray; + + _glGetProgramBinaryOES aglGetProgramBinaryOES; + _glProgramBinaryOES aglProgramBinaryOES; + _glMultiTexCoord4f aglMultiTexCoord4f; + _glActiveStencilFaceEXT aglActiveStencilFaceEXT; + _glStencilOpSeparate aglStencilOpSeparate; + _glActiveTexture aglActiveTexture; + _glBlendColor aglBlendColor; +}; + +static glslFunctions g_glslfuncts; + +#define glCreateShader g_glslfuncts.aglCreateShader +#define glCompileShader g_glslfuncts.aglCompileShader +#define glGetShaderiv g_glslfuncts.aglGetShaderiv +#define glGetShaderInfoLog g_glslfuncts.aglGetShaderInfoLog +#define glDeleteShader g_glslfuncts.aglDeleteShader +#define glCreateProgram g_glslfuncts.aglCreateProgram +#define glDeleteProgram g_glslfuncts.aglDeleteProgram +#define glShaderSource g_glslfuncts.aglShaderSource +#define glAttachShader g_glslfuncts.aglAttachShader +#define glLinkProgram g_glslfuncts.aglLinkProgram +#define glGetProgramiv g_glslfuncts.aglGetProgramiv +#define glGetProgramInfoLog g_glslfuncts.aglGetProgramInfoLog +#define glGetAttribLocation g_glslfuncts.aglGetAttribLocation +#define glGetUniformLocation g_glslfuncts.aglGetUniformLocation +#define glGetProgramiv g_glslfuncts.aglGetProgramiv +#define glVertexAttribPointer g_glslfuncts.aglVertexAttribPointer +#define glEnableVertexAttribArray g_glslfuncts.aglEnableVertexAttribArray +#define glUniform4fv g_glslfuncts.aglUniform4fv +#define glActiveTexture g_glslfuncts.aglActiveTexture +#define glUniform1i g_glslfuncts.aglUniform1i +#define glUseProgram g_glslfuncts.aglUseProgram +#define glUniformMatrix4fv g_glslfuncts.aglUniformMatrix4fv + +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_1D 0x8B5D +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_3D 0x8B5F +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 + +#define GL_VERSION_2_0 +#endif + JQuad::JQuad(JTexture *tex, float x, float y, float width, float height) :mTex(tex), mX(x), mY(y), mWidth(width), mHeight(height) { @@ -160,6 +391,265 @@ JRenderer::~JRenderer() } +#if (defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) +void esMatrixLoadIdentity(ESMatrix *result) +{ + memset(result, 0x0, sizeof(ESMatrix)); + result->m[0][0] = 1.0f; + result->m[1][1] = 1.0f; + result->m[2][2] = 1.0f; + result->m[3][3] = 1.0f; +} + +#define PI 3.1415926535897932384626433832795f + +void esScale(ESMatrix *result, GLfloat sx, GLfloat sy, GLfloat sz) +{ + result->m[0][0] *= sx; + result->m[0][1] *= sx; + result->m[0][2] *= sx; + result->m[0][3] *= sx; + + result->m[1][0] *= sy; + result->m[1][1] *= sy; + result->m[1][2] *= sy; + result->m[1][3] *= sy; + + result->m[2][0] *= sz; + result->m[2][1] *= sz; + result->m[2][2] *= sz; + result->m[2][3] *= sz; +} + +void esTranslate(ESMatrix *result, GLfloat tx, GLfloat ty, GLfloat tz) +{ + result->m[3][0] += (result->m[0][0] * tx + result->m[1][0] * ty + result->m[2][0] * tz); + result->m[3][1] += (result->m[0][1] * tx + result->m[1][1] * ty + result->m[2][1] * tz); + result->m[3][2] += (result->m[0][2] * tx + result->m[1][2] * ty + result->m[2][2] * tz); + result->m[3][3] += (result->m[0][3] * tx + result->m[1][3] * ty + result->m[2][3] * tz); +} + +void esMatrixMultiply(ESMatrix *result, ESMatrix *srcA, ESMatrix *srcB) +{ + ESMatrix tmp; + int i; + + for (i=0; i<4; i++) + { + tmp.m[i][0] = (srcA->m[i][0] * srcB->m[0][0]) + + (srcA->m[i][1] * srcB->m[1][0]) + + (srcA->m[i][2] * srcB->m[2][0]) + + (srcA->m[i][3] * srcB->m[3][0]) ; + + tmp.m[i][1] = (srcA->m[i][0] * srcB->m[0][1]) + + (srcA->m[i][1] * srcB->m[1][1]) + + (srcA->m[i][2] * srcB->m[2][1]) + + (srcA->m[i][3] * srcB->m[3][1]) ; + + tmp.m[i][2] = (srcA->m[i][0] * srcB->m[0][2]) + + (srcA->m[i][1] * srcB->m[1][2]) + + (srcA->m[i][2] * srcB->m[2][2]) + + (srcA->m[i][3] * srcB->m[3][2]) ; + + tmp.m[i][3] = (srcA->m[i][0] * srcB->m[0][3]) + + (srcA->m[i][1] * srcB->m[1][3]) + + (srcA->m[i][2] * srcB->m[2][3]) + + (srcA->m[i][3] * srcB->m[3][3]) ; + } + memcpy(result, &tmp, sizeof(ESMatrix)); +} + +void esRotate(ESMatrix *result, GLfloat angle, GLfloat x, GLfloat y, GLfloat z) +{ + GLfloat sinAngle, cosAngle; + GLfloat mag = sqrtf(x * x + y * y + z * z); + + sinAngle = sinf ( angle * PI / 180.0f ); + cosAngle = cosf ( angle * PI / 180.0f ); + if ( mag > 0.0f ) + { + GLfloat xx, yy, zz, xy, yz, zx, xs, ys, zs; + GLfloat oneMinusCos; + ESMatrix rotMat; + + x /= mag; + y /= mag; + z /= mag; + + xx = x * x; + yy = y * y; + zz = z * z; + xy = x * y; + yz = y * z; + zx = z * x; + xs = x * sinAngle; + ys = y * sinAngle; + zs = z * sinAngle; + oneMinusCos = 1.0f - cosAngle; + + rotMat.m[0][0] = (oneMinusCos * xx) + cosAngle; + rotMat.m[0][1] = (oneMinusCos * xy) - zs; + rotMat.m[0][2] = (oneMinusCos * zx) + ys; + rotMat.m[0][3] = 0.0F; + + rotMat.m[1][0] = (oneMinusCos * xy) + zs; + rotMat.m[1][1] = (oneMinusCos * yy) + cosAngle; + rotMat.m[1][2] = (oneMinusCos * yz) - xs; + rotMat.m[1][3] = 0.0F; + + rotMat.m[2][0] = (oneMinusCos * zx) - ys; + rotMat.m[2][1] = (oneMinusCos * yz) + xs; + rotMat.m[2][2] = (oneMinusCos * zz) + cosAngle; + rotMat.m[2][3] = 0.0F; + + rotMat.m[3][0] = 0.0F; + rotMat.m[3][1] = 0.0F; + rotMat.m[3][2] = 0.0F; + rotMat.m[3][3] = 1.0F; + + esMatrixMultiply( result, &rotMat, result ); + } +} + +void esOrtho(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ) +{ + float deltaX = right - left; + float deltaY = top - bottom; + float deltaZ = farZ - nearZ; + ESMatrix ortho; + + if ( (deltaX == 0.0f) || (deltaY == 0.0f) || (deltaZ == 0.0f) ) + return; + + esMatrixLoadIdentity(&ortho); + ortho.m[0][0] = 2.0f / deltaX; + ortho.m[3][0] = -(right + left) / deltaX; + ortho.m[1][1] = 2.0f / deltaY; + ortho.m[3][1] = -(top + bottom) / deltaY; + ortho.m[2][2] = -2.0f / deltaZ; + ortho.m[3][2] = -(nearZ + farZ) / deltaZ; + + esMatrixMultiply(result, &ortho, result); +} + +/// \brief Load a shader, check for compile errors, print error messages to output log +/// \param type Type of shader (GL_VERTEX_SHADER or GL_FRAGMENT_SHADER) +/// \param shaderSrc Shader source string +/// \return A new shader object on success, 0 on failure +// +GLuint esLoadShader ( GLenum type, const char *shaderSrc ) +{ + GLuint shader; + GLint compiled; + + // Create the shader object + shader = glCreateShader ( type ); + + if ( shader == 0 ) + return 0; + + // Load the shader source + glShaderSource ( shader, 1, &shaderSrc, NULL ); + + // Compile the shader + glCompileShader ( shader ); + + // Check the compile status + glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled ); + + if ( !compiled ) + { + GLint infoLen = 0; + + glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen ); + + if ( infoLen > 1 ) + { + char* infoLog = (char*)malloc (sizeof(char) * infoLen ); + + glGetShaderInfoLog ( shader, infoLen, NULL, infoLog ); + printf ( "Error compiling shader:\n%s\n", infoLog ); + + free ( infoLog ); + } + + glDeleteShader ( shader ); + return 0; + } + + return shader; + +} + + +/// \brief Load a vertex and fragment shader, create a program object, link program. +// Errors output to log. +/// \param vertShaderSrc Vertex shader source code +/// \param fragShaderSrc Fragment shader source code +/// \return A new program object linked with the vertex/fragment shader pair, 0 on failure +// +GLuint esLoadProgram ( const char *vertShaderSrc, const char *fragShaderSrc ) +{ + GLuint vertexShader; + GLuint fragmentShader; + GLuint programObject; + GLint linked; + + // Load the vertex/fragment shaders + vertexShader = esLoadShader ( GL_VERTEX_SHADER, vertShaderSrc ); + if ( vertexShader == 0 ) + return 0; + + fragmentShader = esLoadShader ( GL_FRAGMENT_SHADER, fragShaderSrc ); + if ( fragmentShader == 0 ) + { + glDeleteShader( vertexShader ); + return 0; + } + + // Create the program object + programObject = glCreateProgram ( ); + + if ( programObject == 0 ) + return 0; + + glAttachShader ( programObject, vertexShader ); + glAttachShader ( programObject, fragmentShader ); + + // Link the program + glLinkProgram ( programObject ); + + // Check the link status + glGetProgramiv ( programObject, GL_LINK_STATUS, &linked ); + + if ( !linked ) + { + GLint infoLen = 0; + + glGetProgramiv ( programObject, GL_INFO_LOG_LENGTH, &infoLen ); + + if ( infoLen > 1 ) + { + char* infoLog = (char*)malloc (sizeof(char) * infoLen ); + + glGetProgramInfoLog ( programObject, infoLen, NULL, infoLog ); + printf( "Error linking program:\n%s\n", infoLog ); + + free ( infoLog ); + } + + glDeleteProgram ( programObject ); + return 0; + } + + // Free up no longer needed shader resources + glDeleteShader ( vertexShader ); + glDeleteShader ( fragmentShader ); + + return programObject; +} + +#endif /* GL_ES_VERSION_2_0 || GL_VERSION_2_0*/ void JRenderer::InitRenderer() { @@ -182,17 +672,98 @@ void JRenderer::InitRenderer() #endif mCurrentRenderMode = MODE_UNKNOWN; + + +#if (defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) +#ifdef FORCE_GL2 + g_glslfuncts.load(); +#endif //FORCE_GL2 + + char vShader[] = + "uniform mat4 u_mvp_matrix; \n" + "attribute vec4 a_position; \n" + "attribute vec4 a_color; \n" + "varying vec4 v_color; \n" + "void main() \n" + "{ \n" + " gl_Position = u_mvp_matrix*a_position; \n" + " v_color = a_color; \n" + "} \n"; + char fShader[] = +#ifdef GL_ES_VERSION_2_0 // This line works fine on Windows, but not on Linux and it's required for GL_ES_2... hoh well + "precision mediump float; \n" +#endif //GL_ES_VERSION_2_0 + "varying vec4 v_color; \n" + "void main() \n" + "{ \n" + " gl_FragColor = v_color; \n" + "} \n"; + char vShaderWithTexture[] = + "uniform mat4 u_mvp_matrix; \n" + "attribute vec4 a_position; \n" + "attribute vec2 a_texCoord; \n" + "attribute vec4 a_color; \n" + "varying vec2 v_texCoord; \n" + "varying vec4 v_color; \n" + "void main() \n" + "{ \n" + " gl_Position = u_mvp_matrix*a_position; \n" + " v_texCoord = a_texCoord; \n" + " v_color = a_color; \n" + "} \n"; + char fShaderWithTexture[] = +#ifdef GL_ES_VERSION_2_0 // This line works fine on Windows, but not on Linux and it's required for GL_ES_2... hoh well + "precision mediump float; \n" +#endif //GL_ES_VERSION_2_0 + "varying vec2 v_texCoord; \n" + "varying vec4 v_color; \n" + "uniform sampler2D s_texture; \n" + "void main() \n" + "{ \n" + " vec4 texColor; \n" + " texColor = texture2D(s_texture, v_texCoord); \n" + " gl_FragColor = v_color*texColor; \n" + "} \n"; + + // Load the vertex/fragment shaders + prog1 = esLoadProgram(vShader, fShader); + // Get the attribute locations + prog1_positionLoc = glGetAttribLocation ( prog1, "a_position" ); + prog1_colorLoc = glGetAttribLocation ( prog1, "a_color" ); + // Get the uniform locations + prog1_mvpLoc = glGetUniformLocation( prog1, "u_mvp_matrix" ); + + // Load the vertex/fragment shaders + prog2 = esLoadProgram(vShaderWithTexture, fShaderWithTexture); + // Get the attribute locations + prog2_positionLoc = glGetAttribLocation ( prog2, "a_position" ); + prog2_texCoordLoc = glGetAttribLocation ( prog2, "a_texCoord" ); + prog2_colorLoc = glGetAttribLocation ( prog2, "a_color" ); + // Get the uniform locations + prog2_mvpLoc = glGetUniformLocation( prog2, "u_mvp_matrix" ); + // Get the sampler location + prog2_samplerLoc = glGetUniformLocation ( prog2, "s_texture" ); +#endif //(defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) } void JRenderer::DestroyRenderer() { - +#if (defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) + // Delete program object + glDeleteProgram ( prog1 ); + glDeleteProgram ( prog2 ); +#endif //(defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) } void JRenderer::BeginScene() { glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer - glLoadIdentity (); // Reset The Modelview Matrix +#if (!defined GL_ES_VERSION_2_0) && (!defined GL_VERSION_2_0) + glLoadIdentity (); // Reset The Modelview Matrix +#else + esMatrixLoadIdentity(&theMvpMatrix); + esOrtho(&theMvpMatrix, 0.0f, SCREEN_WIDTH_F, 0.0f, SCREEN_HEIGHT_F-1.0f,-1.0f, 1.0f); +#endif //(!defined GL_ES_VERSION_2_0) && (!defined GL_VERSION_2_0) #ifdef WIN32 float scaleH = (float)actualHeight/SCREEN_HEIGHT_F; float scaleW = (float)actualWidth/SCREEN_WIDTH_F; @@ -212,6 +783,7 @@ void JRenderer::BindTexture(JTexture *tex) if (mCurrentTex != tex->mTexId) { mCurrentTex = tex->mTexId; + glBindTexture(GL_TEXTURE_2D, tex->mTexId); //if (mCurrentTextureFilter != tex->mFilter) @@ -249,7 +821,6 @@ void Swap(float *a, float *b) *b = n; } - void JRenderer::RenderQuad(JQuad* quad, float xo, float yo, float angle, float xScale, float yScale) { //yo = SCREEN_HEIGHT-yo-1;//-(quad->mHeight); @@ -283,10 +854,6 @@ void JRenderer::RenderQuad(JQuad* quad, float xo, float yo, float angle, float x Swap(&uv[1].y, &uv[3].y); } - - //glEnable(GL_BLEND); - //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - BindTexture(quad->mTex); @@ -295,35 +862,133 @@ void JRenderer::RenderQuad(JQuad* quad, float xo, float yo, float angle, float x yo = SCREEN_HEIGHT_F - yo; - glPushMatrix(); - glTranslatef(xo, yo, 0.0f); - glRotatef(-angle*RAD2DEG, 0.0f, 0.0f, 1.0f); - glScalef(xScale, yScale, 1.0f); - glBegin(GL_QUADS); - // bottom left corner - glColor4ub(quad->mColor[0].r, quad->mColor[0].g, quad->mColor[0].b, quad->mColor[0].a); - glTexCoord2f(uv[0].x, uv[0].y); glVertex2f(pt[0].x, pt[0].y); +#if (defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) + ESMatrix mvpMatrix; + memcpy(&mvpMatrix, &theMvpMatrix, sizeof(ESMatrix)); - // bottom right corner - glColor4ub(quad->mColor[1].r, quad->mColor[1].g, quad->mColor[1].b, quad->mColor[1].a); - glTexCoord2f(uv[1].x, uv[1].y); glVertex2f(pt[1].x, pt[1].y); + esTranslate(&mvpMatrix, xo, yo, 0.0f); + esRotate(&mvpMatrix, -angle*RAD2DEG, 0.0f, 0.0f, 1.0f); + esScale(&mvpMatrix, xScale, yScale, 1.0f); - // top right corner - glColor4ub(quad->mColor[2].r, quad->mColor[2].g, quad->mColor[2].b, quad->mColor[2].a); - glTexCoord2f(uv[2].x, uv[2].y); glVertex2f(pt[2].x, pt[2].y); + GLfloat vVertices[] = { + pt[0].x, pt[0].y, 0.0f, + uv[0].x, uv[0].y, + pt[1].x, pt[1].y, 0.0f, + uv[1].x, uv[1].y, + pt[3].x, pt[3].y, 0.0f, + uv[3].x, uv[3].y, + pt[2].x, pt[2].y, 0.0f, + uv[2].x, uv[2].y, + }; - // top left corner - glColor4ub(quad->mColor[3].r, quad->mColor[3].g, quad->mColor[3].b, quad->mColor[3].a); - glTexCoord2f(uv[3].x, uv[3].y); glVertex2f(pt[3].x, pt[3].y); - glEnd(); + GLubyte colorCoords[] = { + quad->mColor[0].r, quad->mColor[0].g, quad->mColor[0].b, quad->mColor[0].a, + quad->mColor[1].r, quad->mColor[1].g, quad->mColor[1].b, quad->mColor[1].a, + quad->mColor[3].r, quad->mColor[3].g, quad->mColor[3].b, quad->mColor[3].a, + quad->mColor[2].r, quad->mColor[2].g, quad->mColor[2].b, quad->mColor[2].a, + }; - glPopMatrix(); + // Use the program object + glUseProgram ( prog2 ); + + // Load the vertex position + glVertexAttribPointer ( prog2_positionLoc, 3, GL_FLOAT, + GL_FALSE, 5 * sizeof(GLfloat), vVertices ); + // Load the texture coordinate + glVertexAttribPointer ( prog2_texCoordLoc, 2, GL_FLOAT, + GL_FALSE, 5 * sizeof(GLfloat), &vVertices[3] ); + // Load the colors + glVertexAttribPointer ( prog2_colorLoc, 4, GL_UNSIGNED_BYTE, + GL_TRUE, 4 * sizeof(GLubyte), colorCoords ); + + glEnableVertexAttribArray ( prog2_positionLoc ); + glEnableVertexAttribArray ( prog2_texCoordLoc ); + glEnableVertexAttribArray ( prog2_colorLoc ); + + // Load the MVP matrix + glUniformMatrix4fv( prog2_mvpLoc, 1, GL_FALSE, (GLfloat*) &mvpMatrix.m[0][0] ); + + // Bind the texture + glActiveTexture ( GL_TEXTURE0 ); + glBindTexture ( GL_TEXTURE_2D, mCurrentTex ); + + // Set the sampler texture unit to 0 + glUniform1i ( prog2_samplerLoc, 0 ); + + //glDrawElements ( GL_TRIANGLE_STRIP, 6, GL_UNSIGNED_SHORT, indices ); + glDrawArrays(GL_TRIANGLE_STRIP,0,4); + +#else + glPushMatrix(); + glTranslatef(xo, yo, 0.0f); + glRotatef(-angle*RAD2DEG, 0.0f, 0.0f, 1.0f); + glScalef(xScale, yScale, 1.0f); + +#if (defined GL_ES_VERSION_1_1) || (defined GL_VERSION_1_1) + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + GLfloat vertCoords[] = { + pt[0].x, pt[0].y, + pt[1].x, pt[1].y, + pt[3].x, pt[3].y, + pt[2].x, pt[2].y, + }; + + GLfloat texCoords[] = { + uv[0].x, uv[0].y, + uv[1].x, uv[1].y, + uv[3].x, uv[3].y, + uv[2].x, uv[2].y, + }; + + GLubyte colorCoords[] = { + quad->mColor[0].r, quad->mColor[0].g, quad->mColor[0].b, quad->mColor[0].a, + quad->mColor[1].r, quad->mColor[1].g, quad->mColor[1].b, quad->mColor[1].a, + quad->mColor[3].r, quad->mColor[3].g, quad->mColor[3].b, quad->mColor[3].a, + quad->mColor[2].r, quad->mColor[2].g, quad->mColor[2].b, quad->mColor[2].a, + }; + + glVertexPointer(2,GL_FLOAT,0,vertCoords); + glTexCoordPointer(2,GL_FLOAT,0, texCoords); + glColorPointer(4, GL_UNSIGNED_BYTE, 0, colorCoords ); + glDrawArrays(GL_TRIANGLE_STRIP,0,4); + + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); +#else + glBegin(GL_QUADS); + + glColor4ub(quad->mColor[0].r, quad->mColor[0].g, quad->mColor[0].b, quad->mColor[0].a); + glTexCoord2f(uv[0].x, uv[0].y); glVertex2f(pt[0].x, pt[0].y); + + // bottom right corner + glColor4ub(quad->mColor[1].r, quad->mColor[1].g, quad->mColor[1].b, quad->mColor[1].a); + glTexCoord2f(uv[1].x, uv[1].y); glVertex2f(pt[1].x, pt[1].y); + + // top right corner + glColor4ub(quad->mColor[2].r, quad->mColor[2].g, quad->mColor[2].b, quad->mColor[2].a); + glTexCoord2f(uv[2].x, uv[2].y); glVertex2f(pt[2].x, pt[2].y); + + // top left corner + glColor4ub(quad->mColor[3].r, quad->mColor[3].g, quad->mColor[3].b, quad->mColor[3].a); + glTexCoord2f(uv[3].x, uv[3].y); glVertex2f(pt[3].x, pt[3].y); + + glEnd(); +#endif //(defined GL_ES_VERSION_1_1) || (defined GL_VERSION_1_1) + + glPopMatrix(); + + //glDisable(GL_BLEND); + + // default color + glColor4ub(255, 255, 255, 255); +#endif //(defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) - //glDisable(GL_BLEND); - // default color - glColor4ub(255, 255, 255, 255); } @@ -344,6 +1009,55 @@ void JRenderer::RenderQuad(JQuad* quad, VertexColor* pt) BindTexture(quad->mTex); +#if (defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) + GLfloat vVertices[] = { + pt[0].x, pt[0].y, 0.0f, + uv[0].x, uv[0].y, + pt[1].x, pt[1].y, 0.0f, + uv[1].x, uv[1].y, + pt[3].x, pt[3].y, 0.0f, + uv[3].x, uv[3].y, + pt[2].x, pt[2].y, 0.0f, + uv[2].x, uv[2].y, + }; + + GLubyte colorCoords[] = { + quad->mColor[0].r, quad->mColor[0].g, quad->mColor[0].b, quad->mColor[0].a, + quad->mColor[1].r, quad->mColor[1].g, quad->mColor[1].b, quad->mColor[1].a, + quad->mColor[3].r, quad->mColor[3].g, quad->mColor[3].b, quad->mColor[3].a, + quad->mColor[2].r, quad->mColor[2].g, quad->mColor[2].b, quad->mColor[2].a, + }; + + // Use the program object + glUseProgram ( prog2 ); + + // Load the vertex position + glVertexAttribPointer ( prog2_positionLoc, 3, GL_FLOAT, + GL_FALSE, 5 * sizeof(GLfloat), vVertices ); + // Load the texture coordinate + glVertexAttribPointer ( prog2_texCoordLoc, 2, GL_FLOAT, + GL_FALSE, 5 * sizeof(GLfloat), &vVertices[3] ); + // Load the colors + glVertexAttribPointer ( prog2_colorLoc, 4, GL_UNSIGNED_BYTE, + GL_TRUE, 4 * sizeof(GLubyte), colorCoords ); + + glEnableVertexAttribArray ( prog2_positionLoc ); + glEnableVertexAttribArray ( prog2_texCoordLoc ); + glEnableVertexAttribArray ( prog2_colorLoc ); + + // Load the MVP matrix + glUniformMatrix4fv( prog2_mvpLoc, 1, GL_FALSE, (GLfloat*) &theMvpMatrix.m[0][0] ); + + // Bind the texture + glActiveTexture ( GL_TEXTURE0 ); + glBindTexture ( GL_TEXTURE_2D, mCurrentTex ); + + // Set the sampler texture unit to 0 + glUniform1i ( prog2_samplerLoc, 0 ); + + //glDrawElements ( GL_TRIANGLE_STRIP, 6, GL_UNSIGNED_SHORT, indices ); + glDrawArrays(GL_TRIANGLE_STRIP,0,4); +#else glRasterPos2f(pt[0].x, pt[0].y); //float w = quad->mWidth; @@ -366,11 +1080,12 @@ void JRenderer::RenderQuad(JQuad* quad, VertexColor* pt) glColor4ub(quad->mColor[3].r, quad->mColor[3].g, quad->mColor[3].b, quad->mColor[3].a); glTexCoord2f(uv[3].x, uv[3].y); glVertex2f(pt[3].x, pt[3].y); glEnd(); + // default color + glColor4ub(255, 255, 255, 255); +#endif //(defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) //glDisable(GL_BLEND); - // default color - glColor4ub(255, 255, 255, 255); } @@ -382,7 +1097,41 @@ void JRenderer::FillRect(float x, float y, float width, float height, PIXEL_TYPE col.color = color; glDisable(GL_TEXTURE_2D); - glColor4ub(col.r, col.g, col.b, col.a); +#if (defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) + GLfloat vVertices[] = { + x, y+height, 0.0f, + x, y, 0.0f, + x+width, y+height, 0.0f, + x+width, y, 0.0f, + }; + + GLubyte colors[] = { + col.r, col.g, col.b, col.a, + col.r, col.g, col.b, col.a, + col.r, col.g, col.b, col.a, + col.r, col.g, col.b, col.a, + }; + + // Use the program object without texture + glUseProgram ( prog1 ); + + // Load the vertex position + glVertexAttribPointer ( prog1_positionLoc, 3, GL_FLOAT, + GL_FALSE, 3 * sizeof(GLfloat), vVertices ); + // Load the color + glVertexAttribPointer(prog1_colorLoc, 4, GL_UNSIGNED_BYTE, + GL_TRUE, 4 * sizeof(GLubyte), colors); + + glEnableVertexAttribArray ( prog1_positionLoc ); + glEnableVertexAttribArray ( prog1_colorLoc ); + + // Load the MVP matrix + glUniformMatrix4fv( prog1_mvpLoc, 1, GL_FALSE, (GLfloat*) &theMvpMatrix.m[0][0] ); + + glDrawArrays(GL_TRIANGLE_STRIP,0,4); +#else + glColor4ub(col.r, col.g, col.b, col.a); + glBegin(GL_QUADS); // top left corner glVertex2f(x, y+height); @@ -397,11 +1146,12 @@ void JRenderer::FillRect(float x, float y, float width, float height, PIXEL_TYPE glVertex2f(x+width, y+height); glEnd(); + // default color + glColor4ub(255, 255, 255, 255); +#endif //(defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) glEnable(GL_TEXTURE_2D); - // default color - glColor4ub(255, 255, 255, 255); } @@ -413,8 +1163,41 @@ void JRenderer::DrawRect(float x, float y, float width, float height, PIXEL_TYPE col.color = color; glDisable(GL_TEXTURE_2D); - glColor4ub(col.r, col.g, col.b, col.a); - glBegin(GL_LINES); +#if (defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) + GLfloat vVertices[] = { + x, y, 0.0f, + x, y+height, 0.0f, + x+width, y+height, 0.0f, + x+width, y, 0.0f, + }; + + GLubyte colors[] = { + col.r, col.g, col.b, col.a, + col.r, col.g, col.b, col.a, + col.r, col.g, col.b, col.a, + col.r, col.g, col.b, col.a, + }; + + // Use the program object without texture + glUseProgram ( prog1 ); + + // Load the vertex position + glVertexAttribPointer ( prog1_positionLoc, 3, GL_FLOAT, + GL_FALSE, 3 * sizeof(GLfloat), vVertices ); + // Load the color + glVertexAttribPointer(prog1_colorLoc, 4, GL_UNSIGNED_BYTE, + GL_TRUE, 4 * sizeof(GLubyte), colors); + + glEnableVertexAttribArray ( prog1_positionLoc ); + glEnableVertexAttribArray ( prog1_colorLoc ); + + // Load the MVP matrix + glUniformMatrix4fv( prog1_mvpLoc, 1, GL_FALSE, (GLfloat*) &theMvpMatrix.m[0][0] ); + + glDrawArrays(GL_LINE_LOOP,0,4); +#else + glColor4ub(col.r, col.g, col.b, col.a); + glBegin(GL_LINES); glVertex2f(x, y); glVertex2f(x, y+height); @@ -430,10 +1213,11 @@ void JRenderer::DrawRect(float x, float y, float width, float height, PIXEL_TYPE glEnd(); - glEnable(GL_TEXTURE_2D); + // default color + glColor4ub(255, 255, 255, 255); +#endif //#if (!defined GL_ES_VERSION_2_0) && (!defined GL_VERSION_2_0) - // default color - glColor4ub(255, 255, 255, 255); + glEnable(GL_TEXTURE_2D); } @@ -452,7 +1236,41 @@ void JRenderer::FillRect(float x, float y, float width, float height, JColor* co y = SCREEN_HEIGHT_F - y - height; glDisable(GL_TEXTURE_2D); - glBegin(GL_QUADS); + +#if (defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) + GLfloat vVertices[] = { + x, y+height, 0.0f, + x, y, 0.0f, + x+width, y+height, 0.0f, + x+width, y, 0.0f, + }; + + GLubyte cols[] = { + colors[0].r, colors[0].g, colors[0].b, colors[0].a, + colors[2].r, colors[2].g, colors[2].b, colors[2].a, + colors[1].r, colors[1].g, colors[1].b, colors[1].a, + colors[3].r, colors[3].g, colors[3].b, colors[3].a, + }; + + // Use the program object without texture + glUseProgram ( prog1 ); + + // Load the vertex position + glVertexAttribPointer ( prog1_positionLoc, 3, GL_FLOAT, + GL_FALSE, 3 * sizeof(GLfloat), vVertices ); + // Load the color + glVertexAttribPointer(prog1_colorLoc, 4, GL_UNSIGNED_BYTE, + GL_TRUE, 4 * sizeof(GLubyte), cols); + + glEnableVertexAttribArray ( prog1_positionLoc ); + glEnableVertexAttribArray ( prog1_colorLoc ); + + // Load the MVP matrix + glUniformMatrix4fv( prog1_mvpLoc, 1, GL_FALSE, (GLfloat*) &theMvpMatrix.m[0][0] ); + + glDrawArrays(GL_TRIANGLE_STRIP,0,4); +#else + glBegin(GL_QUADS); // top left corner glColor4ub(colors[0].r, colors[0].g, colors[0].b, colors[0].a); glVertex2f(x, y+height); @@ -471,12 +1289,12 @@ void JRenderer::FillRect(float x, float y, float width, float height, JColor* co glEnd(); + // default color + glColor4ub(255, 255, 255, 255); +#endif //#if (defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) + glEnable(GL_TEXTURE_2D); - //glDisable(GL_BLEND); - - // default color - glColor4ub(255, 255, 255, 255); } @@ -486,13 +1304,43 @@ void JRenderer::DrawLine(float x1, float y1, float x2, float y2, PIXEL_TYPE colo glDisable(GL_TEXTURE_2D); JColor col; col.color = color; - glColor4ub(col.r, col.g, col.b, col.a); - glBegin(GL_LINES); +#if (defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) + GLfloat vVertices[] = { + x1, SCREEN_HEIGHT_F-y1, 0.0f, + x2, SCREEN_HEIGHT_F-y2, 0.0f, + }; + + GLubyte cols[] = { + col.r, col.g, col.b, col.a, + col.r, col.g, col.b, col.a, + }; + + // Use the program object without texture + glUseProgram ( prog1 ); + + // Load the vertex position + glVertexAttribPointer ( prog1_positionLoc, 3, GL_FLOAT, + GL_FALSE, 3 * sizeof(GLfloat), vVertices ); + // Load the color + glVertexAttribPointer(prog1_colorLoc, 4, GL_UNSIGNED_BYTE, + GL_TRUE, 4 * sizeof(GLubyte), cols); + + glEnableVertexAttribArray ( prog1_positionLoc ); + glEnableVertexAttribArray ( prog1_colorLoc ); + + // Load the MVP matrix + glUniformMatrix4fv( prog1_mvpLoc, 1, GL_FALSE, (GLfloat*) &theMvpMatrix.m[0][0] ); + + glDrawArrays(GL_LINES,0,2); +#else + glColor4ub(col.r, col.g, col.b, col.a); + glBegin(GL_LINES); glVertex2f(x1, SCREEN_HEIGHT_F-y1); glVertex2f(x2, SCREEN_HEIGHT_F-y2); glEnd(); - glEnable(GL_TEXTURE_2D); - glColor4ub(255, 255, 255, 255); + glColor4ub(255, 255, 255, 255); +#endif //#if (!defined GL_ES_VERSION_2_0) && (!defined GL_VERSION_2_0) + glEnable(GL_TEXTURE_2D); } @@ -501,27 +1349,35 @@ void JRenderer::Plot(float x, float y, PIXEL_TYPE color) glDisable(GL_TEXTURE_2D); JColor col; col.color = color; - glColor4ub(col.r, col.g, col.b, col.a); - glBegin(GL_POINTS); +#if (!defined GL_ES_VERSION_2_0) && (!defined GL_VERSION_2_0) + glColor4ub(col.r, col.g, col.b, col.a); + glBegin(GL_POINTS); glVertex2f(x, SCREEN_HEIGHT_F-y); glEnd(); - glEnable(GL_TEXTURE_2D); - glColor4ub(255, 255, 255, 255); + glColor4ub(255, 255, 255, 255); +#else + // FIXME, not used +#endif //#if (!defined GL_ES_VERSION_2_0) && (!defined GL_VERSION_2_0) + glEnable(GL_TEXTURE_2D); } void JRenderer::PlotArray(float *x, float *y, int count, PIXEL_TYPE color) { glDisable(GL_TEXTURE_2D); - JColor col; + JColor col; col.color = color; - glColor4ub(col.r, col.g, col.b, col.a); - glBegin(GL_POINTS); +#if (!defined GL_ES_VERSION_2_0) && (!defined GL_VERSION_2_0) + glColor4ub(col.r, col.g, col.b, col.a); + glBegin(GL_POINTS); for (int i=0;imTexId = texid; + GLenum glError = glGetError(); - if (texid != 0) + if (/*texid*/ glError == 0) { // OpenGL texture has (0,0) at lower-left // Pay attention when doing texture mapping!!! - glBindTexture(GL_TEXTURE_2D, texid); // Bind To The Texture ID - + glBindTexture(GL_TEXTURE_2D, texid); // Bind To The Texture ID +/* NOT USED if (mode == TEX_TYPE_MIPMAP) // generate mipmaps { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_LINEAR); - gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, textureInfo.mTexWidth, textureInfo.mTexHeight, GL_RGBA, GL_UNSIGNED_BYTE, textureInfo.mBits); - } + gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, textureInfo.mTexWidth, textureInfo.mTexHeight, GL_RGBA, GL_UNSIGNED_BYTE, textureInfo.mBits); + } else if (mode == TEX_TYPE_SKYBOX) // for skybox { #define GL_CLAMP_TO_EDGE 0x812F glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, textureInfo.mTexWidth, textureInfo.mTexHeight, GL_RGBA, GL_UNSIGNED_BYTE, textureInfo.mBits); - } + gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, textureInfo.mTexWidth, textureInfo.mTexHeight, GL_RGBA, GL_UNSIGNED_BYTE, textureInfo.mBits); + } else // single texture - { +*/ { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureInfo.mTexWidth, textureInfo.mTexHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureInfo.mBits); - } + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureInfo.mTexWidth, textureInfo.mTexHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureInfo.mBits); + } ret = TRUE; } + else + { + printf("TextureId is 0, GLerror is %u\n", glError); + } } @@ -1154,7 +2017,13 @@ void JRenderer::EnableVSync(bool flag __attribute__((unused))) void JRenderer::ClearScreen(PIXEL_TYPE color) { - FillRect(0.0f, 0.0f, SCREEN_WIDTH_F, SCREEN_HEIGHT_F, color); + JColor col; + col.color = color; + + glClearColor(col.r, col.g, col.b, col.a); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + +// FillRect(0.0f, 0.0f, SCREEN_WIDTH_F, SCREEN_HEIGHT_F, color); } @@ -1198,20 +2067,24 @@ void JRenderer::Enable2D() mCurrentRenderMode = MODE_2D; glViewport (0, 0, (GLsizei)SCREEN_WIDTH, (GLsizei)SCREEN_HEIGHT); // Reset The Current Viewport - glMatrixMode (GL_PROJECTION); // Select The Projection Matrix +#if (!defined GL_ES_VERSION_2_0) && (!defined GL_VERSION_2_0) + glMatrixMode (GL_PROJECTION); // Select The Projection Matrix glLoadIdentity (); // Reset The Projection Matrix gluOrtho2D(0.0f, SCREEN_WIDTH_F, 0.0f, SCREEN_HEIGHT_F-1.0f); glMatrixMode (GL_MODELVIEW); // Select The Modelview Matrix glLoadIdentity (); // Reset The Modelview Matrix +#else + // all the matrix code is in shaders calls +#endif //(!defined GL_ES_VERSION_2_0) && (!defined GL_VERSION_2_0) glDisable (GL_DEPTH_TEST); } void JRenderer::Enable3D() -{ +{ /* NOT USED if (!m3DEnabled) return; @@ -1228,65 +2101,99 @@ void JRenderer::Enable3D() glMatrixMode (GL_MODELVIEW); // Select The Modelview Matrix glLoadIdentity (); // Reset The Modelview Matrix - glEnable (GL_DEPTH_TEST); + glEnable (GL_DEPTH_TEST); */ } void JRenderer::SetClip(int x, int y, int width, int height) -{ - glScissor(x, y, width, height); +{// NOT USED + //glScissor(x, y, width, height); } void JRenderer::LoadIdentity() -{ - glLoadIdentity(); +{// NOT USED + //glLoadIdentity(); } void JRenderer::Translate(float x, float y, float z) -{ - glTranslatef(x, y, z); +{// NOT USED + //glTranslatef(x, y, z); } void JRenderer::RotateX(float angle) -{ - glRotatef(angle*RAD2DEG, 1.0f, 0.0f, 0.0f); +{// NOT USED + //glRotatef(angle*RAD2DEG, 1.0f, 0.0f, 0.0f); } void JRenderer::RotateY(float angle) -{ - glRotatef(angle*RAD2DEG, 0.0f, 1.0f, 0.0f); +{// NOT USED + //glRotatef(angle*RAD2DEG, 0.0f, 1.0f, 0.0f); } void JRenderer::RotateZ(float angle) -{ - glRotatef(angle*RAD2DEG, 0.0f, 0.0f, 1.0f); +{// NOT USED + //glRotatef(angle*RAD2DEG, 0.0f, 0.0f, 1.0f); } void JRenderer::PushMatrix() -{ - glPushMatrix(); +{// NOT USED + //glPushMatrix(); } void JRenderer::PopMatrix() -{ - glPopMatrix(); +{// NOT USED + //glPopMatrix(); } - void JRenderer::RenderTriangles(JTexture* texture, Vertex3D *vertices, int start, int count) { if (texture) BindTexture(texture); - glBegin(GL_TRIANGLES); - int index = start*3; + int index = start*3; +#if (defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) + GLubyte* colorCoords = new GLubyte[count*3*4]; + memset(colorCoords, 255, count*3*4); + + // Use the program object + glUseProgram ( prog2 ); + + // Load the vertex position + glVertexAttribPointer ( prog2_positionLoc, 3, GL_FLOAT, + GL_FALSE, 5 * sizeof(GLfloat), &vertices[index].x ); + // Load the texture coordinate + glVertexAttribPointer ( prog2_texCoordLoc, 2, GL_FLOAT, + GL_FALSE, 5 * sizeof(GLfloat), &vertices[index].u ); + // Load the colors + glVertexAttribPointer ( prog2_colorLoc, 4, GL_UNSIGNED_BYTE, + GL_TRUE, 4 * sizeof(GLubyte), colorCoords ); + + glEnableVertexAttribArray ( prog2_positionLoc ); + glEnableVertexAttribArray ( prog2_texCoordLoc ); + glEnableVertexAttribArray ( prog2_colorLoc ); + + // Load the MVP matrix + glUniformMatrix4fv( prog2_mvpLoc, 1, GL_FALSE, (GLfloat*) &theMvpMatrix.m[0][0] ); + + // Bind the texture + glActiveTexture ( GL_TEXTURE0 ); + glBindTexture ( GL_TEXTURE_2D, mCurrentTex ); + + // Set the sampler texture unit to 0 + glUniform1i ( prog2_samplerLoc, 0 ); + + glDrawArrays(GL_TRIANGLES,0,count*3); + + delete[] colorCoords; +#else + glBegin(GL_TRIANGLES); for (int i = 0; i < count; i++) { glTexCoord2f(vertices[index].u, vertices[index].v); @@ -1306,10 +2213,9 @@ void JRenderer::RenderTriangles(JTexture* texture, Vertex3D *vertices, int start glVertex3f(vertices[index].x, vertices[index].y, vertices[index].z); index++; - } glEnd(); - +#endif //#if (defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) } @@ -1325,20 +2231,62 @@ void JRenderer::FillPolygon(float* x, float* y, int count, PIXEL_TYPE color) col.color = color; glDisable(GL_TEXTURE_2D); - glColor4ub(col.r, col.g, col.b, col.a); - glBegin(GL_TRIANGLE_FAN); +#if (defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) + int i; + GLubyte* colors = new GLubyte[count*4]; + GLfloat* vVertices = new GLfloat[count*3]; + + for(i = 0; i < count; i++) + { + colors[4*i+0]= col.r; + colors[4*i+1]= col.g; + colors[4*i+2]= col.b; + colors[4*i+3]= col.a; + } + + for(i=0; i < count;i++) + { + vVertices[3*i+0] = x[i]; + vVertices[3*i+1] = SCREEN_HEIGHT_F-y[i]; + vVertices[3*i+2] = 0.0f; + } + + // Use the program object without texture + glUseProgram ( prog1 ); + + // Load the vertex position + glVertexAttribPointer ( prog1_positionLoc, 3, GL_FLOAT, + GL_FALSE, 3 * sizeof(GLfloat), vVertices ); + // Load the color + glVertexAttribPointer(prog1_colorLoc, 4, GL_UNSIGNED_BYTE, + GL_TRUE, 4 * sizeof(GLubyte), colors); + + glEnableVertexAttribArray ( prog1_positionLoc ); + glEnableVertexAttribArray ( prog1_colorLoc ); + + // Load the MVP matrix + glUniformMatrix4fv( prog1_mvpLoc, 1, GL_FALSE, (GLfloat*) &theMvpMatrix.m[0][0] ); + + glDrawArrays(GL_TRIANGLE_FAN,0,count); + + delete[] vVertices; + delete[] colors; + +#else + glColor4ub(col.r, col.g, col.b, col.a); + glBegin(GL_TRIANGLE_FAN); for(int i=0; i= 360.0f) + angle -= 360.0f; + } + + // Use the program object without texture + glUseProgram ( prog1 ); + + // Load the vertex position + glVertexAttribPointer ( prog1_positionLoc, 3, GL_FLOAT, + GL_FALSE, 3 * sizeof(GLfloat), vVertices ); + // Load the color + glVertexAttribPointer(prog1_colorLoc, 4, GL_UNSIGNED_BYTE, + GL_TRUE, 4 * sizeof(GLubyte), colors); + + glEnableVertexAttribArray ( prog1_positionLoc ); + glEnableVertexAttribArray ( prog1_colorLoc ); + + // Load the MVP matrix + glUniformMatrix4fv( prog1_mvpLoc, 1, GL_FALSE, (GLfloat*) &theMvpMatrix.m[0][0] ); + + glDrawArrays(GL_LINE_LOOP,0,count); + + delete[] vVertices; + delete[] colors; +#else + glColor4ub(col.r, col.g, col.b, col.a); + glBegin(GL_LINE_LOOP); for(int i=0; i= 360.0f) + angle -= 360.0f; + } + + vVertices[3*(1+count)+0] = x+size*COSF((int)firstAngle); + vVertices[3*(1+count)+1] = SCREEN_HEIGHT_F-y+size*SINF((int)firstAngle); + vVertices[3*(1+count)+2] = 0.0f; + + // Use the program object without texture + glUseProgram ( prog1 ); + + // Load the vertex position + glVertexAttribPointer ( prog1_positionLoc, 3, GL_FLOAT, + GL_FALSE, 3 * sizeof(GLfloat), vVertices ); + // Load the color + glVertexAttribPointer(prog1_colorLoc, 4, GL_UNSIGNED_BYTE, + GL_TRUE, 4 * sizeof(GLubyte), colors); + + glEnableVertexAttribArray ( prog1_positionLoc ); + glEnableVertexAttribArray ( prog1_colorLoc ); + + // Load the MVP matrix + glUniformMatrix4fv( prog1_mvpLoc, 1, GL_FALSE, (GLfloat*) &theMvpMatrix.m[0][0] ); + + glDrawArrays(GL_TRIANGLE_FAN,0,count+2); + + delete[] vVertices; + delete[] colors; +#else + glColor4ub(col.r, col.g, col.b, col.a); + glBegin(GL_TRIANGLE_FAN); glVertex2f(x, SCREEN_HEIGHT_F-y); @@ -1503,13 +2687,13 @@ void JRenderer::FillPolygon(float x, float y, float size, int count, float start glVertex2f(x+size*COSF((int)firstAngle), SCREEN_HEIGHT_F-y+size*SINF((int)firstAngle)); - glEnd(); - glEnable(GL_TEXTURE_2D); + // default color + glColor4ub(255, 255, 255, 255); +#endif //#if (defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) - // default color - glColor4ub(255, 255, 255, 255); + glEnable(GL_TEXTURE_2D); } @@ -1528,8 +2712,100 @@ void JRenderer::DrawRoundRect(float x, float y, float w, float h, float radius, col.color = color; glDisable(GL_TEXTURE_2D); - glColor4ub(col.r, col.g, col.b, col.a); - glBegin(GL_LINE_LOOP); +#if (defined GL_ES_VERSION_2_0) || (defined GL_VERSION_2_0) + int i, index = 1; + int number = 360+2*h+2*w; + GLfloat* vVertices = new GLfloat[3*number]; + GLubyte* colors = new GLubyte[4*number]; + + for(i = 0; i < number; i++) + { + colors[4*i+0]= col.r; + colors[4*i+1]= col.g; + colors[4*i+2]= col.b; + colors[4*i+3]= col.a; + } + + index = 0; + for(i=0; i<90;i++) { + vVertices[3*(index+i)+0] = x+radius*COSF(i); + vVertices[3*(index+i)+1] = SCREEN_HEIGHT_F-y+radius*SINF(i); + vVertices[3*(index+i)+2] = 0.0f; + } + index += 90; + for(i=0; iStopMusic(this); if (mTrack) FSOUND_Sample_Free(mTrack); #endif +#endif } +#ifdef USE_PHONON +void JMusic::seekAtTheBegining() +{ + mMediaObject->seek(0); +} +#endif ////////////////////////////////////////////////////////////////////////// JSample::JSample() +#ifdef USE_PHONON + : mOutput(0), mMediaObject(0) +#endif { } JSample::~JSample() { +#ifdef USE_PHONON + if(mOutput) + delete mOutput; + if(mMediaObject) + delete mMediaObject; +#else #ifdef WITH_FMOD if (mSample) FSOUND_Sample_Free(mSample); #endif +#endif } unsigned long JSample::fileSize() @@ -96,7 +121,9 @@ JSoundSystem::JSoundSystem() { mVolume = 0; mSampleVolume = 0; +#ifdef WITH_FMOD mChannel = FSOUND_FREE; +#endif } JSoundSystem::~JSoundSystem() @@ -121,6 +148,18 @@ void JSoundSystem::DestroySoundSystem() JMusic *JSoundSystem::LoadMusic(const char *fileName) { +#ifdef USE_PHONON + JMusic* music = new JMusic(); + if (music) + { + music->mOutput = new Phonon::AudioOutput(Phonon::GameCategory, 0); + music->mMediaObject = new Phonon::MediaObject(0); + music->mMediaObject->setCurrentSource("Res/" + QString(fileName)); + Phonon::Path path = Phonon::createPath(music->mMediaObject, music->mOutput); + Q_ASSERT(path.isValid()); + } + return music; +#else #ifndef WITH_FMOD return NULL; #else @@ -141,11 +180,24 @@ JMusic *JSoundSystem::LoadMusic(const char *fileName) } return music; #endif +#endif } void JSoundSystem::PlayMusic(JMusic *music, bool looping) { +#ifdef USE_PHONON + if (music && music->mMediaObject && music->mOutput) + { + if(looping) + { + music->mMediaObject->connect(music->mMediaObject, SIGNAL(aboutToFinish()), music, SLOT(seekAtTheBegining())); + } + music->mOutput->setVolume((qreal)mVolume*0.01); + music->mMediaObject->play(); + + } +#else #ifdef WITH_FMOD if (music && music->mTrack) { @@ -158,14 +210,22 @@ void JSoundSystem::PlayMusic(JMusic *music, bool looping) FSOUND_SetLoopMode(mChannel, FSOUND_LOOP_OFF); } #endif +#endif } void JSoundSystem::StopMusic(JMusic *music) { +#ifdef USE_PHONON + if (music && music->mMediaObject && music->mOutput) + { + music->mMediaObject->stop(); + } +#else #ifdef WITH_FMOD FSOUND_StopSound(mChannel); #endif +#endif } @@ -195,6 +255,18 @@ void JSoundSystem::SetSfxVolume(int volume){ JSample *JSoundSystem::LoadSample(const char *fileName) { +#ifdef USE_PHONON + JSample* sample = new JSample(); + if (sample) + { + sample->mOutput = new Phonon::AudioOutput(Phonon::GameCategory, 0); + sample->mMediaObject = new Phonon::MediaObject(0); + sample->mMediaObject->setCurrentSource("Res/" + QString(fileName)); + Phonon::Path path = Phonon::createPath(sample->mMediaObject, sample->mOutput); + Q_ASSERT(path.isValid()); + } + return sample; +#else #ifndef WITH_FMOD return NULL; #else @@ -217,16 +289,25 @@ JSample *JSoundSystem::LoadSample(const char *fileName) } return sample; #endif +#endif } void JSoundSystem::PlaySample(JSample *sample) { +#ifdef USE_PHONON + if (sample && sample->mMediaObject && sample->mOutput) + { + sample->mOutput->setVolume((qreal)mSampleVolume*0.01); + sample->mMediaObject->play(); + } +#else #ifdef WITH_FMOD if (sample && sample->mSample){ int channel = FSOUND_PlaySound(FSOUND_FREE, sample->mSample); FSOUND_SetVolumeAbsolute(channel,mSampleVolume * 2.55); } #endif +#endif } diff --git a/projects/mtg/include/MTGPack.h b/projects/mtg/include/MTGPack.h index d023e94c0..9f22313db 100644 --- a/projects/mtg/include/MTGPack.h +++ b/projects/mtg/include/MTGPack.h @@ -69,7 +69,7 @@ protected: int price; //Base price. int minCards, maxCards; - vector slots; + vector slotss; }; class MTGPacks{ diff --git a/projects/mtg/include/config.h b/projects/mtg/include/config.h index fdcd5b8cc..362f5b1dd 100644 --- a/projects/mtg/include/config.h +++ b/projects/mtg/include/config.h @@ -23,6 +23,10 @@ #define NEW new #endif +#ifdef QT_CONFIG +#include +#define OutputDebugString(val) qDebug(val) +#else #ifdef LINUX #ifdef _DEBUG #define OutputDebugString(val) (std::cerr << val); @@ -30,6 +34,8 @@ #define OutputDebugString(val) {} #endif #endif +#endif + #ifndef RESPATH #define RESPATH "Res" diff --git a/projects/mtg/src/GameStateShop.cpp b/projects/mtg/src/GameStateShop.cpp index d852845bc..ef22e46d3 100644 --- a/projects/mtg/src/GameStateShop.cpp +++ b/projects/mtg/src/GameStateShop.cpp @@ -819,12 +819,15 @@ bool ShopBooster::unitTest(){ u+=ddw->count(c); card++; } + int count = ddw->getCount(); + SAFE_DELETE(ddw); + SAFE_DELETE(d); if(r != 1 || u != 3 ){ sprintf(result, "==Unexpected rarity count==
"); TestSuite::Log(result); res = false; } - if(ddw->getCount() < 14) { + if(count < 14) { sprintf(result, "==Unexpected card count==
"); TestSuite::Log(result); res = false; diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index e5375c158..9f21cb2f3 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -1095,16 +1095,21 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG ab = NEW ABecomes(id,card,target,stypes,pt,sabilities); }return ab; } + //bloodthirst found = s.find("bloodthirst:"); if (found != string::npos){ size_t start = s.find(":",found); size_t end = s.find(" ",start); int amount; - if (end != string::npos){amount = atoi(s.substr(start+1,end-start-1).c_str());} - else{amount = atoi(s.substr(start+1).c_str());} + if (end != string::npos){ + amount = atoi(s.substr(start+1,end-start-1).c_str()); + } else { + amount = atoi(s.substr(start+1).c_str()); + } MTGAbility * a = NEW ABloodThirst(id,card,target,amount); - return a;} + return a; + } diff --git a/projects/mtg/src/MTGPack.cpp b/projects/mtg/src/MTGPack.cpp index 06b47ace2..f343597b2 100644 --- a/projects/mtg/src/MTGPack.cpp +++ b/projects/mtg/src/MTGPack.cpp @@ -93,8 +93,8 @@ int MTGPack::assemblePack(MTGDeck *to){ if(!p) return -1; p->Shuffle(); - for(size_t i=0;iadd(p,to,carryover); + for(size_t i=0;iadd(p,to,carryover); if(carryover > 0) carryover = carryover; //This means we're failing. } @@ -104,8 +104,8 @@ int MTGPack::assemblePack(MTGDeck *to){ void MTGPack::countCards(){ minCards = 0; maxCards = 0; - for(size_t i=0;ientries.size();y++){ @@ -160,7 +160,7 @@ void MTGPack::load(string filename){ std::transform(tag.begin(),tag.end(),tag.begin(),::tolower); if(tag != "slot") continue; MTGPackSlot * s = NEW MTGPackSlot(); - slots.push_back(s); + slotss.push_back(s); holder = pSlot->Attribute("copies"); if(holder) s->copies = atoi(holder); else s->copies = 1; @@ -202,10 +202,10 @@ MTGPackSlot::~MTGPackSlot(){ entries.clear(); } MTGPack::~MTGPack(){ - for(size_t t=0;taddEntry(NEW MTGPackEntryRandom("rarity:mythic;")); for(int i=0;i<7;i++) ps->addEntry(NEW MTGPackEntryRandom("rarity:rare;")); - defaultBooster.slots.push_back(ps); + defaultBooster.slotss.push_back(ps); ps = NEW MTGPackSlot(); ps->copies = 3; ps->addEntry(NEW MTGPackEntryRandom("rarity:uncommon;")); - defaultBooster.slots.push_back(ps); + defaultBooster.slotss.push_back(ps); ps = NEW MTGPackSlot(); ps->copies = 1; ps->addEntry(NEW MTGPackEntryRandom("rarity:land;&type:basic;")); - defaultBooster.slots.push_back(ps); + defaultBooster.slotss.push_back(ps); ps = NEW MTGPackSlot(); ps->copies = 10; ps->addEntry(NEW MTGPackEntryRandom("rarity:common;")); - defaultBooster.slots.push_back(ps); + defaultBooster.slotss.push_back(ps); defaultBooster.bValid = true; defaultBooster.unlockStatus = 1; } diff --git a/projects/mtg/wagic.pro b/projects/mtg/wagic.pro new file mode 100644 index 000000000..b6f481639 --- /dev/null +++ b/projects/mtg/wagic.pro @@ -0,0 +1,321 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2010-06-30T19:48:30 +# +#------------------------------------------------- + +QT += core gui opengl +VERSION = 1.2.3 +TARGET = wagic +TEMPLATE = app +windows:DEFINES += WIN32 +windows:DEFINES += _CRT_SECURE_NO_WARNINGS +windows:DEFINES += FORCE_GL2 +unix:DEFINES += LINUX +DEFINES += QT_CONFIG +maemo5 { +DEFINES += USE_PHONON +QT += phonon +} +windows:INCLUDEPATH += ../../JGE/Dependencies/include +unix:INCLUDEPATH += /usr/include/GL +unix:INCLUDEPATH += /usr/include/freetype2 +INCLUDEPATH += ../../JGE/include +INCLUDEPATH += include + +unix:LIBS += -ljpeg -lgif -lpng12 +windows:LIBS += -LD:\Projects\Wagic\JGE\Dependencies\lib -llibjpeg-static-mt-debug -lgiflib -llibpng -lfmodvc + +# MGT +SOURCES += \ + src/ActionElement.cpp\ + src/ActionLayer.cpp\ + src/ActionStack.cpp\ + src/AIMomirPlayer.cpp\ + src/AIPlayer.cpp\ + src/AIStats.cpp\ + src/CardDescriptor.cpp\ + src/CardDisplay.cpp\ + src/CardEffect.cpp\ + src/CardGui.cpp\ + src/CardPrimitive.cpp\ + src/CardSelector.cpp\ + src/Closest.cpp\ + src/Counters.cpp\ + src/Credits.cpp\ + src/Damage.cpp\ + src/DamagerDamaged.cpp\ + src/DeckDataWrapper.cpp\ + src/DeckMetaData.cpp\ + src/DeckManager.cpp\ + src/DeckStats.cpp\ + src/DuelLayers.cpp\ + src/Effects.cpp\ + src/ExtraCost.cpp\ + src/GameApp.cpp\ + src/GameLauncher.cpp\ + src/GameObserver.cpp\ + src/GameOptions.cpp\ + src/GameStateAwards.cpp\ + src/GameState.cpp\ + src/GameStateDeckViewer.cpp\ + src/GameStateDuel.cpp\ + src/GameStateMenu.cpp\ + src/GameStateOptions.cpp\ + src/GameStateShop.cpp\ + src/GameStateStory.cpp\ + src/GameStateTransitions.cpp\ + src/GuiAvatars.cpp\ + src/GuiBackground.cpp\ + src/GuiCardsController.cpp\ + src/GuiCombat.cpp\ + src/GuiFrame.cpp\ + src/GuiHand.cpp\ + src/GuiLayers.cpp\ + src/GuiMana.cpp\ + src/GuiPhaseBar.cpp\ + src/GuiPlay.cpp\ + src/GuiStatic.cpp\ + src/Logger.cpp\ + src/ManaCost.cpp\ + src/ManaCostHybrid.cpp\ + src/MenuItem.cpp\ + src/MTGAbility.cpp\ + src/MTGCard.cpp\ + src/MTGCardInstance.cpp\ + src/MTGDeck.cpp\ + src/MTGDefinitions.cpp\ + src/MTGGamePhase.cpp\ + src/MTGGameZones.cpp\ + src/MTGPack.cpp\ + src/MTGRules.cpp\ + src/OptionItem.cpp\ + src/PhaseRing.cpp\ + src/Player.cpp\ + src/PlayerData.cpp\ + src/PlayGuiObject.cpp\ + src/PlayGuiObjectController.cpp\ + src/Pos.cpp\ + src/PriceList.cpp\ + src/ReplacementEffects.cpp\ + src/Rules.cpp\ + src/SimpleMenu.cpp\ + src/SimpleMenuItem.cpp\ + src/SimplePad.cpp\ + src/StoryFlow.cpp\ + src/Subtypes.cpp\ + src/StyleManager.cpp\ + src/TargetChooser.cpp\ + src/TargetsList.cpp\ + src/Tasks.cpp\ + src/TestSuiteAI.cpp\ + src/TextScroller.cpp\ + src/ThisDescriptor.cpp\ + src/Token.cpp\ + src/Translate.cpp\ + src/TranslateKeys.cpp\ + src/Trash.cpp\ + src/utils.cpp\ + src/WCachedResource.cpp\ + src/WDataSrc.cpp\ + src/WEvent.cpp\ + src/WFilter.cpp\ + src/WFont.cpp\ + src/WGui.cpp\ + src/WResourceManager.cpp + +HEADERS += \ + include/ExtraCost.h\ + include/ManaCost.h\ + include/SimpleMenuItem.h\ + include/GameApp.h\ + include/ManaCostHybrid.h\ + include/SimplePad.h\ + include/ActionElement.h\ + include/GameObserver.h\ + include/MenuItem.h\ + include/StoryFlow.h\ + include/ActionLayer.h\ + include/GameOptions.h\ + include/MTGAbility.h\ + include/Subtypes.h\ + include/ActionStack.h\ + include/GameStateAwards.h\ + include/MTGCard.h\ + include/AIMomirPlayer.h\ + include/GameStateDeckViewer.h\ + include/MTGCardInstance.h\ + include/Targetable.h\ + include/AIPlayer.h\ + include/GameStateDuel.h\ + include/MTGDeck.h\ + include/TargetChooser.h\ + include/AIStats.h\ + include/GameState.h\ + include/MTGDefinitions.h\ + include/TargetsList.h\ + include/AllAbilities.h\ + include/GameStateMenu.h\ + include/MTGGamePhase.h\ + include/Tasks.h\ + include/CardDescriptor.h\ + include/GameStateOptions.h\ + include/MTGGameZones.h\ + include/TestSuiteAI.h\ + include/CardDisplay.h\ + include/GameStateShop.h\ + include/MTGPack.h\ + include/TextScroller.h\ + include/CardEffect.h\ + include/GameStateStory.h\ + include/MTGRules.h\ + include/ThisDescriptor.h\ + include/CardGui.h\ + include/GameStateTransitions.h\ + include/OptionItem.h\ + include/Token.h\ + include/CardPrimitive.h\ + include/GuiAvatars.h\ + include/OSD.h\ + include/Translate.h\ + include/CardSelector.h\ + include/GuiBackground.h\ + include/PhaseRing.h\ + include/TranslateKeys.h\ + include/config.h\ + include/GuiCardsController.h\ + include/PlayerData.h\ + include/Trash.h\ + include/Counters.h\ + include/GuiCombat.h\ + include/Player.h\ + include/utils.h\ + include/Credits.h\ + include/GuiFrame.h\ + include/PlayGuiObjectController.h\ + include/WCachedResource.h\ + include/Damage.h\ + include/GuiHand.h\ + include/PlayGuiObject.h\ + include/WDataSrc.h\ + include/DamagerDamaged.h\ + include/GuiLayers.h\ + include/Pos.h\ + include/WEvent.h\ + include/DeckDataWrapper.h\ + include/GuiMana.h\ + include/PriceList.h\ + include/WFilter.h\ + include/DeckMetaData.h\ + include/GuiPhaseBar.h\ + include/ReplacementEffects.h\ + include/WGui.h\ + include/DeckStats.h\ + include/GuiPlay.h\ + include/Rules.h\ + include/WResourceManager.h\ + include/DuelLayers.h\ + include/GuiStatic.h\ + include/ShopItem.h\ + include/Effects.h\ + include/Logger.h\ + include/StyleManager.h\ + include/WFont.h\ + include/DeckManager.h\ + include/SimpleMenu.h + +# JGE, could probably be moved outside +SOURCES += \ + ../../JGE/src/Qtmain.cpp\ + ../../JGE/src/Encoding.cpp\ + ../../JGE/src/JAnimator.cpp\ + ../../JGE/src/JApp.cpp\ + ../../JGE/src/JDistortionMesh.cpp\ + ../../JGE/src/JFileSystem.cpp\ + ../../JGE/src/JGameObject.cpp\ + ../../JGE/src/JGBKFont.cpp\ + ../../JGE/src/JGE.cpp\ + ../../JGE/src/JGui.cpp\ + ../../JGE/src/JLBFont.cpp\ + ../../JGE/src/JLogger.cpp\ + ../../JGE/src/JMD2Model.cpp\ + ../../JGE/src/JOBJModel.cpp\ + ../../JGE/src/JParticle.cpp\ + ../../JGE/src/JParticleEffect.cpp\ + ../../JGE/src/JParticleEmitter.cpp\ + ../../JGE/src/JParticleSystem.cpp\ + ../../JGE/src/JResourceManager.cpp\ + ../../JGE/src/JSpline.cpp\ + ../../JGE/src/JSprite.cpp\ + ../../JGE/src/JTTFont.cpp\ + ../../JGE/src/Vector2D.cpp\ + ../../JGE/src/tinyxml/tinystr.cpp\ + ../../JGE/src/tinyxml/tinyxml.cpp\ + ../../JGE/src/tinyxml/tinyxmlerror.cpp\ + ../../JGE/src/tinyxml/tinyxmlparser.cpp\ + ../../JGE/src/hge/hgecolor.cpp\ + ../../JGE/src/hge/hgedistort.cpp\ + ../../JGE/src/hge/hgefont.cpp\ + ../../JGE/src/hge/hgeparticle.cpp\ + ../../JGE/src/hge/hgerect.cpp\ + ../../JGE/src/hge/hgevector.cpp\ + ../../JGE/src/unzip/ioapi.c\ + ../../JGE/src/unzip/mztools.c\ + ../../JGE/src/unzip/unzip.c\ + ../../JGE/src/pc/JSfx.cpp\ + ../../JGE/src/pc/JGfx.cpp + +HEADERS += \ + ../../JGE/include/decoder_prx.h\ + ../../JGE/include/Encoding.h\ + ../../JGE/include/JAnimator.h\ + ../../JGE/include/JApp.h\ + ../../JGE/include/JAssert.h\ + ../../JGE/include/JCooleyesMP3.h\ + ../../JGE/include/JDistortionMesh.h\ + ../../JGE/include/JFileSystem.h\ + ../../JGE/include/JGameLauncher.h\ + ../../JGE/include/JGameObject.h\ + ../../JGE/include/JGBKFont.h\ + ../../JGE/include/JGE.h\ + ../../JGE/include/JGui.h\ + ../../JGE/include/JLBFont.h\ + ../../JGE/include/JLogger.h\ + ../../JGE/include/JMD2Model.h\ + ../../JGE/include/JMP3.h\ + ../../JGE/include/JNetwork.h\ + ../../JGE/include/JOBJModel.h\ + ../../JGE/include/JParticleEffect.h\ + ../../JGE/include/JParticleEmitter.h\ + ../../JGE/include/JParticle.h\ + ../../JGE/include/JParticleSystem.h\ + ../../JGE/include/JRenderer.h\ + ../../JGE/include/JResourceManager.h\ + ../../JGE/include/JSocket.h\ + ../../JGE/include/JSoundSystem.h\ + ../../JGE/include/JSpline.h\ + ../../JGE/include/JSprite.h\ + ../../JGE/include/JTTFont.h\ + ../../JGE/include/JTypes.h\ + ../../JGE/include/Vector2D.h\ + ../../JGE/include/Vector3D.h\ + ../../JGE/include/vram.h\ + ../../JGE/src/tinyxml\tinystr.h\ + ../../JGE/src/tinyxml\tinyxml.h\ + ../../JGE/include/vram.h + +FORMS += + +CONFIG += mobility +MOBILITY = + +symbian { + TARGET.UID3 = 0xe3fa5a9c + # TARGET.CAPABILITY += + TARGET.EPOCSTACKSIZE = 0x14000 + TARGET.EPOCHEAPSIZE = 0x020000 0x800000 +} + +OTHER_FILES += + +RESOURCES +=