2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
6 // $Header: r:/t2repos/thief2/src/engfeat/inv_rend.c,v 1.47 2000/02/19 13:15:07 toml Exp $
7 // code to draw the current inventory object
8 // more generally, code to support the issue of rendering models to various canvases
9 // caching how they look, and so on
11 // massively in progress, particularly:
12 // do we want to allow hand draw models as well for things which look goofy
13 // really need to mip map all this
14 // do we want a way to have a "current" one which rotates somehow
51 #include <dbmem.h> // must be last header!
53 // internal flag bits, public ones are in inv_rend.h
54 #define INVREND_BITMAP (1<<8)
55 #define INVREND_MODEL (1<<9)
56 #define INVREND_CACHEVALID (1<<10) // currently unsupported
57 #define INVREND_IN_QUEUE (1<<11)
58 #define INVREND_FREE_ON_RENDER (1<<12)
60 #define INVREND_HARDWARE (INVREND_HARDWARE_QUEUE|INVREND_HARDWARE_IMMEDIATE)
61 #define INVREND_TYPE (INVREND_BITMAP|INVREND_MODEL)
63 // so we can flag having no model info
64 #define INV_NO_MODEL (-1)
67 // internal structure, we dont expose details of this
68 struct _invRendState
{
70 ObjID obj_id
; // obj_id for us
71 int model_idx
; // what model idx i have
72 int bitmappalnum
; //palette location, if a bitmap resource
73 IRes
*pBMRes
; // Bitmap resource, if not a model
74 short flags
; // any flags
75 grs_canvas
*back_buffer
; // app managed back buffer; if NULL, render to vis_buffer
76 grs_canvas vis_buffer
; // visible buffer; sub canvas of screen canvas specified by draw_rect.
78 sInvRenderType rendtype
;
81 // the override how i draw properties
82 static IInvRenderProperty
* gpInvRendProp
= NULL
;
84 // The path for finding bitmaps
85 #define BITMAP_PATH "obj\\"
86 static ISearchPath
*gpInvRendBitmapPath
= NULL
;
88 static float gRenderZoom
= 4.0;
94 EXTERN BOOL g_null_raster
;
95 int g_inv_bcolor
= -1;
98 static mls_multi_light lights
[] =
100 #ifdef RGB_LIGHTING //zb :
101 // primary, ~30 degrees clockwise from x axis, 100+ feet away
102 { { 85.0, 50.0, 20.0 }, { 0.0 }, { 100.0, 100.0, 100.0 }, },
103 // secondary, behind object but not opposite
104 { { -50.0, -85.0, -10.0 }, { 0.0 }, { 30.0, 30.0, 30.0 }, },
107 // primary, ~30 degrees clockwise from x axis, 100+ feet away
108 { { 85.0, 50.0, 20.0 }, { 0.0 }, 100.0, },
109 // secondary, behind object but not opposite
110 { { -50.0, -85.0, -10.0 }, { 0.0 }, 30.0, },
115 static void start_ir_stride(void)
120 r3d_glob
.cur_stride
= sizeof(g2s_point
); // for
121 mdd_rgb_lighting
= TRUE
;
122 mld_multi_rgb
= TRUE
;
125 mld_multi_rgb
= FALSE
;
127 mdd_rgb_lighting
= FALSE
;
128 r3d_glob
.cur_stride
= sizeof(r3s_point
);
132 static void end_ir_stride(void)
134 r3d_glob
.cur_stride
= sizeof(r3s_point
);
135 mld_multi_rgb
= FALSE
;
138 #define NUM_LIGHTS (sizeof(lights)/sizeof(lights[0]))
140 // if there is a back buffer, render there, else render to vis_buffer
141 static void render_single_obj(invRendState
*us
, BOOL bClearZBuffer
)
143 int clr_color
=g_inv_bcolor
;
144 mxs_real zoom
= gRenderZoom
;
148 // Objects with 32-bit textures would kill us in software rendering.
155 gr_push_canvas(us
->back_buffer
);
157 gr_push_canvas(&us
->vis_buffer
);
159 if ((g_lgd3d
) && (!g_null_raster
))
161 if ((us
->flags
& INVREND_HARDWARE
)&&(us
->flags
& INVREND_MODEL
))
163 // clear the zbuffer for HW
164 lgd3d_set_offsets(us
->draw_rect
.ul
.x
, us
->draw_rect
.ul
.y
);
166 lgd3d_clear_z_rect(0, 0, grd_bm
.w
, grd_bm
.h
);
170 if ((us
->flags
& INVREND_CLEAR
) && (clr_color
== -1))
176 if (us
->flags
&INVREND_MODEL
)
178 // first, pick camera location correctly
179 mxs_vector cam_base
={0,0,0};
180 mxs_vector cam_loc
, obj_loc
={0,0,0};
184 mls_multi_light tmplights
[NUM_LIGHTS
];
186 // check that it's actually an md model
187 // MAHK 7/30: this is basically here to catch mesh models
188 if(objmodelGetModelType(us
->model_idx
)!=OM_TYPE_MD
)
190 ConfigSpew("InvrendSpew",("render_single_obj: unable to render non-md inventory item\n"));
196 cam_base
.el
[0]=us
->cam_dist
*zoom
;
197 if (us
->flags
&INVREND_DISTANT
)
198 cam_base
.el
[0]*=2.00;
200 mx_ang2mat(&cam_mat
,&us
->off_ang
);
201 mx_mat_mul_vec(&cam_loc
,&cam_mat
,&cam_base
);
203 cam_ang
.el
[2]+=0x8000; // does this work?
204 cam_ang
.el
[1]=-cam_ang
.el
[1];
206 // orbit the lights with the camera
209 for (i
= 0; i
< NUM_LIGHTS
; i
++)
212 tmplights
[i
].bright
.x
= us
->lighting
*lights
[i
].bright
.x
;
213 tmplights
[i
].bright
.y
= us
->lighting
*lights
[i
].bright
.y
;
214 tmplights
[i
].bright
.z
= us
->lighting
*lights
[i
].bright
.z
;
216 tmplights
[i
].bright
.x
= us
->lighting
*lights
[i
].bright
.x
;
217 tmplights
[i
].bright
.y
= us
->lighting
*lights
[i
].bright
.y
;
218 tmplights
[i
].bright
.z
= us
->lighting
*lights
[i
].bright
.z
;
220 mx_mat_mul_vec(&tmplights
[i
].loc
,&cam_mat
,&lights
[i
].loc
);
224 // now start up the 3d
228 r3_set_view_angles(&cam_loc
,&cam_ang
,R3_DEFANG
);
230 // @TODO: THIS NEEDS TO BECOME A CALL TO RENDOBJ, OR DOES IT?
231 r3_start_object(&obj_loc
);
233 // @TODO: would like to try to do the DIMMED control
234 md_set_render_light(TRUE
);
235 // md_set_render_light(FALSE);
237 // render the darn thing
238 if ((m
=(mds_model
*)objmodelGetModel(us
->model_idx
))!=NULL
)
239 { // get real joint parms, colors?
240 extern mds_parm
*getRendParms(ObjID obj
, mds_model
*m
);
241 mds_parm
*parms
=NULL
; // this should all be in a function call!
244 parms
=getRendParms(us
->obj_id
,m
);
245 md_mat_colors_set(m
);
246 mld_multi_hilight
= 0;
247 mld_multi_ambient
= 0.1;
248 mld_multi_ambient_only
= FALSE
;
249 mld_multi_unlit
= FALSE
;
250 ml_multi_set_lights_for_object(NUM_LIGHTS
,tmplights
,&obj_loc
,2.0);
251 objmodelSetupMdTextures(us
->obj_id
,m
,us
->model_idx
);
252 // wsf: why was md_fancy_render_model being called twice?
253 // md_fancy_render_model(m,parms);
255 start_ir_stride();//zb
256 md_fancy_render_model(m
,parms
);
257 end_ir_stride(); //zb
260 r3_end_object(); // and close down the frame
263 else if (us
->flags
&INVREND_BITMAP
)
265 grs_bitmap
*bm
= IRes_Lock(us
->pBMRes
);
266 bm
->align
= us
->bitmappalnum
;
268 IRes_Unlock(us
->pBMRes
);
271 Warning(("No modelNum for inv obj %d\n",us
->obj_id
));
277 // cache/canvas controller
278 static void _invInitCamera(invRendState
*us
)
280 if (us
->flags
&INVREND_MODEL
)
283 us
->off_ang
.el
[0]=us
->off_ang
.el
[2]=0;
284 us
->off_ang
.el
[1]=0xf000;
285 us
->cam_dist
=3.0; // hopefully this gets fixed below
286 if ((m
=(mds_model
*)objmodelGetModel(us
->model_idx
))!=NULL
)
287 us
->cam_dist
=m
->radius
+0.7;
288 } // set scale factor here, i guess
291 static void _invGetModelIdx(invRendState
*us
)
295 us
->model_idx
=INV_NO_MODEL
; // so we have a value if nothing works
296 us
->bitmappalnum
=0; // so if we aren't a bitmap, this is set
299 switch (us
->rendtype
.type
)
302 case kInvRenderModel
:
303 if ((new_idx
=objmodelLoadModel(us
->rendtype
.resource
.text
))!=MIDX_INVALID
)
305 us
->model_idx
=new_idx
;
306 objmodelIncRef(us
->model_idx
);
307 us
->flags
|=INVREND_MODEL
;
311 case kInvRenderBitmap
:
313 IResMan
*pResMan
= AppGetObj(IResMan
);
314 IRes
*new_pRes
= IResMan_Bind(pResMan
,
315 us
->rendtype
.resource
.text
,
322 IRes
*pPallRes
= IResMan_Retype(pResMan
,
328 us
->pBMRes
=new_pRes
; //ok, so we send this resource over to "us"
329 //presumably it gets released later.
330 us
->flags
|=INVREND_BITMAP
;
336 void *pPall
= IRes_Lock(pPallRes
);
337 if (us
->bitmappalnum
==0)
339 us
->bitmappalnum
= palmgr_alloc_pal(pPall
);
341 IRes_Unlock(pPallRes
);
343 SafeRelease(pPallRes
);
346 SafeRelease(pResMan
);
350 case kInvRenderDefault
:
351 if (ObjGetModelNumber(us
->obj_id
,&us
->model_idx
))
352 us
->flags
|=INVREND_MODEL
; // just use the default world model for us
355 if ((us
->model_idx
==INV_NO_MODEL
) && (!us
->pBMRes
))
356 Warning(("No Inventory Model IDX for %d",us
->obj_id
));
359 static void _invFreeModelIdx(invRendState
*us
)
362 switch (us
->rendtype
.type
)
364 case kInvRenderModel
:
365 if (us
->model_idx
!=INV_NO_MODEL
)
366 objmodelDecRef(us
->model_idx
);
368 case kInvRenderBitmap
:
369 if (us
->bitmappalnum
!=0)
371 palmgr_release_slot(us
->bitmappalnum
);
375 SafeRelease(us
->pBMRes
);
380 static void invrend_init_state(invRendState
* us
, int flags
, const Rect
*r
, grs_canvas
*draw_cnv
)
382 grs_canvas
*screen_canvas
= ScrnGetDrawCanvas();
384 us
->flags
=flags
&INVREND_USERFLAGS
;
389 us
->draw_rect
.ul
.x
= 0;
390 us
->draw_rect
.ul
.y
= 0;
391 us
->draw_rect
.lr
.x
= screen_canvas
->bm
.w
;
392 us
->draw_rect
.lr
.y
= screen_canvas
->bm
.h
;
395 gr_init_sub_canvas(screen_canvas
, &us
->vis_buffer
,
396 us
->draw_rect
.ul
.x
, us
->draw_rect
.ul
.y
,
397 RectWidth(&us
->draw_rect
), RectHeight(&us
->draw_rect
));
402 us
->back_buffer
=draw_cnv
;
407 // need to look up inv_rend property here!
408 invRendState
*invRendBuildState(int flags
, ObjID o_id
, const Rect
*r
, grs_canvas
*draw_cnv
)
410 invRendState
*us
=(invRendState
*)Malloc(sizeof(invRendState
));
411 sInvRenderType defprop
= { kInvRenderDefault
};
412 sInvRenderType
* rendprop
= &defprop
;
414 PROPERTY_GET(gpInvRendProp
,o_id
,&rendprop
);
415 us
->rendtype
= *rendprop
;
418 invrend_init_state(us
, flags
, r
, draw_cnv
);
423 // need to look up inv_rend property here!
424 invRendState
*invRendBuildStateFromType(int flags
, sInvRenderType
* type
, const Rect
*r
, grs_canvas
*draw_cnv
)
426 invRendState
*us
=(invRendState
*)Malloc(sizeof(invRendState
));
428 us
->obj_id
= OBJ_NULL
;
429 us
->rendtype
= *type
;
431 invrend_init_state(us
, flags
, r
, draw_cnv
);
436 void invRendFreeState(invRendState
*us
)
438 if (us
->flags
& INVREND_IN_QUEUE
) {
439 us
->flags
|= INVREND_FREE_ON_RENDER
;
442 gr_close_canvas(&us
->vis_buffer
);
443 _invFreeModelIdx(us
);
449 void invRendSetCanvas(invRendState
* us
, grs_canvas
* canv
)
452 us
->back_buffer
=canv
;
456 void invRendSetRect(invRendState
* us
, const Rect
*r
)
460 gr_close_canvas(&us
->vis_buffer
);
461 gr_init_sub_canvas(ScrnGetDrawCanvas(), &us
->vis_buffer
, r
->ul
.x
, r
->ul
.y
, RectWidth(r
), RectHeight(r
));
465 void invRendSetType(invRendState
* us
, const sInvRenderType
* type
)
467 // if same, just exit
468 if (us
->rendtype
.type
== type
->type
) // slight overuse of "type"
470 if (type
->type
== kInvRenderDefault
471 || strncmp(us
->rendtype
.resource
.text
,
473 sizeof(us
->rendtype
.resource
.text
)) == 0)
476 _invFreeModelIdx(us
);
477 us
->rendtype
= *type
;
481 // this is the big mess, having to deal with changing whether im now hilight, if my canvas changes, so on
482 void invRendUpdateState(invRendState
*us
, int flags
, ObjID o_id
, const Rect
*r
, grs_canvas
*draw_cnv
)
484 if ((o_id
!=us
->obj_id
)&&(o_id
!=OBJ_NULL
))
486 _invFreeModelIdx(us
);
488 us
->rendtype
.type
= kInvRenderDefault
;
492 invRendSetRect(us
,r
);
493 invRendSetCanvas(us
,draw_cnv
);
494 if (flags
&INVREND_SET
)
497 if ((flags
&INVREND_CACHEPICTURE
)!=(us
->flags
&INVREND_CACHEPICTURE
))
498 Warning(("Hey! cant update state and change from double buffered to not in inv_rend\n"));
499 us
->flags
&=~INVREND_CACHEVALID
;
501 us
->flags
=(us
->flags
&(~INVREND_USERFLAGS
))|(flags
&INVREND_USERFLAGS
);
505 #define QUEUE_SIZE 25
506 static invRendState
*objQueue
[QUEUE_SIZE
];
507 static int numObjs
=0;
510 // draw/update control
511 // Note: we assume draw canvas is locked when this is called.
512 void invRendDrawUpdate(invRendState
*us
)
515 switch (us
->flags
& (INVREND_HARDWARE
|INVREND_TYPE
))
517 case INVREND_HARDWARE_QUEUE
|INVREND_MODEL
:
518 // queue object for hardware accelerated rendering...
519 if (numObjs
>= QUEUE_SIZE
) {
520 Warning(("invRendDrawUpdate(): too many objects to queue.\n"));
521 } else if (us
->back_buffer
!= NULL
) {
522 Warning(("Can't hardware accelerate object rendered off screen.\n"));
524 objQueue
[numObjs
++] = us
;
525 us
->flags
|= INVREND_IN_QUEUE
;
528 case INVREND_HARDWARE_IMMEDIATE
|INVREND_MODEL
:
529 if (us
->back_buffer
!= NULL
) {
530 Warning(("Can't hardware accelerate object rendered off screen.\n"));
531 render_single_obj(us
, TRUE
);
533 extern int rendloop_counter
;
534 BOOL bOverlaysWereOn
; //zb
536 // @TODO really we want a ScrnBreakLock / ScrnRestoreLock here...
537 ScrnUnlockDrawCanvas();
539 lgd3d_start_frame(rendloop_counter
);
540 bOverlaysWereOn
= lgd3d_overlays_master_switch( FALSE
); //zb
542 render_single_obj(us
, TRUE
);
543 lgd3d_set_offsets(0,0);
546 if( bOverlaysWereOn
) //zb
547 lgd3d_overlays_master_switch( TRUE
); //zb
549 ScrnLockDrawCanvas();
553 render_single_obj(us
, TRUE
);
557 render_single_obj(us
, TRUE
);
559 if (us
->flags
&INVREND_ROTATE
)
560 us
->off_ang
.el
[2]+=0x0100;
561 // us->off_ang.el[1]+=0x100; // if you want wack-a-tronic implementation
564 void invRendSetView(invRendState
* us
, const sInvRendView
* view
)
566 *(sInvRendView
*)us
= *view
;
569 // Flush objects queued for hardware rendering
570 // @TODO: these are a frame behind similar overlay state
571 void invRendFlushQueue(void)
574 grs_canvas
* p_screen_canvas
;
579 // Clear the whole z-buffer
580 p_screen_canvas
= ScrnGetDrawCanvas();
582 lgd3d_set_offsets(0,0);
583 lgd3d_clear_z_rect(0, 0, p_screen_canvas
->bm
.w
, p_screen_canvas
->bm
.h
);
586 for (i
=0; i
<numObjs
; i
++)
588 invRendState
*us
=objQueue
[i
];
590 render_single_obj( us
, FALSE
);
592 us
->flags
&= ~INVREND_IN_QUEUE
;
593 if (us
->flags
& INVREND_FREE_ON_RENDER
)
594 invRendFreeState(us
);
596 lgd3d_set_offsets(0,0);
600 void invRendGetView(const invRendState
* us
, sInvRendView
* view
)
602 *view
= *(sInvRendView
*)us
;
606 // build our properties here
609 void invRendInit(void)
611 IResMan
*pResMan
= AppGetObj(IResMan
);
613 gpInvRendProp
= CreateInvRenderProp();
614 gpInvRendBitmapPath
= IResMan_NewSearchPath(pResMan
, BITMAP_PATH
);
616 config_get_float("inv_model_zoom",&gRenderZoom
);
618 SafeRelease(pResMan
);
621 void invRendFreeQueue(void)
625 // Flush queue and free states as appropriate...
626 for (i
=0; i
<numObjs
; i
++) {
627 invRendState
*us
= objQueue
[i
];
628 us
->flags
&= ~INVREND_IN_QUEUE
;
629 if (us
->flags
&INVREND_FREE_ON_RENDER
)
630 invRendFreeState(us
);
635 void invRendTerm(void)
638 SafeRelease(gpInvRendProp
);
639 SafeRelease(gpInvRendBitmapPath
);