2 * << Haru Free PDF Library >> -- hpdf_u3d.c
4 * URL: http://libharu.org
6 * Copyright (c) 1999-2006 Takeshi Kanno <takeshi_kanno@est.hi-ho.ne.jp>
7 * Copyright (c) 2007-2009 Antony Dovgal <tony@daylessday.org>
9 * Permission to use, copy, modify, distribute and sell this software
10 * and its documentation for any purpose is hereby granted without fee,
11 * provided that the above copyright notice appear in all copies and
12 * that both that copyright notice and this permission notice appear
13 * in supporting documentation.
14 * It is provided "as is" without express or implied warranty.
17 #include "hpdf_conf.h"
18 #include "hpdf_utils.h"
24 /* Not defined in MSVC6 */
25 #define M_PI 3.14159265358979323846
29 HPDF_U3D_LoadU3D (HPDF_MMgr mmgr,
33 static const char u3d[] = "U3D";
34 static const char prc[] = "PRC";
36 static HPDF_STATUS Get3DStreamType (HPDF_Stream stream, const char **type)
41 HPDF_PTRACE ((" HPDF_U3D_Get3DStreamType\n"));
44 if (HPDF_Stream_Read (stream, tag, &len) != HPDF_OK) {
45 return HPDF_Error_GetCode (stream->error);
48 if (HPDF_Stream_Seek (stream, 0, HPDF_SEEK_SET) != HPDF_OK) {
49 return HPDF_Error_GetCode (stream->error);
52 if (HPDF_MemCmp(tag, (HPDF_BYTE *)u3d, 4/* yes, \0 is required */) == 0) {
57 if (HPDF_MemCmp(tag, (HPDF_BYTE *)prc, 3) == 0) {
62 return HPDF_INVALID_U3D_DATA;
67 HPDF_U3D_LoadU3DFromMem ( HPDF_MMgr mmgr,
73 HPDF_STATUS ret = HPDF_OK;
75 HPDF_PTRACE ((" HPDF_U3D_LoadU3DFromMem\n"));
77 image = HPDF_DictStream_New (mmgr, xref);
82 image->header.obj_class |= HPDF_OSUBCLASS_XOBJECT;
83 ret = HPDF_Dict_AddName (image, "Type", "XObject");
85 HPDF_Dict_Free(image);
89 ret = HPDF_Dict_AddName (image, "Subtype", "Image");
91 HPDF_Dict_Free(image);
95 if (HPDF_Stream_Write (image->stream, buf, size) != HPDF_OK) {
96 HPDF_Dict_Free(image);
104 HPDF_EXPORT(HPDF_Image)
105 HPDF_LoadU3DFromFile (HPDF_Doc pdf,
106 const char *filename)
108 HPDF_Stream imagedata;
111 HPDF_PTRACE ((" HPDF_LoadU3DFromFile\n"));
113 if (!HPDF_HasDoc (pdf)) {
117 /* create file stream */
118 imagedata = HPDF_FileReader_New (pdf->mmgr, filename);
120 if (HPDF_Stream_Validate (imagedata)) {
121 image = HPDF_U3D_LoadU3D (pdf->mmgr, imagedata, pdf->xref);
126 /* destroy file stream */
127 HPDF_Stream_Free (imagedata);
130 HPDF_CheckError (&pdf->error);
136 HPDF_U3D_LoadU3D (HPDF_MMgr mmgr,
137 HPDF_Stream u3d_data,
143 HPDF_PTRACE ((" HPDF_U3D_LoadU3D\n"));
145 u3d = HPDF_DictStream_New (mmgr, xref);
150 u3d->header.obj_class |= HPDF_OSUBCLASS_XOBJECT;
152 /* add required elements */
153 u3d->filter = HPDF_STREAM_FILTER_NONE;
155 if (HPDF_Dict_AddName (u3d, "Type", "3D") != HPDF_OK) {
160 if (Get3DStreamType (u3d_data, &type) != HPDF_OK) {
165 if (HPDF_Dict_AddName (u3d, "Subtype", type) != HPDF_OK) {
171 HPDF_BYTE buf[HPDF_STREAM_BUF_SIZ];
172 HPDF_UINT len = HPDF_STREAM_BUF_SIZ;
173 HPDF_STATUS ret = HPDF_Stream_Read (u3d_data, buf, &len);
175 if (ret != HPDF_OK) {
176 if (ret == HPDF_STREAM_EOF) {
178 ret = HPDF_Stream_Write (u3d->stream, buf, len);
179 if (ret != HPDF_OK) {
191 if (HPDF_Stream_Write (u3d->stream, buf, len) != HPDF_OK) {
200 HPDF_EXPORT(HPDF_Dict) HPDF_Create3DView(HPDF_MMgr mmgr, const char *name)
202 HPDF_STATUS ret = HPDF_OK;
205 HPDF_PTRACE ((" HPDF_Create3DView\n"));
207 if (name == NULL || name[0] == '\0') {
211 view = HPDF_Dict_New (mmgr);
216 ret = HPDF_Dict_AddName (view, "TYPE", "3DView");
217 if (ret != HPDF_OK) {
218 HPDF_Dict_Free (view);
222 ret = HPDF_Dict_Add (view, "XN", HPDF_String_New (mmgr, name, NULL));
223 if (ret != HPDF_OK) {
224 HPDF_Dict_Free (view);
228 ret = HPDF_Dict_Add (view, "IN", HPDF_String_New (mmgr, name, NULL));
229 if (ret != HPDF_OK) {
230 HPDF_Dict_Free (view);
237 HPDF_EXPORT(HPDF_STATUS) HPDF_U3D_Add3DView(HPDF_U3D u3d, HPDF_Dict view)
239 HPDF_Array views = NULL;
240 HPDF_STATUS ret = HPDF_OK;
242 HPDF_PTRACE ((" HPDF_Add3DView\n"));
244 if (u3d == NULL || view == NULL) {
245 return HPDF_INVALID_U3D_DATA;
248 views = (HPDF_Array)HPDF_Dict_GetItem (u3d, "VA", HPDF_OCLASS_ARRAY);
250 views = HPDF_Array_New (u3d->mmgr);
252 return HPDF_Error_GetCode (u3d->error);
255 ret = HPDF_Dict_Add (u3d, "VA", views);
256 if (ret == HPDF_OK) {
257 ret = HPDF_Dict_AddNumber (u3d, "DV", 0);
259 HPDF_Array_Free (views);
264 if (ret == HPDF_OK) {
265 ret = HPDF_Array_Add( views, view);
272 HPDF_EXPORT(HPDF_STATUS) HPDF_U3D_AddOnInstanciate(HPDF_U3D u3d, HPDF_JavaScript javascript)
274 HPDF_STATUS ret = HPDF_OK;
276 HPDF_PTRACE ((" HPDF_U3D_AddOnInstanciate\n"));
278 if (u3d == NULL || javascript == NULL) {
279 return HPDF_INVALID_U3D_DATA;
282 ret = HPDF_Dict_Add(u3d, "OnInstantiate", javascript);
288 HPDF_EXPORT(HPDF_STATUS) HPDF_U3D_SetDefault3DView(HPDF_U3D u3d, const char *name)
290 HPDF_STATUS ret = HPDF_OK;
292 HPDF_PTRACE ((" HPDF_U3D_SetDefault3DView\n"));
294 if (u3d == NULL || name == NULL || name[0] == '\0') {
295 return HPDF_INVALID_U3D_DATA;
298 ret = HPDF_Dict_Add (u3d, "DV", HPDF_String_New (u3d->mmgr, name, NULL));
302 HPDF_EXPORT(HPDF_STATUS) HPDF_3DView_AddNode(HPDF_Dict view, const char *name, HPDF_REAL opacity, HPDF_BOOL visible)
304 HPDF_Array nodes = NULL;
306 HPDF_STATUS ret = HPDF_OK;
308 HPDF_PTRACE ((" HPDF_3DView_AddNode\n"));
310 if (view == NULL || opacity < 0 || opacity > 1 || name == NULL || name[0] == '\0') {
311 return HPDF_INVALID_U3D_DATA;
314 nodes = (HPDF_Array)HPDF_Dict_GetItem (view, "NA", HPDF_OCLASS_ARRAY);
316 nodes = HPDF_Array_New (view->mmgr);
318 return HPDF_Error_GetCode (view->error);
321 ret = HPDF_Dict_Add (view, "NA", nodes);
322 if (ret != HPDF_OK) {
323 HPDF_Array_Free (nodes);
328 node = HPDF_Dict_New (view->mmgr);
330 HPDF_Array_Free (nodes);
331 return HPDF_Error_GetCode (view->error);
334 ret = HPDF_Dict_AddName (node, "Type", "3DNode");
335 if (ret != HPDF_OK) {
336 HPDF_Array_Free (nodes);
337 HPDF_Dict_Free (node);
341 ret = HPDF_Dict_Add (node, "N", HPDF_String_New (view->mmgr, name, NULL));
342 if (ret != HPDF_OK) {
343 HPDF_Array_Free (nodes);
344 HPDF_Dict_Free (node);
348 ret = HPDF_Dict_AddReal (node, "O", opacity);
349 if (ret != HPDF_OK) {
350 HPDF_Array_Free (nodes);
351 HPDF_Dict_Free (node);
355 ret = HPDF_Dict_AddBoolean (node, "V", visible);
356 if (ret != HPDF_OK) {
357 HPDF_Dict_Free (node);
358 HPDF_Array_Free (nodes);
362 ret = HPDF_Array_Add(nodes, node);
363 if (ret != HPDF_OK) {
364 HPDF_Dict_Free (node);
365 HPDF_Array_Free (nodes);
371 HPDF_EXPORT(HPDF_STATUS) HPDF_3DView_SetLighting(HPDF_Dict view, const char *scheme)
373 HPDF_STATUS ret = HPDF_OK;
376 static const char * const schemes[] =
377 { "Artwork", "None", "White", "Day", "Night", "Hard", "Primary", "Blue", "Red", "Cube", "CAD", "Headlamp" };
379 HPDF_PTRACE ((" HPDF_3DView_SetLighting\n"));
381 if (view == NULL || scheme == NULL || scheme[0] == '\0') {
382 return HPDF_INVALID_U3D_DATA;
385 for (i = 0; i < 12; i++) {
386 if (!strcmp(scheme, schemes[i])) {
392 return HPDF_INVALID_U3D_DATA;
395 lighting = HPDF_Dict_New (view->mmgr);
397 return HPDF_Error_GetCode (view->error);
400 ret = HPDF_Dict_AddName (lighting, "Type", "3DLightingScheme");
401 if (ret != HPDF_OK) {
402 HPDF_Dict_Free (lighting);
406 ret = HPDF_Dict_AddName (lighting, "Subtype", scheme);
407 if (ret != HPDF_OK) {
408 HPDF_Dict_Free (lighting);
412 ret = HPDF_Dict_Add (view, "LS", lighting);
413 if (ret != HPDF_OK) {
414 HPDF_Dict_Free (lighting);
420 HPDF_EXPORT(HPDF_STATUS) HPDF_3DView_SetBackgroundColor(HPDF_Dict view, HPDF_REAL r, HPDF_REAL g, HPDF_REAL b)
423 HPDF_STATUS ret = HPDF_OK;
424 HPDF_Dict background;
426 HPDF_PTRACE ((" HPDF_3DView_SetBackgroundColor\n"));
428 if (view == NULL || r < 0 || r > 1 || g < 0 || g > 1 || b < 0 || b > 1) {
429 return HPDF_INVALID_U3D_DATA;
432 background = HPDF_Dict_New (view->mmgr);
434 return HPDF_Error_GetCode (view->error);
437 color = HPDF_Array_New (view->mmgr);
439 HPDF_Dict_Free (background);
440 return HPDF_Error_GetCode (view->error);
443 ret = HPDF_Array_AddReal (color, r);
444 if (ret != HPDF_OK) {
445 HPDF_Array_Free (color);
446 HPDF_Dict_Free (background);
450 ret = HPDF_Array_AddReal (color, g);
451 if (ret != HPDF_OK) {
452 HPDF_Array_Free (color);
453 HPDF_Dict_Free (background);
457 ret = HPDF_Array_AddReal (color, b);
458 if (ret != HPDF_OK) {
459 HPDF_Array_Free (color);
460 HPDF_Dict_Free (background);
465 ret = HPDF_Dict_AddName (background, "Type", "3DBG");
466 if (ret != HPDF_OK) {
467 HPDF_Array_Free (color);
468 HPDF_Dict_Free (background);
472 ret = HPDF_Dict_Add (background, "C", color);
473 if (ret != HPDF_OK) {
474 HPDF_Array_Free (color);
475 HPDF_Dict_Free (background);
479 ret = HPDF_Dict_Add (view, "BG", background);
480 if (ret != HPDF_OK) {
481 HPDF_Array_Free (color);
482 HPDF_Dict_Free (background);
488 HPDF_EXPORT(HPDF_STATUS) HPDF_3DView_SetPerspectiveProjection(HPDF_Dict view, HPDF_REAL fov)
490 HPDF_STATUS ret = HPDF_OK;
491 HPDF_Dict projection;
493 HPDF_PTRACE ((" HPDF_3DView_SetPerspectiveProjection\n"));
495 if (view == NULL || fov < 0 || fov > 180) {
496 return HPDF_INVALID_U3D_DATA;
499 projection = HPDF_Dict_New (view->mmgr);
501 return HPDF_Error_GetCode (view->error);
504 ret = HPDF_Dict_AddName (projection, "Subtype", "P");
505 if (ret != HPDF_OK) {
506 HPDF_Dict_Free (projection);
510 ret = HPDF_Dict_AddName (projection, "PS", "Min");
511 if (ret != HPDF_OK) {
512 HPDF_Dict_Free (projection);
516 ret = HPDF_Dict_AddReal (projection, "FOV", fov);
517 if (ret != HPDF_OK) {
518 HPDF_Dict_Free (projection);
522 ret = HPDF_Dict_Add (view, "P", projection);
523 if (ret != HPDF_OK) {
524 HPDF_Dict_Free (projection);
530 HPDF_EXPORT(HPDF_STATUS) HPDF_3DView_SetOrthogonalProjection(HPDF_Dict view, HPDF_REAL mag)
532 HPDF_STATUS ret = HPDF_OK;
533 HPDF_Dict projection;
535 HPDF_PTRACE ((" HPDF_3DView_SetOrthogonalProjection\n"));
537 if (view == NULL || mag <= 0) {
538 return HPDF_INVALID_U3D_DATA;
541 projection = HPDF_Dict_New (view->mmgr);
543 return HPDF_Error_GetCode (view->error);
546 ret = HPDF_Dict_AddName (projection, "Subtype", "O");
547 if (ret != HPDF_OK) {
548 HPDF_Dict_Free (projection);
552 ret = HPDF_Dict_AddReal (projection, "OS", mag);
553 if (ret != HPDF_OK) {
554 HPDF_Dict_Free (projection);
558 ret = HPDF_Dict_Add (view, "P", projection);
559 if (ret != HPDF_OK) {
560 HPDF_Dict_Free (projection);
566 #define normalize(x, y, z) \
569 modulo = (float)sqrt((float)(x*x) + (float)(y*y) + (float)(z*z)); \
578 /* building the transformation matrix*/
579 /* #1,#2,#3 centre of orbit coordinates (coo)*/
580 /* #4,#5,#6 centre of orbit to camera direction vector (c2c)*/
581 /* #7 orbital radius (roo)*/
582 /* #8 camera roll (roll)*/
584 HPDF_EXPORT(HPDF_STATUS) HPDF_3DView_SetCamera(HPDF_Dict view, HPDF_REAL coox, HPDF_REAL cooy, HPDF_REAL cooz, HPDF_REAL c2cx, HPDF_REAL c2cy, HPDF_REAL c2cz, HPDF_REAL roo, HPDF_REAL roll)
586 HPDF_REAL viewx, viewy, viewz;
587 HPDF_REAL leftx, lefty, leftz;
588 HPDF_REAL upx, upy, upz;
589 HPDF_REAL transx, transy, transz;
592 HPDF_STATUS ret = HPDF_OK;
594 HPDF_PTRACE ((" HPDF_3DView_SetCamera\n"));
597 return HPDF_INVALID_U3D_DATA;
600 /* view vector (opposite to c2c) */
605 /* c2c = (0, -1, 0) by default */
606 if (viewx == 0.0 && viewy == 0.0 && viewz == 0.0) {
609 /* normalize view vector */
610 normalize(viewx, viewy, viewz);
612 /* rotation matrix */
614 /* top and bottom views */
620 if (viewz < 0.0) /* top view*/
626 else /* bottom view*/
633 if ( fabs(viewx) + fabs(viewy) != 0.0f) /* other views than top and bottom*/
635 /* up-vector = up_world - (up_world dot view) view*/
638 upz = -viewz*viewz + 1.0f;
639 /* normalize up-vector*/
640 normalize(upx, upy, upz);
641 /* left vector = up x view*/
642 leftx = viewz*upy - viewy*upz;
643 lefty = viewx*upz - viewz*upx;
644 leftz = viewy*upx - viewx*upy;
645 /* normalize left vector*/
646 normalize(leftx, lefty, leftz);
648 /* apply camera roll*/
650 HPDF_REAL leftxprime, leftyprime, leftzprime;
651 HPDF_REAL upxprime, upyprime, upzprime;
652 HPDF_REAL sinroll, cosroll;
654 sinroll = (HPDF_REAL)sin((roll/180.0f)*M_PI);
655 cosroll = (HPDF_REAL)cos((roll/180.0f)*M_PI);
656 leftxprime = leftx*cosroll + upx*sinroll;
657 leftyprime = lefty*cosroll + upy*sinroll;
658 leftzprime = leftz*cosroll + upz*sinroll;
659 upxprime = upx*cosroll + leftx*sinroll;
660 upyprime = upy*cosroll + lefty*sinroll;
661 upzprime = upz*cosroll + leftz*sinroll;
670 /* translation vector*/
671 roo = (HPDF_REAL)fabs(roo);
673 roo = (HPDF_REAL)0.000000000000000001;
675 transx = coox - roo*viewx;
676 transy = cooy - roo*viewy;
677 transz = cooz - roo*viewz;
679 /* transformation matrix*/
680 matrix = HPDF_Array_New (view->mmgr);
682 return HPDF_Error_GetCode (view->error);
685 ret = HPDF_Array_AddReal (matrix, leftx);
686 if (ret != HPDF_OK) goto failed;
688 ret = HPDF_Array_AddReal (matrix, lefty);
689 if (ret != HPDF_OK) goto failed;
691 ret = HPDF_Array_AddReal (matrix, leftz);
692 if (ret != HPDF_OK) goto failed;
694 ret = HPDF_Array_AddReal (matrix, upx);
695 if (ret != HPDF_OK) goto failed;
697 ret = HPDF_Array_AddReal (matrix, upy);
698 if (ret != HPDF_OK) goto failed;
700 ret = HPDF_Array_AddReal (matrix, upz);
701 if (ret != HPDF_OK) goto failed;
703 ret = HPDF_Array_AddReal (matrix, viewx);
704 if (ret != HPDF_OK) goto failed;
706 ret = HPDF_Array_AddReal (matrix, viewy);
707 if (ret != HPDF_OK) goto failed;
709 ret = HPDF_Array_AddReal (matrix, viewz);
710 if (ret != HPDF_OK) goto failed;
712 ret = HPDF_Array_AddReal (matrix, transx);
713 if (ret != HPDF_OK) goto failed;
715 ret = HPDF_Array_AddReal (matrix, transy);
716 if (ret != HPDF_OK) goto failed;
718 ret = HPDF_Array_AddReal (matrix, transz);
719 if (ret != HPDF_OK) goto failed;
721 ret = HPDF_Dict_AddName (view, "MS", "M");
722 if (ret != HPDF_OK) goto failed;
724 ret = HPDF_Dict_Add (view, "C2W", matrix);
725 if (ret != HPDF_OK) goto failed;
727 ret = HPDF_Dict_AddNumber (view, "CO", (HPDF_INT32)roo);
730 if (ret != HPDF_OK) {
731 HPDF_Array_Free (matrix);
737 HPDF_Dict HPDF_3DView_New( HPDF_MMgr mmgr, HPDF_Xref xref, HPDF_U3D u3d, const char *name)
739 HPDF_STATUS ret = HPDF_OK;
742 HPDF_PTRACE ((" HPDF_3DView_New\n"));
744 if (name == NULL || name[0] == '\0') {
748 view = HPDF_Dict_New (mmgr);
753 if (HPDF_Xref_Add (xref, view) != HPDF_OK)
756 ret = HPDF_Dict_AddName (view, "TYPE", "3DView");
757 if (ret != HPDF_OK) {
758 HPDF_Dict_Free (view);
762 ret = HPDF_Dict_Add (view, "XN", HPDF_String_New (mmgr, name, NULL));
763 if (ret != HPDF_OK) {
764 HPDF_Dict_Free (view);
768 ret = HPDF_Dict_Add (view, "IN", HPDF_String_New (mmgr, name, NULL));
769 if (ret != HPDF_OK) {
770 HPDF_Dict_Free (view);
774 ret = HPDF_U3D_Add3DView( u3d, view);
775 if (ret != HPDF_OK) {
776 HPDF_Dict_Free (view);
784 HPDF_EXPORT(HPDF_STATUS)
785 HPDF_3DView_Add3DC3DMeasure(HPDF_Dict view,
786 HPDF_3DMeasure measure)
789 HPDF_STATUS ret = HPDF_OK;
793 a = HPDF_Dict_GetItem (view, "MA", HPDF_OCLASS_ARRAY);
797 array = (HPDF_Array)a;
801 array = HPDF_Array_New (view->mmgr);
805 if (HPDF_Dict_Add (view, "MA", array) != HPDF_OK)
809 ret = HPDF_Array_Add(array, measure);
815 HPDF_EXPORT(HPDF_JavaScript) HPDF_CreateJavaScript( HPDF_Doc pdf, const char *code )
817 HPDF_JavaScript javaScript;
820 HPDF_PTRACE ((" HPDF_CreateJavaScript\n"));
822 javaScript = (HPDF_JavaScript) HPDF_DictStream_New(pdf->mmgr, pdf->xref);
827 len = (HPDF_UINT)strlen(code);
828 if (HPDF_Stream_Write (javaScript->stream, (HPDF_BYTE *)code, len) != HPDF_OK) {
829 HPDF_Dict_Free(javaScript);