Sepehr Taghdisian avatar Sepehr Taghdisian committed 1b8cf15

added model preview to h3dimport-gui
fixed some window management issues with app.c

Comments (0)

Files changed (25)

data/shaders/hlsl/df-light.ps.hlsl

 
 float4 main(vso input) : SV_Target0
 {
+#if defined(_LOCAL_LIGHTING_)
+    local_light_tile tile = c_tiles[input.tile_id];
+    [flatten] 
+    if (tile.lightcnt.x == 0)     
+        discard;
+#endif
+
     int3 coord2d = int3(input.pos.xy, 0);
 
     /* reconstruct position */
 #elif defined(_LOCAL_LIGHTING_)
     float3 lit_clr = float3(0, 0, 0);
 
-    local_light_tile tile = c_tiles[input.tile_id];
     for (uint i = 0; i < tile.lightcnt.x; i++)    {
         uint vidx = i/4;
         uint subidx = i % 4;

include/core/prims.h

 CORE_API struct aabb* aabb_xform(struct aabb* rb, const struct aabb* b, const struct mat3f* mat);
 CORE_API struct sphere* sphere_xform(struct sphere* rs, const struct sphere* s,
 		const struct mat3f* m);
+CORE_API bool_t sphere_intersects(const struct sphere* s1, const struct sphere* s2);
 
 /**
  * intersects plane with ray

include/engine/app.h

 ENGINE_API void app_set_rendertarget(OPTIONAL const char* wnd_name);
 ENGINE_API void app_swapbuffers();
 ENGINE_API void app_clear_rendertarget(const fl32 color[4], fl32 depth, uint8 stencil, uint32 flags);
+ENGINE_API result_t app_add_rendertarget(const char* wnd_name, wnd_t wnd, uint32 width, uint32 height);
 
 ENGINE_API bool_t app_get_active();
 ENGINE_API bool_t app_get_wndwidth();

include/engine/components/cmp-light.h

 
 struct ALIGN16 cmp_light
 {
+    /* interface */
 	uint32 type;
 	struct color color;
 	fl32 intensity;

include/engine/components/cmp-xform.h

 result_t cmp_xform_register(struct allocator* alloc);
 void cmp_xform_updatedeps(struct cmp_obj* obj, uint32 flags);
 
+ENGINE_API void cmp_xform_setpos(cmphandle_t hdl, const struct vec3f* pos);
+ENGINE_API void cmp_xform_setposf(cmphandle_t hdl, fl32 x, fl32 y, fl32 z);
+ENGINE_API void cmp_xform_setrot_deg(cmphandle_t hdl, fl32 rx_deg, fl32 ry_deg, fl32 rz_deg);
+ENGINE_API void cmp_xform_setrot(cmphandle_t hdl, fl32 rx, fl32 ry, fl32 rz);
+
 #ifdef __cplusplus
 }
 #endif

include/engine/init-params.h

     GFX_HWVER_GL4_2 = 9, /**< uses GL4.2 graphics capabilities for current gpu (must be _GL_ build) */
     GFX_HWVER_GL4_0 = 8, /**< uses GL4.0 graphics capabilities for current gpu (must be _GL_ build) */
     GFX_HWVER_GL3_3 = 7, /**< uses GL3.3 graphics capabilities for current gpu (must be _GL_ build) */
-    GFX_HWVER_GL3_2 = 6 /**< uses GL3,2 graphics capabilities for current gpu (must be _GL_ build) - not recommended */
+    GFX_HWVER_GL3_2 = 6 /**< uses GL3.2 graphics capabilities for current gpu (must be _GL_ build) - not recommended */
 };
 
 /**
     uint32 adapter_id; /**< graphics adapter Id, if system has more than one gpu, must be set to adapter ID */
     uint32 width; /**< render buffer width in pixels */
     uint32 height; /**< render buffer height in pixels */
+    uint32 refresh_rate; /**< monitor refresh for given resolution */
 };
 
 /**

include/engine/scene-mgr.h

 struct scn_render_query* scn_create_query_csm(uint32 scene_id, struct allocator* alloc,
     const struct aabb* frust_bounds, const struct vec3f* dir_norm, 
     const struct gfx_view_params* params);
+struct scn_render_query* scn_create_query_sphere(uint32 scene_id, struct allocator* alloc,
+    const struct sphere* sphere, const struct gfx_view_params* params);
+
 void scn_destroy_query(struct scn_render_query* query);
 
 void scn_create_csmquery();
     fl32 t = -(p_dot_n + p->d)/v_dot_n;
     return t;
 }
+
+bool_t sphere_intersects(const struct sphere* s1, const struct sphere* s2)
+{
+    struct vec3f d;
+    vec3_setf(s2->x - s1->x, s2->y - s1->y, s2->z - s1->z);
+    fl32 l = vec3_dot(&s1, &s2);
+    fl32 sr = s2->r + s1->r;    
+    return (l*l - sr*sr) < EPSILON;
+}
 
     params->gfx.width = 1280;
     params->gfx.height = 720;
+    params->gfx.refresh_rate = 60;
 
     return params;
 }

src/engine/components/cmp-anim.c

     struct cmp_anim* a = cmp_getinstancedata(hdl);
     if (a->clip_hdl != INVALID_HANDLE)  {
         struct anim_clip* clip = rs_get_anim(a->clip_hdl);
-        ASSERT(clip_idx , clip->subclip_cnt);
+        ASSERT(clip_idx < clip->subclip_cnt);
         return clip->subclips[clip_idx].name;
     }    else   {
         return "";

src/engine/components/cmp-xform.c

 
 	cmp_updateinstance(obj->xform_cmp);
 }
+
+void cmp_xform_setpos(cmphandle_t hdl, const struct vec3f* pos)
+{
+    struct cmp_xform* xf = cmp_getinstancedata(hdl);
+    mat3_set_trans(&xf->mat, pos);
+    cmp_updateinstance(hdl);
+}
+
+void cmp_xform_setposf(cmphandle_t hdl, fl32 x, fl32 y, fl32 z)
+{
+    struct cmp_xform* xf = cmp_getinstancedata(hdl);
+    mat3_set_transf(&xf->mat, x, y, z);
+    cmp_updateinstance(hdl);
+}
+
+void cmp_xform_setrot(cmphandle_t hdl, fl32 rx, fl32 ry, fl32 rz)
+{
+    struct cmp_xform* xf = cmp_getinstancedata(hdl);
+    mat3_set_roteuler(&xf->mat, rx, ry, rz);
+    cmp_updateinstance(hdl);
+}
+
+void cmp_xform_setrot_deg(cmphandle_t hdl, fl32 rx_deg, fl32 ry_deg, fl32 rz_deg)
+{
+    struct cmp_xform* xf = cmp_getinstancedata(hdl);
+    mat3_set_roteuler(&xf->mat, math_torad(rx_deg), math_torad(ry_deg), math_torad(rz_deg));
+    cmp_updateinstance(hdl);
+}

src/engine/d3d/app-d3d.cpp

     uint32 height;
     bool_t vsync;
     bool_t fullscreen;
+    uint32 refresh_rate;
 
     IDXGISwapChain* sc;
     ID3D11Texture2D* backbuff;
     bool_t init;
     bool_t d3d_dbg;
     bool_t wnd_override;
+    uint32 refresh_rate;
 
     /* callbacks */
     pfn_app_create create_fn;
     app->width = width;
     app->height = height;
     app->always_active = TRUE;
+    app->refresh_rate = params->gfx.refresh_rate;
 
     /* create default swapchain */
