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"
42 StateMakerBase
* StateMakerBase::first
= 0;
43 State
* StateMakerBase::current
= 0;
45 int SDL_focus
= SDL_APPACTIVE
| SDL_APPINPUTFOCUS
; // Initial focus state
53 bool tablet_system
= false;
55 char* LoadSaveDialog(bool save
, bool levels
, const char * title
)
58 static char filename
[1025] = "";
59 static char path
[1025] = "C:\\WINDOWS\\Desktop\\New Folder\\Foo\\Levels";
60 char backupPath
[1025];
61 _getcwd(backupPath
, sizeof(backupPath
)/sizeof(backupPath
[0])-1);
63 memset(&f
, 0, sizeof(f
));
65 #define FILTER(desc, f) desc " (" f ")\0" f "\0"
66 f
.lpstrFilter
= FILTER("All known files","*.lev;*.sol")
67 FILTER("Level files","*.lev")
68 FILTER("Solution files","*.sol")
69 FILTER("All files","*.*");
72 f
.lStructSize
= sizeof(f
);
73 f
.lpstrFile
= filename
;
74 f
.nMaxFile
= sizeof(filename
);
75 f
.lpstrInitialDir
= path
;
78 if (GetSaveFileName(&f
)==TRUE
)
80 // Remember user's choice of path!
81 _getcwd(path
, sizeof(path
)/sizeof(path
[0])-1);
85 int i
= strlen(filename
)-1;
86 while (i
>0 && filename
[i
]!='.' && filename
[i
]!='\\' && filename
[i
]!='/') i
--;
87 if (filename
[i
]!='.' && levels
)
88 strcat(filename
, ".lev");
89 if (filename
[i
]!='.' && !levels
)
90 strcat(filename
, ".sol");
100 char* LoadSaveDialog(bool save
, bool levels
, const char * title
)
108 int mouse_buttons
= 0;
109 int mousex
= 10, mousey
= 10;
113 double stylusx
= 0, stylusy
= 0;
115 float styluspressure
= 0;
116 SDL_Surface
* screen
= 0;
117 SDL_Surface
* realScreen
= 0;
118 SDLPango_Context
*context
= 0;
120 extern State
* MakeWorld();
122 bool fullscreen
= false;
127 SDL_GL_SetAttribute( SDL_GL_RED_SIZE
, 5 );
128 SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE
, 5 );
129 SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE
, 5 );
130 SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE
, 16 );
131 SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER
, 1 );
133 // printf("SDL_SetVideoMode (OpenGL)\n");
134 realScreen
= SDL_SetVideoMode(
135 SCREEN_W
, SCREEN_H
, // Width, Height
137 SDL_OPENGL
| (fullscreen
? SDL_FULLSCREEN
: 0) );
139 // printf("SDL_SetVideoMode (non-OpenGL)\n");
140 realScreen
= SDL_SetVideoMode(
141 SCREEN_W
, SCREEN_H
, // Width, Height
143 SDL_SWSURFACE
| SDL_DOUBLEBUF
| (fullscreen
? SDL_FULLSCREEN
: 0) );
147 SDL_FreeSurface(screen
);
149 SDL_Surface
* tempscreen
= SDL_CreateRGBSurface(
152 16, 0xf800, 0x07e0, 0x001f, 0);
154 screen
= SDL_DisplayFormat(tempscreen
);
155 SDL_FreeSurface(tempscreen
);
158 void ToggleFullscreen()
160 fullscreen
= !fullscreen
;
162 StateMakerBase::current
->ScreenModeChanged();
166 /// determine length of longest line with current font (wrapping allowed if text_width != -1)
167 int SDLPangoTextHeight(const std::string
&text_utf8
, int text_width
)
169 // SDLPango_SetMinimumSize limits indeed the maximal size! See
170 // http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=438691
171 SDLPango_SetMinimumSize(context
, text_width
, 0);
172 SDLPango_SetText(context
, text_utf8
.c_str(), -1);
173 return SDLPango_GetLayoutHeight(context
);
176 /** \brief Determine length of longest line with current font
178 * Whether line breaks are allowed or not needs to be set before using
179 * SDLPango_SetMinimumSize!
181 int SDLPangoTextWidth(const std::string
&text_utf8
)
183 SDLPango_SetText(context
, text_utf8
.c_str(), -1);
184 return SDLPango_GetLayoutWidth(context
);
187 /// Display the specified UTF-8 text left aligned at (x,y)
188 void Print_Pango(int x
, int y
, const std::string
&text_utf8
)
190 // Workaround for possible crash, see
191 // http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=439071
192 if (text_utf8
.size() == 0 || text_utf8
.size() == 1 && text_utf8
[0]==127)
194 assert(text_utf8
.find("\n") == std::string::npos
);
195 SDLPango_SetMinimumSize(context
, SCREEN_W
, 0);
196 SDLPango_SetText(context
, text_utf8
.c_str(), -1);
197 SDL_Surface
*surface
= SDLPango_CreateSurfaceDraw(context
);
198 SDL_Rect dst
= {x
, y
, 1, 1};
199 SDL_BlitSurface(surface
, NULL
, screen
, &dst
);
200 SDL_FreeSurface(surface
);
203 /** \brief Display the specified UTF-8 text according to the alignment
205 * If line breaks are already properly set (manually) the will be respected
206 * and no new line breaks will be added. This assumes that th text is not too
209 * \param x the displayed text is horizontally centered around x
210 * \param y the displayed text starts at y
211 * \param width background window size into which the text needs to fit
212 * \param text_utf8 the text to be displayed, in UTF8 encoding
213 * \param align=1: horizontally centered around (x,y)
215 void Print_Pango_Aligned(int x
, int y
, int width
, const std::string
&text_utf8
, int align
)
217 // Workaround for possible crash, see
218 // http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=439071
219 if (text_utf8
.size() == 0 || text_utf8
.size() == 1 && text_utf8
[0]==127)
223 SDLPango_SetMinimumSize(context
, width
, 0);
224 int real_width
= SDLPangoTextWidth(text_utf8
);
225 // Workaround for a crash in SDL Pango, see
226 // http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=439855
227 if (real_width
>width
)
228 SDLPango_SetMinimumSize(context
, real_width
, 0);
230 SDLPango_Alignment alignment
;
232 alignment
= SDLPANGO_ALIGN_LEFT
;
234 alignment
= SDLPANGO_ALIGN_RIGHT
;
237 alignment
= SDLPANGO_ALIGN_CENTER
;
240 // SDLPango_SetText_GivenAlignment is not (yet?) part of the official Pango
241 // distribution, see http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=437865
242 SDLPango_SetText_GivenAlignment(context
, text_utf8
.c_str(), -1, alignment
);
243 SDL_Surface
*surface
= SDLPango_CreateSurfaceDraw(context
);
244 SDL_Rect dst
= {x
, y
, 1, 1};
245 SDL_BlitSurface(surface
, NULL
, screen
, &dst
);
246 SDL_FreeSurface(surface
);
251 static int time
= SDL_GetTicks();
254 int x
= SDL_GetTicks() - time
;
256 if (x
<0) x
= 0, time
= SDL_GetTicks();
262 int main(int argc
, char * argv
[])
265 for (int i
=strlen(base_path
)-1; i
>=0; i
--)
266 if (base_path
[i
]=='/' || base_path
[i
]=='\\')
268 base_path
.truncate(i
+1);
271 // Check the path ends with a directory seperator
272 if (strlen(base_path
)>0)
274 char last
= base_path
[strlen(base_path
)-1];
275 if (last
!='/' && last
!='\\')
279 if (strstr(base_path
, "\\foo2___Win32_Debug\\"))
280 strstr(base_path
, "\\foo2___Win32_Debug\\")[1] = '\0';
281 if (strstr(base_path
, "\\Release\\"))
282 strstr(base_path
, "\\Release\\")[1] = '\0';
284 // printf("SDL_Init\n");
287 // Experimental - create a splash screen window whilst loading
288 SDL_Init(SDL_INIT_VIDEO);
289 screen = SDL_SetVideoMode( 200,200,0,SDL_NOFRAME );
290 SDL_Rect r = {0,0,200,200};
291 SDL_FillRect(screen, &r, SDL_MapRGB(screen->format, 0, 0, 50));
295 SDL_Init(SDL_INIT_EVERYTHING
| SDL_INIT_NOPARACHUTE
);
297 context
= SDLPango_CreateContext_GivenFontDesc("sans-serif bold 12");
298 SDLPango_SetDefaultColor(context
, MATRIX_TRANSPARENT_BACK_WHITE_LETTER
);
299 SDLPango_SetMinimumSize(context
, SCREEN_W
, 0);
301 SDL_Surface
* icon
= SDL_LoadBMP("graphics/icon.bmp");
304 static unsigned int mask
[32] = {
341 for (int i
=0; i
<32; i
++)
342 mask
[i
] = mask
[i
]>>24 | (mask
[i
]>>8)&0xff00 | (mask
[i
]<<8)&0xff0000 | (mask
[i
]<<24)&0xff000000;
343 SDL_WM_SetIcon(icon
, (unsigned char*) mask
);
344 SDL_FreeSurface(icon
);
349 SDL_WarpMouse(SCREEN_W
/2, SCREEN_H
/2);
351 int videoExposed
= 1;
357 bbTabletDevice
&td
= bbTabletDevice::getInstance( );
358 SDL_EventState(SDL_SYSWMEVENT
, SDL_ENABLE
);
361 // printf("Main loop...\n");
363 StateMakerBase::GetNew();
364 int time
= SDL_GetTicks();
369 while(!SDL_PollEvent(&e
) && !quitting
)
373 if ((SDL_focus
& 6)==6)
385 StateMakerBase::current
->Update(x
/ 1000.0);
389 // Not focussed. Try not to eat too much CPU!
395 StateMakerBase::current
->Mouse(mousex
, mousey
, 0, 0, 0, 0, mouse_buttons
);
399 StateMakerBase::current
->Render();
402 SDL_GL_SwapBuffers();
404 if (screen
&& realScreen
!=screen
)
406 SDL_Rect r
= {0,0,SCREEN_W
,SCREEN_H
};
407 SDL_BlitSurface(screen
, &r
, realScreen
, &r
);
409 SDL_Flip(realScreen
);
415 // Tablet ////////////////////////
417 while(hwnd
!=NULL
&& td
.getNextEvent(evt
))
423 GetWindowRect(hwnd
, &r
);
424 stylusx
= evt
.x
* GetSystemMetrics(SM_CXSCREEN
);
425 stylusy
= (1.0 - evt
.y
) * GetSystemMetrics(SM_CYSCREEN
);
426 stylusx
-= (r
.left
+ GetSystemMetrics(SM_CXFIXEDFRAME
));
427 stylusy
-= (r
.top
+ GetSystemMetrics(SM_CYFIXEDFRAME
) + GetSystemMetrics(SM_CYCAPTION
));;
431 GetClientRect(hwnd
, &r
);
432 stylusx
= evt
.x
* r
.right
;
433 stylusy
= (1.0 - evt
.y
) * r
.bottom
;
435 styluspressure
= (evt
.buttons
& 1) ? evt
.pressure
: 0;
438 printf("id=%d csrtype=%d b=%x (%0.3f, %0.3f, %0.3f) p=%0.3f tp=%0.3f\n",
456 case SDL_VIDEOEXPOSE
:
463 SDL_SysWMmsg
* m
= e
.syswm
.msg
;
465 static bool init
=false;
469 DragAcceptFiles(hwnd
, TRUE
);
471 td
.initTablet(hwnd
, tablet_system
? bbTabletDevice::SYSTEM_POINTER
: bbTabletDevice::SEPARATE_POINTER
);
473 printf("No tablet/driver found\n");
476 if (m
->msg
== WM_DROPFILES
)
478 HDROP h
= (HDROP
)m
->wParam
;
481 if (DragQueryFile(h
, 0xffffffff, 0, 0) == 1)
483 DragQueryFile(h
, 0, name
, sizeof(name
)/sizeof(name
[0]));
485 StateMakerBase::current
->FileDrop(name
);
495 case SDL_ACTIVEEVENT
:
497 int gain
= e
.active
.gain
? e
.active
.state
: 0;
498 int loss
= e
.active
.gain
? 0 : e
.active
.state
;
499 SDL_focus
= (SDL_focus
| gain
) & ~loss
;
500 if (gain
& SDL_APPACTIVE
)
501 StateMakerBase::current
->ScreenModeChanged();
502 if (loss
& SDL_APPMOUSEFOCUS
)
504 else if (gain
& SDL_APPMOUSEFOCUS
)
510 case SDL_MOUSEMOTION
:
512 StateMakerBase::current
->Mouse(e
.motion
.x
, e
.motion
.y
, e
.motion
.x
-mousex
, e
.motion
.y
-mousey
, 0, 0, mouse_buttons
);
513 mousex
= e
.motion
.x
; mousey
= e
.motion
.y
;
515 case SDL_MOUSEBUTTONUP
:
517 mouse_buttons
&= ~(1<<(e
.button
.button
-1));
518 StateMakerBase::current
->Mouse(e
.button
.x
, e
.button
.y
, e
.button
.x
-mousex
, e
.button
.y
-mousey
,
519 0, 1<<(e
.button
.button
-1), mouse_buttons
);
520 mousex
= e
.button
.x
; mousey
= e
.button
.y
;
522 case SDL_MOUSEBUTTONDOWN
:
524 mouse_buttons
|= 1<<(e
.button
.button
-1);
525 StateMakerBase::current
->Mouse(e
.button
.x
, e
.button
.y
, e
.button
.x
-mousex
, e
.button
.y
-mousey
,
526 1<<(e
.button
.button
-1), 0, mouse_buttons
);
527 mousex
= e
.button
.x
; mousey
= e
.button
.y
;
531 StateMakerBase::current
->KeyReleased(e
.key
.keysym
.sym
);
536 SDL_KeyboardEvent
& k
= e
.key
;
538 if (k
.keysym
.sym
==SDLK_F4
&& (k
.keysym
.mod
& KMOD_ALT
))
542 else if (k
.keysym
.sym
==SDLK_F12
)
544 // Toggle system pointer controlled by tablet or not
548 tablet_system
= !tablet_system
;
549 td
.setPointerMode(tablet_system
? bbTabletDevice::SYSTEM_POINTER
: bbTabletDevice::SEPARATE_POINTER
);
553 else if (k
.keysym
.sym
==SDLK_RETURN
&& (k
.keysym
.mod
& KMOD_ALT
) && !(k
.keysym
.mod
& KMOD_CTRL
))
557 else if (StateMakerBase::current
->KeyPressed(k
.keysym
.sym
, k
.keysym
.mod
))
560 else if ((k
.keysym
.mod
& (KMOD_ALT
| KMOD_CTRL
))==0)
562 StateMakerBase::GetNew(k
.keysym
.sym
);
573 SDLPango_FreeContext(context
);