1"====================================================================== 2| 3| SdlDisplay wrapper class for libsdl 4| 5| 6 ======================================================================" 7 8 9"====================================================================== 10| 11| Copyright 2008 Free Software Foundation, Inc. 12| Written by Tony Garnock-Jones and Michael Bridgen. 13| 14| This file is part of the GNU Smalltalk class library. 15| 16| The GNU Smalltalk class library is free software; you can redistribute it 17| and/or modify it under the terms of the GNU Lesser General Public License 18| as published by the Free Software Foundation; either version 2.1, or (at 19| your option) any later version. 20| 21| The GNU Smalltalk class library is distributed in the hope that it will be 22| useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 23| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 24| General Public License for more details. 25| 26| You should have received a copy of the GNU Lesser General Public License 27| along with the GNU Smalltalk class library; see the file COPYING.LIB. 28| If not, write to the Free Software Foundation, 59 Temple Place - Suite 29| 330, Boston, MA 02110-1301, USA. 30| 31 ======================================================================" 32 33 34Object subclass: SdlDisplayFormat [ 35 | caption iconCaption extent resizable fullScreen | 36 37 flags [ 38 <category: 'private'> 39 self fullScreen ifTrue: [ ^SdlVideo sdlFullScreen ]. 40 self resizable ifTrue: [ ^SdlVideo sdlResizable ]. 41 ^0 42 ] 43 44 caption [ 45 "Answer the caption of the window when it is not minimized." 46 47 <category: 'accessing'> 48 caption ifNil: [ caption := 'GNU Smalltalk' ]. 49 ^caption 50 ] 51 52 caption: aString [ 53 "Set the caption of the window when it is not minimized." 54 55 <category: 'accessing'> 56 caption := aString. 57 ] 58 59 iconCaption [ 60 "Answer the caption of the window when it is minimized." 61 62 <category: 'accessing'> 63 ^iconCaption ifNil: [ caption ]. 64 ] 65 66 iconCaption: aString [ 67 "Set the caption of the window when it is minimized. A value of nil 68 means the caption will not change when the window is minimized." 69 70 <category: 'accessing'> 71 iconCaption := aString 72 ] 73 74 extent [ 75 "Return the size of the window." 76 77 <category: 'accessing'> 78 extent ifNil: [ extent := 640 @ 480 ]. 79 ^extent 80 ] 81 82 extent: aPoint [ 83 "Set the size of the window." 84 85 <category: 'accessing'> 86 extent := aPoint 87 ] 88 89 fullScreen [ 90 "Answer whether the SDL surface will be full-screen." 91 92 <category: 'accessing'> 93 fullScreen ifNil: [ fullScreen := false ]. 94 ^fullScreen 95 ] 96 97 fullScreen: aBoolean [ 98 "Set whether the SDL surface will be full-screen." 99 100 <category: 'accessing'> 101 fullScreen := aBoolean 102 ] 103 104 resizable [ 105 "Answer whether the SDL surface will be resizable. If it is, the 106 program will have to send the #resize: method to the display when 107 it gets a resize event (the default SdlEventHandler does this)." 108 109 <category: 'accessing'> 110 resizable ifNil: [ resizable := false ]. 111 ^resizable 112 ] 113 114 resizable: aBoolean [ 115 "Set whether the SDL surface will be resizable. If it is, the 116 program will have to send the #resize: method to the display when 117 it gets a resize event (the default SdlEventHandler does this)." 118 119 <category: 'accessing'> 120 resizable := aBoolean 121 ] 122] 123 124Object subclass: SdlDisplay [ 125 <category: 'LibSDL-Wrapper'> 126 <comment: 'I provide an object-oriented wrapper for some SDL_video 127functions. A Display can be connected to an EventSource and be used 128as the destination for a Cairo surface.'> 129 130 | surface flags extent caption iconCaption eventSource | 131 132 CurrentDisplay := nil. 133 DefaultFormat := nil. 134 SdlDisplay class >> current [ 135 "Return the default display, creating one if none exists." 136 137 <category: 'accessing'> 138 "Creating the display will set CurrentDisplay too." 139 CurrentDisplay isNil ifTrue: [ ^self new ]. 140 ^CurrentDisplay 141 ] 142 143 SdlDisplay class >> current: aDisplay [ 144 "Set the default display." 145 146 <category: 'accessing'> 147 CurrentDisplay := aDisplay 148 ] 149 150 SdlDisplay class >> initialize [ 151 "Initialize the class, and initialize SDL when the library is loaded." 152 153 <category: 'initialization'> 154 ObjectMemory addDependent: self. 155 self sdlInit. 156 ] 157 158 SdlDisplay class >> update: aspect [ 159 "Tie the event loop to image quit and restart." 160 161 <category: 'initialization'> 162 aspect == #returnFromSnapshot ifTrue: [ self sdlInit ]. 163 self changed: aspect 164 ] 165 166 SdlDisplay class >> sdlInit [ 167 "Initialize the SDL video subsystem, which is needed to get events." 168 Sdl sdlInit: (Sdl sdlInitVideo bitOr: Sdl sdlInitNoParachute). 169 ] 170 171 SdlDisplay class >> defaultFormat [ 172 "Return the default format of the display, which is also the 173 format used when #current is called and there is no default 174 display." 175 176 <category: 'accessing'> 177 DefaultFormat isNil ifTrue: [ DefaultFormat := SdlDisplayFormat new ]. 178 ^ DefaultFormat 179 ] 180 181 SdlDisplay class >> defaultSize [ 182 "Return the default size of the display, which is also the 183 size used when #current is called and there is no default 184 display." 185 186 <category: 'accessing'> 187 ^ self defaultFormat extent 188 ] 189 190 SdlDisplay class >> defaultFormat: aDisplayFormat [ 191 "Set the default format of the display." 192 193 <category: 'accessing'> 194 DefaultFormat := aDisplayFormat 195 ] 196 197 SdlDisplay class >> defaultSize: aPoint [ 198 "Set the default size of the display." 199 200 <category: 'accessing'> 201 self defaultFormat extent: aPoint 202 ] 203 204 SdlDisplay class >> format: aSdlDisplayFormat [ 205 "Return an SdlDisplay with the given format." 206 207 <category: 'instance creation'> 208 ^self basicNew initialize: aSdlDisplayFormat 209 ] 210 211 SdlDisplay class >> extent: aPoint [ 212 "Return an SdlDisplay with the given width and height." 213 214 <category: 'instance creation'> 215 ^self format: (self defaultFormat copy extent: aPoint; yourself) 216 ] 217 218 SdlDisplay class >> new [ 219 "Return an SdlDisplay with the default width and height." 220 221 <category: 'instance creation'> 222 ^self format: self defaultFormat 223 ] 224 225 sdlSurface [ 226 <category: 'private - accessing'> 227 ^surface 228 ] 229 230 sdlSurface: anSdlSurface [ 231 <category: 'private - accessing'> 232 surface := anSdlSurface 233 ] 234 235 mapRed: r green: g blue: b [ 236 "Return an SDL color index for the given red/green/blue triplet." 237 238 <category: 'drawing-SDL'> 239 ^ SdlVideo sdlMapRGB: surface format value r: r g: g b: b 240 ] 241 242 fillRect: aRect color: aColorNumber [ 243 "Fill a rectangle in the display with the color whose index is in 244 aColorNumber." 245 246 <category: 'drawing-SDL'> 247 | r | 248 r := SDL.SdlRect gcNew. 249 r x value: aRect left. 250 r y value: aRect top. 251 r w value: aRect width. 252 r h value: aRect height. 253 SdlVideo sdlFillRect: surface dstRect: r color: aColorNumber 254 ] 255 256 critical: aBlock [ 257 "Execute aBlock while the surface is locked. This must be 258 called while drawing on the surface directly (e.g. via Cairo)" 259 260 <category: 'drawing-direct'> 261 (SdlVideo sdlLockSurface: surface) == 0 ifFalse: [ 262 self error: 'Could not lock surface ', surface]. 263 ^ aBlock ensure: [SdlVideo sdlUnlockSurface: surface] 264 ] 265 266 extent [ 267 "Return the size of the display." 268 ^ extent 269 ] 270 271 initialize: aFormat [ 272 "Initialize the display by hooking it up to the SdlEventSource." 273 274 <category: 'initialization'> 275 caption := aFormat caption. 276 iconCaption := aFormat iconCaption. 277 extent := aFormat extent. 278 flags := aFormat flags. 279 280 self class addDependent: self. 281 282 "It's our first run - simulate returning from a saved image in 283 order to set up the display window etc." 284 CurrentDisplay isNil ifTrue: [ self class current: self ]. 285 self create 286 ] 287 288 update: aspect [ 289 "Tie the event loop to image quit and restart." 290 291 <category: 'initialization'> 292 aspect == #returnFromSnapshot ifTrue: [ 293 self create. 294 self eventSource handler isNil ifFalse: [ self eventSource startEventLoop ]. 295 self changed: #returnFromSnapshot. 296 ^self]. 297 aspect == #aboutToQuit ifTrue: [ 298 self shutdown. 299 self eventSource interruptEventLoop. 300 ^self]. 301 ] 302 303 shutdown [ 304 self sdlSurface: nil. 305 ] 306 307 eventSource [ 308 "Return the EventSource associated to this display." 309 eventSource isNil ifTrue: [ eventSource := SdlEventSource new ]. 310 ^eventSource 311 ] 312 313 caption [ 314 "Return the caption of the window when it is not minimized." 315 316 <category: 'accessing'> 317 ^caption 318 ] 319 320 iconCaption [ 321 "Return the caption of the window when it is minimized." 322 323 <category: 'accessing'> 324 ^iconCaption 325 ] 326 327 caption: aString [ 328 "Set the caption of the window when it is not minimized." 329 330 <category: 'accessing'> 331 caption := aString. 332 self setCaptions. 333 ] 334 335 iconCaption: aString [ 336 "Set the caption of the window when it is minimized." 337 338 <category: 'accessing'> 339 iconCaption := aString. 340 self setCaptions. 341 ] 342 343 caption: aCaptionString iconCaption: anIconCaptionString [ 344 "Set up the window to use aCaptionString as its caption when it is 345 not minimized, and anIconCaptionString when it is." 346 347 <category: 'accessing'> 348 caption := aCaptionString. 349 iconCaption := anIconCaptionString. 350 self setCaptions. 351 ] 352 353 create [ 354 "Private - Actually create the display. 355 356 TODO: add more accessors to match SDL flags (e.g. fullscreen, double 357 buffer, resizable, h/w surfaces)." 358 359 <category: 'initialization'> 360 | flags screen | 361 screen := SdlVideo sdlSetVideoMode: extent x height: extent y bpp: 32 flags: self flags. 362 self sdlSurface: screen. 363 self setCaptions. 364 ] 365 366 resize: newSize [ 367 "Change the extent of the display to newSize." 368 369 <category: 'resize'> 370 self shutdown. 371 extent := newSize. 372 self create. 373 self changed: #resize 374 ] 375 376 flags [ 377 "Private - Return the SDL_SetVideoMode flags." 378 379 <category: 'private'> 380 ^flags " bitOr: SdlVideo sdlFullScreen." 381 ] 382 383 setCaptions [ 384 "Private - sets captions from my instance variables." 385 386 <category: 'private'> 387 SdlVideo sdlWMSetCaption: self caption icon: self iconCaption. 388 ] 389 390 flip [ 391 "Move the contents of the surface to the screen. Optimized for 392 double-buffered surfaces, but always works." 393 394 <category: 'drawing'> 395 SdlVideo sdlFlip: self sdlSurface. 396 ] 397 398 isGLDisplay [ 399 "Return true if this is an OpenGL display and graphics should be 400 performed using OpenGL calls." 401 402 <category: 'testing'> 403 ^false 404 ] 405 406 updateRectangle: aRect [ 407 "Move the contents of the given rectangle from the surface to the 408 screen." 409 410 <category: 'drawing'> 411 | x y | 412 SdlVideo sdlUpdateRect: self sdlSurface 413 x: (x := aRect left floor) 414 y: (y := aRect top floor) 415 w: aRect right ceiling - x 416 h: aRect height ceiling - y. 417 ] 418 419 updateRectangles: upTo rects: sdlrects [ 420 "Private - Move the contents of the given SdlRect objects from the 421 surface to the screen." 422 423 <category: 'drawing-SDL'> 424 SdlVideo sdlUpdateRects: self sdlSurface 425 numRects: upTo 426 rects: sdlrects. 427 ] 428]. 429 430Eval [ 431 SdlDisplay initialize 432] 433