-    r = app_add_swapchain(app->name, app->hwnd, width, height, 60, 
+    r = app_add_swapchain(app->name, app->hwnd, width, height, params->gfx.refresh_rate, 
         BIT_CHECK(params->gfx.flags, GFX_FLAG_FULLSCREEN), 
         BIT_CHECK(params->gfx.flags, GFX_FLAG_VSYNC));
     if (IS_FAIL(r)) {
     RELEASE(app->dxgi_factory);
 }
 
+result_t app_add_rendertarget(const char* wnd_name, wnd_t wnd, uint32 width, uint32 height)
+{
+    return app_add_swapchain(wnd_name, (HWND)wnd, width, height, g_app->refresh_rate, FALSE, FALSE);
+}
+
 result_t app_add_swapchain(const char* name, HWND hwnd, uint32 width, uint32 height, 
     uint32 refresh_rate, bool_t fullscreen, bool_t vsync)
 {
     sc->height = height;
     sc->vsync = vsync;
     sc->fullscreen = fullscreen;
+    sc->refresh_rate = refresh_rate;
     
     list_add(&app->swapchains, &sc->lnode, sc);
     return RET_OK;
     rsc->height = height;
 
     /* for main window (this is where main render buffers are created), resize internal buffers */
-    if (str_isequal(name, app->name) && (app->width != width || app->height != height))   {
+    if (app->width != width || app->height != height)   {
         gfx_resize(width, height);  
         app->width = width;
         app->height = height;
     }
 
     /* if the current (render target) swapchain is resized, update variables */
-    if (rsc == app->render_target)
+    if (rsc == app->render_target) 
         gfx_set_rtvsize(width, height);
 
     return RET_OK;
 
     if (sc != NULL) {
         app->render_target = sc;
+        app->main_ctx->OMSetRenderTargets(1, &sc->rtv, sc->dsv);
 
-        app->main_ctx->OMSetRenderTargets(1, &sc->rtv, sc->dsv);
+        /* resize render buffers (if size is actually changed) - heavy operation */
+        gfx_resize(sc->width, sc->height);
 
         /* reset rendering variables that depend on size */
         gfx_set_rtvsize(sc->width, sc->height);
 /* primary pass provides render data and send it to additem for further processing
  * @param trans_items: item is gfx_transparent_item
  * @param trans_idxs: item is uint32 (index to trans_items) */
-void gfx_renderpass_processprimary(struct allocator* alloc, const struct frustum* frust, 
+void gfx_renderpass_process_primary(struct allocator* alloc, const struct frustum* frust, 
     struct array* trans_items, struct array* trans_idxs, const struct gfx_view_params* params);
 /* for each pass processing, there are items that are need to be added and batched 
  * each pass includes a number of subpasses which share the same render-path
         params->adapter_id = json_geti_child(gfx, "adapter-id", 0);
         params->width = json_geti_child(gfx, "width", 1280);
         params->height = json_geti_child(gfx, "height", 720);
+        params->refresh_rate = json_geti_child(gfx, "refresh-rate", 60);
     }	else	{
     	params->width = 1280;
     	params->height = 720;
 {
 	int32 width = (int32)g_gfx.params.width;
 	int32 height = (int32)g_gfx.params.height;
+
 	fl32 widthf = (fl32)width;
 	fl32 heightf = (fl32)height;
     gfx_cmdqueue cmdqueue = g_gfx.cmdqueue;
     r |= arr_create(tmp_alloc, &trans_idxs, sizeof(uint32), 50, 200, MID_GFX);
     ASSERT(IS_OK(r));
 
-    /* create primary pass */
+    /* create primary pass (note that primary pass is actually rendered last in render passes) */
     PRF_OPENSAMPLE("batch-primary");
     g_gfx.passes[GFX_RENDERPASS_PRIMARY] = gfx_renderpass_create(tmp_alloc);
-    gfx_renderpass_processprimary(tmp_alloc, &viewfrust, &trans_items, &trans_idxs, &params);
+    gfx_renderpass_process_primary(tmp_alloc, &viewfrust, &trans_items, &trans_idxs, &params);
     PRF_CLOSESAMPLE();
 
     PRF_OPENSAMPLE("batch-csm");
     return rpass;
 }
 
-void gfx_renderpass_processprimary(struct allocator* alloc, const struct frustum* frust, 
+void gfx_renderpass_process_primary(struct allocator* alloc, const struct frustum* frust, 
     struct array* trans_items, struct array* trans_idxs, const struct gfx_view_params* params)
 {
     struct gfx_renderpass* pass = g_gfx.passes[GFX_RENDERPASS_PRIMARY];
 
 void gfx_resize(uint32 width, uint32 height)
 {
+    if (g_gfx.params.width == width && g_gfx.params.height == height)
+        return;
+    if (g_gfx.rpaths.item_cnt == 0)
+        return;
+
     /* apply resizing to all render-paths */
     result_t r;
     for (uint32 i = 0; i < g_gfx.rpaths.item_cnt; i++)  {
     gfx_pfx_tonemap_resize(g_gfx.tonemap, width, height);
     if (g_gfx.fxaa != NULL)
         gfx_pfx_fxaa_resize(g_gfx.fxaa, width, height);
+
+    char txt[64];        sprintf(txt, "%dx%d", width, height);        puts(txt);
 }
 
 result_t gfx_composite_init()
 
 void gfx_render_grid(gfx_cmdqueue cmdqueue, const struct gfx_view_params* params)
 {
+    gfx_canvas_setlinecolor(&g_color_white);
+
     gfx_canvas_setztest(TRUE);
-    gfx_canvas_setlinecolor(&g_color_white);
+    struct mat3f center_mat;  
+    mat3_setidentity(&center_mat);
     gfx_canvas_grid(5.0f, 70.0f, params->cam);
     gfx_canvas_setztest(FALSE);
+    gfx_canvas_coords(&center_mat, &params->cam_pos, 0.5f);
 }
 
 void gfx_set_gridcallback()

src/engine/gl/app-gl.c

 
     uint32 width;
     uint32 height;
+    uint32 refresh_rate;
 
     struct linked_list lnode;
 };
     char name[32];
     uint32 width;
     uint32 height;
+    uint32 refresh_rate;
     bool_t active;
     bool_t always_active;
     bool_t init;
     glfwSwapInterval(BIT_CHECK(params->gfx.flags, GFX_FLAG_VSYNC) ? 1 : 0);
 
     log_print(LOG_INFO, "  init OpenGL ...");
-    struct app_wnd* wnd = app_add_window(app->name, width, height, 0, 
+    struct app_wnd* wnd = app_add_window(app->name, width, height, params->gfx.refresh_rate, 
         BIT_CHECK(params->gfx.flags, GFX_FLAG_FULLSCREEN), wnd_override);
     if (wnd == NULL)    {
         err_print(__FILE__, __LINE__, "gl-app init failed: coult not create main context/window");
     app->width = width;
     app->height = height;
     app->always_active = TRUE;
+    app->refresh_rate = params->gfx.refresh_rate;
     return RET_OK;
 }
 
         return RET_FAIL;
 
     /* for main window (this is where main render buffers are created), resize internal buffers */
-    if (str_isequal(wnd_name, app->name) && (app->width != width || app->height != height))   {
+    if (app->width != width || app->height != height)   {
         gfx_resize(width, height);  
         app->width = width;
         app->height = height;
     return g_app->active;
 }
 
+result_t app_add_rendertarget(const char* wnd_name, wnd_t wnd, uint32 width, uint32 height)
+{
+    struct app_wnd* w = app_add_window(wnd_name, width, height, g_app->refresh_rate, FALSE, wnd);
+    if (w == NULL)
+        return RET_FAIL;
+    return RET_OK;
+}
+
 struct app_wnd* app_add_window(const char* name, uint32 width, uint32 height, uint32 refresh_rate, 
     bool_t fullscreen, void* wnd_override)
 {
     strcpy(wnd->name, name);
     wnd->width = width;
     wnd->height = height;
+    wnd->refresh_rate = refresh_rate;
 
     if (fullscreen)
         g_app->active = TRUE;

src/engine/pybind/dheng.py

   return _dheng.app_resize_window(*args)
 app_resize_window = _dheng.app_resize_window
 
+def app_add_rendertarget(*args):
+  return _dheng.app_add_rendertarget(*args)
+app_add_rendertarget = _dheng.app_add_rendertarget
+
 def eng_init(*args):
   return _dheng.eng_init(*args)
 eng_init = _dheng.eng_init

src/engine/pybind/pyengine.i

 void app_swapbuffers();
 void app_set_rendertarget(const char* wnd_name);
 result_t app_resize_window(OPTIONAL const char* name, uint32 width, uint32 height);
+result_t app_add_rendertarget(const char* wnd_name, wnd_t wnd, uint32 width, uint32 height);
 
 /* engine.h */
 result_t eng_init(const struct init_params* params);

src/engine/pybind/pyengine_wrap.c

 }
 
 
+SWIGINTERN PyObject *_wrap_app_add_rendertarget(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  char *arg1 = (char *) 0 ;
+  wnd_t arg2 = (wnd_t) 0 ;
+  uint32 arg3 ;
+  uint32 arg4 ;
+  int res1 ;
+  char *buf1 = 0 ;
+  int alloc1 = 0 ;
+  int res2 ;
+  unsigned int val3 ;
+  int ecode3 = 0 ;
+  unsigned int val4 ;
+  int ecode4 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  result_t result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OOOO:app_add_rendertarget",&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
+  res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1);
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "app_add_rendertarget" "', argument " "1"" of type '" "char const *""'");
+  }
+  arg1 = (char *)(buf1);
+  res2 = SWIG_ConvertPtr(obj1,SWIG_as_voidptrptr(&arg2), 0, 0);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "app_add_rendertarget" "', argument " "2"" of type '" "wnd_t""'"); 
+  }
+  ecode3 = SWIG_AsVal_unsigned_SS_int(obj2, &val3);
+  if (!SWIG_IsOK(ecode3)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "app_add_rendertarget" "', argument " "3"" of type '" "uint32""'");
+  } 
+  arg3 = (uint32)(val3);
+  ecode4 = SWIG_AsVal_unsigned_SS_int(obj3, &val4);
+  if (!SWIG_IsOK(ecode4)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "app_add_rendertarget" "', argument " "4"" of type '" "uint32""'");
+  } 
+  arg4 = (uint32)(val4);
+  result = (result_t)app_add_rendertarget((char const *)arg1,arg2,arg3,arg4);
+  resultobj = SWIG_From_int((int)(result));
+  if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+  return resultobj;
+fail:
+  if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+  return NULL;
+}
+
+
 SWIGINTERN PyObject *_wrap_eng_init(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   struct init_params *arg1 = (struct init_params *) 0 ;
 	 { (char *)"app_swapbuffers", _wrap_app_swapbuffers, METH_VARARGS, NULL},
 	 { (char *)"app_set_rendertarget", _wrap_app_set_rendertarget, METH_VARARGS, NULL},
 	 { (char *)"app_resize_window", _wrap_app_resize_window, METH_VARARGS, NULL},
+	 { (char *)"app_add_rendertarget", _wrap_app_add_rendertarget, METH_VARARGS, NULL},
 	 { (char *)"eng_init", _wrap_eng_init, METH_VARARGS, NULL},
 	 { (char *)"eng_release", _wrap_eng_release, METH_VARARGS, NULL},
 	 { (char *)"eng_update", _wrap_eng_update, METH_VARARGS, NULL},

src/engine/renderpaths/gfx-deferred.c

     uint32 cnt; /* tile count */
     uint32 cnt_x;
     uint32 cnt_y;
-    struct vec4f* simd_data; /* screen-space SIMD friendly tile rects (count = (tile_count) * 2) */
+    struct vec4f* simd_data; /* screen-space SIMD friendly tile rects (count = (tile_count)*2) */
     struct deferred_shader_tile* light_lists;   /* light index list for each tile */
     struct rect2di* rects;  /* tile rectangles */
     struct hashtable_open light_table;  /* key: light cmp handle, value: index to lights array */
 
     /* states */
     gfx_output_setblendstate(cmdqueue, g_deferred->blend_add, NULL);
-    //gfx_output_setrasterstate(cmdqueue, g_deferred->rs_scissor);
 
     /* fetch shader */
     struct gfx_shader* shader = 
     gfx_shader_setf(shader, SHADER_NAME(c_camfar), params->cam->ffar);
     gfx_shader_set2f(shader, SHADER_NAME(c_rtsz), rtvsz);
     gfx_shader_set3ui(shader, SHADER_NAME(c_grid), grid);
-    gfx_shader_bindcblocks(cmdqueue, shader,
-        (const struct gfx_cblock**)&g_deferred->cb_light, 1);
+    gfx_shader_bindcblocks(cmdqueue, shader, (const struct gfx_cblock**)&g_deferred->cb_light, 1);
     gfx_input_setlayout(cmdqueue, g_deferred->tile_il);
 
     /* textures */

src/engine/scene-mgr.c

 		uint32 startidx, uint32 endidx);
 void scene_cullspheres_nosimd(bool_t* vis, const struct plane frust[6], const struct sphere* bounds,
 		uint32 startidx, uint32 endidx);
+uint32 scene_cullgrid_sphere(const struct scn_grid* grid, OUT struct cmp_obj** objs, 
+    const struct sphere* sphere);
 void scene_cull_aabbs_sweep(bool_t* vis, const struct aabb* frust_aabb, const struct vec3f* dir,
     const struct aabb* aabbs, uint32 startidx, uint32 endidx);
 void scene_draw_occluders(struct allocator* alloc, struct cmp_obj** objs, uint32 obj_cnt, 
     /* gather objects and cull against the spatial structure */
     vis_cnt = s->obj_cnt;
     vis_objs = A_ALLOC(alloc, sizeof(struct cmp_obj*)*vis_cnt, MID_SCN);
-    memcpy(vis_objs, s->objs, sizeof(struct cmp_obj*)*vis_cnt);
-    vis_cnt = scene_cullgrid(&s->grid, vis_objs, 0, vis_cnt, 
-        frust_planes);
+    vis_cnt = scene_cullgrid(&s->grid, vis_objs, 0, vis_cnt, frust_planes);
 
     /* create and get objects bounds */
     rq->bounds = A_ALIGNED_ALLOC(alloc, sizeof(struct sphere)*vis_cnt, MID_SCN);
     r |= arr_create(alloc, &tmp_lights, sizeof(struct scn_render_light), 60, 100, MID_SCN);        
     if (IS_FAIL(r))
         goto err_cleanup;
-    r = arr_create(alloc, &tmp_mats, sizeof(struct mat3f), 
-        vis_cnt + (vis_cnt/2), vis_cnt, MID_SCN);
+    r = arr_create(alloc, &tmp_mats, sizeof(struct mat3f), vis_cnt + (vis_cnt/2), vis_cnt, MID_SCN);
     if (IS_FAIL(r))
         goto err_cleanup;
 
     return NULL;
 }
 
+struct scn_render_query* scn_create_query_sphere(uint32 scene_id, struct allocator* alloc,
+    const struct sphere* sphere, const struct gfx_view_params* params)
+{
+    result_t r;
+    struct scn_data* s = scene_get(scene_id);
+    uint32 idx = 0;
+    uint32 item_idx = 0;
+    uint32 obj_idx = 0;
+
+    /* create query */
+    struct scn_render_query* rq = A_ALLOC(alloc, sizeof(struct scn_render_query), MID_SCN);
+    if (rq == NULL)
+        return NULL;
+    memset(rq, 0x00, sizeof(struct scn_render_query));
+    rq->alloc = alloc;
+
+    /* allocate temp object array */
+    uint32 vis_cnt = s->obj_cnt;
+    struct cmp_obj** objs = A_ALLOC(alloc, sizeof(struct cmp_obj*)*vis_cnt, MID_SCN);
+
+    /* cull with grid
+     * grid is expected to visibility culled before (scn_create_query), in the current frame */
+    uint32 grid_obj_cnt  = scene_cullgrid_sphere(&s->grid, objs, sphere);
+
+    /* create output buffers (mats, models, lights, etc. - in form of array) */
+    struct array tmp_models;
+    struct array tmp_mats;
+    r = arr_create(alloc, &tmp_models, sizeof(struct scn_render_model), 
+        grid_obj_cnt + (grid_obj_cnt/2), grid_obj_cnt, MID_SCN);
+    if (IS_FAIL(r))
+        goto err_cleanup;
+    
+    /* intersect with bounds of objects */
+    for (uint32 i = 0; i < grid_obj_cnt; i++)   {
+        struct cmp_obj* obj = objs[i];
+
+        /* filter out all objects except models */
+        if (obj->type != CMP_OBJTYPE_MODEL)
+            continue;
+
+        ASSERT(obj->bounds_cmp != INVALID_HANDLE);
+        struct cmp_bounds* b = cmp_getinstancedata(obj->bounds_cmp);
+        
+        if (sphere_intersects(sphere, &b->ws_s))    {
+            item_idx += scene_add_model_shadow(obj, i, item_idx, &tmp_mats, &tmp_models, params, 
+                &obj_idx);
+        }
+    }
+
+    /* fill data */
+    rq->obj_cnt = obj_idx;
+    rq->mat_cnt = tmp_mats.item_cnt;
+    rq->mats = tmp_mats.buffer;
+    rq->model_cnt = tmp_models.item_cnt;
+    rq->models = tmp_models.buffer;
+
+    /* cleanup */
+    A_FREE(alloc, objs);
+
+    return rq;
+
+err_cleanup:
+    if (objs != NULL)
+        A_ALIGNED_FREE(alloc, objs);
+    arr_destroy(&tmp_models);
+    arr_destroy(&tmp_mats);
+    if (rq != NULL)
+        scn_destroy_query(rq);
+    return NULL;
+}
+
 
 void scn_destroy_query(struct scn_render_query* query)
 {
  * @param objs (in/out) inputs objects that needs to be tested, outputs shrinked visible array 
  * @return number of unculled objects
  */
-uint32 scene_cullgrid(const struct scn_grid* grid, INOUT struct cmp_obj** objs, uint32 start_idx, 
+uint32 scene_cullgrid(const struct scn_grid* grid, OUT struct cmp_obj** objs, uint32 start_idx, 
     uint32 end_idx, const struct plane frust[6])
 {
     union f_t
     return c;
 }
 
+/* cull with visible cells only */
+uint32 scene_cullgrid_sphere(const struct scn_grid* grid, OUT struct cmp_obj** objs, 
+    const struct sphere* sphere)
+{
+    /* project spheres into XZ plane */
+    simd_t smin = _mm_set_ps(sphere->z - sphere->r, sphere->x - sphere->r, 
+        sphere->z - sphere->r, sphere->x - sphere->r);
+    simd_t smax = _mm_set_ps(sphere->z + sphere->r, sphere->x + sphere->r, 
+        sphere->z + sphere->r, sphere->x + sphere->r);
+
+    /* check with cells and extract unculled cell objects */
+    uint32 obj_cnt = 0;
+    struct vec4f* cells = grid->cells;
+    for (uint32 c = 0, cell_cnt = grid->cell_cnt; c < cell_cnt; c++)    {
+        if (!grid->vis_cells[c])
+            continue;
+
+        simd_t cmin = _mm_load_ps(cells[2*c].f);
+        simd_t cmax = _mm_load_ps(cells[2*c + 1].f);
+
+        simd_t r1 = _mm_cmpgt_ps(cmin, smax); /* cell-min > obj-max ? */
+        simd_t r2 = _mm_cmplt_ps(cmax, smin); /* cell-max < obj-min ? */
+        simd_t r = _mm_or_ps(r1, r2);
+        int32 mask = _mm_movemask_ps(r);
+
+        if ((mask & 0x3) == 0)  {
+            struct linked_list* node = grid->items[c];
+            while (node != NULL)    {
+                struct scn_grid_item* item = node->data;
+
+                /* search in existing objects for duplicates */
+                for (uint32 i = 0; i < obj_cnt; i++)    {
+                    if (item->obj == objs[i])
+                        goto skip_obj;
+                }
+                objs[obj_cnt++] = item->obj;
+skip_obj:
+                node = node->next;
+            }
+        }
+    }
+
+    return obj_cnt;
+}
+
 void scene_calc_frustum_projxz(struct plane frust_proj[4], const struct plane frust_planes[6])
 {
     const struct plane* p;

src/game-test/main.cpp

     scn_setcam(&g_cam);
 
     /* load sample script (which populates the scene) */
-    sct_runfile("test-data/test8.lua");
+    sct_runfile("test-data/test4.lua");
 
     return TRUE;
 }

src/h3dimport-gui/clipedit.py

-from PyQt4 import QtCore, QtGui
+from PyQt4.QtGui import *
+from PyQt4.QtCore import *
 import os, platform, sys, json, math
 import dheng
 from dhwidgets import eng_view
 from dhutil import util
 import engine
 
-class qClipList(QtGui.QWidget):
+class qClipList(QWidget):
     def __init__(self, parent):
         super(qClipList, self).__init__(parent)
         self.clips = []
         self.setFixedWidth(200)
 
         # layout and controls
-        layout = QtGui.QVBoxLayout()
+        layout = QVBoxLayout()
         self.setLayout(layout)
 
-        lbl_framecnt = QtGui.QLabel('frame-cnt: ', self)
+        lbl_framecnt = QLabel('frame-cnt: ', self)
         layout.addWidget(lbl_framecnt)
 
         imgpath = os.path.normcase(util.get_exec_dir(__file__) + '/img/')
-        layout2 = QtGui.QHBoxLayout()
+        layout2 = QHBoxLayout()
         layout2.setSpacing(1)
-        ed_name = QtGui.QLineEdit(self)
+        ed_name = QLineEdit(self)
         ed_name.setMaxLength(30)
         layout2.addWidget(ed_name)
-        btn_add = QtGui.QPushButton(self)
-        btn_remove = QtGui.QPushButton(self)
-        btn_add.setIcon(QtGui.QIcon(imgpath + 'glyphicons_432_plus.png'))
-        btn_remove.setIcon(QtGui.QIcon(imgpath + 'glyphicons_207_remove_2.png'))
+        btn_add = QPushButton(self)
+        btn_remove = QPushButton(self)
+        btn_add.setIcon(QIcon(imgpath + 'glyphicons_432_plus.png'))
+        btn_remove.setIcon(QIcon(imgpath + 'glyphicons_207_remove_2.png'))
         btn_add.setFixedSize(24, 24)
         btn_remove.setFixedSize(24, 24)
         layout2.addWidget(btn_add)
         self.btn_remove = btn_remove
         self.btn_add = btn_add
 
-        lbl_clips = QtGui.QLabel('Clips', self)
-        self.lst_clips = QtGui.QListWidget(self)
+        lbl_clips = QLabel('Clips', self)
+        self.lst_clips = QListWidget(self)
         self.lst_clips.setMaximumHeight(150)
         lst_palette = self.lst_clips.palette()
-        lst_palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Highlight,
-            lst_palette.brush(QtGui.QPalette.Active, QtGui.QPalette.Highlight))
-        lst_palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.HighlightedText,
-            lst_palette.brush(QtGui.QPalette.Active, QtGui.QPalette.HighlightedText))
+        lst_palette.setBrush(QPalette.Inactive, QPalette.Highlight,
+            lst_palette.brush(QPalette.Active, QPalette.Highlight))
+        lst_palette.setBrush(QPalette.Inactive, QPalette.HighlightedText,
+            lst_palette.brush(QPalette.Active, QPalette.HighlightedText))
         self.lst_clips.setPalette(lst_palette)
 
         layout.addWidget(lbl_clips)
         layout.addWidget(self.lst_clips)
 
-        layout3 = QtGui.QFormLayout()
-        self.ed_start = QtGui.QLineEdit(self)
-        self.ed_start.setValidator(QtGui.QIntValidator())
-        self.ed_end = QtGui.QLineEdit(self)
-        self.ed_end.setValidator(QtGui.QIntValidator())
-        self.chk_looped = QtGui.QCheckBox(self)
+        layout3 = QFormLayout()
+        self.ed_start = QLineEdit(self)
+        self.ed_start.setValidator(QIntValidator())
+        self.ed_end = QLineEdit(self)
+        self.ed_end.setValidator(QIntValidator())
+        self.chk_looped = QCheckBox(self)
         layout3.addRow('Start: ', self.ed_start)
         layout3.addRow('End: ', self.ed_end)
         layout3.addRow('Looped: ', self.chk_looped)
     def chk_looped_changed(self, state):
         row = self.lst_clips.currentRow()
         if row != -1:
-            self.clips[row]['looped'] = (state == QtCore.Qt.Checked)
+            self.clips[row]['looped'] = (state == Qt.Checked)
 
     def set_framecnt(self, framecnt):
         self.frame_cnt = framecnt
         for i in range(0, self.lst_clips.count()):
             item = self.lst_clips.item(i)
             if item.text() == self.ed_name.text():
-                QtGui.QMessageBox.information(self, 'clip-editor', 'Name already exist in clips')
+                QMessageBox.information(self, 'clip-editor', 'Name already exist in clips')
                 return
 
         for widget in self.edit_widgets: widget.setEnabled(True)
             self.parent().play_stop()
             del self.clips[selected_id]
 
-class qClipController(QtGui.QWidget):
+class qClipController(QWidget):
     def __init__(self, parent):
         super(qClipController, self).__init__(parent)
         self.page_sz = 10
         w = self.width()
         h = self.height()
 
-        qp = QtGui.QPainter()
+        qp = QPainter()
         qp.begin(self)
-        qp.fillRect(-1, -1, w + 1, h + 1, QtGui.QColor(150, 150, 150))
+        qp.fillRect(-1, -1, w + 1, h + 1, QColor(150, 150, 150))
 
         w -= 4
         start_x = 2
             x = start_x + self.calc_frame_x(self.frame_cursor_start, w)
             qp.fillRect(x, 3, \
                 self.calc_frame_x(self.frame_cursor_end, w) - x + 1, h - 3, \
-                QtGui.QBrush(QtGui.QColor(70, 150, 70), QtCore.Qt.Dense4Pattern))
+                QBrush(QColor(70, 150, 70), Qt.Dense4Pattern))
 
         ## ticks
