Menu

[r760]: / trunk / lispbuilder-sdl / base / surfaces.lisp  Maximize  Restore  History

Download this file

397 lines (359 with data), 15.0 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
;; SDL (Simple Media Layer) library using CFFI for foreign function interfacing...
;; (C)2006 Justin Heyes-Jones <justinhj@gmail.com> and Luke Crook <luke@balooga.com>
;; Thanks to Frank Buss and Surendra Singh
;; see COPYING for license
;; This file contains some useful functions for using SDL from Common lisp
;; using sdl.lisp (the CFFI wrapper)
(in-package #:lispbuilder-sdl-base)
(defmacro with-surface ((var &optional surface (free t))
&body body)
"Don't use this for managing the display surface."
(let ((body-value (gensym "body-value-")))
(if (or surface (atom var))
`(let ((,body-value nil)
(,@(if surface
`(,var ,surface)
`(,var ,var))))
(symbol-macrolet ((w (surf-w ,var))
(h (surf-h ,var)))
(setf ,body-value (progn ,@body)))
(when ,free
(sdl-cffi::sdl-Free-Surface ,var))
,body-value)
(error "VAR must be a symbol or variable, not a function."))))
(defmacro with-surface-slots ((var &optional surface)
&body body)
"Don't use this for managing the display surface."
`(with-surface (,var ,surface nil)
,@body))
;; Taken from CFFI, with-foreign-objects in types.lisp
(defmacro with-surfaces (bindings &rest body)
(if bindings
(return-with-surface bindings body)))
(defun return-with-surface (bindings body)
(if bindings
`(with-surface (,@(car bindings))
,(return-with-surface (cdr bindings) body))
`(progn ,@body)))
(defmacro with-locked-surface ((var &optional surface)
&body body)
(let ((body-value (gensym "body-value-")))
`(let ((,body-value nil))
(with-surface (,var ,surface ,nil)
(unwind-protect
(progn (when (must-lock? ,var)
(when (/= (the fixnum (sdl-cffi::sdl-Lock-Surface ,var)) 0)
(error "Cannot lock surface")))
(setf ,body-value (progn ,@body))
(when (must-lock? ,var)
(Sdl-Cffi::Sdl-Unlock-Surface ,var))))
,body-value))))
(defmacro with-locked-surfaces (bindings &rest body)
(if bindings
(return-with-locked-surface bindings body)))
(defun return-with-locked-surface (bindings body)
(if bindings
`(with-locked-surface (,@(car bindings))
,(return-with-locked-surface (cdr bindings) body))
`(progn ,@body)))
(defmacro with-possible-lock-and-update ((var &key surface template)
&body body)
(let ((body-value (gensym "body-value-")))
`(let ((,body-value nil))
(with-locked-surface (,var ,surface)
(setf ,body-value (progn ,@body)))
(when ,template
(update-surface ,var :template ,template))
,body-value)))
(defun surface-flag (surface flag)
(logand (cffi:foreign-slot-value surface 'sdl-cffi::sdl-surface 'sdl-cffi::flags)
flag))
(defun alpha-enabled-p (surface)
(surface-flag surface sdl-cffi::SDL-SRC-ALPHA))
(defun alpha (surface)
(cffi:foreign-slot-value (pixel-format surface) 'sdl-cffi::sdl-pixel-format 'sdl-cffi::alpha))
(defun color-key-enabled-p (surface)
(surface-flag surface sdl-cffi::SDL-SRC-COLOR-KEY))
(defun color-key (surface)
(cffi:foreign-slot-value (pixel-format surface) 'sdl-cffi::sdl-pixel-format 'sdl-cffi::colorkey))
(defun pixel-alpha-enabled-p (surface)
(cffi:foreign-slot-value (pixel-format surface) 'sdl-cffi::sdl-pixel-format 'sdl-cffi::amask))
(defun rle-accel-enabled-p (surface)
(surface-flag surface sdl-cffi::SDL-RLE-ACCEL))
(defun (setf alpha-enabled-p) (value surface)
(let ((flags (logior (rle-accel-enabled-p surface)
(if value sdl-cffi::SDL-SRC-ALPHA 0))))
(with-foreign-slots ((sdl-cffi::alpha)
(pixel-format surface)
sdl-cffi::SDL-Pixel-Format)
(sdl-cffi::SDL-Set-Alpha surface flags sdl-cffi::alpha))))
(defun (setf alpha) (value surface)
(let ((flags (logior (rle-accel-enabled-p surface)
(alpha-enabled-p surface))))
(sdl-cffi::SDL-Set-Alpha surface flags (clamp (to-int value) 0 255))))
(defun (setf color-key-enabled-p) (value surface)
(let ((flags (logior (rle-accel-enabled-p surface)
(if value sdl-cffi::SDL-SRC-COLOR-KEY 0))))
(with-foreign-slots ((sdl-cffi::colorkey)
(pixel-format surface)
sdl-cffi::SDL-Pixel-Format)
(sdl-cffi::SDL-Set-Color-Key surface flags sdl-cffi::colorkey))))
(defun (setf color-key) (value surface)
(let ((flags (logior (rle-accel-enabled-p surface)
(color-key-enabled-p surface))))
(sdl-cffi::SDL-Set-Color-Key surface flags value)))
(defun (setf rle-accel-enabled-p) (value surface)
(cond
((> (alpha-enabled-p surface) 0)
(let ((flags (logior (if value sdl-cffi::SDL-RLE-ACCEL 0)
(alpha-enabled-p surface))))
(with-foreign-slots ((sdl-cffi::alpha)
(pixel-format surface)
sdl-cffi::SDL-Pixel-Format)
(sdl-cffi::SDL-Set-Alpha surface flags sdl-cffi::alpha))))
((> (color-key-enabled-p surface) 0)
(let ((flags (logior (if value sdl-cffi::SDL-RLE-ACCEL 0)
(color-key-enabled-p surface))))
(with-foreign-slots ((sdl-cffi::colorkey)
(pixel-format surface)
sdl-cffi::SDL-Pixel-Format)
(sdl-cffi::SDL-Set-Color-Key surface flags sdl-cffi::colorkey))))))
;; (defun set-color-key (surface color &optional (enable-color-key nil) (rle-accel nil))
;; "Sets the key color for the given surface. The key color is made transparent."
;; (when (is-valid-ptr surface)
;; (let ((flags 0))
;; (when rle-accel
;; (setf flags (logior sdl-cffi::SDL-RLE-ACCEL flags)))
;; (when enable-color-key
;; (setf flags (logior sdl-cffi::SDL-SRC-COLOR-KEY flags)))
;; (with-foreign-slots ((sdl-cffi::colorkey)
;; (pixel-format surface)
;; sdl-cffi::SDL-Pixel-Format)
;; ;; Unless color is an INTEGER, set it to the
;; ;; current colorkey.
;; (unless (integerp color)
;; (setf color sdl-cffi::colorkey)))
;; (sdl-cffi::SDL-Set-Color-Key surface flags color))
;; surface))
;; (defun set-alpha (surface alpha &optional (source-alpha nil) (rle-accel nil))
;; "Sets the alpha value for the given surface."
;; (when (is-valid-ptr surface)
;; (let ((flags 0))
;; (when rle-accel
;; (setf flags (logior sdl-cffi::SDL-RLE-ACCEL flags)))
;; (when source-alpha
;; (setf flags (logior sdl-cffi::SDL-SRC-ALPHA flags)))
;; (with-foreign-slots ((sdl-cffi::alpha)
;; (pixel-format surface)
;; sdl-cffi::SDL-Pixel-Format)
;; ;; Unless alpha is an INTEGER, set it to the
;; ;; current surface alpha.
;; (unless (integerp alpha)
;; (setf alpha sdl-cffi::alpha)))
;; (sdl-cffi::SDL-Set-Alpha surface flags (clamp (to-int alpha) 0 255)))
;; surface))
(defun get-surface-rect (surface rectangle)
(setf (rect-x rectangle) 0
(rect-y rectangle) 0
(rect-w rectangle) (surf-w surface)
(rect-h rectangle) (surf-h surface))
rectangle)
(defun get-clip-rect (surface rectangle)
(sdl-cffi::sdl-get-clip-rect surface rectangle)
rectangle)
(defun set-clip-rect (surface rectangle)
(sdl-cffi::sdl-set-clip-rect surface rectangle)
rectangle)
(defun convert-surface-to-display-format (surface
&key enable-color-key enable-alpha pixel-alpha (free nil))
"Returns a new surface that has been converted to the display format and optionally free the source surface.
Returns NIL if the surface cannot be converted."
;; LJC: Added support for converting to an alpha surface.
;; LJC: Freeing surface is now optional.
(setf (color-key-enabled-p surface) enable-color-key
(alpha-enabled-p surface) enable-alpha)
(let ((display-surface (if pixel-alpha
(sdl-cffi::SDL-Display-Format-Alpha surface)
(sdl-cffi::SDL-Display-Format surface))))
(unless (is-valid-ptr display-surface)
(error "ERROR, CONVERT-SURFACE-TO-DISPLAY-FORMAT: Cannot convert surface to display format."))
(when free
(sdl-cffi::sdl-Free-Surface surface))
display-surface))
(defun convert-surface (surface to-surface
&key enable-color-key enable-alpha (rle-accel nil) (type :sw) (free nil))
"Returns a new surface of the specified pixel format,
and then copies and maps the given surface to it. Returns NIL if the surface cannot be converted."
(let ((flags nil))
(when enable-color-key
(push sdl-cffi::SDL-SRC-COLOR-KEY flags))
(when enable-alpha
(push sdl-cffi::SDL-SRC-ALPHA flags))
(when rle-accel
(push sdl-cffi::SDL-RLE-ACCEL flags))
(case type
(:sw (push sdl-cffi::SDL-SW-SURFACE flags))
(:hw (push sdl-cffi::SDL-HW-SURFACE flags)))
(let ((surf (sdl-cffi::SDL-convert-surface surface (pixel-format to-surface) flags)))
(unless (is-valid-ptr surf)
(error "ERROR, CONVERT-SURFACE Cannot convert surface to display format."))
(when free
(sdl-cffi::sdl-Free-Surface surface))
surf)))
(defun create-surface (width height
&key (bpp 32) surface (type :sw) enable-color-key pixel-alpha enable-alpha rle-accel pixels pitch)
"create a surface compatible with the supplied :surface, if provided."
(let ((surf nil) (flags nil))
(when enable-color-key
(push sdl-cffi::SDL-SRC-COLOR-KEY flags))
(when enable-alpha
(push sdl-cffi::SDL-SRC-ALPHA flags))
(when rle-accel
(push sdl-cffi::SDL-RLE-ACCEL flags))
(case type
(:sw (push sdl-cffi::SDL-SW-SURFACE flags))
(:hw (push sdl-cffi::SDL-HW-SURFACE flags)))
(if (is-valid-ptr surface)
(with-foreign-slots ((sdl-cffi::BitsPerPixel
sdl-cffi::Rmask
sdl-cffi::Gmask
sdl-cffi::Bmask
sdl-cffi::Amask)
(pixel-format surface)
sdl-cffi::SDL-Pixel-Format)
(setf surf (sdl-cffi::SDL-Create-RGB-Surface (set-flags flags)
width height
sdl-cffi::BitsPerPixel
sdl-cffi::Rmask sdl-cffi::Gmask sdl-cffi::Bmask sdl-cffi::Amask)))
(let ((Rmask 0) (Gmask 0) (Bmask 0) (Amask 0))
;; Set masks according to endianess of machine
;; Little-endian (X86)
#+(or X86 PC386 little-endian)
(progn
(setf rmask #x000000ff
gmask #x0000ff00
bmask #x00ff0000)
(when pixel-alpha
(setf amask #xff000000)))
;; Big-endian (Motorola)
#-(or X86 PC386 little-endian)
(progn
(setf rmask #xff000000
gmask #x00ff0000
bmask #x0000ff00)
(when pixel-alpha
(setf amask #x000000ff)))
(if (and pixels pitch)
;; Pixels not yet supported.
nil
(setf surf (sdl-cffi::SDL-Create-RGB-Surface (set-flags flags)
width height
bpp Rmask Gmask Bmask Amask)))))
surf))
;; cl-sdl "sdl-ext.lisp"
(defun must-lock? (surface)
"Checks if a surface can be locked.
Re-implementation of the SDL_MUSTLOCK macro.
Returns
T if the surface can be locked.
NIL if the surface cannot be locked."
(or (/= 0 (cffi:foreign-slot-value surface 'sdl-cffi::sdl-surface 'sdl-cffi::offset))
(/= 0 (logand (cffi:foreign-slot-value surface 'sdl-cffi::sdl-surface 'sdl-cffi::flags)
(logior sdl-cffi::SDL-HW-SURFACE
sdl-cffi::SDL-ASYNC-BLIT
sdl-cffi::SDL-RLE-ACCEL)))))
(defun pixel-format (surface)
"Returns the pixel format of a surface."
(cffi:foreign-slot-value surface 'sdl-cffi::SDL-Surface 'sdl-cffi::format))
(defun surf-w (surface)
"return the width of the SDL_surface."
(cffi:foreign-slot-value surface 'sdl-cffi::Sdl-Surface 'sdl-cffi::w))
(defun surf-h (surface)
"return the height of the Sdl-Surface."
(cffi:foreign-slot-value surface 'sdl-cffi::Sdl-Surface 'sdl-cffi::h))
(defun clip-to-surface (template surface)
"Clips the rectangle `TEMPLATE` to the surface `SURFACE`s `X`, `Y`, `WIDTH` and `HEIGHT`.
*Note*: `TEMPLATE` is modified."
(let* ((x (rect-x template)) (y (rect-y template))
(w (rect-w template)) (h (rect-h template))
(x2 (+ x w)) (y2 (+ y h)))
(setf (rect-x template) (clamp x 0 (surf-w surface))
(rect-y template) (clamp y 0 (surf-h surface))
(rect-w template) (- (clamp x2 0 (surf-w surface))
(rect-x template))
(rect-h template) (- (clamp y2 0 (surf-h surface))
(rect-y template))))
template)
(defun clip-to-coords (x y w h w-coord h-coord)
"Clips the rectangle `TEMPLATE` to the `X`, `Y`, `WIDTH` and `HEIGHT` coordinates.
*Note*: `TEMPLATE` is modified."
(let ((x2 (+ x w)) (y2 (+ y h)))
(setf x (clamp x 0 w-coord)
y (clamp y 0 h-coord)
w (- (clamp x2 0 w-coord)
x)
h (- (clamp y2 0 h-coord)
y)))
(values x y w h))
(defun update-surface (surface &key template x y w h (clipping t))
"Updates the screen using the keyword co-ordinates in the Vector, :template.
All co-ordinates default to 0, updating the entire screen."
(if template
(progn
(when clipping
(setf template (clip-to-surface template surface)))
(sdl-cffi::SDL-Update-Rect surface (rect-x template) (rect-y template) (rect-w template) (rect-h template)))
(if x
(progn
(when clipping
(multiple-value-bind (clip-x clip-y clip-w clip-h)
(clip-to-coords x y w h (surf-w surface) (surf-h surface))
(sdl-cffi::SDL-Update-Rect surface clip-x clip-y clip-w clip-h))))
(sdl-cffi::SDL-Update-Rect surface 0 0 0 0)))
surface)
(defun blit-surface (src dst src-rect dst-rect &key (update nil))
"Blits the entire SRC Sdl-Surface to the DST Sdl-Surface using SDL_BlitSurface.
use :src-rect SDL_Rect to blit only a portion of the SRC to the DST surface
Use :dst-rect SDL_Rect to position the SRC on the DST surface."
(sdl-cffi::sdl-upper-Blit src src-rect
dst dst-rect)
(when update
(update-surface dst :template dst-rect :clipping t))
dst-rect)
(defun fill-surface (surface color &key (template nil) (update nil) (clipping nil))
"fill the entire surface with the specified RGB/A color.
Use :template to specify the SDL_Rect to be used as the fill template.
Use :update to call SDL_UpdateRect, using :template if provided. This allows for a
'dirty recs' screen update.
*Note*: `TEMPLATE` is clipped to the surface `SURFACE`, when `CLIPPING` is `T`."
(if template
(progn (if clipping
(setf template (clip-to-surface template surface)))
(sdl-cffi::sdl-Fill-Rect surface template color))
(sdl-cffi::sdl-Fill-Rect surface (cffi:null-pointer) color))
(when update
(if template
(update-surface surface
:template template
:clipping nil)
(sdl-cffi::SDL-Update-Rect surface 0 0 0 0)))
template)
(defun map-color (surface r g b &optional a)
(if a
(sdl-cffi::SDL-Map-RGBA (pixel-format surface) r g b a)
(sdl-cffi::SDL-Map-RGB (pixel-format surface) r g b)))
(defun map-pixel (pixel surface &optional a)
(if a
(cffi:with-foreign-objects ((r :uint8) (g :uint8) (b :uint8) (a :uint8))
(sdl-cffi::SDL-Get-RGBA pixel (pixel-format surface) r g b a)
(values
(cffi:mem-aref r :uint8)
(cffi:mem-aref g :uint8)
(cffi:mem-aref b :uint8)
(cffi:mem-aref a :uint8)))
(cffi:with-foreign-objects ((r :uint8) (g :uint8) (b :uint8))
(sdl-cffi::SDL-Get-RGB pixel (pixel-format surface) r g b)
(values
(cffi:mem-aref r :uint8)
(cffi:mem-aref g :uint8)
(cffi:mem-aref b :uint8)))))
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.