2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/Graphics/GrD3DRender.cpp $
15 * Code to actually render stuff using Direct3D
18 * Revision 1.2 2002/06/09 04:41:17 relnev
19 * added copyright header
21 * Revision 1.1.1.1 2002/05/03 03:28:09 root
25 * 27 9/13/99 11:30a Dave
26 * Added checkboxes and functionality for disabling PXO banners as well as
27 * disabling d3d zbuffer biasing.
29 * 26 9/08/99 12:03a Dave
30 * Make squad logos render properly in D3D all the time. Added intel anim
33 * 25 8/30/99 5:01p Dave
34 * Made d3d do less state changing in the nebula. Use new chat server for
37 * 24 7/30/99 4:04p Anoop
40 * 23 7/29/99 10:47p Dave
41 * Standardized D3D fogging using vertex fog. Shook out Savage 4 bugs.
43 * 22 7/27/99 3:09p Dave
44 * Made g400 work. Whee.
46 * 21 7/24/99 4:19p Dave
47 * Fixed dumb code with briefing bitmaps. Made d3d zbuffer work much
48 * better. Made model code use zbuffer more intelligently.
50 * 20 7/24/99 1:54p Dave
51 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
54 * 19 7/19/99 3:29p Dave
55 * Fixed gamma bitmap in the options screen.
57 * 18 7/14/99 9:42a Dave
58 * Put in clear_color debug function. Put in base for 3dnow stuff / P3
61 * 17 7/13/99 1:15p Dave
62 * 32 bit support. Whee!
64 * 16 7/12/99 11:42a Jefff
65 * Made rectangle drawing smarter in D3D. Made plines draw properly on Ati
68 * 15 6/29/99 10:35a Dave
69 * Interface polygon bitmaps! Whee!
71 * 14 5/05/99 9:02p Dave
72 * Fixed D3D aabitmap rendering. Spiffed up nebula effect a bit (added
73 * rotations, tweaked values, made bitmap selection more random). Fixed
74 * D3D beam weapon clipping problem. Added D3d frame dumping.
76 * 13 2/03/99 11:44a Dave
77 * Fixed d3d transparent textures.
79 * 12 1/30/99 5:08p Dave
80 * More new hi-res stuff.Support for nice D3D textures.
82 * 11 12/18/98 1:13a Dave
83 * Rough 1024x768 support for Direct3D. Proper detection and usage through
86 * 10 12/08/98 7:03p Dave
87 * Much improved D3D fogging. Also put in vertex fogging for the cheesiest
90 * 9 12/08/98 2:47p Johnson
91 * Made D3D fog use eye-relative fog instead of z depth fog.
93 * 8 12/08/98 9:36a Dave
94 * Almost done nebula effect for D3D. Looks 85% as good as Glide.
96 * 7 12/07/98 5:51p Dave
97 * Finally got d3d fog working! Now we just need to tweak values.
99 * 6 12/07/98 9:00a Dave
100 * Fixed d3d rendered. Still don't have fog working.
102 * 5 12/06/98 6:53p Dave
104 * 4 12/01/98 5:54p Dave
105 * Simplified the way pixel data is swizzled. Fixed tga bitmaps to work
106 * properly in D3D and Glide.
108 * 3 11/30/98 1:07p Dave
109 * 16 bit conversion, first run.
111 * 2 10/07/98 10:52a Dave
114 * 1 10/07/98 10:49a Dave
116 * 54 5/25/98 10:32a John
117 * Took out redundant code for font bitmap offsets that converted to a
118 * float, then later on converted back to an integer. Quite unnecessary.
120 * 53 5/24/98 6:45p John
121 * let direct3d do all clipping.
123 * 52 5/24/98 3:42p John
124 * Let Direct3D do clipping on any linear textures, like lasers.
126 * 51 5/23/98 7:18p John
127 * optimized the uv bashing a bit.
129 * 50 5/22/98 1:11p John
130 * Added code to actually detect which offset a line needs
132 * 49 5/22/98 12:54p John
133 * added .5 to each pixel of a line. This seemed to make single pixel
134 * lines draw on all cards.
136 * 48 5/22/98 9:00a John
137 * Fixed problem of no fading out of additive textures due to Permedia2
138 * fix. Did this by dimming out the vertex RGB values.
140 * 47 5/21/98 9:56p John
141 * Made Direct3D work with classic alpha-blending only devices, like the
142 * Virge. Added a texture type XPARENT that fills the alpha in in the
143 * bitmap for Virge. Added support for Permedia by making making
144 * additive alphablending be one/one instead of alpha/one, which didn't
145 * work, and there is no way to tell this from caps.
147 * 46 5/20/98 9:45p John
148 * added code so the places in code that change half the palette don't
149 * have to clear the screen.
151 * 45 5/20/98 3:10p John
152 * Made lines work even if no alphagouraud capabilities on the card.
154 * 44 5/19/98 4:50p Lawrance
155 * JAS: Fixed some bugs on Alan's nVidia Riva128 PCI where some
156 * unitiallized fields, namely vertex->shw were causing glitches.
158 * 43 5/19/98 1:46p John
159 * Fixed Rendition/Riva128 uv problems.
161 * 42 5/19/98 12:34p John
162 * added code to fix uv's on rendition. added code to fix zbuffering
163 * problem on rendition.
165 * 41 5/18/98 8:26p John
166 * Made scanline be line. Made lines work if no line alpha blending
167 * supported. Made no alpha mode use alpha off.
169 * 40 5/17/98 4:13p John
170 * Made zbuffer clear only clear current clip region
172 * 39 5/17/98 3:23p John
173 * Took out capibility check for additive blending. Made gr_bitmap_ex
174 * clip properly in glide and direct3d.
176 * 38 5/15/98 8:48a John
177 * Fixed bug where one-pixel line was getting left on right and bottom.
179 * 37 5/12/98 8:43p John
180 * fixed particle zbuffering.
182 * 36 5/12/98 10:34a John
183 * Added d3d_shade functionality. Added d3d_flush function, since the
184 * shader seems to get reorganzed behind the overlay text stuff!
186 * 35 5/12/98 10:06a John
187 * Made all tmaps "clamp-clip". This fixed bug with offscreen hud
188 * indicators not rendering.
190 * 34 5/12/98 8:18a John
191 * Put in code to use a different texture format for alpha textures and
192 * normal textures. Turned off filtering for aabitmaps. Took out
193 * destblend=invsrccolor alpha mode that doesn't work on riva128.
195 * 33 5/11/98 10:58a John
196 * Fixed pilot name cursor bug. Started adding in code for alphachannel
199 * 32 5/09/98 12:37p John
200 * More texture caching
202 * 31 5/09/98 12:16p John
203 * Even better texture caching.
205 * 30 5/08/98 10:12a John
206 * took out an mprintf
208 * 29 5/07/98 11:31a John
209 * Removed DEMO defines
211 * 28 5/07/98 10:28a John
212 * Made texture format use 4444. Made fonts use alpha to render.
214 * 27 5/07/98 10:09a John
215 * Fixed some bugs with short lines in D3D.
217 * 26 5/07/98 9:54a John
218 * Added in palette flash functionallity.
220 * 25 5/07/98 9:40a John
221 * Fixed some bitmap transparency issues with Direct3D.
223 * 24 5/06/98 11:21p John
224 * Fixed a bitmap bug with Direct3D. Started adding new caching code into
227 * 23 5/06/98 8:41p John
228 * Fixed some font clipping bugs. Moved texture handle set code for d3d
229 * into the texture module.
231 * 22 5/06/98 8:07p John
232 * made d3d clear work correctly.
234 * 21 5/06/98 8:00p John
235 * Got stars working under D3D.
237 * 20 5/06/98 5:30p John
238 * Removed unused cfilearchiver. Removed/replaced some unused/little used
239 * graphics functions, namely gradient_h and _v and pixel_sp. Put in new
240 * DirectX header files and libs that fixed the Direct3D alpha blending
243 * 19 5/05/98 10:37p John
244 * Added code to optionally use execute buffers.
246 * 18 5/04/98 3:36p John
247 * Got zbuffering working with Direct3D.
249 * 17 5/03/98 10:52a John
250 * Made D3D sort of work on 3dfx.
252 * 16 5/03/98 10:43a John
253 * Working on Direct3D.
255 * 15 4/14/98 12:15p John
256 * Made 16-bpp movies work.
258 * 14 4/10/98 5:20p John
259 * Changed RGB in lighting structure to be ubytes. Removed old
260 * not-necessary 24 bpp software stuff.
262 * 13 4/09/98 11:05a John
263 * Removed all traces of Direct3D out of the demo version of Freespace and
266 * 12 3/12/98 5:36p John
267 * Took out any unused shaders. Made shader code take rgbc instead of
268 * matrix and vector since noone used it like a matrix and it would have
269 * been impossible to do in hardware. Made Glide implement a basic
270 * shader for online help.
272 * 11 3/11/98 1:55p John
275 * 10 3/10/98 4:18p John
276 * Cleaned up graphics lib. Took out most unused gr functions. Made D3D
277 * & Glide have popups and print screen. Took out all >8bpp software
278 * support. Made Fred zbuffer. Made zbuffer allocate dynamically to
279 * support Fred. Made zbuffering key off of functions rather than one
282 * 9 3/08/98 12:33p John
283 * Added more lines, tris, and colored flat polys (lasers!) correctly.
285 * 8 3/08/98 10:25a John
288 * 7 3/07/98 8:29p John
289 * Put in some Direct3D features. Transparency on bitmaps. Made fonts &
290 * aabitmaps render nice.
292 * 6 3/06/98 5:39p John
293 * Started adding in aabitmaps
295 * 5 3/02/98 5:42p John
296 * Removed WinAVI stuff from Freespace. Made all HUD gauges wriggle from
297 * afterburner. Made gr_set_clip work good with negative x &y. Made
298 * model_caching be on by default. Made each cached model have it's own
299 * bitmap id. Made asteroids not rotate when model_caching is on.
301 * 4 2/26/98 3:24p John
302 * fixed optimized warning
304 * 3 2/17/98 7:28p John
305 * Got fonts and texturing working in Direct3D
307 * 2 2/07/98 7:50p John
308 * Added code so that we can use the old blending type of alphacolors if
309 * we want to. Made the stars use them.
311 * 1 2/03/98 9:24p John
316 #include "grd3dinternal.h"
326 typedef enum gr_texture_source {
328 TEXTURE_SOURCE_DECAL,
329 TEXTURE_SOURCE_NO_FILTERING,
332 typedef enum gr_alpha_blend {
333 ALPHA_BLEND_NONE, // 1*SrcPixel + 0*DestPixel
334 ALPHA_BLEND_ALPHA_ADDITIVE, // Alpha*SrcPixel + 1*DestPixel
335 ALPHA_BLEND_ALPHA_BLEND_ALPHA, // Alpha*SrcPixel + (1-Alpha)*DestPixel
336 ALPHA_BLEND_ALPHA_BLEND_SRC_COLOR, // Alpha*SrcPixel + (1-SrcPixel)*DestPixel
339 typedef enum gr_zbuffer_type {
346 int D3d_last_state = -1;
348 // Hack! move to another file!
349 extern int D3d_rendition_uvs;
351 // Hack! move to another file!
352 extern int D3D_fog_mode;
354 void gr_d3d_set_state( gr_texture_source ts, gr_alpha_blend ab, gr_zbuffer_type zt )
356 int current_state = 0;
358 current_state = current_state | (ts<<0);
359 current_state = current_state | (ab<<5);
360 current_state = current_state | (zt<<10);
362 if ( current_state == D3d_last_state ) {
365 D3d_last_state = current_state;
368 case TEXTURE_SOURCE_NONE:
369 d3d_SetRenderState(D3DRENDERSTATE_TEXTUREHANDLE, NULL );
370 // Let the texture cache system know whe set the handle to NULL
371 gr_tcache_set(-1, -1, NULL, NULL );
374 case TEXTURE_SOURCE_DECAL:
375 d3d_SetRenderState(D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_LINEAR );
376 d3d_SetRenderState(D3DRENDERSTATE_TEXTUREMAG, D3DFILTER_LINEAR );
378 if ( lpDevDesc->dpcTriCaps.dwTextureBlendCaps & D3DPTBLENDCAPS_MODULATEALPHA ) {
379 d3d_SetRenderState(D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA );
381 d3d_SetRenderState(D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATE );
385 case TEXTURE_SOURCE_NO_FILTERING:
386 d3d_SetRenderState(D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_NEAREST );
387 d3d_SetRenderState(D3DRENDERSTATE_TEXTUREMAG, D3DFILTER_NEAREST );
388 if ( lpDevDesc->dpcTriCaps.dwTextureBlendCaps & D3DPTBLENDCAPS_MODULATEALPHA ) {
389 d3d_SetRenderState(D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA );
391 d3d_SetRenderState(D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATE );
400 case ALPHA_BLEND_NONE: // 1*SrcPixel + 0*DestPixel
401 d3d_SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, FALSE );
404 case ALPHA_BLEND_ALPHA_ADDITIVE: // Alpha*SrcPixel + 1*DestPixel
405 case ALPHA_BLEND_ALPHA_BLEND_SRC_COLOR: // Alpha*SrcPixel + (1-SrcPixel)*DestPixel
406 if ( lpDevDesc->dpcTriCaps.dwDestBlendCaps & D3DPBLENDCAPS_ONE ) {
407 d3d_SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE );
408 // Must use ONE:ONE as the Permedia2 can't do SRCALPHA:ONE.
409 // But I lower RGB values so we don't loose anything.
410 d3d_SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_ONE );
411 //d3d_SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA );
412 d3d_SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ONE );
415 // Fall through to normal alpha blending mode...
417 case ALPHA_BLEND_ALPHA_BLEND_ALPHA: // Alpha*SrcPixel + (1-Alpha)*DestPixel
418 if ( lpDevDesc->dpcTriCaps.dwSrcBlendCaps & D3DPBLENDCAPS_SRCALPHA ) {
419 d3d_SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE );
420 d3d_SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA );
421 d3d_SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA );
423 d3d_SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE );
424 d3d_SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_BOTHSRCALPHA );
435 case ZBUFFER_TYPE_NONE:
436 d3d_SetRenderState(D3DRENDERSTATE_ZENABLE,FALSE);
437 d3d_SetRenderState(D3DRENDERSTATE_ZWRITEENABLE,FALSE);
440 case ZBUFFER_TYPE_READ:
441 d3d_SetRenderState(D3DRENDERSTATE_ZENABLE,TRUE);
442 d3d_SetRenderState(D3DRENDERSTATE_ZWRITEENABLE,FALSE);
445 case ZBUFFER_TYPE_WRITE:
446 d3d_SetRenderState(D3DRENDERSTATE_ZENABLE,FALSE);
447 d3d_SetRenderState(D3DRENDERSTATE_ZWRITEENABLE,TRUE);
450 case ZBUFFER_TYPE_FULL:
451 d3d_SetRenderState(D3DRENDERSTATE_ZENABLE,TRUE);
452 d3d_SetRenderState(D3DRENDERSTATE_ZWRITEENABLE,TRUE);
461 extern int D3D_zbias;
462 void d3d_zbias(int bias)
465 d3d_SetRenderState(D3DRENDERSTATE_ZBIAS, bias);
469 // If mode is FALSE, turn zbuffer off the entire frame,
470 // no matter what people pass to gr_zbuffer_set.
471 void gr_d3d_zbuffer_clear(int mode)
475 gr_zbuffering_mode = GR_ZBUFF_FULL;
476 gr_global_zbuffering = 1;
478 // Make sure zbuffering is on
479 gr_d3d_set_state( TEXTURE_SOURCE_NONE, ALPHA_BLEND_NONE, ZBUFFER_TYPE_FULL );
482 // An application can clear z-buffers by using the IDirectDrawSurface2::Blt method.
483 // The DDBLT_DEPTHFILL flag indicates that the blit clears z-buffers. If this flag
484 // is specified, the DDBLTFX structure passed to the IDirectDrawSurface2::Blt method
485 // should have its dwFillDepth member set to the required z-depth. If the DirectDraw device
486 // driver for a 3D-accelerated display card is designed to provide support for z-buffer
487 // clearing in hardware, it should export the DDCAPS_BLTDEPTHFILL flag and should
488 // handle DDBLT_DEPTHFILL blits. The destination surface of a depth-fill blit must
490 // Note The actual interpretation of a depth value is specific to the 3D renderer.
494 rect.x1 = gr_screen.clip_left + gr_screen.offset_x;
495 rect.y1 = gr_screen.clip_top + gr_screen.offset_y;
496 rect.x2 = gr_screen.clip_right + gr_screen.offset_x;
497 rect.y2 = gr_screen.clip_bottom + gr_screen.offset_y;
499 if (lpViewport->Clear( 1, &rect, D3DCLEAR_ZBUFFER ) != D3D_OK ) {
500 mprintf(( "Failed to clear zbuffer!\n" ));
507 gr_zbuffering_mode = GR_ZBUFF_NONE;
508 gr_global_zbuffering = 0;
512 // internal d3d rect function
513 void gr_d3d_rect_internal(int x, int y, int w, int h, int r, int g, int b, int a)
517 vertex *verts[4] = {&v[0], &v[1], &v[2], &v[3]};
519 saved_zbuf = gr_zbuffer_get();
521 // start the frame, no zbuffering, no culling
523 gr_zbuffer_set(GR_ZBUFF_NONE);
532 v[0].flags = PF_PROJECTED;
539 v[1].sx = i2fl(x + w);
544 v[1].flags = PF_PROJECTED;
551 v[2].sx = i2fl(x + w);
552 v[2].sy = i2fl(y + h);
556 v[2].flags = PF_PROJECTED;
564 v[3].sy = i2fl(y + h);
568 v[3].flags = PF_PROJECTED;
576 g3_draw_poly_constant_sw(4, verts, TMAP_FLAG_GOURAUD | TMAP_FLAG_RGB | TMAP_FLAG_ALPHA, 0.1f);
580 // restore zbuffer and culling
581 gr_zbuffer_set(saved_zbuf);
585 int gr_d3d_zbuffer_get()
587 if ( !gr_global_zbuffering ) {
588 return GR_ZBUFF_NONE;
590 return gr_zbuffering_mode;
593 int gr_d3d_zbuffer_set(int mode)
596 if ( !gr_global_zbuffering ) {
598 return GR_ZBUFF_NONE;
602 int tmp = gr_zbuffering_mode;
604 gr_zbuffering_mode = mode;
606 if ( gr_zbuffering_mode == GR_ZBUFF_NONE ) {
614 float D3D_line_offset = 0.0f;
616 void d3d_make_rect( D3DTLVERTEX *a, D3DTLVERTEX *b, int x1, int y1, int x2, int y2 )
618 // Alan's nvidia riva128 PCI screws up targetting brackets if
619 // rhw are uninitialized.
623 // just for completeness, initialize specular and sz.
630 a->sx = i2fl(x1 + gr_screen.offset_x)+D3D_line_offset;
631 a->sy = i2fl(y1 + gr_screen.offset_y)+D3D_line_offset;
633 b->sx = i2fl(x2 + gr_screen.offset_x)+D3D_line_offset;
634 b->sy = i2fl(y2 + gr_screen.offset_y)+D3D_line_offset;
638 if ( a->sy < b->sy ) {
643 } else if ( y1 == y2 ) {
645 if ( a->sx < b->sx ) {
654 // basically just fills in the alpha component of the specular color. Hardware does the rest
655 // when rendering the poly
656 void gr_d3d_stuff_fog_value(float z, D3DCOLOR *spec)
661 // linear fog formula
662 f_float = (gr_screen.fog_far - z) / (gr_screen.fog_far - gr_screen.fog_near);
665 } else if(f_float > 1.0f){
668 *spec = D3DRGBA(0.0f, 0.0f, 0.0f, f_float);
671 float z_mult = 30000.0f;
674 dc_get_arg(ARG_FLOAT);
675 z_mult = Dc_arg_float;
678 float flCAP( float x, float minx, float maxx)
682 } else if ( x > maxx ) {
688 #define NEBULA_COLORS 20
690 void gr_d3d_tmapper_internal( int nverts, vertex **verts, uint flags, int is_scaler )
693 float u_scale = 1.0f, v_scale = 1.0f;
696 // Make nebula use the texture mapper... this blends the colors better.
697 if ( flags & TMAP_FLAG_NEBULA ){
700 flags |= TMAP_FLAG_TEXTURED | TMAP_FLAG_CORRECT;
702 static int test_bmp = -1;
703 static ushort data[16];
704 if ( test_bmp == -1 ){
709 // stuff the fake bitmap
710 a = 1; r = 255; g = 255; b = 255;
712 bm_set_components((ubyte*)&pix, &r, &g, &b, &a);
713 for(idx=0; idx<16; idx++){
716 test_bmp = bm_create( 16, 4, 4, data );
718 gr_set_bitmap( test_bmp );
720 for (i=0; i<nverts; i++ ) {
721 verts[i]->u = verts[i]->v = 0.5f;
726 gr_texture_source texture_source = (gr_texture_source)-1;
727 gr_alpha_blend alpha_blend = (gr_alpha_blend)-1;
728 gr_zbuffer_type zbuffer_type = (gr_zbuffer_type)-1;
731 if ( gr_zbuffering ) {
732 if ( is_scaler || (gr_screen.current_alphablend_mode == GR_ALPHABLEND_FILTER) ) {
733 zbuffer_type = ZBUFFER_TYPE_READ;
735 zbuffer_type = ZBUFFER_TYPE_FULL;
738 zbuffer_type = ZBUFFER_TYPE_NONE;
743 int tmap_type = TCACHE_TYPE_NORMAL;
747 if ( flags & TMAP_FLAG_TEXTURED ) {
752 r = gr_screen.current_color.red;
753 g = gr_screen.current_color.green;
754 b = gr_screen.current_color.blue;
757 if ( gr_screen.current_alphablend_mode == GR_ALPHABLEND_FILTER ) {
759 if ( lpDevDesc->dpcTriCaps.dwDestBlendCaps & D3DPBLENDCAPS_ONE ) {
760 tmap_type = TCACHE_TYPE_NORMAL;
761 alpha_blend = ALPHA_BLEND_ALPHA_ADDITIVE;
763 // Blend with screen pixel using src*alpha+dst
764 float factor = gr_screen.current_alpha;
768 if ( factor <= 1.0f ) {
769 int tmp_alpha = fl2i(gr_screen.current_alpha*255.0f);
770 r = (r*tmp_alpha)/255;
771 g = (g*tmp_alpha)/255;
772 b = (b*tmp_alpha)/255;
776 tmap_type = TCACHE_TYPE_XPARENT;
778 alpha_blend = ALPHA_BLEND_ALPHA_BLEND_ALPHA;
780 // Blend with screen pixel using src*alpha+dst
781 float factor = gr_screen.current_alpha;
783 if ( factor > 1.0f ) {
786 alpha = fl2i(gr_screen.current_alpha*255.0f);
790 if(Bm_pixel_format == BM_PIXEL_FORMAT_ARGB_D3D){
791 alpha_blend = ALPHA_BLEND_ALPHA_BLEND_ALPHA;
793 alpha_blend = ALPHA_BLEND_NONE;
798 if(flags & TMAP_FLAG_BITMAP_SECTION){
799 tmap_type = TCACHE_TYPE_BITMAP_SECTION;
802 texture_source = TEXTURE_SOURCE_NONE;
804 if ( flags & TMAP_FLAG_TEXTURED ) {
805 if ( !gr_tcache_set(gr_screen.current_bitmap, tmap_type, &u_scale, &v_scale, 0, gr_screen.current_bitmap_sx, gr_screen.current_bitmap_sy )) {
806 mprintf(( "Not rendering a texture because it didn't fit in VRAM!\n" ));
810 // use nonfiltered textures for bitmap sections
811 if(flags & TMAP_FLAG_BITMAP_SECTION){
812 texture_source = TEXTURE_SOURCE_NO_FILTERING;
814 texture_source = TEXTURE_SOURCE_DECAL;
818 gr_d3d_set_state( texture_source, alpha_blend, zbuffer_type );
820 D3DTLVERTEX d3d_verts[32];
821 D3DTLVERTEX *src_v = d3d_verts;
824 x1 = gr_screen.clip_left*16;
825 x2 = gr_screen.clip_right*16+15;
826 y1 = gr_screen.clip_top*16;
827 y2 = gr_screen.clip_bottom*16+15;
829 float uoffset = 0.0f;
830 float voffset = 0.0f;
832 float minu=0.0f, minv=0.0f, maxu=1.0f, maxv=1.0f;
834 if ( flags & TMAP_FLAG_TEXTURED ) {
835 if ( D3d_rendition_uvs ) {
836 bm_get_info(gr_screen.current_bitmap, &bw, &bh);
838 uoffset = 2.0f/i2fl(bw);
839 voffset = 2.0f/i2fl(bh);
844 maxu = 1.0f - uoffset;
845 maxv = 1.0f - voffset;
849 // turn on pixel fog if we're rendering against a fullneb background
850 // if(flags & TMAP_FLAG_PIXEL_FOG){
852 // gr_fog_set(GR_FOGMODE_FOG, gr_screen.current_fog_color.red, gr_screen.current_fog_color.green, gr_screen.current_fog_color.blue);
855 for (i=0; i<nverts; i++ ) {
856 vertex * va = verts[i];
858 // store in case we're doing vertex fog.
859 if ( gr_zbuffering || (flags & TMAP_FLAG_NEBULA) ) {
860 src_v->sz = va->z / z_mult; // For zbuffering and fogging
861 if ( src_v->sz > 0.98f ) {
868 if ( flags & TMAP_FLAG_CORRECT ) {
869 src_v->rhw = va->sw; // For texture correction
871 src_v->rhw = 1.0f; // For texture correction
876 if ( flags & TMAP_FLAG_ALPHA ) {
882 if ( flags & TMAP_FLAG_NEBULA ) {
883 int pal = (verts[i]->b*(NEBULA_COLORS-1))/255;
884 r = gr_palette[pal*3+0];
885 g = gr_palette[pal*3+1];
886 b = gr_palette[pal*3+2];
887 } else if ( (flags & TMAP_FLAG_RAMP) && (flags & TMAP_FLAG_GOURAUD) ) {
888 r = Gr_gamma_lookup[verts[i]->b];
889 g = Gr_gamma_lookup[verts[i]->b];
890 b = Gr_gamma_lookup[verts[i]->b];
891 } else if ( (flags & TMAP_FLAG_RGB) && (flags & TMAP_FLAG_GOURAUD) ) {
892 // Make 0.75 be 256.0f
893 r = Gr_gamma_lookup[verts[i]->r];
894 g = Gr_gamma_lookup[verts[i]->g];
895 b = Gr_gamma_lookup[verts[i]->b];
897 // use constant RGB values...
900 src_v->color = RGBA_MAKE(r, g, b, a);
902 // if we're fogging and we're doing vertex fog
903 if((gr_screen.current_fog_mode != GR_FOGMODE_NONE) && (D3D_fog_mode == 1)){
904 gr_d3d_stuff_fog_value(va->z, &src_v->specular);
910 x = fl2i(va->sx*16.0f);
911 y = fl2i(va->sy*16.0f);
913 x += gr_screen.offset_x*16;
914 y += gr_screen.offset_y*16;
916 src_v->sx = i2fl(x) / 16.0f;
917 src_v->sy = i2fl(y) / 16.0f;
919 if ( flags & TMAP_FLAG_TEXTURED ) {
921 if ( D3d_rendition_uvs ){
922 // tiled texture (ships, etc), bitmap sections
923 if(flags & TMAP_FLAG_TILED){
924 src_v->tu = va->u*u_scale;
925 src_v->tv = va->v*v_scale;
928 else if(flags & TMAP_FLAG_BITMAP_SECTION){
930 bm_get_section_size(gr_screen.current_bitmap, gr_screen.current_bitmap_sx, gr_screen.current_bitmap_sy, &sw, &sh);
932 src_v->tu = (va->u + (0.5f / i2fl(sw))) * u_scale;
933 src_v->tv = (va->v + (0.5f / i2fl(sh))) * v_scale;
937 src_v->tu = flCAP(va->u, minu, maxu);
938 src_v->tv = flCAP(va->v, minv, maxv);
941 // yay. non-rendition
943 src_v->tu = va->u*u_scale;
944 src_v->tv = va->v*v_scale;
953 // if we're rendering against a fullneb background
954 if(flags & TMAP_FLAG_PIXEL_FOG){
959 // get the average pixel color behind the vertices
960 for(i=0; i<nverts; i++){
961 neb2_get_pixel((int)d3d_verts[i].sx, (int)d3d_verts[i].sy, &r, &g, &b);
971 gr_fog_set(GR_FOGMODE_FOG, ra, ga, ba);
974 d3d_DrawPrimitive(D3DPT_TRIANGLEFAN, D3DVT_TLVERTEX, (LPVOID)d3d_verts, nverts, NULL);
977 // if(flags & TMAP_FLAG_PIXEL_FOG){
978 // gr_fog_set(GR_FOGMODE_NONE, 0, 0, 0);
982 void gr_d3d_tmapper( int nverts, vertex **verts, uint flags )
984 gr_d3d_tmapper_internal( nverts, verts, flags, 0 );
987 #define FIND_SCALED_NUM(x,x0,x1,y0,y1) (((((x)-(x0))*((y1)-(y0)))/((x1)-(x0)))+(y0))
989 void gr_d3d_scaler(vertex *va, vertex *vb )
991 float x0, y0, x1, y1;
992 float u0, v0, u1, v1;
993 float clipped_x0, clipped_y0, clipped_x1, clipped_y1;
994 float clipped_u0, clipped_v0, clipped_u1, clipped_v1;
995 float xmin, xmax, ymin, ymax;
996 int dx0, dy0, dx1, dy1;
998 //============= CLIP IT =====================
1000 x0 = va->sx; y0 = va->sy;
1001 x1 = vb->sx; y1 = vb->sy;
1003 xmin = i2fl(gr_screen.clip_left); ymin = i2fl(gr_screen.clip_top);
1004 xmax = i2fl(gr_screen.clip_right); ymax = i2fl(gr_screen.clip_bottom);
1006 u0 = va->u; v0 = va->v;
1007 u1 = vb->u; v1 = vb->v;
1009 // Check for obviously offscreen bitmaps...
1010 if ( (y1<=y0) || (x1<=x0) ) return;
1011 if ( (x1<xmin ) || (x0>xmax) ) return;
1012 if ( (y1<ymin ) || (y0>ymax) ) return;
1014 clipped_u0 = u0; clipped_v0 = v0;
1015 clipped_u1 = u1; clipped_v1 = v1;
1017 clipped_x0 = x0; clipped_y0 = y0;
1018 clipped_x1 = x1; clipped_y1 = y1;
1020 // Clip the left, moving u0 right as necessary
1022 clipped_u0 = FIND_SCALED_NUM(xmin,x0,x1,u0,u1);
1026 // Clip the right, moving u1 left as necessary
1028 clipped_u1 = FIND_SCALED_NUM(xmax,x0,x1,u0,u1);
1032 // Clip the top, moving v0 down as necessary
1034 clipped_v0 = FIND_SCALED_NUM(ymin,y0,y1,v0,v1);
1038 // Clip the bottom, moving v1 up as necessary
1040 clipped_v1 = FIND_SCALED_NUM(ymax,y0,y1,v0,v1);
1044 dx0 = fl2i(clipped_x0); dx1 = fl2i(clipped_x1);
1045 dy0 = fl2i(clipped_y0); dy1 = fl2i(clipped_y1);
1047 if (dx1<=dx0) return;
1048 if (dy1<=dy0) return;
1050 //============= DRAW IT =====================
1064 v[1].sx = clipped_x1;
1065 v[1].sy = clipped_y0;
1068 v[1].u = clipped_u1;
1069 v[1].v = clipped_v0;
1072 v[2].sx = clipped_x1;
1073 v[2].sy = clipped_y1;
1076 v[2].u = clipped_u1;
1077 v[2].v = clipped_v1;
1080 v[3].sx = clipped_x0;
1081 v[3].sy = clipped_y1;
1084 v[3].u = clipped_u0;
1085 v[3].v = clipped_v1;
1087 gr_d3d_tmapper_internal( 4, vl, TMAP_FLAG_TEXTURED, 1 );
1090 void gr_d3d_aascaler(vertex *va, vertex *vb )
1095 void gr_d3d_pixel(int x, int y)
1103 // Turn off zbuffering so this doesn't clear the zbuffer
1104 gr_d3d_set_state( TEXTURE_SOURCE_NONE, ALPHA_BLEND_NONE, ZBUFFER_TYPE_NONE );
1110 // Get the surface desc
1111 ddsd.dwSize = sizeof(ddsd);
1112 lpBackBuffer->GetSurfaceDesc(&ddsd);
1114 memset(&ddbltfx, 0, sizeof(ddbltfx));
1115 ddbltfx.dwSize = sizeof(DDBLTFX);
1117 ddbltfx.dwFillColor = RGB_MAKE(gr_screen.current_clear_color.red, gr_screen.current_clear_color.green, gr_screen.current_clear_color.blue);
1119 dst.left = gr_screen.clip_left+gr_screen.offset_x;
1120 dst.top = gr_screen.clip_top+gr_screen.offset_y;
1121 dst.right = gr_screen.clip_right+1+gr_screen.offset_x;
1122 dst.bottom = gr_screen.clip_bottom+1+gr_screen.offset_y;
1124 if ( lpBackBuffer->Blt( &dst, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx ) != DD_OK ) {
1130 // sets the clipping region & offset
1131 void gr_d3d_set_clip(int x,int y,int w,int h)
1133 gr_screen.offset_x = x;
1134 gr_screen.offset_y = y;
1136 gr_screen.clip_left = 0;
1137 gr_screen.clip_right = w-1;
1139 gr_screen.clip_top = 0;
1140 gr_screen.clip_bottom = h-1;
1142 // check for sanity of parameters
1143 if ( gr_screen.clip_left+x < 0 ) {
1144 gr_screen.clip_left = -x;
1145 } else if ( gr_screen.clip_left+x > gr_screen.max_w-1 ) {
1146 gr_screen.clip_left = gr_screen.max_w-1-x;
1148 if ( gr_screen.clip_right+x < 0 ) {
1149 gr_screen.clip_right = -x;
1150 } else if ( gr_screen.clip_right+x >= gr_screen.max_w-1 ) {
1151 gr_screen.clip_right = gr_screen.max_w-1-x;
1154 if ( gr_screen.clip_top+y < 0 ) {
1155 gr_screen.clip_top = -y;
1156 } else if ( gr_screen.clip_top+y > gr_screen.max_h-1 ) {
1157 gr_screen.clip_top = gr_screen.max_h-1-y;
1160 if ( gr_screen.clip_bottom+y < 0 ) {
1161 gr_screen.clip_bottom = -y;
1162 } else if ( gr_screen.clip_bottom+y > gr_screen.max_h-1 ) {
1163 gr_screen.clip_bottom = gr_screen.max_h-1-y;
1166 gr_screen.clip_width = gr_screen.clip_right - gr_screen.clip_left + 1;
1167 gr_screen.clip_height = gr_screen.clip_bottom - gr_screen.clip_top + 1;
1169 // Setup the viewport for a reasonable viewing area
1170 D3DVIEWPORT viewdata;
1174 // Compensate for aspect ratio
1175 if ( gr_screen.clip_width > gr_screen.clip_height )
1176 largest_side = gr_screen.clip_width;
1178 largest_side = gr_screen.clip_height;
1180 viewdata.dwSize = sizeof( viewdata );
1181 viewdata.dwX = gr_screen.clip_left+x;
1182 viewdata.dwY = gr_screen.clip_top+y;
1183 viewdata.dwWidth = gr_screen.clip_width;
1184 viewdata.dwHeight = gr_screen.clip_height;
1185 viewdata.dvScaleX = largest_side / 2.0F;
1186 viewdata.dvScaleY = largest_side / 2.0F;
1187 viewdata.dvMaxX = ( float ) ( viewdata.dwWidth / ( 2.0F * viewdata.dvScaleX ) );
1188 viewdata.dvMaxY = ( float ) ( viewdata.dwHeight / ( 2.0F * viewdata.dvScaleY ) );
1189 viewdata.dvMinZ = 0.0F;
1190 viewdata.dvMaxZ = 0.0F; // choose something appropriate here!
1192 ddrval = lpViewport->SetViewport( &viewdata );
1193 if ( ddrval != DD_OK ) {
1194 mprintf(( "GR_D3D_SET_CLIP: SetViewport failed.\n" ));
1200 void gr_d3d_reset_clip()
1202 gr_screen.offset_x = 0;
1203 gr_screen.offset_y = 0;
1204 gr_screen.clip_left = 0;
1205 gr_screen.clip_top = 0;
1206 gr_screen.clip_right = gr_screen.max_w - 1;
1207 gr_screen.clip_bottom = gr_screen.max_h - 1;
1208 gr_screen.clip_width = gr_screen.max_w;
1209 gr_screen.clip_height = gr_screen.max_h;
1211 // Setup the viewport for a reasonable viewing area
1212 D3DVIEWPORT viewdata;
1216 // Compensate for aspect ratio
1217 if ( gr_screen.clip_width > gr_screen.clip_height )
1218 largest_side = gr_screen.clip_width;
1220 largest_side = gr_screen.clip_height;
1222 viewdata.dwSize = sizeof( viewdata );
1223 viewdata.dwX = gr_screen.clip_left;
1224 viewdata.dwY = gr_screen.clip_top;
1225 viewdata.dwWidth = gr_screen.clip_width;
1226 viewdata.dwHeight = gr_screen.clip_height;
1227 viewdata.dvScaleX = largest_side / 2.0F;
1228 viewdata.dvScaleY = largest_side / 2.0F;
1229 viewdata.dvMaxX = ( float ) ( viewdata.dwWidth / ( 2.0F * viewdata.dvScaleX ) );
1230 viewdata.dvMaxY = ( float ) ( viewdata.dwHeight / ( 2.0F * viewdata.dvScaleY ) );
1231 viewdata.dvMinZ = 0.0F;
1232 viewdata.dvMaxZ = 0.0F; // choose something appropriate here!
1234 ddrval = lpViewport->SetViewport( &viewdata );
1235 if ( ddrval != DD_OK ) {
1236 mprintf(( "GR_D3D_SET_CLIP: SetViewport failed.\n" ));
1241 void gr_d3d_init_color(color *c, int r, int g, int b)
1243 c->screen_sig = gr_screen.signature;
1244 c->red = unsigned char(r);
1245 c->green = unsigned char(g);
1246 c->blue = unsigned char(b);
1248 c->ac_type = AC_TYPE_NONE;
1250 c->is_alphacolor = 0;
1254 void gr_d3d_init_alphacolor( color *clr, int r, int g, int b, int alpha, int type )
1256 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1257 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1258 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1259 if ( alpha < 0 ) alpha = 0; else if ( alpha > 255 ) alpha = 255;
1261 gr_d3d_init_color( clr, r, g, b );
1263 clr->alpha = unsigned char(alpha);
1264 clr->ac_type = (ubyte)type;
1265 clr->alphacolor = -1;
1266 clr->is_alphacolor = 1;
1269 void gr_d3d_set_color( int r, int g, int b )
1271 SDL_assert((r >= 0) && (r < 256));
1272 SDL_assert((g >= 0) && (g < 256));
1273 SDL_assert((b >= 0) && (b < 256));
1275 gr_d3d_init_color( &gr_screen.current_color, r, g, b );
1278 void gr_d3d_get_color( int * r, int * g, int * b )
1280 if (r) *r = gr_screen.current_color.red;
1281 if (g) *g = gr_screen.current_color.green;
1282 if (b) *b = gr_screen.current_color.blue;
1285 void gr_d3d_set_color_fast(color *dst)
1287 if ( dst->screen_sig != gr_screen.signature ) {
1288 if ( dst->is_alphacolor ) {
1289 gr_d3d_init_alphacolor( dst, dst->red, dst->green, dst->blue, dst->alpha, dst->ac_type );
1291 gr_d3d_init_color( dst, dst->red, dst->green, dst->blue );
1294 gr_screen.current_color = *dst;
1297 void gr_d3d_set_bitmap( int bitmap_num, int alphablend_mode, int bitblt_mode, float alpha, int sx, int sy )
1299 gr_screen.current_alpha = alpha;
1300 gr_screen.current_alphablend_mode = alphablend_mode;
1301 gr_screen.current_bitblt_mode = bitblt_mode;
1302 gr_screen.current_bitmap = bitmap_num;
1303 gr_screen.current_bitmap_sx = sx;
1304 gr_screen.current_bitmap_sy = sy;
1307 void gr_d3d_bitmap_ex_internal(int x,int y,int w,int h,int sx,int sy)
1316 memset( &ddsd, 0, sizeof( ddsd ) );
1317 ddsd.dwSize = sizeof( ddsd );
1319 ddrval = lpBackBuffer->Lock( NULL, &ddsd, DDLOCK_WAIT, NULL );
1320 if ( ddrval != DD_OK ) {
1321 mprintf(( "Error locking surface for bitmap_ex, %s\n", d3d_error_string(ddrval) ));
1325 dptr = (ushort *)((int)ddsd.lpSurface+ddsd.lPitch*(y+gr_screen.offset_y)+(x+gr_screen.offset_x)*2);
1327 bmp = bm_lock( gr_screen.current_bitmap, 16, 0 );
1328 sptr = (ushort *)( bmp->data + (sy*bmp->w + sx) );
1330 // nice and speedy compared to the old way
1331 for (i=0; i<h; i++ ) {
1332 for ( j=0; j<w; j++ ) {
1333 // if its not transparent, blit it
1334 if(sptr[j] != Gr_green.mask){
1339 // next row on the screen
1340 dptr = (ushort *)((uint)dptr + ddsd.lPitch);
1342 // next row in the bitmap
1346 bm_unlock(gr_screen.current_bitmap);
1348 // Unlock the back buffer
1349 lpBackBuffer->Unlock( NULL );
1352 void gr_d3d_bitmap_ex(int x,int y,int w,int h,int sx,int sy)
1359 int dx1=x, dx2=x+w-1;
1360 int dy1=y, dy2=y+h-1;
1363 bm_get_info( gr_screen.current_bitmap, &bw, &bh, NULL );
1368 if ( count > 1 ) Int3();
1372 if ((dx1 > gr_screen.clip_right ) || (dx2 < gr_screen.clip_left)) return;
1373 if ((dy1 > gr_screen.clip_bottom ) || (dy2 < gr_screen.clip_top)) return;
1374 if ( dx1 < gr_screen.clip_left ) { sx += gr_screen.clip_left-dx1; dx1 = gr_screen.clip_left; }
1375 if ( dy1 < gr_screen.clip_top ) { sy += gr_screen.clip_top-dy1; dy1 = gr_screen.clip_top; }
1376 if ( dx2 > gr_screen.clip_right ) { dx2 = gr_screen.clip_right; }
1377 if ( dy2 > gr_screen.clip_bottom ) { dy2 = gr_screen.clip_bottom; }
1394 if ( sx + w > bw ) {
1399 if ( sy + h > bh ) {
1404 if ( w < 1 ) return; // clipped away!
1405 if ( h < 1 ) return; // clipped away!
1409 // Make sure clipping algorithm works
1411 SDL_assert( w > 0 );
1412 SDL_assert( h > 0 );
1413 SDL_assert( w == (dx2-dx1+1) );
1414 SDL_assert( h == (dy2-dy1+1) );
1415 SDL_assert( sx >= 0 );
1416 SDL_assert( sy >= 0 );
1417 SDL_assert( sx+w <= bw );
1418 SDL_assert( sy+h <= bh );
1419 SDL_assert( dx2 >= dx1 );
1420 SDL_assert( dy2 >= dy1 );
1421 SDL_assert( (dx1 >= gr_screen.clip_left ) && (dx1 <= gr_screen.clip_right) );
1422 SDL_assert( (dx2 >= gr_screen.clip_left ) && (dx2 <= gr_screen.clip_right) );
1423 SDL_assert( (dy1 >= gr_screen.clip_top ) && (dy1 <= gr_screen.clip_bottom) );
1424 SDL_assert( (dy2 >= gr_screen.clip_top ) && (dy2 <= gr_screen.clip_bottom) );
1427 // We now have dx1,dy1 and dx2,dy2 and sx, sy all set validly within clip regions.
1428 // Draw bitmap bm[sx,sy] into (dx1,dy1)-(dx2,dy2)
1430 gr_d3d_bitmap_ex_internal(dx1,dy1,dx2-dx1+1,dy2-dy1+1,sx,sy);
1433 void gr_d3d_bitmap(int x, int y)
1438 bm_get_info( gr_screen.current_bitmap, &w, &h, NULL );
1439 int dx1=x, dx2=x+w-1;
1440 int dy1=y, dy2=y+h-1;
1443 if ((dx1 > gr_screen.clip_right ) || (dx2 < gr_screen.clip_left)) return;
1444 if ((dy1 > gr_screen.clip_bottom ) || (dy2 < gr_screen.clip_top)) return;
1445 if ( dx1 < gr_screen.clip_left ) { sx = gr_screen.clip_left-dx1; dx1 = gr_screen.clip_left; }
1446 if ( dy1 < gr_screen.clip_top ) { sy = gr_screen.clip_top-dy1; dy1 = gr_screen.clip_top; }
1447 if ( dx2 > gr_screen.clip_right ) { dx2 = gr_screen.clip_right; }
1448 if ( dy2 > gr_screen.clip_bottom ) { dy2 = gr_screen.clip_bottom; }
1450 if ( sx < 0 ) return;
1451 if ( sy < 0 ) return;
1452 if ( sx >= w ) return;
1453 if ( sy >= h ) return;
1455 // Draw bitmap bm[sx,sy] into (dx1,dy1)-(dx2,dy2)
1457 gr_d3d_bitmap_ex_internal(dx1,dy1,dx2-dx1+1,dy2-dy1+1,sx,sy);
1462 void gr_d3d_aabitmap_ex_internal(int x,int y,int w,int h,int sx,int sy)
1464 if ( w < 1 ) return;
1465 if ( h < 1 ) return;
1467 if ( !gr_screen.current_color.is_alphacolor ) return;
1469 float u_scale, v_scale;
1471 gr_d3d_set_state( TEXTURE_SOURCE_NO_FILTERING, ALPHA_BLEND_ALPHA_BLEND_ALPHA, ZBUFFER_TYPE_NONE );
1473 if ( !gr_tcache_set( gr_screen.current_bitmap, TCACHE_TYPE_AABITMAP, &u_scale, &v_scale ) ) {
1474 // Couldn't set texture
1475 //mprintf(( "GLIDE: Error setting aabitmap texture!\n" ));
1479 LPD3DTLVERTEX src_v;
1480 D3DTLVERTEX d3d_verts[4];
1482 float u0, u1, v0, v1;
1483 float x1, x2, y1, y2;
1486 bm_get_info( gr_screen.current_bitmap, &bw, &bh );
1489 if ( D3d_rendition_uvs ) {
1490 u0 = u_scale*(i2fl(sx)+0.5f)/i2fl(bw);
1491 v0 = v_scale*(i2fl(sy)+0.5f)/i2fl(bh);
1493 u1 = u_scale*(i2fl(sx+w)+0.5f)/i2fl(bw);
1494 v1 = v_scale*(i2fl(sy+h)+0.5f)/i2fl(bh);
1496 u0 = u_scale*i2fl(sx)/i2fl(bw);
1497 v0 = v_scale*i2fl(sy)/i2fl(bh);
1499 u1 = u_scale*i2fl(sx+w)/i2fl(bw);
1500 v1 = v_scale*i2fl(sy+h)/i2fl(bh);
1503 x1 = i2fl(x+gr_screen.offset_x);
1504 y1 = i2fl(y+gr_screen.offset_y);
1505 x2 = i2fl(x+w+gr_screen.offset_x);
1506 y2 = i2fl(y+h+gr_screen.offset_y);
1512 if ( gr_screen.current_color.is_alphacolor ) {
1513 if ( lpDevDesc->dpcTriCaps.dwTextureBlendCaps & D3DPTBLENDCAPS_MODULATEALPHA ) {
1514 color = RGBA_MAKE(gr_screen.current_color.red, gr_screen.current_color.green, gr_screen.current_color.blue,gr_screen.current_color.alpha);
1516 int r = (gr_screen.current_color.red*gr_screen.current_color.alpha)/255;
1517 int g = (gr_screen.current_color.green*gr_screen.current_color.alpha)/255;
1518 int b = (gr_screen.current_color.blue*gr_screen.current_color.alpha)/255;
1520 color = RGBA_MAKE(r,g,b, 255 );
1523 color = RGB_MAKE(gr_screen.current_color.red, gr_screen.current_color.green, gr_screen.current_color.blue);
1528 src_v->color = color;
1529 src_v->specular = 0;
1538 src_v->color = color;
1539 src_v->specular = 0;
1548 src_v->color = color;
1549 src_v->specular = 0;
1558 src_v->color = color;
1559 src_v->specular = 0;
1565 d3d_DrawPrimitive(D3DPT_TRIANGLEFAN,D3DVT_TLVERTEX,(LPVOID)d3d_verts,4,NULL);
1568 void gr_d3d_aabitmap_ex(int x,int y,int w,int h,int sx,int sy)
1575 int dx1=x, dx2=x+w-1;
1576 int dy1=y, dy2=y+h-1;
1579 bm_get_info( gr_screen.current_bitmap, &bw, &bh, NULL );
1584 if ( count > 1 ) Int3();
1588 if ((dx1 > gr_screen.clip_right ) || (dx2 < gr_screen.clip_left)) return;
1589 if ((dy1 > gr_screen.clip_bottom ) || (dy2 < gr_screen.clip_top)) return;
1590 if ( dx1 < gr_screen.clip_left ) { sx += gr_screen.clip_left-dx1; dx1 = gr_screen.clip_left; }
1591 if ( dy1 < gr_screen.clip_top ) { sy += gr_screen.clip_top-dy1; dy1 = gr_screen.clip_top; }
1592 if ( dx2 > gr_screen.clip_right ) { dx2 = gr_screen.clip_right; }
1593 if ( dy2 > gr_screen.clip_bottom ) { dy2 = gr_screen.clip_bottom; }
1610 if ( sx + w > bw ) {
1615 if ( sy + h > bh ) {
1620 if ( w < 1 ) return; // clipped away!
1621 if ( h < 1 ) return; // clipped away!
1625 // Make sure clipping algorithm works
1627 SDL_assert( w > 0 );
1628 SDL_assert( h > 0 );
1629 SDL_assert( w == (dx2-dx1+1) );
1630 SDL_assert( h == (dy2-dy1+1) );
1631 SDL_assert( sx >= 0 );
1632 SDL_assert( sy >= 0 );
1633 SDL_assert( sx+w <= bw );
1634 SDL_assert( sy+h <= bh );
1635 SDL_assert( dx2 >= dx1 );
1636 SDL_assert( dy2 >= dy1 );
1637 SDL_assert( (dx1 >= gr_screen.clip_left ) && (dx1 <= gr_screen.clip_right) );
1638 SDL_assert( (dx2 >= gr_screen.clip_left ) && (dx2 <= gr_screen.clip_right) );
1639 SDL_assert( (dy1 >= gr_screen.clip_top ) && (dy1 <= gr_screen.clip_bottom) );
1640 SDL_assert( (dy2 >= gr_screen.clip_top ) && (dy2 <= gr_screen.clip_bottom) );
1643 // We now have dx1,dy1 and dx2,dy2 and sx, sy all set validly within clip regions.
1644 gr_d3d_aabitmap_ex_internal(dx1,dy1,dx2-dx1+1,dy2-dy1+1,sx,sy);
1647 void gr_d3d_aabitmap(int x, int y)
1651 bm_get_info( gr_screen.current_bitmap, &w, &h, NULL );
1652 int dx1=x, dx2=x+w-1;
1653 int dy1=y, dy2=y+h-1;
1656 if ((dx1 > gr_screen.clip_right ) || (dx2 < gr_screen.clip_left)) return;
1657 if ((dy1 > gr_screen.clip_bottom ) || (dy2 < gr_screen.clip_top)) return;
1658 if ( dx1 < gr_screen.clip_left ) { sx = gr_screen.clip_left-dx1; dx1 = gr_screen.clip_left; }
1659 if ( dy1 < gr_screen.clip_top ) { sy = gr_screen.clip_top-dy1; dy1 = gr_screen.clip_top; }
1660 if ( dx2 > gr_screen.clip_right ) { dx2 = gr_screen.clip_right; }
1661 if ( dy2 > gr_screen.clip_bottom ) { dy2 = gr_screen.clip_bottom; }
1663 if ( sx < 0 ) return;
1664 if ( sy < 0 ) return;
1665 if ( sx >= w ) return;
1666 if ( sy >= h ) return;
1668 // Draw bitmap bm[sx,sy] into (dx1,dy1)-(dx2,dy2)
1669 gr_aabitmap_ex(dx1,dy1,dx2-dx1+1,dy2-dy1+1,sx,sy);
1673 void gr_d3d_string( int sx, int sy, char *s )
1675 int width, spacing, letter;
1678 if ( !Current_font ) {
1682 gr_set_bitmap(Current_font->bitmap_id);
1687 if (sx==0x8000) { //centered
1688 x = get_centered_x(s);
1698 while (*s== '\n' ) {
1700 y += Current_font->h;
1701 if (sx==0x8000) { //centered
1702 x = get_centered_x(s);
1707 if (*s == 0 ) break;
1709 letter = get_char_width(s[0],s[1],&width,&spacing);
1712 //not in font, draw as space
1720 // Check if this character is totally clipped
1721 if ( x + width < gr_screen.clip_left ) continue;
1722 if ( y + Current_font->h < gr_screen.clip_top ) continue;
1723 if ( x > gr_screen.clip_right ) continue;
1724 if ( y > gr_screen.clip_bottom ) continue;
1727 if ( x < gr_screen.clip_left ) xd = gr_screen.clip_left - x;
1728 if ( y < gr_screen.clip_top ) yd = gr_screen.clip_top - y;
1732 wc = width - xd; hc = Current_font->h - yd;
1733 if ( xc + wc > gr_screen.clip_right ) wc = gr_screen.clip_right - xc;
1734 if ( yc + hc > gr_screen.clip_bottom ) hc = gr_screen.clip_bottom - yc;
1736 if ( wc < 1 ) continue;
1737 if ( hc < 1 ) continue;
1741 ch = &Current_font->char_data[letter];
1743 int u = Current_font->bm_u[letter];
1744 int v = Current_font->bm_v[letter];
1746 gr_d3d_aabitmap_ex_internal( xc, yc, wc, hc, u+xd, v+yd );
1750 void gr_d3d_rect(int x,int y,int w,int h)
1752 gr_d3d_rect_internal(x, y, w, h, gr_screen.current_color.red, gr_screen.current_color.green, gr_screen.current_color.blue, gr_screen.current_color.alpha);
1755 void gr_d3d_flash(int r, int g, int b)
1761 if ( r || g || b ) {
1763 if ( lpDevDesc->dpcTriCaps.dwDestBlendCaps & D3DPBLENDCAPS_ONE ) {
1764 gr_d3d_set_state( TEXTURE_SOURCE_NONE, ALPHA_BLEND_ALPHA_ADDITIVE, ZBUFFER_TYPE_NONE );
1765 color = RGBA_MAKE(r, g, b, 255);
1767 gr_d3d_set_state( TEXTURE_SOURCE_NONE, ALPHA_BLEND_ALPHA_BLEND_ALPHA, ZBUFFER_TYPE_NONE );
1770 color = RGBA_MAKE(r,g,b,a);
1773 float x1, x2, y1, y2;
1774 x1 = i2fl(gr_screen.clip_left+gr_screen.offset_x);
1775 y1 = i2fl(gr_screen.clip_top+gr_screen.offset_y);
1776 x2 = i2fl(gr_screen.clip_right+gr_screen.offset_x);
1777 y2 = i2fl(gr_screen.clip_bottom+gr_screen.offset_y);
1779 LPD3DTLVERTEX src_v;
1780 D3DTLVERTEX d3d_verts[4];
1786 src_v->color = color;
1787 src_v->specular = 0;
1794 src_v->color = color;
1795 src_v->specular = 0;
1802 src_v->color = color;
1803 src_v->specular = 0;
1810 src_v->color = color;
1811 src_v->specular = 0;
1815 d3d_DrawPrimitive(D3DPT_TRIANGLEFAN,D3DVT_TLVERTEX,(LPVOID)d3d_verts,4,NULL);
1821 void gr_d3d_create_shader(shader * shade, float r, float g, float b, float c )
1823 shade->screen_sig = gr_screen.signature;
1830 void gr_d3d_set_shader( shader * shade )
1833 if (shade->screen_sig != gr_screen.signature) {
1834 gr_create_shader( shade, shade->r, shade->g, shade->b, shade->c );
1836 gr_screen.current_shader = *shade;
1838 gr_create_shader( &gr_screen.current_shader, 0.0f, 0.0f, 0.0f, 0.0f );
1842 void gr_d3d_shade(int x,int y,int w,int h)
1846 float shade1 = 1.0f;
1847 float shade2 = 6.0f;
1849 r = fl2i(gr_screen.current_shader.r*255.0f*shade1);
1850 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1851 g = fl2i(gr_screen.current_shader.g*255.0f*shade1);
1852 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1853 b = fl2i(gr_screen.current_shader.b*255.0f*shade1);
1854 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1855 a = fl2i(gr_screen.current_shader.c*255.0f*shade2);
1856 if ( a < 0 ) a = 0; else if ( a > 255 ) a = 255;
1858 gr_d3d_rect_internal(x, y, w, h, r, g, b, a);
1861 void gr_d3d_circle( int xc, int yc, int d )
1872 if ( (xc+r) < gr_screen.clip_left ) return;
1873 if ( (xc-r) > gr_screen.clip_right ) return;
1874 if ( (yc+r) < gr_screen.clip_top ) return;
1875 if ( (yc-r) > gr_screen.clip_bottom ) return;
1878 // Draw the first octant
1879 gr_d3d_line( xc-y, yc-x, xc+y, yc-x );
1880 gr_d3d_line( xc-y, yc+x, xc+y, yc+x );
1885 // Draw the second octant
1886 gr_d3d_line( xc-x, yc-y, xc+x, yc-y );
1887 gr_d3d_line( xc-x, yc+y, xc+x, yc+y );
1894 gr_d3d_line( xc-x, yc-y, xc+x, yc-y );
1895 gr_d3d_line( xc-x, yc+y, xc+x, yc+y );
1902 void gr_d3d_line(int x1,int y1,int x2,int y2)
1904 int clipped = 0, swapped=0;
1907 // Set up Render State - flat shading - alpha blending
1908 if ( (lpDevDesc->dpcLineCaps.dwSrcBlendCaps & D3DPBLENDCAPS_SRCALPHA) && (lpDevDesc->dpcLineCaps.dwDestBlendCaps & D3DPBLENDCAPS_INVSRCALPHA) ) {
1909 gr_d3d_set_state( TEXTURE_SOURCE_NONE, ALPHA_BLEND_ALPHA_BLEND_ALPHA, ZBUFFER_TYPE_NONE );
1910 color = RGBA_MAKE(gr_screen.current_color.red, gr_screen.current_color.green, gr_screen.current_color.blue, gr_screen.current_color.alpha );
1912 // Matrox MGA-G200 doesn't support alpha-blended lines.
1913 gr_d3d_set_state( TEXTURE_SOURCE_NONE, ALPHA_BLEND_NONE, ZBUFFER_TYPE_NONE );
1915 int r = (gr_screen.current_color.red*gr_screen.current_color.alpha)/255;
1916 int g = (gr_screen.current_color.green*gr_screen.current_color.alpha)/255;
1917 int b = (gr_screen.current_color.blue*gr_screen.current_color.alpha)/255;
1919 color = RGBA_MAKE(r,g,b, 255 );
1922 INT_CLIPLINE(x1,y1,x2,y2,gr_screen.clip_left,gr_screen.clip_top,gr_screen.clip_right,gr_screen.clip_bottom,return,clipped=1,swapped=1);
1924 D3DTLVERTEX d3d_verts[2];
1925 D3DTLVERTEX *a = d3d_verts;
1926 D3DTLVERTEX *b = d3d_verts+1;
1928 d3d_make_rect(a,b,x1,y1,x2,y2);
1933 d3d_DrawPrimitive(D3DPT_LINELIST,D3DVT_TLVERTEX,(LPVOID)d3d_verts,2,NULL);
1936 void gr_d3d_aaline(vertex *v1, vertex *v2)
1938 gr_d3d_line( fl2i(v1->sx), fl2i(v1->sy), fl2i(v2->sx), fl2i(v2->sy) );
1942 void gr_d3d_gradient(int x1,int y1,int x2,int y2)
1944 int clipped = 0, swapped=0;
1946 if ( !gr_screen.current_color.is_alphacolor ) {
1947 gr_line( x1, y1, x2, y2 );
1951 INT_CLIPLINE(x1,y1,x2,y2,gr_screen.clip_left,gr_screen.clip_top,gr_screen.clip_right,gr_screen.clip_bottom,return,clipped=1,swapped=1);
1953 uint color1, color2;
1955 // Set up Render State - flat shading - alpha blending
1956 if ( (lpDevDesc->dpcLineCaps.dwSrcBlendCaps & D3DPBLENDCAPS_SRCALPHA) && (lpDevDesc->dpcLineCaps.dwDestBlendCaps & D3DPBLENDCAPS_INVSRCALPHA) ) {
1957 gr_d3d_set_state( TEXTURE_SOURCE_NONE, ALPHA_BLEND_ALPHA_BLEND_ALPHA, ZBUFFER_TYPE_NONE );
1959 if (lpDevDesc->dpcLineCaps.dwShadeCaps & D3DPSHADECAPS_ALPHAGOURAUDBLEND ) {
1960 color1 = RGBA_MAKE(gr_screen.current_color.red, gr_screen.current_color.green, gr_screen.current_color.blue, gr_screen.current_color.alpha );
1961 color2 = RGBA_MAKE(gr_screen.current_color.red, gr_screen.current_color.green, gr_screen.current_color.blue, 0 );
1962 } else if (lpDevDesc->dpcLineCaps.dwShadeCaps & D3DPSHADECAPS_COLORGOURAUDRGB ) {
1963 color1 = RGBA_MAKE(gr_screen.current_color.red,gr_screen.current_color.green,gr_screen.current_color.blue,gr_screen.current_color.alpha);
1964 color2 = RGBA_MAKE(0,0,0,gr_screen.current_color.alpha);
1966 color1 = RGBA_MAKE(gr_screen.current_color.red,gr_screen.current_color.green,gr_screen.current_color.blue,gr_screen.current_color.alpha);
1967 color2 = RGBA_MAKE(gr_screen.current_color.red,gr_screen.current_color.green,gr_screen.current_color.blue,gr_screen.current_color.alpha);
1970 // Matrox MGA-G200 doesn't support alpha-blended lines.
1971 gr_d3d_set_state( TEXTURE_SOURCE_NONE, ALPHA_BLEND_NONE, ZBUFFER_TYPE_NONE );
1973 int r = (gr_screen.current_color.red*gr_screen.current_color.alpha)/255;
1974 int g = (gr_screen.current_color.green*gr_screen.current_color.alpha)/255;
1975 int b = (gr_screen.current_color.blue*gr_screen.current_color.alpha)/255;
1977 if (lpDevDesc->dpcLineCaps.dwShadeCaps & D3DPSHADECAPS_COLORGOURAUDRGB ) {
1978 color1 = RGBA_MAKE(r,g,b, 255 );
1979 color2 = RGBA_MAKE(0,0,0, 255 );
1981 color1 = RGBA_MAKE(r,g,b, 255 );
1982 color2 = RGBA_MAKE(r,g,b, 255 );
1986 // gr_d3d_set_state( TEXTURE_SOURCE_NONE, ALPHA_BLEND_NONE, ZBUFFER_TYPE_NONE );
1987 // color1 = RGBA_MAKE(gr_screen.current_color.red,gr_screen.current_color.green,gr_screen.current_color.blue,255);
1988 // color2 = RGBA_MAKE(gr_screen.current_color.red,gr_screen.current_color.green,gr_screen.current_color.blue,255);
1990 D3DTLVERTEX d3d_verts[2];
1991 D3DTLVERTEX *a = d3d_verts;
1992 D3DTLVERTEX *b = d3d_verts+1;
1994 d3d_make_rect( a, b, x1, y1, x2, y2 );
2003 d3d_DrawPrimitive(D3DPT_LINELIST,D3DVT_TLVERTEX,(LPVOID)d3d_verts,2,NULL);
2007 void gr_d3d_set_palette(ubyte *new_palette, int restrict_alphacolor)
2012 // copy from one pixel buffer to another
2014 // from pointer to source buffer
2015 // to pointer to dest. buffet
2016 // pixels number of pixels to copy
2017 // fromsize source pixel size
2018 // tosize dest. pixel size
2020 static int tga_copy_data(char *to, char *from, int pixels, int fromsize, int tosize)
2022 if ( (fromsize == 2) && (tosize == 3) ) {
2023 ushort *src = (ushort *)from;
2024 ubyte *dst = (ubyte *)to;
2027 for (i=0; i<pixels; i++ ) {
2028 ushort pixel = *src++;
2030 *dst++ = ubyte(((pixel & Gr_blue.mask)>>Gr_blue.shift)*Gr_blue.scale);
2031 *dst++ = ubyte(((pixel & Gr_green.mask)>>Gr_green.shift)*Gr_green.scale);
2032 *dst++ = ubyte(((pixel & Gr_red.mask)>>Gr_red.shift)*Gr_red.scale);
2034 return tosize*pixels;
2035 } else if( (fromsize == 4) && (tosize == 3) ){
2036 uint *src = (uint *)from;
2037 ubyte *dst = (ubyte *)to;
2040 for (i=0; i<pixels; i++ ) {
2041 uint pixel = *src++;
2043 *dst++ = ubyte(((pixel & Gr_blue.mask)>>Gr_blue.shift)*Gr_blue.scale);
2044 *dst++ = ubyte(((pixel & Gr_green.mask)>>Gr_green.shift)*Gr_green.scale);
2045 *dst++ = ubyte(((pixel & Gr_red.mask)>>Gr_red.shift)*Gr_red.scale);
2047 return tosize*pixels;
2050 return tosize*pixels;
2055 // tga_pixels_equal -- Test if two pixels are identical
2061 static int tga_pixels_equal(char *pix1, char *pix2, int pixbytes)
2064 if ( *pix1++ != *pix2++ ) {
2067 } while ( --pixbytes > 0 );
2073 // tga_compress - Do the Run Length Compression
2076 // out Buffer to write it out to
2077 // in Buffer to compress
2078 // bytecount Number of bytes input
2079 // pixsize Number of bytes in input pixel
2080 // outsize Number of bytes in output buffer
2082 static int tga_compress(char *out, char *in, int bytecount, int pixsize )
2086 int pixcount; // number of pixels in the current packet
2087 char *inputpixel=NULL; // current input pixel position
2088 char *matchpixel=NULL; // pixel value to match for a run
2089 char *flagbyte=NULL; // location of last flag byte to set
2090 int rlcount; // current count in r.l. string
2091 int rlthresh; // minimum valid run length
2092 char *copyloc; // location to begin copying at
2094 // set the threshold -- the minimum valid run length
2097 rlthresh = 2; // for 8bpp, require a 2 pixel span before rle'ing
2102 // set the first pixel up
2104 flagbyte = out; // place to put next flag if run
2108 copyloc = (char *)0;
2110 // loop till data processing complete
2113 // if we have accumulated a 128-byte packet, process it
2114 if ( pixcount == 129 ) {
2117 // set the run flag if this is a run
2119 if ( rlcount >= rlthresh ) {
2124 // copy the data into place
2126 flagbyte += tga_copy_data(flagbyte, copyloc, pixcount-1, pixsize, outsize);
2129 // set up for next packet
2133 // if zeroth byte, handle as special case
2134 if ( pixcount == 1 ) {
2136 copyloc = inputpixel; /* point to 1st guy in packet */
2137 matchpixel = inputpixel; /* set pointer to pix to match */
2139 inputpixel += pixsize;
2143 // assembling a packet -- look at next pixel
2145 // current pixel == match pixel?
2146 if ( tga_pixels_equal(inputpixel, matchpixel, outsize) ) {
2148 // establishing a run of enough length to
2149 // save space by doing it
2150 // -- write the non-run length packet
2151 // -- start run-length packet
2153 if ( ++rlcount == rlthresh ) {
2155 // close a non-run packet
2157 if ( pixcount > (rlcount+1) ) {
2158 // write out length and do not set run flag
2160 *flagbyte++ = (char)(pixcount - 2 - rlthresh);
2162 flagbyte += tga_copy_data(flagbyte, copyloc, (pixcount-1-rlcount), pixsize, outsize);
2164 copyloc = inputpixel;
2165 pixcount = rlcount + 1;
2170 // no match -- either break a run or continue without one
2171 // if a run exists break it:
2172 // write the bytes in the string (outsize+1)
2173 // start the next string
2175 if ( rlcount >= rlthresh ) {
2177 *flagbyte++ = (char)(0x80 | rlcount);
2178 flagbyte += tga_copy_data(flagbyte, copyloc, 1, pixsize, outsize);
2183 // not a match and currently not a run
2184 // - save the current pixel
2185 // - reset the run-length flag
2187 matchpixel = inputpixel;
2191 inputpixel += pixsize;
2192 } while ( inputpixel < (in + bytecount));
2194 // quit this buffer without loosing any data
2196 if ( --pixcount >= 1 ) {
2197 *flagbyte = (char)(pixcount - 1);
2198 if ( rlcount >= rlthresh ) {
2203 // copy the data into place
2205 flagbyte += tga_copy_data(flagbyte, copyloc, pixcount, pixsize, outsize);
2207 return(flagbyte-out);
2210 void gr_d3d_print_screen(char *filename)
2214 ubyte outrow[1024*3*4];
2216 if ( gr_screen.max_w > 1024 ) {
2217 mprintf(( "Screen too wide for print_screen\n" ));
2221 memset( &ddsd, 0, sizeof( ddsd ) );
2222 ddsd.dwSize = sizeof( ddsd );
2224 ddrval = lpBackBuffer->Lock( NULL, &ddsd, DDLOCK_WAIT, NULL );
2225 if ( ddrval != DD_OK ) {
2226 mprintf(( "Error locking surface for print_screen, %s\n", d3d_error_string(ddrval) ));
2229 ubyte *dptr = (ubyte *)ddsd.lpSurface;
2233 strcpy( tmp, NOX(".\\")); // specify a path mean files goes in root
2234 strcat( tmp, filename );
2235 strcat( tmp, NOX(".tga"));
2237 CFILE *f = cfopen(tmp, "wb");
2239 // Write the TGA header
2240 cfwrite_ubyte( 0, f ); // IDLength;
2241 cfwrite_ubyte( 0, f ); // ColorMapType;
2242 cfwrite_ubyte( 10, f ); // ImageType; // 2 = 24bpp, uncompressed, 10=24bpp rle compressed
2243 cfwrite_ushort( 0, f ); // CMapStart;
2244 cfwrite_ushort( 0, f ); // CMapLength;
2245 cfwrite_ubyte( 0, f ); // CMapDepth;
2246 cfwrite_ushort( 0, f ); // XOffset;
2247 cfwrite_ushort( 0, f ); // YOffset;
2248 cfwrite_ushort( (ushort)gr_screen.max_w, f ); // Width;
2249 cfwrite_ushort( (ushort)gr_screen.max_h, f ); // Height;
2250 cfwrite_ubyte( 24, f ); //PixelDepth;
2251 cfwrite_ubyte( 0, f ); //ImageDesc;
2253 // Go through and read our pixels
2255 for (i=0;i<gr_screen.max_h;i++) {
2256 int len = tga_compress( (char *)outrow, (char *)&dptr[(gr_screen.max_h-i-1)*ddsd.lPitch], gr_screen.max_w * gr_screen.bytes_per_pixel, gr_screen.bytes_per_pixel );
2258 cfwrite(outrow, len, 1, f);
2263 // Unlock the back buffer
2264 lpBackBuffer->Unlock( NULL );