-        qp.setPen(QtGui.QPen(QtGui.QColor(0, 0, 0), 1))
+        qp.setPen(QPen(QColor(0, 0, 0), 1))
         ticks = []
         for i in range(0, self.frame_cnt, self.tick_sz):
             x = self.calc_frame_x(i, w)
-            ticks.append(QtCore.QLine(start_x + x, max(0, h-3), start_x + x, max(h-8, 5)))
+            ticks.append(QLine(start_x + x, max(0, h-3), start_x + x, max(h-8, 5)))
         qp.drawLines(ticks)
 
         ## pages
-        qp.setPen(QtGui.QPen(QtGui.QColor(0, 0, 0), 2))
+        qp.setPen(QPen(QColor(0, 0, 0), 2))
         pages = []
         for i in range(0, self.frame_cnt, self.page_sz):
             x = self.calc_frame_x(i, w)
-            pages.append(QtCore.QLine(start_x + x, max(0, h-3), start_x + x, max(h-15, 12)))
+            pages.append(QLine(start_x + x, max(0, h-3), start_x + x, max(h-15, 12)))
         qp.drawLines(pages)
 
         ## indicator (snap to frames)
         cursor_x = self.calc_frame_x(self.frame_cursor, w)
-        qp.setPen(QtGui.QPen(QtGui.QColor(200, 0, 0), 2))
-        qp.drawLine(QtCore.QLine(start_x + cursor_x, max(0, h-3), start_x + cursor_x, 3))
+        qp.setPen(QPen(QColor(200, 0, 0), 2))
+        qp.drawLine(QLine(start_x + cursor_x, max(0, h-3), start_x + cursor_x, 3))
 
         ## frame index
         if self.frame_cursor_start == self.frame_cursor_end:
         else:
             ftext = str(self.frame_cursor_start) + '-' + str(self.frame_cursor_end)
             text_offset = 16
