Mercurial > sdl-ios-xcode
comparison src/video/nds/SDL_ndsrender.c @ 2698:e1da92da346c gsoc2008_nds
Clean up.
author | Darren Alton <dalton@stevens.edu> |
---|---|
date | Wed, 27 Aug 2008 04:23:38 +0000 |
parents | 0b395a60deff |
children |
comparison
equal
deleted
inserted
replaced
2697:c9121b04cffa | 2698:e1da92da346c |
---|---|
32 #include "SDL_video.h" | 32 #include "SDL_video.h" |
33 #include "../SDL_sysvideo.h" | 33 #include "../SDL_sysvideo.h" |
34 #include "../SDL_yuv_sw_c.h" | 34 #include "../SDL_yuv_sw_c.h" |
35 #include "../SDL_renderer_sw.h" | 35 #include "../SDL_renderer_sw.h" |
36 | 36 |
37 #define TRACE | |
38 //#define TRACE printf | |
39 | |
40 /* NDS sprite-related functions */ | 37 /* NDS sprite-related functions */ |
41 #define SPRITE_DMA_CHANNEL 3 | 38 #define SPRITE_DMA_CHANNEL 3 |
42 #define SPRITE_ANGLE_MASK 0x01FF | 39 #define SPRITE_ANGLE_MASK 0x01FF |
43 | 40 |
44 void | 41 void |
45 NDS_OAM_Update(tOAM *oam, int sub) | 42 NDS_OAM_Update(tOAM * oam, int sub) |
46 { | 43 { |
47 DC_FlushAll(); | 44 DC_FlushAll(); |
48 dmaCopyHalfWords(SPRITE_DMA_CHANNEL, oam->spriteBuffer, sub?OAM_SUB:OAM, | 45 dmaCopyHalfWords(SPRITE_DMA_CHANNEL, oam->spriteBuffer, |
49 SPRITE_COUNT * sizeof(SpriteEntry)); | 46 sub ? OAM_SUB : OAM, SPRITE_COUNT * sizeof(SpriteEntry)); |
50 } | 47 } |
51 | 48 |
52 void | 49 void |
53 NDS_OAM_RotateSprite(SpriteRotation *spriteRotation, u16 angle) | 50 NDS_OAM_RotateSprite(SpriteRotation * spriteRotation, u16 angle) |
54 { | 51 { |
55 s16 s = SIN[angle & SPRITE_ANGLE_MASK] >> 4; | 52 s16 s = SIN[angle & SPRITE_ANGLE_MASK] >> 4; |
56 s16 c = COS[angle & SPRITE_ANGLE_MASK] >> 4; | 53 s16 c = COS[angle & SPRITE_ANGLE_MASK] >> 4; |
57 | 54 |
58 spriteRotation->hdx = c; | 55 spriteRotation->hdx = c; |
60 spriteRotation->vdx = -s; | 57 spriteRotation->vdx = -s; |
61 spriteRotation->vdy = c; | 58 spriteRotation->vdy = c; |
62 } | 59 } |
63 | 60 |
64 void | 61 void |
65 NDS_OAM_Init(tOAM *oam, int sub) | 62 NDS_OAM_Init(tOAM * oam, int sub) |
66 { | 63 { |
67 int i; | 64 int i; |
68 for(i = 0; i < SPRITE_COUNT; i++) { | 65 for (i = 0; i < SPRITE_COUNT; i++) { |
69 oam->spriteBuffer[i].attribute[0] = ATTR0_DISABLED; | 66 oam->spriteBuffer[i].attribute[0] = ATTR0_DISABLED; |
70 oam->spriteBuffer[i].attribute[1] = 0; | 67 oam->spriteBuffer[i].attribute[1] = 0; |
71 oam->spriteBuffer[i].attribute[2] = 0; | 68 oam->spriteBuffer[i].attribute[2] = 0; |
72 } | 69 } |
73 for(i = 0; i < MATRIX_COUNT; i++) { | 70 for (i = 0; i < MATRIX_COUNT; i++) { |
74 NDS_OAM_RotateSprite(&(oam->matrixBuffer[i]), 0); | 71 NDS_OAM_RotateSprite(&(oam->matrixBuffer[i]), 0); |
75 } | 72 } |
76 swiWaitForVBlank(); | 73 swiWaitForVBlank(); |
77 NDS_OAM_Update(oam, sub); | 74 NDS_OAM_Update(oam, sub); |
78 } | 75 } |
79 | 76 |
80 void | 77 void |
81 NDS_OAM_HideSprite(SpriteEntry *spriteEntry) | 78 NDS_OAM_HideSprite(SpriteEntry * spriteEntry) |
82 { | 79 { |
83 spriteEntry->isRotoscale = 0; | 80 spriteEntry->isRotoscale = 0; |
84 spriteEntry->isHidden = 1; | 81 spriteEntry->isHidden = 1; |
85 } | 82 } |
86 | 83 |
87 void | 84 void |
88 NDS_OAM_ShowSprite(SpriteEntry *spriteEntry, int affine, int double_bound) | 85 NDS_OAM_ShowSprite(SpriteEntry * spriteEntry, int affine, int double_bound) |
89 { | 86 { |
90 if (affine) { | 87 if (affine) { |
91 spriteEntry->isRotoscale = 1; | 88 spriteEntry->isRotoscale = 1; |
92 spriteEntry->rsDouble = double_bound; | 89 spriteEntry->rsDouble = double_bound; |
93 } else { | 90 } else { |
101 static SDL_Renderer *NDS_CreateRenderer(SDL_Window * window, Uint32 flags); | 98 static SDL_Renderer *NDS_CreateRenderer(SDL_Window * window, Uint32 flags); |
102 static int NDS_ActivateRenderer(SDL_Renderer * renderer); | 99 static int NDS_ActivateRenderer(SDL_Renderer * renderer); |
103 static int NDS_DisplayModeChanged(SDL_Renderer * renderer); | 100 static int NDS_DisplayModeChanged(SDL_Renderer * renderer); |
104 static int NDS_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); | 101 static int NDS_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); |
105 static int NDS_QueryTexturePixels(SDL_Renderer * renderer, | 102 static int NDS_QueryTexturePixels(SDL_Renderer * renderer, |
106 SDL_Texture * texture, void **pixels, | 103 SDL_Texture * texture, void **pixels, |
107 int *pitch); | 104 int *pitch); |
108 static int NDS_SetTexturePalette(SDL_Renderer * renderer, | 105 static int NDS_SetTexturePalette(SDL_Renderer * renderer, |
109 SDL_Texture * texture, | 106 SDL_Texture * texture, |
110 const SDL_Color * colors, int firstcolor, | 107 const SDL_Color * colors, int firstcolor, |
111 int ncolors); | 108 int ncolors); |
112 static int NDS_GetTexturePalette(SDL_Renderer * renderer, | 109 static int NDS_GetTexturePalette(SDL_Renderer * renderer, |
113 SDL_Texture * texture, SDL_Color * colors, | 110 SDL_Texture * texture, SDL_Color * colors, |
114 int firstcolor, int ncolors); | 111 int firstcolor, int ncolors); |
115 static int NDS_SetTextureColorMod(SDL_Renderer * renderer, | 112 static int NDS_SetTextureColorMod(SDL_Renderer * renderer, |
116 SDL_Texture * texture); | 113 SDL_Texture * texture); |
117 static int NDS_SetTextureAlphaMod(SDL_Renderer * renderer, | 114 static int NDS_SetTextureAlphaMod(SDL_Renderer * renderer, |
118 SDL_Texture * texture); | 115 SDL_Texture * texture); |
119 static int NDS_SetTextureBlendMode(SDL_Renderer * renderer, | 116 static int NDS_SetTextureBlendMode(SDL_Renderer * renderer, |
120 SDL_Texture * texture); | 117 SDL_Texture * texture); |
121 static int NDS_SetTextureScaleMode(SDL_Renderer * renderer, | 118 static int NDS_SetTextureScaleMode(SDL_Renderer * renderer, |
122 SDL_Texture * texture); | 119 SDL_Texture * texture); |
123 static int NDS_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, | 120 static int NDS_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, |
124 const SDL_Rect * rect, const void *pixels, | 121 const SDL_Rect * rect, const void *pixels, |
125 int pitch); | 122 int pitch); |
126 static int NDS_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, | 123 static int NDS_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, |
127 const SDL_Rect * rect, int markDirty, void **pixels, | 124 const SDL_Rect * rect, int markDirty, |
128 int *pitch); | 125 void **pixels, int *pitch); |
129 static void NDS_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture); | 126 static void NDS_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture); |
130 static void NDS_DirtyTexture(SDL_Renderer * renderer, | 127 static void NDS_DirtyTexture(SDL_Renderer * renderer, |
131 SDL_Texture * texture, int numrects, | 128 SDL_Texture * texture, int numrects, |
132 const SDL_Rect * rects); | 129 const SDL_Rect * rects); |
133 static int NDS_RenderFill(SDL_Renderer * renderer, Uint8 r, Uint8 g, | 130 static int NDS_RenderFill(SDL_Renderer * renderer, Uint8 r, Uint8 g, |
134 Uint8 b, Uint8 a, const SDL_Rect * rect); | 131 Uint8 b, Uint8 a, const SDL_Rect * rect); |
135 static int NDS_RenderCopy(SDL_Renderer * renderer, | 132 static int NDS_RenderCopy(SDL_Renderer * renderer, |
136 SDL_Texture * texture, | 133 SDL_Texture * texture, |
137 const SDL_Rect * srcrect, | 134 const SDL_Rect * srcrect, const SDL_Rect * dstrect); |
138 const SDL_Rect * dstrect); | |
139 static void NDS_RenderPresent(SDL_Renderer * renderer); | 135 static void NDS_RenderPresent(SDL_Renderer * renderer); |
140 static void NDS_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture); | 136 static void NDS_DestroyTexture(SDL_Renderer * renderer, |
137 SDL_Texture * texture); | |
141 static void NDS_DestroyRenderer(SDL_Renderer * renderer); | 138 static void NDS_DestroyRenderer(SDL_Renderer * renderer); |
142 | 139 |
143 | 140 |
144 SDL_RenderDriver NDS_RenderDriver = { | 141 SDL_RenderDriver NDS_RenderDriver = { |
145 NDS_CreateRenderer, | 142 NDS_CreateRenderer, |
146 { "nds", /* char* name */ | 143 {"nds", /* char* name */ |
147 (SDL_RENDERER_SINGLEBUFFER | | 144 (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTDISCARD | SDL_RENDERER_PRESENTVSYNC), /* u32 flags */ |
148 SDL_RENDERER_ACCELERATED | | 145 (SDL_TEXTUREMODULATE_NONE), /* u32 mod_modes */ |
149 SDL_RENDERER_PRESENTDISCARD | | 146 (SDL_TEXTUREBLENDMODE_MASK), /* u32 blend_modes */ |
150 SDL_RENDERER_PRESENTVSYNC), /* u32 flags */ | 147 (SDL_TEXTURESCALEMODE_FAST), /* u32 scale_modes */ |
151 (SDL_TEXTUREMODULATE_NONE), /* u32 mod_modes */ | 148 3, /* u32 num_texture_formats */ |
152 (SDL_TEXTUREBLENDMODE_MASK), /* u32 blend_modes */ | 149 { |
153 (SDL_TEXTURESCALEMODE_FAST), /* u32 scale_modes */ | 150 SDL_PIXELFORMAT_INDEX8, |
154 3, /* u32 num_texture_formats */ | 151 SDL_PIXELFORMAT_ABGR1555, |
155 { | 152 SDL_PIXELFORMAT_BGR555, |
156 SDL_PIXELFORMAT_INDEX8, | 153 }, /* u32 texture_formats[20] */ |
157 SDL_PIXELFORMAT_ABGR1555, | 154 (256), /* int max_texture_width */ |
158 SDL_PIXELFORMAT_BGR555, | 155 (256), /* int max_texture_height */ |
159 }, /* u32 texture_formats[20] */ | 156 } |
160 (256), /* int max_texture_width */ | |
161 (256), /* int max_texture_height */ | |
162 } | |
163 }; | 157 }; |
164 | 158 |
165 typedef struct | 159 typedef struct |
166 { | 160 { |
167 bg_attribute *bg; /* backgrounds */ | 161 bg_attribute *bg; /* backgrounds */ |
168 tOAM oam_copy; /* sprites */ | 162 tOAM oam_copy; /* sprites */ |
169 u8 bg_taken[4]; | 163 u8 bg_taken[4]; |
170 int sub; | 164 int sub; |
171 } NDS_RenderData; | 165 } NDS_RenderData; |
172 | 166 |
173 typedef struct | 167 typedef struct |
174 { | 168 { |
175 enum { NDSTX_BG, NDSTX_SPR } type; /* represented in a bg or sprite. */ | 169 enum |
176 int hw_index; /* sprite: index in the OAM. / bg: 2 or 3. */ | 170 { NDSTX_BG, NDSTX_SPR } type; /* represented in a bg or sprite. */ |
171 int hw_index; /* sprite: index in the OAM. / bg: 2 or 3. */ | |
177 struct | 172 struct |
178 { | 173 { |
179 int hdx, hdy, vdx, vdy; /* affine transformation, used for scaling. */ | 174 int hdx, hdy, vdx, vdy; /* affine transformation, used for scaling. */ |
180 int pitch, bpp; /* some useful info */ | 175 int pitch, bpp; /* some useful info */ |
181 } dim; | 176 } dim; |
182 u16 *vram_pixels; /* where the pixel data is stored (a pointer into VRAM) */ | 177 u16 *vram_pixels; /* where the pixel data is stored (a pointer into VRAM) */ |
183 u16 *vram_palette; /* where the palette data is stored if it's indexed.*/ | 178 u16 *vram_palette; /* where the palette data is stored if it's indexed. */ |
184 /*int size;*/ | 179 /*int size; */ |
185 } NDS_TextureData; | 180 } NDS_TextureData; |
186 | 181 |
187 | 182 |
188 | 183 |
189 SDL_Renderer * | 184 SDL_Renderer * |
195 NDS_RenderData *data; | 190 NDS_RenderData *data; |
196 int i, n; | 191 int i, n; |
197 int bpp; | 192 int bpp; |
198 Uint32 Rmask, Gmask, Bmask, Amask; | 193 Uint32 Rmask, Gmask, Bmask, Amask; |
199 | 194 |
200 TRACE("+NDS_CreateRenderer\n"); | |
201 if (!SDL_PixelFormatEnumToMasks(displayMode->format, &bpp, | 195 if (!SDL_PixelFormatEnumToMasks(displayMode->format, &bpp, |
202 &Rmask, &Gmask, &Bmask, &Amask)) { | 196 &Rmask, &Gmask, &Bmask, &Amask)) { |
203 SDL_SetError("Unknown display format"); | 197 SDL_SetError("Unknown display format"); |
204 return NULL; | 198 return NULL; |
205 } | 199 } |
206 switch(displayMode->format) { | 200 switch (displayMode->format) { |
207 case SDL_PIXELFORMAT_INDEX8: | 201 case SDL_PIXELFORMAT_INDEX8: |
208 case SDL_PIXELFORMAT_ABGR1555: | 202 case SDL_PIXELFORMAT_ABGR1555: |
209 case SDL_PIXELFORMAT_BGR555: | 203 case SDL_PIXELFORMAT_BGR555: |
210 /* okay */ | 204 /* okay */ |
211 break; | 205 break; |
212 case SDL_PIXELFORMAT_RGB555: | 206 case SDL_PIXELFORMAT_RGB555: |
213 case SDL_PIXELFORMAT_RGB565: | 207 case SDL_PIXELFORMAT_RGB565: |
214 case SDL_PIXELFORMAT_ARGB1555: | 208 case SDL_PIXELFORMAT_ARGB1555: |
215 /* we'll take these too for now */ | 209 /* we'll take these too for now */ |
216 break; | 210 break; |
217 default: | 211 default: |
218 printf("DEBUG: wrong display format!\n"); | 212 SDL_SetError("Warning: wrong display format for NDS!\n"); |
219 break; | 213 break; |
220 } | 214 } |
221 | 215 |
222 renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); | 216 renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); |
223 if (!renderer) { | 217 if (!renderer) { |
224 SDL_OutOfMemory(); | 218 SDL_OutOfMemory(); |
266 renderer->info.max_texture_width = | 260 renderer->info.max_texture_width = |
267 NDS_RenderDriver.info.max_texture_width; | 261 NDS_RenderDriver.info.max_texture_width; |
268 renderer->info.max_texture_height = | 262 renderer->info.max_texture_height = |
269 NDS_RenderDriver.info.max_texture_height; | 263 NDS_RenderDriver.info.max_texture_height; |
270 | 264 |
271 data->sub = 0; /* TODO: this is hard-coded to the "main" screen. | 265 data->sub = 0; /* TODO: this is hard-coded to the "main" screen. |
272 figure out how to detect whether to set it to | 266 figure out how to detect whether to set it to |
273 "sub" screen. window->id, perhaps? */ | 267 "sub" screen. window->id, perhaps? */ |
274 if(!data->sub) { | 268 if (!data->sub) { |
275 data->bg = &BACKGROUND; | 269 data->bg = &BACKGROUND; |
276 } else { | 270 } else { |
277 data->bg = &BACKGROUND_SUB; | 271 data->bg = &BACKGROUND_SUB; |
278 } | 272 } |
279 data->bg_taken[2] = data->bg_taken[3] = 0; | 273 data->bg_taken[2] = data->bg_taken[3] = 0; |
280 | 274 |
281 NDS_OAM_Init(&(data->oam_copy), data->sub); /* init sprites. */ | 275 NDS_OAM_Init(&(data->oam_copy), data->sub); /* init sprites. */ |
282 | 276 |
283 TRACE("-NDS_CreateRenderer\n"); | |
284 return renderer; | 277 return renderer; |
285 } | 278 } |
286 | 279 |
287 static int | 280 static int |
288 NDS_ActivateRenderer(SDL_Renderer * renderer) | 281 NDS_ActivateRenderer(SDL_Renderer * renderer) |
289 { | 282 { |
290 NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata; | 283 NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata; |
291 TRACE("!NDS_ActivateRenderer\n"); | 284 |
292 return 0; | 285 return 0; |
293 } | 286 } |
294 | 287 |
295 static int | 288 static int |
296 NDS_DisplayModeChanged(SDL_Renderer * renderer) | 289 NDS_DisplayModeChanged(SDL_Renderer * renderer) |
297 { | 290 { |
298 NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata; | 291 NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata; |
299 TRACE("!NDS_DisplayModeChanged\n"); | 292 |
300 return 0; | 293 return 0; |
301 } | 294 } |
302 | 295 |
303 static int | 296 static int |
304 NDS_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) | 297 NDS_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) |
307 NDS_TextureData *txdat = NULL; | 300 NDS_TextureData *txdat = NULL; |
308 int i; | 301 int i; |
309 int bpp; | 302 int bpp; |
310 Uint32 Rmask, Gmask, Bmask, Amask; | 303 Uint32 Rmask, Gmask, Bmask, Amask; |
311 | 304 |
312 TRACE("+NDS_CreateTexture\n"); | |
313 if (!SDL_PixelFormatEnumToMasks | 305 if (!SDL_PixelFormatEnumToMasks |
314 (texture->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) { | 306 (texture->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) { |
315 SDL_SetError("Unknown texture format"); | 307 SDL_SetError("Unknown texture format"); |
316 return -1; | 308 return -1; |
317 } | 309 } |
318 | 310 |
319 /* conditional statements on w/h to place it as bg/sprite | 311 /* conditional statements on w/h to place it as bg/sprite |
320 depending on which one it fits. */ | 312 depending on which one it fits. */ |
321 if(texture->w <= 64 && texture->h <= 64) { | 313 if (texture->w <= 64 && texture->h <= 64) { |
322 int whichspr = -1; | 314 int whichspr = -1; |
323 printf("Tried to make a sprite.\n"); | 315 printf("Tried to make a sprite.\n"); |
324 txdat->type = NDSTX_SPR; | 316 txdat->type = NDSTX_SPR; |
325 for(i = 0; i < SPRITE_COUNT; ++i) { | 317 for (i = 0; i < SPRITE_COUNT; ++i) { |
326 if(data->oam_copy.spriteBuffer[i].attribute[0] & ATTR0_DISABLED) { | 318 if (data->oam_copy.spriteBuffer[i].attribute[0] & ATTR0_DISABLED) { |
327 whichspr = i; | 319 whichspr = i; |
328 break; | 320 break; |
329 } | 321 } |
330 } | 322 } |
331 if(whichspr >= 0) { | 323 if (whichspr >= 0) { |
332 SpriteEntry *sprent = &(data->oam_copy.spriteBuffer[whichspr]); | 324 SpriteEntry *sprent = &(data->oam_copy.spriteBuffer[whichspr]); |
333 int maxside = texture->w > texture->h ? texture->w : texture->h; | 325 int maxside = texture->w > texture->h ? texture->w : texture->h; |
334 int pitch; | 326 int pitch; |
335 | 327 |
336 texture->driverdata = SDL_calloc(1, sizeof(NDS_TextureData)); | 328 texture->driverdata = SDL_calloc(1, sizeof(NDS_TextureData)); |
337 txdat = (NDS_TextureData*)texture->driverdata; | 329 txdat = (NDS_TextureData *) texture->driverdata; |
338 if(!txdat) { | 330 if (!txdat) { |
339 SDL_OutOfMemory(); | 331 SDL_OutOfMemory(); |
340 return -1; | 332 return -1; |
341 } | 333 } |
342 | 334 |
343 sprent->objMode = OBJMODE_BITMAP; | 335 sprent->objMode = OBJMODE_BITMAP; |
344 sprent->posX = 0; sprent->posY = 0; | 336 sprent->posX = 0; |
345 sprent->colMode = OBJCOLOR_16; /* OBJCOLOR_256 for INDEX8 */ | 337 sprent->posY = 0; |
338 sprent->colMode = OBJCOLOR_16; /* OBJCOLOR_256 for INDEX8 */ | |
346 | 339 |
347 /* the first 32 sprites get transformation matrices. | 340 /* the first 32 sprites get transformation matrices. |
348 first come, first served */ | 341 first come, first served */ |
349 if(whichspr < MATRIX_COUNT) { | 342 if (whichspr < MATRIX_COUNT) { |
350 sprent->isRotoscale = 1; | 343 sprent->isRotoscale = 1; |
351 sprent->rsMatrixIdx = whichspr; | 344 sprent->rsMatrixIdx = whichspr; |
352 } | 345 } |
353 | 346 |
354 /* containing shape (square or 2:1 rectangles) */ | 347 /* containing shape (square or 2:1 rectangles) */ |
355 sprent->objShape = OBJSHAPE_SQUARE; | 348 sprent->objShape = OBJSHAPE_SQUARE; |
356 if(texture->w/2 >= texture->h) { | 349 if (texture->w / 2 >= texture->h) { |
357 sprent->objShape = OBJSHAPE_WIDE; | 350 sprent->objShape = OBJSHAPE_WIDE; |
358 } else if(texture->h/2 >= texture->w) { | 351 } else if (texture->h / 2 >= texture->w) { |
359 sprent->objShape = OBJSHAPE_TALL; | 352 sprent->objShape = OBJSHAPE_TALL; |
360 } | 353 } |
361 | 354 |
362 /* size in pixels */ | 355 /* size in pixels */ |
363 /* FIXME: "pitch" is hardcoded for 2bytes per pixel. */ | 356 /* FIXME: "pitch" is hardcoded for 2bytes per pixel. */ |
364 sprent->objSize = OBJSIZE_64; | 357 sprent->objSize = OBJSIZE_64; |
365 pitch = 128; | 358 pitch = 128; |
366 if(maxside <= 8) { | 359 if (maxside <= 8) { |
367 sprent->objSize = OBJSIZE_8; | 360 sprent->objSize = OBJSIZE_8; |
368 pitch = 16; | 361 pitch = 16; |
369 } else if(maxside <= 16) { | 362 } else if (maxside <= 16) { |
370 sprent->objSize = OBJSIZE_16; | 363 sprent->objSize = OBJSIZE_16; |
371 pitch = 32; | 364 pitch = 32; |
372 } else if(maxside <= 32) { | 365 } else if (maxside <= 32) { |
373 sprent->objSize = OBJSIZE_32; | 366 sprent->objSize = OBJSIZE_32; |
374 pitch = 64; | 367 pitch = 64; |
375 } | 368 } |
376 | 369 |
377 /* FIXME: this is hard-coded and will obviously only work for one | 370 /* FIXME: this is hard-coded and will obviously only work for one |
380 sprent->tileIdx = 0; | 373 sprent->tileIdx = 0; |
381 | 374 |
382 /* now for the texture data */ | 375 /* now for the texture data */ |
383 txdat->type = NDSTX_SPR; | 376 txdat->type = NDSTX_SPR; |
384 txdat->hw_index = whichspr; | 377 txdat->hw_index = whichspr; |
385 txdat->dim.hdx = 0x100; txdat->dim.hdy = 0; | 378 txdat->dim.hdx = 0x100; |
386 txdat->dim.vdx = 0; txdat->dim.vdy = 0x100; | 379 txdat->dim.hdy = 0; |
380 txdat->dim.vdx = 0; | |
381 txdat->dim.vdy = 0x100; | |
387 txdat->dim.pitch = pitch; | 382 txdat->dim.pitch = pitch; |
388 txdat->dim.bpp = bpp; | 383 txdat->dim.bpp = bpp; |
389 txdat->vram_pixels = (u16*)(data->sub ? | 384 txdat->vram_pixels = (u16 *) (data->sub ? SPRITE_GFX_SUB : SPRITE_GFX); /* FIXME: use tileIdx*boundary |
390 SPRITE_GFX_SUB : SPRITE_GFX); /* FIXME: use tileIdx*boundary | 385 to point to proper location */ |
391 to point to proper location */ | |
392 } else { | 386 } else { |
393 SDL_SetError("Out of NDS sprites."); | 387 SDL_SetError("Out of NDS sprites."); |
394 } | 388 } |
395 } else if(texture->w <= 256 && texture->h <= 256) { | 389 } else if (texture->w <= 256 && texture->h <= 256) { |
396 int whichbg = -1, base = 0; | 390 int whichbg = -1, base = 0; |
397 if(!data->bg_taken[2]) { | 391 if (!data->bg_taken[2]) { |
398 whichbg = 2; | 392 whichbg = 2; |
399 } else if(!data->bg_taken[3]) { | 393 } else if (!data->bg_taken[3]) { |
400 whichbg = 3; | 394 whichbg = 3; |
401 base = 4; | 395 base = 4; |
402 } | 396 } |
403 if(whichbg >= 0) { | 397 if (whichbg >= 0) { |
404 texture->driverdata = SDL_calloc(1, sizeof(NDS_TextureData)); | 398 texture->driverdata = SDL_calloc(1, sizeof(NDS_TextureData)); |
405 txdat = (NDS_TextureData*)texture->driverdata; | 399 txdat = (NDS_TextureData *) texture->driverdata; |
406 if(!txdat) { | 400 if (!txdat) { |
407 SDL_OutOfMemory(); | 401 SDL_OutOfMemory(); |
408 return -1; | 402 return -1; |
409 } | 403 } |
410 | 404 |
411 /* this is hard-coded to being 256x256 ABGR1555 for now. */ | 405 /* this is hard-coded to being 256x256 ABGR1555 for now. */ |
417 data->bg->scroll[whichbg].x = 0; | 411 data->bg->scroll[whichbg].x = 0; |
418 data->bg->scroll[whichbg].y = 0; | 412 data->bg->scroll[whichbg].y = 0; |
419 | 413 |
420 txdat->type = NDSTX_BG; | 414 txdat->type = NDSTX_BG; |
421 txdat->hw_index = whichbg; | 415 txdat->hw_index = whichbg; |
422 txdat->dim.hdx = 0x100; txdat->dim.hdy = 0; | 416 txdat->dim.hdx = 0x100; |
423 txdat->dim.vdx = 0; txdat->dim.vdy = 0x100; | 417 txdat->dim.hdy = 0; |
418 txdat->dim.vdx = 0; | |
419 txdat->dim.vdy = 0x100; | |
424 txdat->dim.pitch = 512; | 420 txdat->dim.pitch = 512; |
425 txdat->dim.bpp = bpp; | 421 txdat->dim.bpp = bpp; |
426 txdat->vram_pixels = (u16*)(data->sub ? | 422 txdat->vram_pixels = (u16 *) (data->sub ? |
427 BG_BMP_RAM_SUB(base) : BG_BMP_RAM(base)); | 423 BG_BMP_RAM_SUB(base) : |
428 | 424 BG_BMP_RAM(base)); |
429 /*txdat->size = txdat->dim.pitch * texture->h;*/ | 425 |
426 /*txdat->size = txdat->dim.pitch * texture->h; */ | |
430 } else { | 427 } else { |
431 SDL_SetError("Out of NDS backgrounds."); | 428 SDL_SetError("Out of NDS backgrounds."); |
432 } | 429 } |
433 } else { | 430 } else { |
434 SDL_SetError("Texture too big for NDS hardware."); | 431 SDL_SetError("Texture too big for NDS hardware."); |
435 } | 432 } |
436 | 433 |
437 TRACE("-NDS_CreateTexture\n"); | |
438 if (!texture->driverdata) { | 434 if (!texture->driverdata) { |
439 return -1; | 435 return -1; |
440 } | 436 } |
441 | 437 |
442 return 0; | 438 return 0; |
443 } | 439 } |
444 | 440 |
445 static int | 441 static int |
446 NDS_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture, | 442 NDS_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture, |
447 void **pixels, int *pitch) | 443 void **pixels, int *pitch) |
448 { | 444 { |
449 NDS_TextureData *txdat = (NDS_TextureData *) texture->driverdata; | 445 NDS_TextureData *txdat = (NDS_TextureData *) texture->driverdata; |
450 TRACE("+NDS_QueryTexturePixels\n"); | |
451 *pixels = txdat->vram_pixels; | 446 *pixels = txdat->vram_pixels; |
452 *pitch = txdat->dim.pitch; | 447 *pitch = txdat->dim.pitch; |
453 TRACE("-NDS_QueryTexturePixels\n"); | |
454 return 0; | 448 return 0; |
455 } | 449 } |
456 | 450 |
457 static int | 451 static int |
458 NDS_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, | 452 NDS_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, |
459 const SDL_Rect * rect, const void *pixels, int pitch) | 453 const SDL_Rect * rect, const void *pixels, int pitch) |
460 { | 454 { |
461 NDS_TextureData *txdat; | 455 NDS_TextureData *txdat; |
462 Uint8 *src, *dst; | 456 Uint8 *src, *dst; |
463 int row; size_t length; | 457 int row; |
464 TRACE("+NDS_UpdateTexture\n"); | 458 size_t length; |
465 | 459 |
466 txdat = (NDS_TextureData *) texture->driverdata; | 460 txdat = (NDS_TextureData *) texture->driverdata; |
467 | 461 |
468 src = (Uint8 *) pixels; | 462 src = (Uint8 *) pixels; |
469 dst = | 463 dst = |
470 (Uint8 *) txdat->vram_pixels + rect->y * txdat->dim.pitch + | 464 (Uint8 *) txdat->vram_pixels + rect->y * txdat->dim.pitch + |
471 rect->x * ((txdat->dim.bpp+1)/8); | 465 rect->x * ((txdat->dim.bpp + 1) / 8); |
472 length = rect->w * ((txdat->dim.bpp+1)/8); | 466 length = rect->w * ((txdat->dim.bpp + 1) / 8); |
473 | 467 |
474 if(rect->w == texture->w) { | 468 if (rect->w == texture->w) { |
475 dmaCopy(src, dst, length*rect->h); | 469 dmaCopy(src, dst, length * rect->h); |
476 } else { | 470 } else { |
477 for (row = 0; row < rect->h; ++row) { | 471 for (row = 0; row < rect->h; ++row) { |
478 dmaCopy(src, dst, length); | 472 dmaCopy(src, dst, length); |
479 src += pitch; | 473 src += pitch; |
480 dst += txdat->dim.pitch; | 474 dst += txdat->dim.pitch; |
481 } | 475 } |
482 } | 476 } |
483 | 477 |
484 TRACE("-NDS_UpdateTexture\n"); | |
485 return 0; | 478 return 0; |
486 } | 479 } |
487 | 480 |
488 static int | 481 static int |
489 NDS_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, | 482 NDS_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, |
490 const SDL_Rect * rect, int markDirty, void **pixels, | 483 const SDL_Rect * rect, int markDirty, void **pixels, |
491 int *pitch) | 484 int *pitch) |
492 { | 485 { |
493 NDS_TextureData *txdat = (NDS_TextureData *) texture->driverdata; | 486 NDS_TextureData *txdat = (NDS_TextureData *) texture->driverdata; |
494 TRACE("+NDS_LockTexture\n"); | 487 |
495 | 488 *pixels = (void *) ((u8 *) txdat->vram_pixels + rect->y |
496 *pixels = (void *) ((u8 *)txdat->vram_pixels + rect->y | 489 * txdat->dim.pitch + |
497 * txdat->dim.pitch + rect->x * ((txdat->dim.bpp+1)/8)); | 490 rect->x * ((txdat->dim.bpp + 1) / 8)); |
498 *pitch = txdat->dim.pitch; | 491 *pitch = txdat->dim.pitch; |
499 | 492 |
500 TRACE("-NDS_LockTexture\n"); | |
501 return 0; | 493 return 0; |
502 } | 494 } |
503 | 495 |
504 static void | 496 static void |
505 NDS_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) | 497 NDS_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) |
506 { | 498 { |
507 TRACE("+NDS_UnlockTexture\n"); | 499 /* stub! */ |
508 TRACE("-NDS_UnlockTexture\n"); | |
509 } | 500 } |
510 | 501 |
511 static void | 502 static void |
512 NDS_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, | 503 NDS_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, |
513 int numrects, const SDL_Rect * rects) | 504 int numrects, const SDL_Rect * rects) |
514 { | 505 { |
515 /* stub */ | 506 /* stub! */ |
516 TRACE("!NDS_DirtyTexture\n"); | |
517 } | 507 } |
518 | 508 |
519 static int | 509 static int |
520 NDS_RenderFill(SDL_Renderer * renderer, Uint8 r, Uint8 g, Uint8 b, | 510 NDS_RenderFill(SDL_Renderer * renderer, Uint8 r, Uint8 g, Uint8 b, |
521 Uint8 a, const SDL_Rect * rect) | 511 Uint8 a, const SDL_Rect * rect) |
522 { | 512 { |
523 NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata; | 513 NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata; |
524 SDL_Rect real_rect = *rect; | 514 SDL_Rect real_rect = *rect; |
525 u16 color; | 515 u16 color; |
526 int i, j; | 516 int i, j; |
527 | 517 |
528 TRACE("+NDS_RenderFill\n"); | 518 color = RGB8(r, g, b); /* <-- macro in libnds that makes an ARGB1555 pixel */ |
529 color = RGB8(r,g,b); /* <-- macro in libnds that makes an ARGB1555 pixel */ | |
530 /* TODO: make a single-color sprite and stretch it. | 519 /* TODO: make a single-color sprite and stretch it. |
531 calculate the "HDX" width modifier of the sprite by: | 520 calculate the "HDX" width modifier of the sprite by: |
532 let S be the actual sprite's width (like, 32 pixels for example) | 521 let S be the actual sprite's width (like, 32 pixels for example) |
533 let R be the rectangle's width (maybe 50 pixels) | 522 let R be the rectangle's width (maybe 50 pixels) |
534 HDX = (R<<8) / S; | 523 HDX = (R<<8) / S; |
535 (it's fixed point, hence the bit shift. same goes for vertical. | 524 (it's fixed point, hence the bit shift. same goes for vertical. |
536 be sure to use 32-bit int's for the bit shift before the division!) | 525 be sure to use 32-bit int's for the bit shift before the division!) |
537 */ | 526 */ |
538 | 527 |
539 TRACE("-NDS_RenderFill\n"); | |
540 return 0; | 528 return 0; |
541 } | 529 } |
542 | 530 |
543 static int | 531 static int |
544 NDS_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, | 532 NDS_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, |
545 const SDL_Rect * srcrect, const SDL_Rect * dstrect) | 533 const SDL_Rect * srcrect, const SDL_Rect * dstrect) |
546 { | 534 { |
547 NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata; | 535 NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata; |
548 NDS_TextureData *txdat = (NDS_TextureData *) texture->driverdata; | 536 NDS_TextureData *txdat = (NDS_TextureData *) texture->driverdata; |
549 SDL_Window *window = SDL_GetWindowFromID(renderer->window); | 537 SDL_Window *window = SDL_GetWindowFromID(renderer->window); |
550 SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window); | 538 SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window); |
551 int i; | 539 int i; |
552 int bpp = SDL_BYTESPERPIXEL(texture->format); | 540 int bpp = SDL_BYTESPERPIXEL(texture->format); |
553 int pitch = txdat->dim.pitch; | 541 int pitch = txdat->dim.pitch; |
554 | 542 |
555 TRACE("+NDS_RenderCopy\n"); | 543 if (txdat->type == NDSTX_BG) { |
556 if(txdat->type == NDSTX_BG) { | |
557 bg_rotation *bgrot = (txdat->hw_index == 2) ? | 544 bg_rotation *bgrot = (txdat->hw_index == 2) ? |
558 &(data->bg->bg2_rotation) : &(data->bg->bg3_rotation); | 545 &(data->bg->bg2_rotation) : &(data->bg->bg3_rotation); |
559 bgrot->xdx = txdat->dim.hdx; | 546 bgrot->xdx = txdat->dim.hdx; |
560 bgrot->xdy = txdat->dim.hdy; | 547 bgrot->xdy = txdat->dim.hdy; |
561 bgrot->ydx = txdat->dim.vdx; | 548 bgrot->ydx = txdat->dim.vdx; |
568 } else { | 555 } else { |
569 /* sprites not fully implemented yet */ | 556 /* sprites not fully implemented yet */ |
570 SpriteEntry *spr = &(data->oam_copy.spriteBuffer[txdat->hw_index]); | 557 SpriteEntry *spr = &(data->oam_copy.spriteBuffer[txdat->hw_index]); |
571 spr->posX = dstrect->x; | 558 spr->posX = dstrect->x; |
572 spr->posY = dstrect->y; | 559 spr->posY = dstrect->y; |
573 if(txdat->hw_index < MATRIX_COUNT && spr->isRotoscale) { | 560 if (txdat->hw_index < MATRIX_COUNT && spr->isRotoscale) { |
574 SpriteRotation *sprot = &(data->oam_copy.matrixBuffer[txdat->hw_index]); | 561 SpriteRotation *sprot = |
562 &(data->oam_copy.matrixBuffer[txdat->hw_index]); | |
575 sprot->hdx = txdat->dim.hdx; | 563 sprot->hdx = txdat->dim.hdx; |
576 sprot->hdy = txdat->dim.hdy; | 564 sprot->hdy = txdat->dim.hdy; |
577 sprot->vdx = txdat->dim.vdx; | 565 sprot->vdx = txdat->dim.vdx; |
578 sprot->vdy = txdat->dim.vdy; | 566 sprot->vdy = txdat->dim.vdy; |
579 } | 567 } |
580 printf("tried to RenderCopy a sprite.\n"); | 568 } |
581 } | |
582 TRACE("-NDS_RenderCopy\n"); | |
583 | 569 |
584 return 0; | 570 return 0; |
585 } | 571 } |
586 | 572 |
587 | 573 |
590 { | 576 { |
591 NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata; | 577 NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata; |
592 SDL_Window *window = SDL_GetWindowFromID(renderer->window); | 578 SDL_Window *window = SDL_GetWindowFromID(renderer->window); |
593 SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window); | 579 SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window); |
594 | 580 |
595 TRACE("+NDS_RenderPresent\n"); | |
596 /* update sprites */ | 581 /* update sprites */ |
597 NDS_OAM_Update(&(data->oam_copy), data->sub); | 582 NDS_OAM_Update(&(data->oam_copy), data->sub); |
598 /* vsync for NDS */ | 583 /* vsync for NDS */ |
599 if (renderer->info.flags & SDL_RENDERER_PRESENTVSYNC) { | 584 if (renderer->info.flags & SDL_RENDERER_PRESENTVSYNC) { |
600 swiWaitForVBlank(); | 585 swiWaitForVBlank(); |
601 } | 586 } |
602 TRACE("-NDS_RenderPresent\n"); | |
603 } | 587 } |
604 | 588 |
605 static void | 589 static void |
606 NDS_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) | 590 NDS_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) |
607 { | 591 { |
608 NDS_TextureData *txdat = texture->driverdata; | 592 NDS_TextureData *txdat = texture->driverdata; |
609 TRACE("+NDS_DestroyTexture\n"); | |
610 /* free anything else allocated for texture */ | 593 /* free anything else allocated for texture */ |
611 /*SDL_FreeDirtyRects(&txdat->dirty);*/ | |
612 SDL_free(txdat); | 594 SDL_free(txdat); |
613 TRACE("-NDS_DestroyTexture\n"); | |
614 } | 595 } |
615 | 596 |
616 static void | 597 static void |
617 NDS_DestroyRenderer(SDL_Renderer * renderer) | 598 NDS_DestroyRenderer(SDL_Renderer * renderer) |
618 { | 599 { |
619 NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata; | 600 NDS_RenderData *data = (NDS_RenderData *) renderer->driverdata; |
620 SDL_Window *window = SDL_GetWindowFromID(renderer->window); | 601 SDL_Window *window = SDL_GetWindowFromID(renderer->window); |
621 SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window); | 602 SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window); |
622 int i; | 603 int i; |
623 | 604 |
624 TRACE("+NDS_DestroyRenderer\n"); | |
625 if (data) { | 605 if (data) { |
626 /* TODO: free anything else relevant. */ | 606 /* free anything else relevant if anything else is allocated. */ |
627 /*if (data->surface.format) { | |
628 SDL_SetSurfacePalette(&data->surface, NULL); | |
629 SDL_FreeFormat(data->surface.format); | |
630 } | |
631 if (display->palette) { | |
632 SDL_DelPaletteWatch(display->palette, DisplayPaletteChanged, | |
633 data); | |
634 }*/ | |
635 /*SDL_FreeDirtyRects(&data->dirty);*/ | |
636 SDL_free(data); | 607 SDL_free(data); |
637 } | 608 } |
638 SDL_free(renderer); | 609 SDL_free(renderer); |
639 TRACE("-NDS_DestroyRenderer\n"); | |
640 } | 610 } |
641 | 611 |
642 static int | 612 static int |
643 NDS_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture, | 613 NDS_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture, |
644 const SDL_Color * colors, int firstcolor, int ncolors) | 614 const SDL_Color * colors, int firstcolor, int ncolors) |
645 { | 615 { |
646 NDS_TextureData *txdat = (NDS_TextureData *) texture->driverdata; | 616 NDS_TextureData *txdat = (NDS_TextureData *) texture->driverdata; |
647 TRACE("+NDS_SetTexturePalette\n"); | |
648 /* set 8-bit modes in the background control registers | 617 /* set 8-bit modes in the background control registers |
649 for backgrounds, BGn_CR |= BG_256_COLOR */ | 618 for backgrounds, BGn_CR |= BG_256_COLOR */ |
650 TRACE("-NDS_SetTexturePalette\n"); | 619 |
651 return 0; | 620 return 0; |
652 } | 621 } |
653 | 622 |
654 static int | 623 static int |
655 NDS_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture, | 624 NDS_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture, |
656 SDL_Color * colors, int firstcolor, int ncolors) | 625 SDL_Color * colors, int firstcolor, int ncolors) |
657 { | 626 { |
658 NDS_TextureData *txdat = (NDS_TextureData *) texture->driverdata; | 627 NDS_TextureData *txdat = (NDS_TextureData *) texture->driverdata; |
659 TRACE("!NDS_GetTexturePalette\n"); | 628 /* stub! */ |
660 return 0; | 629 return 0; |
661 } | 630 } |
662 | 631 |
663 static int | 632 static int |
664 NDS_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture) | 633 NDS_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture) |
665 { | 634 { |
666 TRACE("!NDS_SetTextureColorMod\n"); | |
667 /* stub! */ | 635 /* stub! */ |
668 return 0; | 636 return 0; |
669 } | 637 } |
670 | 638 |
671 static int | 639 static int |
672 NDS_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture) | 640 NDS_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture) |
673 { | 641 { |
674 TRACE("!NDS_SetTextureAlphaMod\n"); | |
675 /* stub! */ | 642 /* stub! */ |
676 return 0; | 643 return 0; |
677 } | 644 } |
678 | 645 |
679 static int | 646 static int |
680 NDS_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture) | 647 NDS_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture) |
681 { | 648 { |
682 TRACE("!NDS_SetTextureBlendMode\n"); | |
683 /* stub! */ | 649 /* stub! */ |
684 return 0; | 650 return 0; |
685 } | 651 } |
686 | 652 |
687 static int | 653 static int |
688 NDS_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture) | 654 NDS_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture) |
689 { | 655 { |
690 TRACE("!NDS_SetTextureScaleMode\n"); | |
691 /* stub! (note: NDS hardware scaling is nearest neighbor.) */ | 656 /* stub! (note: NDS hardware scaling is nearest neighbor.) */ |
692 return 0; | 657 return 0; |
693 } | 658 } |
694 | 659 |
695 /* vi: set ts=4 sw=4 expandtab: */ | 660 /* vi: set ts=4 sw=4 expandtab: */ |