2 Copyright (C) 2005-2007 Tom Beaumont
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include <SDL_syswm.h>
26 #include <shellapi.h> // Windows header for drag & drop
28 #include "bbtablet/bbtablet.h"
34 // If included multiple times:
35 // BUG: multiple definition of `MATRIX_WHITE_BACK'
36 // see http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=437517
37 #include "SDL_Pango.h"
46 StateMakerBase
* StateMakerBase::first
= 0;
47 State
* StateMakerBase::current
= 0;
49 int SDL_focus
= SDL_APPACTIVE
| SDL_APPINPUTFOCUS
; // Initial focus state
57 bool tablet_system
= false;
59 char* LoadSaveDialog(bool save
, bool levels
, const char * title
)
62 static char filename
[1025] = "";
63 static char path
[1025] = "C:\\WINDOWS\\Desktop\\New Folder\\Foo\\Levels";
64 char backupPath
[1025];
65 _getcwd(backupPath
, sizeof(backupPath
)/sizeof(backupPath
[0])-1);
67 memset(&f
, 0, sizeof(f
));
69 #define FILTER(desc, f) desc " (" f ")\0" f "\0"
70 f
.lpstrFilter
= FILTER("All known files","*.lev;*.sol")
71 FILTER("Level files","*.lev")
72 FILTER("Solution files","*.sol")
73 FILTER("All files","*.*");
76 f
.lStructSize
= sizeof(f
);
77 f
.lpstrFile
= filename
;
78 f
.nMaxFile
= sizeof(filename
);
79 f
.lpstrInitialDir
= path
;
82 if (GetSaveFileName(&f
)==TRUE
)
84 // Remember user's choice of path!
85 _getcwd(path
, sizeof(path
)/sizeof(path
[0])-1);
89 int i
= strlen(filename
)-1;
90 while (i
>0 && filename
[i
]!='.' && filename
[i
]!='\\' && filename
[i
]!='/') i
--;
91 if (filename
[i
]!='.' && levels
)
92 strcat(filename
, ".lev");
93 if (filename
[i
]!='.' && !levels
)
94 strcat(filename
, ".sol");
104 char* LoadSaveDialog(bool /*save*/, bool /*levels*/, const char * /*title*/)
112 int mouse_buttons
= 0;
113 int mousex
= 10, mousey
= 10;
117 double stylusx
= 0, stylusy
= 0;
119 float styluspressure
= 0;
120 SDL_Surface
* screen
= 0;
121 SDL_Surface
* realScreen
= 0;
122 SDLPango_Context
*context
= 0;
124 extern State
* MakeWorld();
126 bool fullscreen
= false;
131 SDL_GL_SetAttribute( SDL_GL_RED_SIZE
, 5 );
132 SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE
, 5 );
133 SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE
, 5 );
134 SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE
, 16 );
135 SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER
, 1 );
137 // printf("SDL_SetVideoMode (OpenGL)\n");
138 realScreen
= SDL_SetVideoMode(
139 SCREEN_W
, SCREEN_H
, // Width, Height
141 SDL_OPENGL
| (fullscreen
? SDL_FULLSCREEN
: 0) );
143 // printf("SDL_SetVideoMode (non-OpenGL)\n");
144 realScreen
= SDL_SetVideoMode(
145 SCREEN_W
, SCREEN_H
, // Width, Height
147 SDL_SWSURFACE
| SDL_DOUBLEBUF
| (fullscreen
? SDL_FULLSCREEN
: 0) );
151 SDL_FreeSurface(screen
);
153 SDL_Surface
* tempscreen
= SDL_CreateRGBSurface(
156 16, 0xf800, 0x07e0, 0x001f, 0);
158 screen
= SDL_DisplayFormat(tempscreen
);
159 SDL_FreeSurface(tempscreen
);
162 void ToggleFullscreen()
164 fullscreen
= !fullscreen
;
166 StateMakerBase::current
->ScreenModeChanged();
170 /// determine length of longest line with current font (wrapping allowed if text_width != -1)
171 int SDLPangoTextHeight(const std::string
&text_utf8
, int text_width
)
173 // SDLPango_SetMinimumSize limits indeed the maximal size! See
174 // http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=438691
175 SDLPango_SetMinimumSize(context
, text_width
, 0);
176 SDLPango_SetText(context
, text_utf8
.c_str(), -1);
177 return SDLPango_GetLayoutHeight(context
);
180 /** \brief Determine length of longest line with current font
182 * Whether line breaks are allowed or not needs to be set before using
183 * SDLPango_SetMinimumSize!
185 int SDLPangoTextWidth(const std::string
&text_utf8
)
187 SDLPango_SetText(context
, text_utf8
.c_str(), -1);
188 return SDLPango_GetLayoutWidth(context
);
191 /// Display the specified UTF-8 text left aligned at (x,y)
192 void Print_Pango(int x
, int y
, const std::string
&text_utf8
)
194 // Workaround for possible crash, see
195 // http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=439071
196 if (text_utf8
.size() == 0 || text_utf8
.size() == 1 && text_utf8
[0]==127)
198 assert(text_utf8
.find("\n") == std::string::npos
);
199 SDLPango_SetMinimumSize(context
, SCREEN_W
, 0);
200 SDLPango_SetText(context
, text_utf8
.c_str(), -1);
201 SDL_Surface
*surface
= SDLPango_CreateSurfaceDraw(context
);
202 SDL_Rect dst
= {x
, y
, 1, 1};
203 SDL_BlitSurface(surface
, NULL
, screen
, &dst
);
204 SDL_FreeSurface(surface
);
207 /** \brief Display the specified UTF-8 text according to the alignment
209 * If line breaks are already properly set (manually) the will be respected
210 * and no new line breaks will be added. This assumes that th text is not too
213 * \param x the displayed text is horizontally centered around x
214 * \param y the displayed text starts at y
215 * \param width background window size into which the text needs to fit
216 * \param text_utf8 the text to be displayed, in UTF8 encoding
217 * \param align=1: horizontally centered around (x,y)
219 void Print_Pango_Aligned(int x
, int y
, int width
, const std::string
&text_utf8
, int align
)
221 // Workaround for possible crash, see
222 // http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=439071
223 if (text_utf8
.size() == 0 || text_utf8
.size() == 1 && text_utf8
[0]==127)
227 SDLPango_SetMinimumSize(context
, width
, 0);
228 int real_width
= SDLPangoTextWidth(text_utf8
);
229 // Workaround for a crash in SDL Pango, see
230 // http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=439855
231 if (real_width
>width
)
232 SDLPango_SetMinimumSize(context
, real_width
, 0);
234 SDLPango_Alignment alignment
;
236 alignment
= SDLPANGO_ALIGN_LEFT
;
238 alignment
= SDLPANGO_ALIGN_RIGHT
;
241 alignment
= SDLPANGO_ALIGN_CENTER
;
244 // SDLPango_SetText_GivenAlignment is not (yet?) part of the official Pango
245 // distribution, see http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=437865
246 SDLPango_SetText_GivenAlignment(context
, text_utf8
.c_str(), -1, alignment
);
247 SDL_Surface
*surface
= SDLPango_CreateSurfaceDraw(context
);
248 SDL_Rect dst
= {x
, y
, 1, 1};
249 SDL_BlitSurface(surface
, NULL
, screen
, &dst
);
250 SDL_FreeSurface(surface
);
255 static int time
= SDL_GetTicks();
258 int x
= SDL_GetTicks() - time
;
260 if (x
<0) x
= 0, time
= SDL_GetTicks();
266 int main(int /*argc*/, char * /*argv*/[])
268 base_path
= DATA_DIR
"/";
269 for (int i
=strlen(base_path
)-1; i
>=0; i
--)
270 if (base_path
[i
]=='/' || base_path
[i
]=='\\')
272 base_path
.truncate(i
+1);
275 // Check the path ends with a directory seperator
276 if (strlen(base_path
)>0)
278 char last
= base_path
[strlen(base_path
)-1];
279 if (last
!='/' && last
!='\\')
283 if (strstr(base_path
, "\\foo2___Win32_Debug\\"))
284 strstr(base_path
, "\\foo2___Win32_Debug\\")[1] = '\0';
285 if (strstr(base_path
, "\\Release\\"))
286 strstr(base_path
, "\\Release\\")[1] = '\0';
288 // printf("SDL_Init\n");
291 // Experimental - create a splash screen window whilst loading
292 SDL_Init(SDL_INIT_VIDEO);
293 screen = SDL_SetVideoMode( 200,200,0,SDL_NOFRAME );
294 SDL_Rect r = {0,0,200,200};
295 SDL_FillRect(screen, &r, SDL_MapRGB(screen->format, 0, 0, 50));
299 SDL_Init(SDL_INIT_VIDEO
| SDL_INIT_NOPARACHUTE
);
301 context
= SDLPango_CreateContext_GivenFontDesc("sans-serif bold 12");
302 SDLPango_SetDefaultColor(context
, MATRIX_TRANSPARENT_BACK_WHITE_LETTER
);
303 SDLPango_SetMinimumSize(context
, SCREEN_W
, 0);
305 SDL_Surface
* icon
= SDL_LoadBMP("graphics/icon.bmp");
308 static unsigned int mask
[32] = {
345 for (int i
=0; i
<32; i
++)
346 mask
[i
] = mask
[i
]>>24 | (mask
[i
]>>8)&0xff00 | (mask
[i
]<<8)&0xff0000 | (mask
[i
]<<24)&0xff000000;
347 SDL_WM_SetIcon(icon
, (unsigned char*) mask
);
348 SDL_FreeSurface(icon
);
353 SDL_WarpMouse(SCREEN_W
/2, SCREEN_H
/2);
355 int videoExposed
= 1;
361 bbTabletDevice
&td
= bbTabletDevice::getInstance( );
362 SDL_EventState(SDL_SYSWMEVENT
, SDL_ENABLE
);
365 // printf("Main loop...\n");
367 StateMakerBase::GetNew();
372 while(!SDL_PollEvent(&e
) && !quitting
)
376 if ((SDL_focus
& 6)==6)
388 StateMakerBase::current
->Update(x
/ 1000.0);
392 // Not focussed. Try not to eat too much CPU!
398 StateMakerBase::current
->Mouse(mousex
, mousey
, 0, 0, 0, 0, mouse_buttons
);
402 StateMakerBase::current
->Render();
405 SDL_GL_SwapBuffers();
407 if (screen
&& realScreen
!=screen
)
409 SDL_Rect r
= {0,0,SCREEN_W
,SCREEN_H
};
410 SDL_BlitSurface(screen
, &r
, realScreen
, &r
);
412 SDL_Flip(realScreen
);
420 // Tablet ////////////////////////
422 while(hwnd
!=NULL
&& td
.getNextEvent(evt
))
428 GetWindowRect(hwnd
, &r
);
429 stylusx
= evt
.x
* GetSystemMetrics(SM_CXSCREEN
);
430 stylusy
= (1.0 - evt
.y
) * GetSystemMetrics(SM_CYSCREEN
);
431 stylusx
-= (r
.left
+ GetSystemMetrics(SM_CXFIXEDFRAME
));
432 stylusy
-= (r
.top
+ GetSystemMetrics(SM_CYFIXEDFRAME
) + GetSystemMetrics(SM_CYCAPTION
));;
436 GetClientRect(hwnd
, &r
);
437 stylusx
= evt
.x
* r
.right
;
438 stylusy
= (1.0 - evt
.y
) * r
.bottom
;
440 styluspressure
= (evt
.buttons
& 1) ? evt
.pressure
: 0;
443 printf("id=%d csrtype=%d b=%x (%0.3f, %0.3f, %0.3f) p=%0.3f tp=%0.3f\n",
461 case SDL_VIDEOEXPOSE
:
468 SDL_SysWMmsg
* m
= e
.syswm
.msg
;
470 static bool init
=false;
474 DragAcceptFiles(hwnd
, TRUE
);
476 td
.initTablet(hwnd
, tablet_system
? bbTabletDevice::SYSTEM_POINTER
: bbTabletDevice::SEPARATE_POINTER
);
478 printf("No tablet/driver found\n");
481 if (m
->msg
== WM_DROPFILES
)
483 HDROP h
= (HDROP
)m
->wParam
;
486 if (DragQueryFile(h
, 0xffffffff, 0, 0) == 1)
488 DragQueryFile(h
, 0, name
, sizeof(name
)/sizeof(name
[0]));
490 StateMakerBase::current
->FileDrop(name
);
500 case SDL_ACTIVEEVENT
:
502 int gain
= e
.active
.gain
? e
.active
.state
: 0;
503 int loss
= e
.active
.gain
? 0 : e
.active
.state
;
504 SDL_focus
= (SDL_focus
| gain
) & ~loss
;
505 if (gain
& SDL_APPACTIVE
)
506 StateMakerBase::current
->ScreenModeChanged();
507 if (loss
& SDL_APPMOUSEFOCUS
)
509 else if (gain
& SDL_APPMOUSEFOCUS
)
515 case SDL_MOUSEMOTION
:
517 StateMakerBase::current
->Mouse(e
.motion
.x
, e
.motion
.y
, e
.motion
.x
-mousex
, e
.motion
.y
-mousey
, 0, 0, mouse_buttons
);
518 mousex
= e
.motion
.x
; mousey
= e
.motion
.y
;
520 case SDL_MOUSEBUTTONUP
:
522 mouse_buttons
&= ~(1<<(e
.button
.button
-1));
523 StateMakerBase::current
->Mouse(e
.button
.x
, e
.button
.y
, e
.button
.x
-mousex
, e
.button
.y
-mousey
,
524 0, 1<<(e
.button
.button
-1), mouse_buttons
);
525 mousex
= e
.button
.x
; mousey
= e
.button
.y
;
527 case SDL_MOUSEBUTTONDOWN
:
529 mouse_buttons
|= 1<<(e
.button
.button
-1);
530 StateMakerBase::current
->Mouse(e
.button
.x
, e
.button
.y
, e
.button
.x
-mousex
, e
.button
.y
-mousey
,
531 1<<(e
.button
.button
-1), 0, mouse_buttons
);
532 mousex
= e
.button
.x
; mousey
= e
.button
.y
;
536 StateMakerBase::current
->KeyReleased(e
.key
.keysym
.sym
);
541 SDL_KeyboardEvent
& k
= e
.key
;
543 if (k
.keysym
.sym
==SDLK_F4
&& (k
.keysym
.mod
& KMOD_ALT
))
547 else if (k
.keysym
.sym
==SDLK_F12
)
549 // Toggle system pointer controlled by tablet or not
553 tablet_system
= !tablet_system
;
554 td
.setPointerMode(tablet_system
? bbTabletDevice::SYSTEM_POINTER
: bbTabletDevice::SEPARATE_POINTER
);
558 else if (k
.keysym
.sym
==SDLK_RETURN
&& (k
.keysym
.mod
& KMOD_ALT
) && !(k
.keysym
.mod
& KMOD_CTRL
))
562 else if (StateMakerBase::current
->KeyPressed(k
.keysym
.sym
, k
.keysym
.mod
))
565 else if ((k
.keysym
.mod
& (KMOD_ALT
| KMOD_CTRL
))==0)
567 StateMakerBase::GetNew(k
.keysym
.sym
);
578 SDLPango_FreeContext(context
);