-        qp.setBackground(QtGui.QColor(200, 0, 0))
-        qp.setBackgroundMode(QtCore.Qt.OpaqueMode)
-        qp.setPen(QtGui.QPen(QtGui.QColor(255, 255, 255), 1))
-        qp.drawText(w - 30 - text_offset, 3, w - 3, 24, QtCore.Qt.TextDontClip, ftext)
+        qp.setBackground(QColor(200, 0, 0))
+        qp.setBackgroundMode(Qt.OpaqueMode)
+        qp.setPen(QPen(QColor(255, 255, 255), 1))
+        qp.drawText(w - 30 - text_offset, 3, w - 3, 24, Qt.TextDontClip, ftext)
 
         qp.end()
 
             cursor_x = max(e.pos().x() - 2, 0)
             self.parent().play_stop()
 
-            if e.modifiers() & QtCore.Qt.ShiftModifier:
+            if e.modifiers() & Qt.ShiftModifier:
                 self.frame_cursor_end = self.calc_frame_n(cursor_x, w)
                 dheng.cmp_modifyui(self.anim_cmp, 'frame_idx', self.frame_cursor_end)
                 if self.frame_cursor_start > self.frame_cursor_end:
         if self.mouse_dwn:
             w = self.width() - 4
             cursor_x = max(e.pos().x() - 2, 0)
-            if e.modifiers() & QtCore.Qt.ShiftModifier:
+            if e.modifiers() & Qt.ShiftModifier:
                 self.frame_cursor_end = self.calc_frame_n(cursor_x, w)
                 dheng.cmp_modifyui(self.anim_cmp, 'frame_idx', self.frame_cursor_end)
                 if self.frame_cursor > self.frame_cursor_end:
             self.frame_cursor = f 
             self.update()
 
-class qClipEditDlg(QtGui.QDialog):
+class qClipEditDlg(QDialog):
     def __init__(self, parent):
         super(qClipEditDlg, self).__init__(parent)
         
         self.setSizeGripEnabled(True)
 
         exedir = util.get_exec_dir(__file__)
-        self.icn_play = QtGui.QIcon(os.path.normcase(exedir + '/img/glyphicons_173_play.png'))
-        self.icn_pause = QtGui.QIcon(os.path.normcase(exedir + '/img/glyphicons_174_pause.png'))
+        self.icn_play = QIcon(os.path.normcase(exedir + '/img/glyphicons_173_play.png'))
+        self.icn_pause = QIcon(os.path.normcase(exedir + '/img/glyphicons_174_pause.png'))
 
-        layout = QtGui.QVBoxLayout()
+        layout = QVBoxLayout()
 
-        layout2 = QtGui.QHBoxLayout()
+        layout2 = QHBoxLayout()
         self.eng_view = eng_view.qEngineView(self)
         layout2.addWidget(self.eng_view)
         self.wnd_clips = qClipList(self)
         layout2.addWidget(self.wnd_clips)
         layout.addLayout(layout2)
 
-        layout3 = QtGui.QHBoxLayout()
-        self.btn_play = QtGui.QPushButton(self)
+        layout3 = QHBoxLayout()
+        self.btn_play = QPushButton(self)
         self.btn_play.setIcon(self.icn_play)
         self.btn_play_state = False # keeps playing state of 'play/pause' button
         self.btn_play_state_prev = False
 
         self.setLayout(layout)
 
-        self.tm_play = QtCore.QTimer(self)
+        self.tm_play = QTimer(self)
         self.tm_play.setInterval(20)
 
-        self.tm_preview = QtCore.QTimer(self)
+        self.tm_preview = QTimer(self)
         self.tm_preview.setInterval(33)
         self.preview_clip = {}
         self.preview_frame = 0
+        self.camera = None
 
         # events
         self.btn_play.clicked.connect(self.btn_play_clicked)
         e.accept()
 
     def load_props(self, model_file, anim_file, clips_jsonfile):
-        self.eng_view.set_cam(engine.camera)
+        # initialize camera
+        if self.camera == None:
+            self.camera = dheng.camera()
+            pos = dheng.vec4f()
+            lookat = dheng.vec4f()
+            pos.y = 2
+            pos.z = -5
+            dheng.cam_init(self.camera, pos, lookat, 0.2, 300, dheng.math_torad(50))
+        
+        dheng.cam_update(self.camera)
+        self.eng_view.set_cam(self.camera)
 
         # ground
         ground = dheng.scn_create_obj(dheng.scn_getactive(), 'ground', dheng.CMP_OBJTYPE_MODEL)

src/h3dimport-gui/engine.py

 import os
 
 is_init = False
-camera = None
 scene = 0
+rts = []
 
 def initialize(assetdir, widget):
-    global is_init
+    global is_init, rts
+    name = str(widget.winId().__hex__())
+    hwnd = dheng.str_toptr(widget.winId().__hex__())
+
     if is_init:
+        if widget not in rts:
+            if not dheng.app_add_rendertarget(name, hwnd, widget.width(), widget.height()):
+                return False
+            else:
+                rts.append(widget)
         return True
 
     if not dheng.core_init(True):
 
     params = dheng.init_params()
     params.flags = dheng.ENG_FLAG_DEBUG
-    params.gfx.flags = dheng.GFX_FLAG_DEBUG        
+    params.gfx.flags = dheng.GFX_FLAG_DEBUG | dheng.GFX_FLAG_FXAA
     params.gfx.width = 128
     params.gfx.height = 128
     params.data_dir = os.path.abspath(util.get_exec_dir(__file__) + '/../../data') 
 
-    hwnd = dheng.str_toptr(widget.winId().__hex__())
-    if not dheng.app_init('main', params, hwnd):
+    if not dheng.app_init(name, params, hwnd):
         dheng.err_sendtolog(False)
         dheng.core_release(False)
         return False
 
     dheng.gfx_set_debug_renderfunc(dheng.gfx_render_grid)
 
-    ## set path for out stuff
+    ## set path for our stuff
     dheng.io_addvdir(assetdir, True)
 
     ## single scene with camera
-    global camera
     global scene
-    camera = dheng.camera()
     scene = dheng.scn_create_scene('main')
     dheng.scn_setactive(scene)
-    dheng.scn_setcam(camera)
 
     is_init = True
+    rts.append(widget)
     return True
 
 def release():

src/h3dimport-gui/h3dimport-gui.py

-from PyQt4 import QtCore, QtGui
+from PyQt4.QtGui import *
+from PyQt4.QtCore import *
+
 import ConfigParser, os, platform, subprocess, sys, json
 from copy_reg import add_extension
 
 sys.path.append(mod_path)
 from dhdlg import about
 from dhutil import util
-import dheng
-import clipedit
-import engine
+import dheng, clipedit, engine, modelprev
 
 def add_extension(filepath, ext):
     (filename, fileext) = os.path.splitext(filepath)
     return filepath
 
 ###############################################################################################
-class w_prefs(QtGui.QDialog):
+class w_prefs(QDialog):
     def __init__(self, parent):
         super(w_prefs, self).__init__(parent)
         self.init_ui()
         self.setWindowTitle('Preferences')
         #self.setFixedHeight(100) 
 
-        layout = QtGui.QVBoxLayout(self)
+        layout = QVBoxLayout(self)
 
-        self.edit_bin = QtGui.QLineEdit(self)
-        self.check_verbose = QtGui.QCheckBox("Verbose mode", self)
+        self.edit_bin = QLineEdit(self)
+        self.check_verbose = QCheckBox("Verbose mode", self)
         
-        btn_browse = QtGui.QPushButton("Browse ...", self)
+        btn_browse = QPushButton("Browse ...", self)
         btn_browse.setFixedWidth(80)
         btn_browse.clicked.connect(self.browse_clicked)
         
-        layout2 = QtGui.QHBoxLayout()
-        layout2.addWidget(QtGui.QLabel("Importer binary :"))
+        layout2 = QHBoxLayout()
+        layout2.addWidget(QLabel("Importer binary :"))
         layout2.addWidget(self.edit_bin)
         layout2.addWidget(btn_browse)
         layout.addLayout(layout2)
 
-        layout4 = QtGui.QHBoxLayout()
-        ed_assetdir = QtGui.QLineEdit(self)
-        btn_browse = QtGui.QPushButton('Browse', self)
+        layout4 = QHBoxLayout()
+        ed_assetdir = QLineEdit(self)
+        btn_browse = QPushButton('Browse', self)
         btn_browse.setFixedWidth(80)
         btn_browse.clicked.connect(self.btn_assetdir_clicked)
-        layout4.addWidget(QtGui.QLabel('Asset Directory :')) 
+        layout4.addWidget(QLabel('Asset Directory :')) 
         layout4.addWidget(ed_assetdir)
         layout4.addWidget(btn_browse)
         layout.addLayout(layout4)
 
         layout.addWidget(self.check_verbose)
 
-        btn_ok = QtGui.QPushButton("Ok", self)
-        btn_cancel = QtGui.QPushButton("Cancel", self)
+        btn_ok = QPushButton("Ok", self)
+        btn_cancel = QPushButton("Cancel", self)
         btn_ok.clicked.connect(self.ok_clicked)
         btn_cancel.clicked.connect(self.cancel_clicked)
-        layout3 = QtGui.QHBoxLayout()
+        layout3 = QHBoxLayout()
         layout3.addWidget(btn_ok)
         layout3.addWidget(btn_cancel)
         layout3.addStretch()
         self.setLayout(layout)
 
     def btn_assetdir_clicked(self, checked):
-        dlg = QtGui.QFileDialog(self, "Choose asset directory", self.ed_assetdir.text())
-        dlg.setFileMode(QtGui.QFileDialog.Directory)
+        dlg = QFileDialog(self, "Choose asset directory", self.ed_assetdir.text())
+        dlg.setFileMode(QFileDialog.Directory)
         if dlg.exec_():
             dirs = dlg.selectedFiles()
             self.ed_assetdir.setText(os.path.abspath(str(dirs[0])))
             filters = "Executables (*.exe)"
         else:
             filters = "Executables (*)"
-        binfile = QtGui.QFileDialog.getOpenFileName(self, "Open h3dimport binary", "", filters)
+        binfile = QFileDialog.getOpenFileName(self, "Open h3dimport binary", "", filters)
         if binfile != "":
             self.edit_bin.setText(binfile)
     
         prefs['assetdir'] = str(self.ed_assetdir.text())
           
 ###############################################################################################
-class w_phx(QtGui.QWidget):
+class w_phx(QWidget):
     def __init__(self, parent):
         super(w_phx, self).__init__(parent)
         self.infiledir = ""
         self.outfiledir = ""
         self.ctrls = []
         self.quiet_mode = False
-        self.watcher = QtCore.QFileSystemWatcher(self)
+        self.watcher = QFileSystemWatcher(self)
         self.watcher.fileChanged.connect(self.filemon_onfilechange)    
         self.init_ui()
 
     def init_ui(self):
-        layout = QtGui.QFormLayout(self)
+        layout = QFormLayout(self)
         self.setLayout(layout)
         
         # make controls
-        self.edit_infilepath = QtGui.QLineEdit(self)
+        self.edit_infilepath = QLineEdit(self)
         self.edit_infilepath.setReadOnly(True)
-        btn_browse_infile = QtGui.QPushButton("Browse", self)
+        btn_browse_infile = QPushButton("Browse", self)
         btn_browse_infile.setFixedWidth(60)
-        self.combo_names = QtGui.QComboBox(self)
-        self.edit_outfilepath = QtGui.QLineEdit(self)
+        self.combo_names = QComboBox(self)
+        self.edit_outfilepath = QLineEdit(self)
         self.edit_outfilepath.setReadOnly(True)
-        btn_browse_outfile = QtGui.QPushButton("Browse", self)
+        btn_browse_outfile = QPushButton("Browse", self)
         btn_browse_outfile.setFixedWidth(60)
-        self.check_zup = QtGui.QCheckBox(self)
+        self.check_zup = QCheckBox(self)
         
-        btn_auto = QtGui.QCheckBox("Auto", self)
+        btn_auto = QCheckBox("Auto", self)
         btn_auto.setMaximumWidth(50)
-        btn_import = QtGui.QPushButton("Import", self)
+        btn_import = QPushButton("Import", self)
 
         self.btn_auto = btn_auto
         self.btn_import = btn_import        
         
         # layouts
-        layout_infile = QtGui.QHBoxLayout()
+        layout_infile = QHBoxLayout()
         layout_infile.addWidget(self.edit_infilepath)
         layout_infile.addWidget(btn_browse_infile)
         layout.addRow("Input file:", layout_infile)
         
         layout.addRow("Object name:", self.combo_names)
         
-        layout_outfile = QtGui.QHBoxLayout()
+        layout_outfile = QHBoxLayout()
         layout_outfile.addWidget(self.edit_outfilepath)
         layout_outfile.addWidget(btn_browse_outfile)
         layout.addRow("Output file:", layout_outfile)
         
         layout.addRow("Up is Z (3dsmax):", self.check_zup)
 
-        layout_import = QtGui.QHBoxLayout()
+        layout_import = QHBoxLayout()
         layout_import.addWidget(btn_import)
         layout_import.addWidget(btn_auto)
         layout.addRow(layout_import)
             c.setEnabled(enable)
         
     def btn_auto_checkstate(self, state):
-        if state == QtCore.Qt.Checked:
+        if state == Qt.Checked:
             self.btn_import.setCheckable(True)
             self.btn_import_click(True)
             self.btn_import.setChecked(True)
                 self.watcher.removePath(self.edit_infilepath.text())
             
     def btn_browseinfile_click(self):
-        dlg = QtGui.QFileDialog(self, "Open physics", self.infiledir, \
+        dlg = QFileDialog(self, "Open physics", self.infiledir, \
             "Physx3 files (*.RepX)")
-        dlg.setFileMode(QtGui.QFileDialog.ExistingFile)
+        dlg.setFileMode(QFileDialog.ExistingFile)
         if dlg.exec_():
             files = dlg.selectedFiles()
             self.edit_infilepath.setText(os.path.normpath(str(files[0])))
             self.enum_phxobjects()
         
     def btn_browseoutfile_click(self):
-        dlg = QtGui.QFileDialog(self, "Save h3dp file", self.outfiledir, \
+        dlg = QFileDialog(self, "Save h3dp file", self.outfiledir, \
             "dark-hammer physics (*.h3dp)")
-        dlg.setFileMode(QtGui.QFileDialog.AnyFile)
-        dlg.setAcceptMode(QtGui.QFileDialog.AcceptSave)
+        dlg.setFileMode(QFileDialog.AnyFile)
+        dlg.setAcceptMode(QFileDialog.AcceptSave)
         if dlg.exec_():
             relative_path = util.get_rel_path(str(dlg.selectedFiles()[0]), prefs['assetdir'])
             if not relative_path:
-                QtGui.QMessageBox.warning(self, 'h3dimport', \
+                QMessageBox.warning(self, 'h3dimport', \
                     'Path must be under asset directory tree')
                 return
             self.edit_outfilepath.setText(add_extension(relative_path, "h3dp"))
             args.extend(["-zup"])
         if prefs['verbose']:
             args.extend(["-v"])
-        QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor))
+        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
         r = subprocess.call(args)
-        QtGui.QApplication.restoreOverrideCursor()
+        QApplication.restoreOverrideCursor()
         if r == -1 and not self.quiet_mode:
-            QtGui.QMessageBox.critical(self, "h3dimport", """Failed to import file, see the"""\
+            QMessageBox.critical(self, "h3dimport", """Failed to import file, see the"""\
                                        """ terminal for more info""")        
             
     def save_config(self, cfg):
             r = subprocess.check_output(args)
         except subprocess.CalledProcessError as ce:
             print ce.output
-            QtGui.QMessageBox.critical(self, "h3dimport", "h3dimport raised error!")
+            QMessageBox.critical(self, "h3dimport", "h3dimport raised error!")
         else:
             objs = str(r).replace("\r", "").split("\n")
             for ln in objs:
                 self.combo_names.setCurrentIndex(1)
 
 ###############################################################################################
-class w_anim(QtGui.QWidget):
+class w_anim(QWidget):
     def __init__(self, parent):
         super(w_anim, self).__init__(parent)
         global prefs
         self.dlg_clipedit = clipedit.qClipEditDlg(self)
 
     def init_ui(self):
-        layout = QtGui.QFormLayout(self)
+        layout = QFormLayout(self)
         self.setLayout(layout)
         
         # make controls
-        self.edit_infilepath = QtGui.QLineEdit(self)
+        self.edit_infilepath = QLineEdit(self)
         self.edit_infilepath.setReadOnly(True)
-        btn_browse_infile = QtGui.QPushButton("Browse", self)
+        btn_browse_infile = QPushButton("Browse", self)
         btn_browse_infile.setFixedWidth(60)
-        self.edit_outfilepath = QtGui.QLineEdit(self)
+        self.edit_outfilepath = QLineEdit(self)
         self.edit_outfilepath.setReadOnly(True)
-        btn_browse_outfile = QtGui.QPushButton("Browse", self)
+        btn_browse_outfile = QPushButton("Browse", self)
         btn_browse_outfile.setFixedWidth(60)
-        btn_import = QtGui.QPushButton("Import", self)
-        self.edit_fps = QtGui.QLineEdit("30", self)
+        btn_import = QPushButton("Import", self)
+        self.edit_fps = QLineEdit("30", self)
         self.edit_fps.setMaximumWidth(40)
-        self.check_zup = QtGui.QCheckBox(self)
-        btn_clipedit = QtGui.QPushButton('Edit clips', self)
+        self.check_zup = QCheckBox(self)
+        btn_clipedit = QPushButton('Edit clips', self)
 
         # add to layout
-        layout_infile = QtGui.QHBoxLayout()
+        layout_infile = QHBoxLayout()
         layout_infile.addWidget(self.edit_infilepath)
         layout_infile.addWidget(btn_browse_infile)
         layout.addRow("Input file:", layout_infile)
         
-        layout_outfile = QtGui.QHBoxLayout()
+        layout_outfile = QHBoxLayout()
         layout_outfile.addWidget(self.edit_outfilepath)
         layout_outfile.addWidget(btn_browse_outfile)
         layout.addRow("Output file:", layout_outfile)
         self.in_jsonfile = in_jsonfile
 
     def browse_infile_clicked(self):
-        dlg = QtGui.QFileDialog(self, "Open animation", self.infiledir, \
+        dlg = QFileDialog(self, "Open animation", self.infiledir, \
             "Animation files (*.dae *.obj *.x *.ase *.ms3d)")
-        dlg.setFileMode(QtGui.QFileDialog.ExistingFile)
+        dlg.setFileMode(QFileDialog.ExistingFile)
         if dlg.exec_():
             files = dlg.selectedFiles()
             self.edit_infilepath.setText(os.path.normpath(str(files[0])))
             self.init_clips_jsonfile()
 
     def browse_outfile_clicked(self):
-        dlg = QtGui.QFileDialog(self, "Save h3da file", self.outfiledir, \
+        dlg = QFileDialog(self, "Save h3da file", self.outfiledir, \
             "dark-hammer anims (*.h3da)")
-        dlg.setFileMode(QtGui.QFileDialog.AnyFile)
-        dlg.setAcceptMode(QtGui.QFileDialog.AcceptSave)
+        dlg.setFileMode(QFileDialog.AnyFile)
+        dlg.setAcceptMode(QFileDialog.AcceptSave)
         if dlg.exec_():
             relative_path = util.get_rel_path(str(dlg.selectedFiles()[0]), prefs['assetdir'])
             if not relative_path:
-                QtGui.QMessageBox.warning(self, 'h3dimport', \
+                QMessageBox.warning(self, 'h3dimport', \
                     'Path must be under asset directory tree')
                 return            
             self.edit_outfilepath.setText(add_extension(relative_path, "h3da"))
             args.extend(["-v"])
         if self.check_zup.isChecked():
             args.extend(["-zup"])
-        QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor))
+        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
         r = subprocess.call(args)
-        QtGui.QApplication.restoreOverrideCursor()
+        QApplication.restoreOverrideCursor()
         if r == -1:
-            QtGui.QMessageBox.critical(self, "h3dimport", """Failed to import file, see the"""\
+            QMessageBox.critical(self, "h3dimport", """Failed to import file, see the"""\
                                        """ terminal for more info""") 
 
     def save_config(self, cfg):
         self.init_clips_jsonfile()
 
 ###############################################################################################
-class w_model(QtGui.QWidget):
+class w_model(QWidget):
     def __init__(self, parent):
         super(w_model, self).__init__(parent)
         self.infile_dir = ""
         self.outfile_dir = ""
         self.texdir_dir = ""
-        self.watcher = QtCore.QFileSystemWatcher(self)
+        self.watcher = QFileSystemWatcher(self)
         self.watcher.fileChanged.connect(self.monitor_onfilechange)
         self.quiet_mode = False
         self.ctrls = []
         self.init_ui()
         
     def init_ui(self):
-        layout = QtGui.QFormLayout(self)
+        layout = QFormLayout(self)
         self.setLayout(layout)
         
-        self.edit_infilepath = QtGui.QLineEdit(self)
+        self.edit_infilepath = QLineEdit(self)
         self.edit_infilepath.setReadOnly(True)
-        self.combo_names = QtGui.QComboBox(self)
-        self.combo_occ = QtGui.QComboBox(self)
-        self.edit_outfilepath = QtGui.QLineEdit(self)
+        self.combo_names = QComboBox(self)
+        self.combo_occ = QComboBox(self)
+        self.edit_outfilepath = QLineEdit(self)
         self.edit_outfilepath.setReadOnly(True)
-        self.edit_texdir = QtGui.QLineEdit(self)
+        self.edit_texdir = QLineEdit(self)
         self.edit_texdir.setReadOnly(True)
-        self.check_calctng = QtGui.QCheckBox(self)
-        self.check_fastcompress = QtGui.QCheckBox(self)
-        self.check_dxt3 = QtGui.QCheckBox(self)
-        self.check_zup = QtGui.QCheckBox(self)
+        self.check_calctng = QCheckBox(self)
+        self.check_fastcompress = QCheckBox(self)
+        self.check_dxt3 = QCheckBox(self)
+        self.check_zup = QCheckBox(self)
 
-        btn_browse_infile = QtGui.QPushButton("Browse", self)
-        btn_browse_outfile = QtGui.QPushButton("Browse", self)
-        btn_choose_texdir = QtGui.QPushButton("Choose", self)
+        btn_browse_infile = QPushButton("Browse", self)
+        btn_browse_outfile = QPushButton("Browse", self)
+        btn_choose_texdir = QPushButton("Choose", self)
         btn_browse_infile.setFixedWidth(60)
         btn_browse_outfile.setFixedWidth(60)
         btn_choose_texdir.setFixedWidth(60)
-        layout_infile = QtGui.QHBoxLayout()
+        layout_infile = QHBoxLayout()
         layout_infile.addWidget(self.edit_infilepath)
         layout_infile.addWidget(btn_browse_infile)
-        layout_outfile = QtGui.QHBoxLayout()
+        layout_outfile = QHBoxLayout()
         layout_outfile.addWidget(self.edit_outfilepath)
         layout_outfile.addWidget(btn_browse_outfile)
-        layout_texdir = QtGui.QHBoxLayout()
+        layout_texdir = QHBoxLayout()
         layout_texdir.addWidget(self.edit_texdir)
         layout_texdir.addWidget(btn_choose_texdir)
         
         self.cmbo_names_update = True
         self.combo_names.currentIndexChanged.connect(self.cmbo_names_changed)
         
-        layout_import = QtGui.QHBoxLayout()
-        btn_auto = QtGui.QCheckBox("Auto", self)
+        btn_prev = QPushButton('Preview', self)
+        btn_prev.clicked.connect(self.btn_prev_clicked)
+
+        layout_import = QHBoxLayout()
+        btn_auto = QCheckBox("Auto", self)
         btn_auto.stateChanged.connect(self.btn_auto_checkstate)
         btn_auto.setMaximumWidth(50)
         self.btn_auto = btn_auto
-        btn_import = QtGui.QPushButton("Import", self)
+        btn_import = QPushButton("Import", self)
         btn_import.clicked.connect(self.import_clicked)
+        layout_import.addWidget(btn_prev)
         layout_import.addWidget(btn_import)
         layout_import.addWidget(btn_auto)
         self.btn_import = btn_import
         layout.addRow("Fast texture compress:", self.check_fastcompress)
         layout.addRow("Force DXT3 for alpha:", self.check_dxt3)
         layout.addRow("Up is Z (3dsmax):", self.check_zup)
-        
         layout.addRow(layout_import)
         
         # add main controls to array for group enable/disable
         self.ctrls = [btn_browse_infile, self.edit_infilepath, self.combo_names, self.combo_occ, \
             self.edit_outfilepath, self.edit_texdir, self.check_calctng, self.check_dxt3, \
             self.check_fastcompress, btn_browse_outfile, btn_choose_texdir, btn_import]
+
+        self.dlg_prev = modelprev.qModelPrev(self)
     
+    def btn_prev_clicked(self, checked):
+        global prefs
+        if not engine.initialize(prefs['assetdir'], self.dlg_prev.eng_view):
+            print 'could not initialize dark-hammer engine'
+        else:
+            # get model file from the current imported model
+            global main_wnd
+
+            # before anything, do the animation import process
+            self.import_clicked(True)
+
+            model_file = str(self.edit_outfilepath.text())
+            self.dlg_prev.load_props(model_file)
+            self.dlg_prev.exec_()        
+
     def import_texture(self, tex_filepath, tex_type):
         global prefs
         texdir = os.path.normcase(prefs['assetdir'] + '/' + str(self.edit_texdir.text()))
         args.extend(["-ttype", str(tex_type)])
             
         # call h3dimport command
-        QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor))
+        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
         r = subprocess.call(args)
-        QtGui.QApplication.restoreOverrideCursor()
+        QApplication.restoreOverrideCursor()
         if r == -1 and not self.quiet_mode:
-            QtGui.QMessageBox.critical(self, "h3dimport", """Failed to import file, see the"""\
+            QMessageBox.critical(self, "h3dimport", """Failed to import file, see the"""\
                                        """ terminal for more info""")
         self.watcher.addPaths(self.textures.keys())
         
             r = subprocess.check_output(args)
         except subprocess.CalledProcessError as ce:
             print ce.output
-            QtGui.QMessageBox.critical(self, "h3dimport", "h3dimport raised error!")
+            QMessageBox.critical(self, "h3dimport", "h3dimport raised error!")
         else:
             self.textures = {}
             objs = str(r).replace("\r", "").split("\n")
             c.setEnabled(enable)
         
     def btn_auto_checkstate(self, state):
-        if state == QtCore.Qt.Checked:
+        if state == Qt.Checked:
             self.btn_import.setCheckable(True)
             self.import_clicked(True)
             self.btn_import.setChecked(True)
             r = subprocess.check_output(args)
         except subprocess.CalledProcessError as ce:
             print ce.output
-            QtGui.QMessageBox.critical(self, "h3dimport", "h3dimport raised error!")
+            QMessageBox.critical(self, "h3dimport", "h3dimport raised error!")
             self.cmbo_names_update = True
         else:
             self.textures = {}
 
     def browse_infile_clicked(self, checked):
         global prefs
-        dlg = QtGui.QFileDialog(self, "Open model", self.infile_dir, \
+        dlg = QFileDialog(self, "Open model", self.infile_dir, \
             "Models (*.dae *.obj *.x *.ase *.ms3d)")
-        dlg.setFileMode(QtGui.QFileDialog.ExistingFile)
+        dlg.setFileMode(QFileDialog.ExistingFile)
         if dlg.exec_():
             filepath = os.path.normcase(str(dlg.selectedFiles()[0]))
             self.edit_infilepath.setText(filepath)
             self.edit_outfilepath.setText(util.make_samefname(out_filepath, in_filepath, "h3dm"))
 
     def browse_outfile_clicked(self, checked):
-        dlg = QtGui.QFileDialog(self, "Save h3dm file", self.outfile_dir, \
+        dlg = QFileDialog(self, "Save h3dm file", self.outfile_dir, \
             "dark-hammer models (*.h3dm)")
-        dlg.setFileMode(QtGui.QFileDialog.AnyFile)
-        dlg.setAcceptMode(QtGui.QFileDialog.AcceptSave)
+        dlg.setFileMode(QFileDialog.AnyFile)
+        dlg.setAcceptMode(QFileDialog.AcceptSave)
         if dlg.exec_():
             relative_path = util.get_rel_path(str(dlg.selectedFiles()[0]), prefs['assetdir'])
             if not relative_path:
-                QtGui.QMessageBox.warning(self, 'h3dimport', \
+                QMessageBox.warning(self, 'h3dimport', \
                     'Path must be under asset directory tree')
                 return
             self.edit_outfilepath.setText(add_extension(relative_path, "h3dm"))
             self.outfile_dir = os.path.normpath(str(dlg.directory().path()))
         
     def choose_texdir_clicked(self, checked):
-        dlg = QtGui.QFileDialog(self, "Choose texture output directory", self.texdir_dir)
-        dlg.setFileMode(QtGui.QFileDialog.Directory)
+        dlg = QFileDialog(self, "Choose texture output directory", self.texdir_dir)
+        dlg.setFileMode(QFileDialog.Directory)
         if dlg.exec_():
             relative_path = util.get_rel_path(str(dlg.selectedFiles()[0]), prefs['assetdir'])
             if not relative_path:
-                QtGui.QMessageBox.warning(self, 'h3dimport', \
+                QMessageBox.warning(self, 'h3dimport', \
                     'Path must be under asset directory tree')
                 return
 
             args.extend(["-zup"])
             
         # call h3dimport command
-        QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor))
+        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
         r = subprocess.call(args)
-        QtGui.QApplication.restoreOverrideCursor()
+        QApplication.restoreOverrideCursor()
         if r == -1 and not self.quiet_mode:
-            QtGui.QMessageBox.critical(self, "h3dimport", """Failed to import file, see the""" \
+            QMessageBox.critical(self, "h3dimport", """Failed to import file, see the""" \
                                        """ terminal for more info""")            
             
 ###############################################################################################
-class w_main(QtGui.QMainWindow):
+class w_main(QMainWindow):
     def __init__(self):
         super(w_main, self).__init__()
         self.init_ui()
         engine.release()
 
     def init_ui(self):
-        main_menu = QtGui.QMenuBar(self)
+        main_menu = QMenuBar(self)
         
         main_menu.addAction("Preferences", self.pref_clicked)
-        mnu_help = QtGui.QMenu("Help", self)
+        mnu_help = QMenu("Help", self)
         mnu_help.addAction("About", self.mnu_help_click)
         main_menu.addMenu(mnu_help)
         
         self.setMenuBar(main_menu)
         
-        self.main_tab = QtGui.QTabWidget(self)
+        self.main_tab = QTabWidget(self)
         self.setCentralWidget(self.main_tab)
         
         # child tabs
         self.setMinimumWidth(600)
         self.setWindowTitle("h3dimport gui: dark-hammer toolset")
         self.show()
-        self.setSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
+        self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
         
         self.main_tab.currentChanged.connect(self.tab_change)
 
 ###############################################################################################
 def main():
     global main_wnd
-    app = QtGui.QApplication(sys.argv)
+    app = QApplication(sys.argv)
     main_wnd = w_main()
     r = app.exec_()
     del main_wnd

src/h3dimport-gui/modelprev.py

+from PyQt4.QtGui import *
+from PyQt4.QtCore import *
+
+import dheng
+from dhwidgets import eng_view
+from dhutil import util
+import engine
+
+class qModelPrev(QDialog):
+    def __init__(self, parent):
+        super(qModelPrev, self).__init__(parent)
+        
+        self.setMinimumSize(800, 600)
+        self.setWindowTitle('Model preview')
+        self.setSizeGripEnabled(True)
+
+        layout = QVBoxLayout()
+        self.eng_view = eng_view.qEngineView(self)
+        layout.addWidget(self.eng_view)
+        self.setLayout(layout)
+
+        self.camera = None
+
+    def load_props(self, model_file):
+        # initialize camera
+        if self.camera == None:
+            self.camera = dheng.camera()
+            pos = dheng.vec4f()
+            lookat = dheng.vec4f()
+            pos.y = 2
+            pos.z = -5
+            dheng.cam_init(self.camera, pos, lookat, 0.2, 300, dheng.math_torad(50))
+
+        dheng.cam_update(self.camera)
+        self.eng_view.set_cam(self.camera)
+
+        # ground
+        ground = dheng.scn_create_obj(dheng.scn_getactive(), 'ground', dheng.CMP_OBJTYPE_MODEL)
+        dheng.cmp_modifys(dheng.cmp_findinstance_inobj(ground, 'model'), 'model_file',
+            'test-data/plane.h3dm')
+        ## 
+        obj = dheng.scn_create_obj(dheng.scn_getactive(), 'test', dheng.CMP_OBJTYPE_MODEL)
+        model_cmp = dheng.cmp_findinstance_inobj(obj, 'model')
+        dheng.cmp_modifys(model_cmp, 'model_file', model_file)
+
+        self.obj = obj
+        self.ground = ground
+
+    def unload_props(self):
+        if self.obj:        dheng.scn_destroy_obj(self.obj)
+        if self.ground:     dheng.scn_destroy_obj(self.ground)
+        self.ground = None
+        self.obj = None
+
+    def closeEvent(self, e):
+        self.unload_props()
+        e.accept()
+
+
+

src/pymodules/dhwidgets/eng_view.py

         self.sz_timer.timeout.connect(self.resize)
 
     def set_cam(self, cam):
-        pos = dheng.vec4f()
-        lookat = dheng.vec4f()
-
-        pos.y = 2
-        pos.z = -5
-        dheng.cam_init(cam, pos, lookat, 0.2, 300, dheng.math_torad(60))
-        dheng.cam_update(cam)
-        dheng.cam_set_viewsize(cam, self.width(), self.height())
-
+        dheng.app_set_rendertarget(str(self.winId().__hex__()))
+        if cam != None:
+            dheng.scn_setcam(cam)
+            dheng.cam_set_viewsize(cam, self.width(), self.height())
         self.cam = cam
 
     def paintEvent(self, e):
     def resize(self):
         if not self.cam:
             return
-        dheng.app_resize_window('main', self.width(), self.height())
+        dheng.app_resize_window(str(self.winId().__hex__()), self.width(), self.height())
         dheng.cam_set_viewsize(self.cam, self.width(), self.height())
 
     def keyPressEvent(self, e):
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.