comparison src/gl-render.cc @ 12358:a076a3d89fce release-3-4-x

opengl_renderer::draw_axes: simplify with subfunctions
author John W. Eaton <jwe@octave.org>
date Tue, 01 Feb 2011 04:39:21 -0500
parents 23385f2c90b7
children 2ad37783bf01
comparison
equal deleted inserted replaced
12357:8fab4aca41fd 12358:a076a3d89fce
619 619
620 draw (props.get_all_children ()); 620 draw (props.get_all_children ());
621 } 621 }
622 622
623 void 623 void
624 opengl_renderer::render_grid (std::string& gridstyle, Matrix& ticks, 624 opengl_renderer::render_grid (const std::string& gridstyle,
625 double lim1, double lim2, 625 const Matrix& ticks, double lim1, double lim2,
626 double p1, double p1N, double p2, double p2N, 626 double p1, double p1N, double p2, double p2N,
627 int xyz, bool is_3D) 627 int xyz, bool is_3D)
628 { 628 {
629 set_linestyle (gridstyle, true); 629 set_linestyle (gridstyle, true);
630 glBegin (GL_LINES); 630 glBegin (GL_LINES);
665 glEnd (); 665 glEnd ();
666 set_linestyle ("-", true); 666 set_linestyle ("-", true);
667 } 667 }
668 668
669 void 669 void
670 opengl_renderer::render_tickmarks(Matrix& ticks, double lim1, double lim2, 670 opengl_renderer::render_tickmarks (const Matrix& ticks,
671 double p1, double p1N, double p2, double p2N, 671 double lim1, double lim2,
672 double dx, double dy, double dz, 672 double p1, double p1N,
673 int xyz, bool doubleside) 673 double p2, double p2N,
674 double dx, double dy, double dz,
675 int xyz, bool doubleside)
674 { 676 {
675 glBegin (GL_LINES); 677 glBegin (GL_LINES);
678
676 for (int i = 0; i < ticks.numel (); i++) 679 for (int i = 0; i < ticks.numel (); i++)
677 { 680 {
678 double val = ticks(i); 681 double val = ticks(i);
679 682
680 if (lim1 <= val && val <= lim2) 683 if (lim1 <= val && val <= lim2)
709 glVertex3d (p1N-dx, p2N-dy, val); 712 glVertex3d (p1N-dx, p2N-dy, val);
710 } 713 }
711 } 714 }
712 } 715 }
713 } 716 }
717
714 glEnd (); 718 glEnd ();
715 } 719 }
716 720
717 void 721 void
718 opengl_renderer::render_ticktexts(Matrix& ticks, string_vector& ticklabels, 722 opengl_renderer::render_ticktexts (const Matrix& ticks,
719 double lim1, double lim2, 723 const string_vector& ticklabels,
720 double p1, double p2, 724 double lim1, double lim2,
721 int xyz, int ha, int va, 725 double p1, double p2,
722 int& wmax, int& hmax) 726 int xyz, int ha, int va,
727 int& wmax, int& hmax)
723 { 728 {
724 int n = std::min (ticklabels.numel (), ticks.numel ()); 729 int n = std::min (ticklabels.numel (), ticks.numel ());
725 730
726 for (int i = 0; i < n; i++) 731 for (int i = 0; i < n; i++)
727 { 732 {
750 } 755 }
751 } 756 }
752 } 757 }
753 758
754 void 759 void
755 opengl_renderer::draw_axes (const axes::properties& props) 760 opengl_renderer::setup_opengl_transformation (const axes::properties& props)
756 { 761 {
757 // setup OpenGL transformation 762 // setup OpenGL transformation
758 763
759 Matrix x_zlim = props.get_transform_zlim (); 764 Matrix x_zlim = props.get_transform_zlim ();
765
766 xZ1 = x_zlim(0)-(x_zlim(1)-x_zlim(0))/2;
767 xZ2 = x_zlim(1)+(x_zlim(1)-x_zlim(0))/2;
768
760 Matrix x_mat1 = props.get_opengl_matrix_1 (); 769 Matrix x_mat1 = props.get_opengl_matrix_1 ();
761 Matrix x_mat2 = props.get_opengl_matrix_2 (); 770 Matrix x_mat2 = props.get_opengl_matrix_2 ();
762
763 xZ1 = x_zlim(0)-(x_zlim(1)-x_zlim(0))/2;
764 xZ2 = x_zlim(1)+(x_zlim(1)-x_zlim(0))/2;
765 771
766 #if defined (HAVE_FRAMEWORK_OPENGL) 772 #if defined (HAVE_FRAMEWORK_OPENGL)
767 GLint vw[4]; 773 GLint vw[4];
768 #else 774 #else
769 int vw[4]; 775 int vw[4];
784 glClear (GL_DEPTH_BUFFER_BIT); 790 glClear (GL_DEPTH_BUFFER_BIT);
785 791
786 // store axes transformation data 792 // store axes transformation data
787 793
788 xform = props.get_transform (); 794 xform = props.get_transform ();
789 795 }
790 // draw axes object 796
791 797 void
792 GLboolean antialias; 798 opengl_renderer::draw_axes_planes (bool visible, const Matrix& axe_color,
793 glGetBooleanv (GL_LINE_SMOOTH, &antialias); 799 const Matrix& xlim, const Matrix& ylim,
794 glDisable (GL_LINE_SMOOTH); 800 const Matrix& zlim, double x_plane,
795 801 double y_plane, double z_plane)
796 Matrix xlim = xform.xscale (props.get_xlim ().matrix_value ()); 802 {
797 Matrix ylim = xform.yscale (props.get_ylim ().matrix_value ()); 803 // Axes planes
798 Matrix zlim = xform.zscale (props.get_zlim ().matrix_value ()); 804
799 double x_min = xlim(0), x_max = xlim(1); 805 if (axe_color.numel () > 0 && visible)
800 double y_min = ylim(0), y_max = ylim(1); 806 {
801 double z_min = zlim(0), z_max = zlim(1); 807 set_color (axe_color);
802 808 set_polygon_offset (true, 2.5);
803 double xd = (props.xdir_is ("normal") ? 1 : -1); 809
804 double yd = (props.ydir_is ("normal") ? 1 : -1); 810 glBegin (GL_QUADS);
805 double zd = (props.zdir_is ("normal") ? 1 : -1); 811
812 double x_min = xlim(0);
813 double x_max = xlim(1);
814
815 double y_min = ylim(0);
816 double y_max = ylim(1);
817
818 double z_min = zlim(0);
819 double z_max = zlim(1);
820
821 // X plane
822 glVertex3d (x_plane, y_min, z_min);
823 glVertex3d (x_plane, y_max, z_min);
824 glVertex3d (x_plane, y_max, z_max);
825 glVertex3d (x_plane, y_min, z_max);
826
827 // Y plane
828 glVertex3d (x_min, y_plane, z_min);
829 glVertex3d (x_max, y_plane, z_min);
830 glVertex3d (x_max, y_plane, z_max);
831 glVertex3d (x_min, y_plane, z_max);
832
833 // Z plane
834 glVertex3d (x_min, y_min, z_plane);
835 glVertex3d (x_max, y_min, z_plane);
836 glVertex3d (x_max, y_max, z_plane);
837 glVertex3d (x_min, y_max, z_plane);
838
839 glEnd ();
840
841 set_polygon_offset (false);
842 }
843 }
844
845 void
846 opengl_renderer::draw_axes_boxes (const axes::properties& props,
847 bool visible, bool box, bool xySym,
848 double xPlane, double yPlane, double zPlane,
849 double xPlaneN, double yPlaneN, double zPlaneN,
850 double xpTick, double ypTick, double zpTick,
851 double xpTickN, double ypTickN, double zpTickN)
852 {
853 // Axes box
854
855 set_linestyle ("-", true);
856 set_linewidth (props.get_linewidth ());
857
858 if (visible)
859 {
860 glBegin (GL_LINES);
861
862 // X box
863 set_color (props.get_xcolor_rgb ());
864 glVertex3d (xPlaneN, ypTick, zpTick);
865 glVertex3d (xPlane, ypTick, zpTick);
866
867 if (box)
868 {
869 glVertex3d (xPlaneN, ypTickN, zpTick);
870 glVertex3d (xPlane, ypTickN, zpTick);
871 glVertex3d (xPlaneN, ypTickN, zpTickN);
872 glVertex3d (xPlane, ypTickN, zpTickN);
873 glVertex3d (xPlaneN, ypTick, zpTickN);
874 glVertex3d (xPlane, ypTick, zpTickN);
875 }
876
877 // Y box
878 set_color (props.get_ycolor_rgb ());
879 glVertex3d (xpTick, yPlaneN, zpTick);
880 glVertex3d (xpTick, yPlane, zpTick);
881
882 if (box)
883 {
884 glVertex3d (xpTickN, yPlaneN, zpTick);
885 glVertex3d (xpTickN, yPlane, zpTick);
886 glVertex3d (xpTickN, yPlaneN, zpTickN);
887 glVertex3d (xpTickN, yPlane, zpTickN);
888 glVertex3d (xpTick, yPlaneN, zpTickN);
889 glVertex3d (xpTick, yPlane, zpTickN);
890 }
891
892 // Z box
893 set_color (props.get_zcolor_rgb ());
894
895 if (xySym)
896 {
897 glVertex3d (xPlaneN, yPlane, zPlaneN);
898 glVertex3d (xPlaneN, yPlane, zPlane);
899 }
900 else
901 {
902 glVertex3d (xPlane, yPlaneN, zPlaneN);
903 glVertex3d (xPlane, yPlaneN, zPlane);
904 }
905
906 if (box)
907 {
908 glVertex3d (xPlane, yPlane, zPlaneN);
909 glVertex3d (xPlane, yPlane, zPlane);
910
911 if (xySym)
912 {
913 glVertex3d (xPlane, yPlaneN, zPlaneN);
914 glVertex3d (xPlane, yPlaneN, zPlane);
915 }
916 else
917 {
918 glVertex3d (xPlaneN, yPlane, zPlaneN);
919 glVertex3d (xPlaneN, yPlane, zPlane);
920 }
921
922 glVertex3d (xPlaneN, yPlaneN, zPlaneN);
923 glVertex3d (xPlaneN, yPlaneN, zPlane);
924 }
925
926 glEnd ();
927 }
928 }
929
930 void
931 opengl_renderer::draw_axes_x_grid (const axes::properties& props,
932 bool visible, bool box,
933 const std::string& gridstyle,
934 const std::string& minorgridstyle,
935 bool nearhoriz, double tickdir,
936 bool xyzSym, bool layer2Dtop,
937 bool x2Dtop, int xstate,
938 double x_min, double x_max,
939 double xticklen, double xtickoffset,
940 double fy, double yPlane, double yPlaneN,
941 double ypTick, double ypTickN,
942 double fz, int zstate, double zPlane,
943 double zPlaneN, double zpTick,
944 double zpTickN)
945 {
946 // X grid
947
948 if (visible && xstate != AXE_DEPTH_DIR)
949 {
950 bool do_xgrid = (props.is_xgrid () && (gridstyle != "none"));
951 bool do_xminorgrid = (props.is_xminorgrid () && (minorgridstyle != "none"));
952 bool do_xminortick = props.is_xminortick ();
953 Matrix xticks = xform.xscale (props.get_xtick ().matrix_value ());
954 Matrix xmticks = xform.xscale (props.get_xmtick ().matrix_value ());
955 string_vector xticklabels = props.get_xticklabel ().all_strings ();
956 int wmax = 0, hmax = 0;
957 bool tick_along_z = nearhoriz || xisinf (fy);
958
959 set_color (props.get_xcolor_rgb ());
960
961 // grid lines
962 if (do_xgrid)
963 render_grid (gridstyle, xticks, x_min, x_max,
964 yPlane, yPlaneN, layer2Dtop ? zPlaneN : zPlane,
965 zPlaneN, 0, (zstate != AXE_DEPTH_DIR));
966
967 // tick marks
968 if (tick_along_z)
969 {
970 render_tickmarks (xticks, x_min, x_max, ypTick, ypTick,
971 zpTick, zpTickN, 0., 0.,
972 signum(zpTick-zpTickN)*fz*xticklen*tickdir,
973 0, (box && xstate != AXE_ANY_DIR));
974 }
975 else
976 {
977 render_tickmarks (xticks, x_min, x_max, ypTick, ypTickN,
978 zpTick, zpTick, 0.,
979 signum(ypTick-ypTickN)*fy*xticklen*tickdir,
980 0., 0, (box && xstate != AXE_ANY_DIR));
981 }
982
983 // tick texts
984 if (xticklabels.numel () > 0)
985 {
986 int halign = (xstate == AXE_HORZ_DIR ? 1 : (xyzSym ? 0 : 2));
987 int valign = (xstate == AXE_VERT_DIR ? 1 : (x2Dtop ? 0 : 2));
988
989 if (tick_along_z)
990 render_ticktexts (xticks, xticklabels, x_min, x_max, ypTick,
991 zpTick+signum(zpTick-zpTickN)*fz*xtickoffset,
992 0, halign, valign, wmax, hmax);
993 else
994 render_ticktexts (xticks, xticklabels, x_min, x_max,
995 ypTick+signum(ypTick-ypTickN)*fy*xtickoffset,
996 zpTick, 0, halign, valign, wmax, hmax);
997 }
998
999 // minor grid lines
1000 if (do_xminorgrid)
1001 render_grid (minorgridstyle, xmticks, x_min, x_max,
1002 yPlane, yPlaneN, layer2Dtop ? zPlaneN : zPlane,
1003 zPlaneN, 0, (zstate != AXE_DEPTH_DIR));
1004
1005 // minor tick marks
1006 if (do_xminortick)
1007 {
1008 if (tick_along_z)
1009 render_tickmarks (xmticks, x_min, x_max, ypTick, ypTick,
1010 zpTick, zpTickN, 0., 0.,
1011 signum(zpTick-zpTickN)*fz*xticklen/2*tickdir,
1012 0, (box && xstate != AXE_ANY_DIR));
1013 else
1014 render_tickmarks (xmticks, x_min, x_max, ypTick, ypTickN,
1015 zpTick, zpTick, 0.,
1016 signum(ypTick-ypTickN)*fy*xticklen/2*tickdir,
1017 0., 0, (box && xstate != AXE_ANY_DIR));
1018 }
1019
1020 text::properties& xlabel_props =
1021 reinterpret_cast<text::properties&> (gh_manager::get_object (props.get_xlabel ()).get_properties ());
1022
1023 xlabel_props.set_visible ("on");
1024
1025 if (! xlabel_props.get_string ().empty ())
1026 {
1027 if (xlabel_props.horizontalalignmentmode_is ("auto"))
1028 {
1029 xlabel_props.set_horizontalalignment
1030 (xstate > AXE_DEPTH_DIR
1031 ? "center" : (xyzSym ? "left" : "right"));
1032
1033 xlabel_props.set_horizontalalignmentmode ("auto");
1034 }
1035
1036 if (xlabel_props.verticalalignmentmode_is ("auto"))
1037 {
1038 xlabel_props.set_verticalalignment
1039 (xstate == AXE_VERT_DIR || x2Dtop ? "bottom" : "top");
1040
1041 xlabel_props.set_verticalalignmentmode ("auto");
1042 }
1043
1044 if (xlabel_props.positionmode_is ("auto")
1045 || xlabel_props.rotationmode_is ("auto"))
1046 {
1047 double angle = 0;
1048 ColumnVector p
1049 = graphics_xform::xform_vector ((x_min+x_max)/2,
1050 ypTick, zpTick);
1051
1052 if (tick_along_z)
1053 p(2) += (signum(zpTick-zpTickN)*fz*xtickoffset);
1054 else
1055 p(1) += (signum(ypTick-ypTickN)*fy*xtickoffset);
1056
1057 p = xform.transform (p(0), p(1), p(2), false);
1058
1059 switch (xstate)
1060 {
1061 case AXE_ANY_DIR:
1062 p(0) += (xyzSym ? wmax : -wmax);
1063 p(1) += hmax;
1064 break;
1065
1066 case AXE_VERT_DIR:
1067 p(0) -= wmax;
1068 angle = 90;
1069 break;
1070
1071 case AXE_HORZ_DIR:
1072 p(1) += (x2Dtop ? -hmax : hmax);
1073 break;
1074 }
1075
1076 if (xlabel_props.positionmode_is ("auto"))
1077 {
1078 p = xform.untransform (p(0), p(1), p(2), true);
1079 xlabel_props.set_position (p.extract_n (0, 3).transpose ());
1080 xlabel_props.set_positionmode ("auto");
1081 }
1082
1083 if (xlabel_props.rotationmode_is ("auto"))
1084 {
1085 xlabel_props.set_rotation (angle);
1086 xlabel_props.set_rotationmode ("auto");
1087 }
1088 }
1089 }
1090 }
1091 else
1092 gh_manager::get_object (props.get_xlabel ()).set ("visible", "off");
1093 }
1094
1095 void
1096 opengl_renderer::draw_axes_y_grid (const axes::properties& props,
1097 bool visible, bool box,
1098 const std::string& gridstyle,
1099 const std::string& minorgridstyle,
1100 bool nearhoriz, double tickdir,
1101 bool xyzSym, bool layer2Dtop,
1102 bool y2Dright, int ystate,
1103 double y_min, double y_max,
1104 double yticklen, double ytickoffset,
1105 double fx, double xPlane, double xPlaneN,
1106 double xpTick, double xpTickN,
1107 double fz, int zstate, double zPlane,
1108 double zPlaneN, double zpTick,
1109 double zpTickN)
1110 {
1111 // Y grid
1112
1113 if (ystate != AXE_DEPTH_DIR && visible)
1114 {
1115 bool do_ygrid = (props.is_ygrid () && (gridstyle != "none"));
1116 bool do_yminorgrid = (props.is_yminorgrid () && (minorgridstyle != "none"));
1117 bool do_yminortick = props.is_yminortick ();
1118 Matrix yticks = xform.yscale (props.get_ytick ().matrix_value ());
1119 Matrix ymticks = xform.yscale (props.get_ymtick ().matrix_value ());
1120 string_vector yticklabels = props.get_yticklabel ().all_strings ();
1121 int wmax = 0, hmax = 0;
1122 bool tick_along_z = nearhoriz || xisinf (fx);
1123
1124 set_color (props.get_ycolor_rgb ());
1125
1126 // grid lines
1127 if (do_ygrid)
1128 render_grid (gridstyle, yticks, y_min, y_max,
1129 xPlane, xPlaneN, layer2Dtop ? zPlaneN : zPlane,
1130 zPlaneN, 1, (zstate != AXE_DEPTH_DIR));
1131
1132 // tick marks
1133 if (tick_along_z)
1134 render_tickmarks (yticks, y_min, y_max, xpTick, xpTick,
1135 zpTick, zpTickN, 0., 0.,
1136 signum(zpTick-zpTickN)*fz*yticklen*tickdir,
1137 1, (box && ystate != AXE_ANY_DIR));
1138 else
1139 render_tickmarks (yticks, y_min, y_max, xpTick, xpTickN,
1140 zpTick, zpTick,
1141 signum(xPlaneN-xPlane)*fx*yticklen*tickdir,
1142 0., 0., 1, (box && ystate != AXE_ANY_DIR));
1143
1144 // tick texts
1145 if (yticklabels.numel () > 0)
1146 {
1147 int halign = (ystate == AXE_HORZ_DIR
1148 ? 1 : (!xyzSym || y2Dright ? 0 : 2));
1149 int valign = (ystate == AXE_VERT_DIR ? 1 : 2);
1150
1151 if (tick_along_z)
1152 render_ticktexts (yticks, yticklabels, y_min, y_max, xpTick,
1153 zpTick+signum(zpTick-zpTickN)*fz*ytickoffset,
1154 1, halign, valign, wmax, hmax);
1155 else
1156 render_ticktexts (yticks, yticklabels, y_min, y_max,
1157 xpTick+signum(xpTick-xpTickN)*fx*ytickoffset,
1158 zpTick, 1, halign, valign, wmax, hmax);
1159 }
1160
1161 // minor grid lines
1162 if (do_yminorgrid)
1163 render_grid (minorgridstyle, ymticks, y_min, y_max,
1164 xPlane, xPlaneN, layer2Dtop ? zPlaneN : zPlane,
1165 zPlaneN, 1, (zstate != AXE_DEPTH_DIR));
1166
1167 // minor tick marks
1168 if (do_yminortick)
1169 {
1170 if (tick_along_z)
1171 render_tickmarks (ymticks, y_min, y_max, xpTick, xpTick,
1172 zpTick, zpTickN, 0., 0.,
1173 signum(zpTick-zpTickN)*fz*yticklen/2*tickdir,
1174 1, (box && ystate != AXE_ANY_DIR));
1175 else
1176 render_tickmarks (ymticks, y_min, y_max, xpTick, xpTickN,
1177 zpTick, zpTick,
1178 signum(xpTick-xpTickN)*fx*yticklen/2*tickdir,
1179 0., 0., 1, (box && ystate != AXE_ANY_DIR));
1180 }
1181
1182 text::properties& ylabel_props =
1183 reinterpret_cast<text::properties&> (gh_manager::get_object (props.get_ylabel ()).get_properties ());
1184
1185 ylabel_props.set_visible ("on");
1186
1187 if (! ylabel_props.get_string ().empty ())
1188 {
1189 if (ylabel_props.horizontalalignmentmode_is ("auto"))
1190 {
1191 ylabel_props.set_horizontalalignment
1192 (ystate > AXE_DEPTH_DIR
1193 ? "center" : (!xyzSym ? "left" : "right"));
1194
1195 ylabel_props.set_horizontalalignmentmode ("auto");
1196 }
1197
1198 if (ylabel_props.verticalalignmentmode_is ("auto"))
1199 {
1200 ylabel_props.set_verticalalignment
1201 (ystate == AXE_VERT_DIR && !y2Dright ? "bottom" : "top");
1202
1203 ylabel_props.set_verticalalignmentmode ("auto");
1204 }
1205
1206 if (ylabel_props.positionmode_is ("auto")
1207 || ylabel_props.rotationmode_is ("auto"))
1208 {
1209 double angle = 0;
1210 ColumnVector p = graphics_xform::xform_vector (xpTick, (y_min+y_max)/2, zpTick);
1211
1212 if (tick_along_z)
1213 p(2) += (signum(zpTick-zpTickN)*fz*ytickoffset);
1214 else
1215 p(0) += (signum(xpTick-xpTickN)*fx*ytickoffset);
1216
1217 p = xform.transform (p(0), p(1), p(2), false);
1218
1219 switch (ystate)
1220 {
1221 case AXE_ANY_DIR:
1222 p(0) += (!xyzSym ? wmax : -wmax);
1223 p(1) += hmax;
1224 break;
1225
1226 case AXE_VERT_DIR:
1227 p(0) += (y2Dright ? wmax : -wmax);
1228 angle = 90;
1229 break;
1230
1231 case AXE_HORZ_DIR:
1232 p(1) += hmax;
1233 break;
1234 }
1235
1236 if (ylabel_props.positionmode_is ("auto"))
1237 {
1238 p = xform.untransform (p(0), p(1), p(2), true);
1239 ylabel_props.set_position (p.extract_n (0, 3).transpose ());
1240 ylabel_props.set_positionmode ("auto");
1241 }
1242
1243 if (ylabel_props.rotationmode_is ("auto"))
1244 {
1245 ylabel_props.set_rotation (angle);
1246 ylabel_props.set_rotationmode ("auto");
1247 }
1248 }
1249 }
1250 }
1251 else
1252 gh_manager::get_object (props.get_ylabel ()).set ("visible", "off");
1253 }
1254
1255 void
1256 opengl_renderer::draw_axes_z_grid (const axes::properties& props,
1257 bool visible, bool box,
1258 const std::string& gridstyle,
1259 const std::string& minorgridstyle,
1260 double tickdir, bool xySym, bool zSign,
1261 int zstate, double z_min, double z_max,
1262 double zticklen, double ztickoffset,
1263 double fx, double xPlane, double xPlaneN,
1264 double fy, double yPlane, double yPlaneN)
1265 {
1266 // Z Grid
1267
1268 if (zstate != AXE_DEPTH_DIR && visible)
1269 {
1270 bool do_zgrid = (props.is_zgrid () && (gridstyle != "none"));
1271 bool do_zminorgrid = (props.is_zminorgrid () && (minorgridstyle != "none"));
1272 bool do_zminortick = props.is_zminortick ();
1273 Matrix zticks = xform.zscale (props.get_ztick ().matrix_value ());
1274 Matrix zmticks = xform.zscale (props.get_zmtick ().matrix_value ());
1275 string_vector zticklabels = props.get_zticklabel ().all_strings ();
1276 int wmax = 0, hmax = 0;
1277
1278 set_color (props.get_zcolor_rgb ());
1279
1280 // grid lines
1281 if (do_zgrid)
1282 render_grid (gridstyle, zticks, z_min, z_max,
1283 xPlane, xPlaneN, yPlane, yPlaneN, 2, true);
1284
1285 // tick marks
1286 if (xySym)
1287 {
1288 if (xisinf (fy))
1289 render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlane,
1290 yPlane, yPlane,
1291 signum(xPlaneN-xPlane)*fx*zticklen*tickdir,
1292 0., 0., 2, (box && zstate != AXE_ANY_DIR));
1293 else
1294 render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlaneN,
1295 yPlane, yPlane, 0.,
1296 signum(yPlane-yPlaneN)*fy*zticklen*tickdir,
1297 0., 2, false);
1298 }
1299 else
1300 {
1301 if (xisinf (fx))
1302 render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlane,
1303 yPlaneN, yPlane, 0.,
1304 signum(yPlaneN-yPlane)*fy*zticklen*tickdir,
1305 0., 2, (box && zstate != AXE_ANY_DIR));
1306 else
1307 render_tickmarks (zticks, z_min, z_max, xPlane, xPlane,
1308 yPlaneN, yPlane,
1309 signum(xPlane-xPlaneN)*fx*zticklen*tickdir,
1310 0., 0., 2, false);
1311 }
1312
1313 // FIXME: tick texts
1314 if (zticklabels.numel () > 0)
1315 {
1316 int halign = 2;
1317 int valign = (zstate == AXE_VERT_DIR ? 1 : (zSign ? 3 : 2));
1318
1319 if (xySym)
1320 {
1321 if (xisinf (fy))
1322 render_ticktexts (zticks, zticklabels, z_min, z_max,
1323 xPlaneN+signum(xPlaneN-xPlane)*fx*ztickoffset,
1324 yPlane, 2, halign, valign, wmax, hmax);
1325 else
1326 render_ticktexts (zticks, zticklabels, z_min, z_max, xPlaneN,
1327 yPlane+signum(yPlane-yPlaneN)*fy*ztickoffset,
1328 2, halign, valign, wmax, hmax);
1329 }
1330 else
1331 {
1332 if (xisinf (fx))
1333 render_ticktexts (zticks, zticklabels, z_min, z_max, xPlane,
1334 yPlaneN+signum(yPlaneN-yPlane)*fy*ztickoffset,
1335 2, halign, valign, wmax, hmax);
1336 else
1337 render_ticktexts (zticks, zticklabels, z_min, z_max,
1338 xPlane+signum(xPlane-xPlaneN)*fx*ztickoffset,
1339 yPlaneN, 2, halign, valign, wmax, hmax);
1340 }
1341 }
1342
1343 // minor grid lines
1344 if (do_zminorgrid)
1345 render_grid (minorgridstyle, zmticks, z_min, z_max,
1346 xPlane, xPlaneN, yPlane, yPlaneN, 2, true);
1347
1348 // minor tick marks
1349 if (do_zminortick)
1350 {
1351 if (xySym)
1352 {
1353 if (xisinf (fy))
1354 render_tickmarks (zmticks, z_min, z_max, xPlaneN, xPlane,
1355 yPlane, yPlane,
1356 signum(xPlaneN-xPlane)*fx*zticklen/2*tickdir,
1357 0., 0., 2, (box && zstate != AXE_ANY_DIR));
1358 else
1359 render_tickmarks (zmticks, z_min, z_max, xPlaneN, xPlaneN,
1360 yPlane, yPlane, 0.,
1361 signum(yPlane-yPlaneN)*fy*zticklen/2*tickdir,
1362 0., 2, false);
1363 }
1364 else
1365 {
1366 if (xisinf (fx))
1367 render_tickmarks (zmticks, z_min, z_max, xPlane, xPlane,
1368 yPlaneN, yPlane, 0.,
1369 signum(yPlaneN-yPlane)*fy*zticklen/2*tickdir,
1370 0., 2, (box && zstate != AXE_ANY_DIR));
1371 else
1372 render_tickmarks (zmticks, z_min, z_max, xPlane, xPlane,
1373 yPlaneN, yPlaneN,
1374 signum(xPlane-xPlaneN)*fx*zticklen/2*tickdir,
1375 0., 0., 2, false);
1376 }
1377 }
1378
1379 text::properties& zlabel_props =
1380 reinterpret_cast<text::properties&> (gh_manager::get_object (props.get_zlabel ()).get_properties ());
1381
1382 zlabel_props.set_visible ("on");
1383
1384 if (! zlabel_props.get_string ().empty ())
1385 {
1386 bool camAuto = props.cameraupvectormode_is ("auto");
1387
1388 if (zlabel_props.horizontalalignmentmode_is ("auto"))
1389 {
1390 zlabel_props.set_horizontalalignment
1391 ((zstate > AXE_DEPTH_DIR || camAuto) ? "center" : "right");
1392
1393 zlabel_props.set_horizontalalignmentmode ("auto");
1394 }
1395
1396 if (zlabel_props.verticalalignmentmode_is ("auto"))
1397 {
1398 zlabel_props.set_verticalalignment
1399 (zstate == AXE_VERT_DIR
1400 ? "bottom" : ((zSign || camAuto) ? "bottom" : "top"));
1401
1402 zlabel_props.set_verticalalignmentmode ("auto");
1403 }
1404
1405 if (zlabel_props.positionmode_is ("auto")
1406 || zlabel_props.rotationmode_is ("auto"))
1407 {
1408 double angle = 0;
1409 ColumnVector p;
1410
1411 if (xySym)
1412 {
1413 p = graphics_xform::xform_vector (xPlaneN, yPlane,
1414 (z_min+z_max)/2);
1415 if (xisinf (fy))
1416 p(0) += (signum(xPlaneN-xPlane)*fx*ztickoffset);
1417 else
1418 p(1) += (signum(yPlane-yPlaneN)*fy*ztickoffset);
1419 }
1420 else
1421 {
1422 p = graphics_xform::xform_vector (xPlane, yPlaneN,
1423 (z_min+z_max)/2);
1424 if (xisinf (fx))
1425 p(1) += (signum(yPlaneN-yPlane)*fy*ztickoffset);
1426 else
1427 p(0) += (signum(xPlane-xPlaneN)*fx*ztickoffset);
1428 }
1429
1430 p = xform.transform (p(0), p(1), p(2), false);
1431
1432 switch (zstate)
1433 {
1434 case AXE_ANY_DIR:
1435 if (camAuto)
1436 {
1437 p(0) -= wmax;
1438 angle = 90;
1439 }
1440
1441 // FIXME -- what's the correct offset?
1442 //
1443 // p[0] += (!xySym ? wmax : -wmax);
1444 // p[1] += (zSign ? hmax : -hmax);
1445
1446 break;
1447
1448 case AXE_VERT_DIR:
1449 p(0) -= wmax;
1450 angle = 90;
1451 break;
1452
1453 case AXE_HORZ_DIR:
1454 p(1) += hmax;
1455 break;
1456 }
1457
1458 if (zlabel_props.positionmode_is ("auto"))
1459 {
1460 p = xform.untransform (p(0), p(1), p(2), true);
1461 zlabel_props.set_position (p.extract_n (0, 3).transpose ());
1462 zlabel_props.set_positionmode ("auto");
1463 }
1464
1465 if (zlabel_props.rotationmode_is ("auto"))
1466 {
1467 zlabel_props.set_rotation (angle);
1468 zlabel_props.set_rotationmode ("auto");
1469 }
1470 }
1471 }
1472 }
1473 else
1474 gh_manager::get_object (props.get_zlabel ()).set ("visible", "off");
1475 }
1476
1477 void
1478 opengl_renderer::draw_axes_title (const axes::properties& props,
1479 double x_min, double x_max,
1480 double y_min, double y_max,
1481 double z_min, double z_max)
1482 {
1483 // Title
806 1484
807 ColumnVector bbox(4); 1485 ColumnVector bbox(4);
808 bbox(0) = octave_Inf; 1486 bbox(0) = octave_Inf;
809 bbox(1) = octave_Inf; 1487 bbox(1) = octave_Inf;
810 bbox(2) = -octave_Inf; 1488 bbox(2) = -octave_Inf;
811 bbox(3) = -octave_Inf; 1489 bbox(3) = -octave_Inf;
812 for (int i = 0; i <= 1; i++) 1490 for (int i = 0; i <= 1; i++)
813 for (int j = 0; j <= 1; j++) 1491 for (int j = 0; j <= 1; j++)
814 for (int k = 0; k <= 1; k++) 1492 for (int k = 0; k <= 1; k++)
815 { 1493 {
816 ColumnVector p = xform.transform (i ? x_max : x_min, j ? y_max : y_min, 1494 ColumnVector p = xform.transform (i ? x_max : x_min,
1495 j ? y_max : y_min,
817 k ? z_max : z_min, false); 1496 k ? z_max : z_min, false);
818 bbox(0) = std::min (bbox(0), p(0)); 1497 bbox(0) = std::min (bbox(0), p(0));
819 bbox(1) = std::min (bbox(1), p(1)); 1498 bbox(1) = std::min (bbox(1), p(1));
820 bbox(2) = std::max (bbox(2), p(0)); 1499 bbox(2) = std::max (bbox(2), p(0));
821 bbox(3) = std::max (bbox(3), p(1)); 1500 bbox(3) = std::max (bbox(3), p(1));
822 } 1501 }
1502
823 bbox(2) = bbox(2)-bbox(0); 1503 bbox(2) = bbox(2)-bbox(0);
824 bbox(3) = bbox(3)-bbox(1); 1504 bbox(3) = bbox(3)-bbox(1);
1505
1506 Matrix x_zlim = props.get_transform_zlim ();
1507
1508 text::properties& title_props =
1509 reinterpret_cast<text::properties&> (gh_manager::get_object (props.get_title ()).get_properties ());
1510
1511 if (! title_props.get_string ().empty ()
1512 && title_props.positionmode_is ("auto"))
1513 {
1514 ColumnVector p = xform.untransform (bbox(0)+bbox(2)/2, (bbox(1)-10),
1515 (x_zlim(0)+x_zlim(1))/2, true);
1516
1517 title_props.set_position (p.extract_n(0, 3).transpose ());
1518 title_props.set_positionmode ("auto");
1519 }
1520
1521 set_clipbox (x_min, x_max, y_min, y_max, z_min, z_max);
1522 }
1523
1524 void
1525 opengl_renderer::draw_axes_children (const axes::properties& props)
1526 {
1527 // Children
1528
1529 GLboolean antialias;
1530 glGetBooleanv (GL_LINE_SMOOTH, &antialias);
1531
1532 if (antialias == GL_TRUE)
1533 glEnable (GL_LINE_SMOOTH);
1534 else
1535 glDisable (GL_LINE_SMOOTH);
1536
1537 Matrix children = props.get_all_children ();
1538 std::list<graphics_object> obj_list;
1539 std::list<graphics_object>::iterator it;
1540
1541 // 1st pass: draw light objects
1542
1543 // Start with the last element of the array of child objects to
1544 // display them in the oder they were added to the array.
1545
1546 for (octave_idx_type i = children.numel () - 1; i >= 0; i--)
1547 {
1548 graphics_object go = gh_manager::get_object (children (i));
1549
1550 if (go.get_properties ().is_visible ())
1551 {
1552 if (go.isa ("light"))
1553 draw (go);
1554 else
1555 obj_list.push_back (go);
1556 }
1557 }
1558
1559 // 2nd pass: draw other objects (with units set to "data")
1560
1561 it = obj_list.begin ();
1562 while (it != obj_list.end ())
1563 {
1564 graphics_object go = (*it);
1565
1566 // FIXME: check whether object has "units" property and it is set
1567 // to "data"
1568 if (! go.isa ("text") || go.get ("units").string_value () == "data")
1569 {
1570 set_clipping (go.get_properties ().is_clipping ());
1571 draw (go);
1572
1573 it = obj_list.erase (it);
1574 }
1575 else
1576 it++;
1577 }
1578
1579 // 3rd pass: draw remaining objects
1580
1581 glDisable (GL_DEPTH_TEST);
1582
1583 for (it = obj_list.begin (); it != obj_list.end (); it++)
1584 {
1585 graphics_object go = (*it);
1586
1587 set_clipping (go.get_properties ().is_clipping ());
1588 draw (go);
1589 }
1590
1591 glEnable (GL_DEPTH_TEST);
1592
1593 set_clipping (false);
1594
1595 // FIXME: finalize rendering (transparency processing)
1596 // FIXME: draw zoom box, if needed
1597 }
1598
1599 void
1600 opengl_renderer::draw_axes (const axes::properties& props)
1601 {
1602 setup_opengl_transformation (props);
1603
1604 // draw axes object
1605
1606 const Matrix xlim = xform.xscale (props.get_xlim ().matrix_value ());
1607 const Matrix ylim = xform.yscale (props.get_ylim ().matrix_value ());
1608 const Matrix zlim = xform.zscale (props.get_zlim ().matrix_value ());
1609
1610 double x_min = xlim(0), x_max = xlim(1);
1611 double y_min = ylim(0), y_max = ylim(1);
1612 double z_min = zlim(0), z_max = zlim(1);
1613
1614 double xd = (props.xdir_is ("normal") ? 1 : -1);
1615 double yd = (props.ydir_is ("normal") ? 1 : -1);
1616 double zd = (props.zdir_is ("normal") ? 1 : -1);
825 1617
826 ColumnVector p1, p2, xv (3), yv (3), zv (3); 1618 ColumnVector p1, p2, xv (3), yv (3), zv (3);
827 int xstate, ystate, zstate; 1619 int xstate, ystate, zstate;
828 1620
829 xstate = ystate = zstate = AXE_ANY_DIR; 1621 xstate = ystate = zstate = AXE_ANY_DIR;
974 1766
975 Matrix axe_color = props.get_color_rgb (); 1767 Matrix axe_color = props.get_color_rgb ();
976 bool visible = props.is_visible (); 1768 bool visible = props.is_visible ();
977 bool box = props.is_box (); 1769 bool box = props.is_box ();
978 1770
979 // Axes planes 1771 draw_axes_planes (visible, axe_color, xlim, ylim, zlim,
980 1772 xPlane, yPlane, zPlane);
981 if (axe_color.numel () > 0 && visible) 1773
982 { 1774 draw_axes_boxes (props, visible, box, xySym, xPlane, yPlane, zPlane,
983 set_color (axe_color); 1775 xPlaneN, yPlaneN, zPlaneN, xpTick, ypTick, zpTick,
984 set_polygon_offset (true, 2.5); 1776 xpTickN, ypTickN, zpTickN);
985 1777
986 glBegin (GL_QUADS);
987
988 // X plane
989 glVertex3d (xPlane, y_min, z_min);
990 glVertex3d (xPlane, y_max, z_min);
991 glVertex3d (xPlane, y_max, z_max);
992 glVertex3d (xPlane, y_min, z_max);
993
994 // Y plane
995 glVertex3d (x_min, yPlane, z_min);
996 glVertex3d (x_max, yPlane, z_min);
997 glVertex3d (x_max, yPlane, z_max);
998 glVertex3d (x_min, yPlane, z_max);
999
1000 // Z plane
1001 glVertex3d (x_min, y_min, zPlane);
1002 glVertex3d (x_max, y_min, zPlane);
1003 glVertex3d (x_max, y_max, zPlane);
1004 glVertex3d (x_min, y_max, zPlane);
1005
1006 glEnd ();
1007
1008 set_polygon_offset (false);
1009 }
1010
1011 // Axes box
1012
1013 set_linestyle ("-", true);
1014 set_linewidth (props.get_linewidth ());
1015
1016 if (visible)
1017 {
1018 glBegin (GL_LINES);
1019
1020 // X box
1021 set_color (props.get_xcolor_rgb ());
1022 glVertex3d (xPlaneN, ypTick, zpTick);
1023 glVertex3d (xPlane, ypTick, zpTick);
1024 if (box)
1025 {
1026 glVertex3d (xPlaneN, ypTickN, zpTick);
1027 glVertex3d (xPlane, ypTickN, zpTick);
1028 glVertex3d (xPlaneN, ypTickN, zpTickN);
1029 glVertex3d (xPlane, ypTickN, zpTickN);
1030 glVertex3d (xPlaneN, ypTick, zpTickN);
1031 glVertex3d (xPlane, ypTick, zpTickN);
1032 }
1033
1034 // Y box
1035 set_color (props.get_ycolor_rgb ());
1036 glVertex3d (xpTick, yPlaneN, zpTick);
1037 glVertex3d (xpTick, yPlane, zpTick);
1038 if (box)
1039 {
1040 glVertex3d (xpTickN, yPlaneN, zpTick);
1041 glVertex3d (xpTickN, yPlane, zpTick);
1042 glVertex3d (xpTickN, yPlaneN, zpTickN);
1043 glVertex3d (xpTickN, yPlane, zpTickN);
1044 glVertex3d (xpTick, yPlaneN, zpTickN);
1045 glVertex3d (xpTick, yPlane, zpTickN);
1046 }
1047
1048 // Z box
1049 set_color (props.get_zcolor_rgb ());
1050 if (xySym)
1051 {
1052 glVertex3d (xPlaneN, yPlane, zPlaneN);
1053 glVertex3d (xPlaneN, yPlane, zPlane);
1054 }
1055 else
1056 {
1057 glVertex3d (xPlane, yPlaneN, zPlaneN);
1058 glVertex3d (xPlane, yPlaneN, zPlane);
1059 }
1060 if (box)
1061 {
1062 glVertex3d (xPlane, yPlane, zPlaneN);
1063 glVertex3d (xPlane, yPlane, zPlane);
1064 if (xySym)
1065 {
1066 glVertex3d (xPlane, yPlaneN, zPlaneN);
1067 glVertex3d (xPlane, yPlaneN, zPlane);
1068 }
1069 else
1070 {
1071 glVertex3d (xPlaneN, yPlane, zPlaneN);
1072 glVertex3d (xPlaneN, yPlane, zPlane);
1073 }
1074 glVertex3d (xPlaneN, yPlaneN, zPlaneN);
1075 glVertex3d (xPlaneN, yPlaneN, zPlane);
1076 }
1077
1078 glEnd ();
1079 }
1080 1778
1081 std::string gridstyle = props.get_gridlinestyle (); 1779 std::string gridstyle = props.get_gridlinestyle ();
1082 std::string minorgridstyle = props.get_minorgridlinestyle (); 1780 std::string minorgridstyle = props.get_minorgridlinestyle ();
1083 1781
1084 set_font (props); 1782 set_font (props);
1085 1783
1086 // X grid 1784 draw_axes_x_grid (props, visible, box, gridstyle, minorgridstyle,
1087 1785 nearhoriz, tickdir, xyzSym, layer2Dtop, x2Dtop,
1088 if (visible && xstate != AXE_DEPTH_DIR) 1786 xstate, xlim(0), xlim(1), xticklen, xtickoffset,
1089 { 1787 fy, yPlane, yPlaneN, ypTick, ypTickN,
1090 bool do_xgrid = (props.is_xgrid () && (gridstyle != "none")); 1788 fz, zstate, zPlane, zPlaneN, zpTick, zpTickN);
1091 bool do_xminorgrid = (props.is_xminorgrid () && (minorgridstyle != "none")); 1789
1092 bool do_xminortick = props.is_xminortick (); 1790 draw_axes_y_grid (props, visible, box, gridstyle, minorgridstyle,
1093 Matrix xticks = xform.xscale (props.get_xtick ().matrix_value ()); 1791 nearhoriz, tickdir, xyzSym, layer2Dtop, y2Dright,
1094 Matrix xmticks = xform.xscale (props.get_xmtick ().matrix_value ()); 1792 ystate, ylim(0), ylim(1), yticklen, ytickoffset,
1095 string_vector xticklabels = props.get_xticklabel ().all_strings (); 1793 fx, xPlane, xPlaneN, xpTick, xpTickN,
1096 int wmax = 0, hmax = 0; 1794 fz, zstate, zPlane, zPlaneN, zpTick, zpTickN);
1097 bool tick_along_z = nearhoriz || xisinf (fy); 1795
1098 1796 draw_axes_z_grid (props, visible, box, gridstyle, minorgridstyle,
1099 set_color (props.get_xcolor_rgb ()); 1797 tickdir, xySym, zSign, zstate, zlim(0), zlim(1),
1100 1798 zticklen, ztickoffset, fx, xPlane, xPlaneN,
1101 // grid lines 1799 fy, yPlane, yPlaneN);
1102 if (do_xgrid)
1103 render_grid (gridstyle, xticks, x_min, x_max,
1104 yPlane, yPlaneN, layer2Dtop ? zPlaneN : zPlane, zPlaneN,
1105 0, (zstate != AXE_DEPTH_DIR));
1106
1107 // tick marks
1108 if (tick_along_z)
1109 {
1110 render_tickmarks (xticks, x_min, x_max, ypTick, ypTick, zpTick, zpTickN,
1111 0., 0., signum(zpTick-zpTickN)*fz*xticklen*tickdir,
1112 0, (box && xstate != AXE_ANY_DIR));
1113 }
1114 else
1115 {
1116 render_tickmarks (xticks, x_min, x_max, ypTick, ypTickN, zpTick, zpTick,
1117 0., signum(ypTick-ypTickN)*fy*xticklen*tickdir, 0.,
1118 0, (box && xstate != AXE_ANY_DIR));
1119 }
1120
1121 // tick texts
1122 if (xticklabels.numel () > 0)
1123 {
1124 int halign = (xstate == AXE_HORZ_DIR ? 1 : (xyzSym ? 0 : 2));
1125 int valign = (xstate == AXE_VERT_DIR ? 1 : (x2Dtop ? 0 : 2));
1126
1127 if (tick_along_z)
1128 {
1129 render_ticktexts (xticks, xticklabels, x_min, x_max,
1130 ypTick, zpTick+signum(zpTick-zpTickN)*fz*xtickoffset,
1131 0, halign, valign, wmax, hmax);
1132 }
1133 else
1134 {
1135 render_ticktexts (xticks, xticklabels, x_min, x_max,
1136 ypTick+signum(ypTick-ypTickN)*fy*xtickoffset, zpTick,
1137 0, halign, valign, wmax, hmax);
1138 }
1139 }
1140
1141 // minor grid lines
1142 if (do_xminorgrid)
1143 render_grid (minorgridstyle, xmticks, x_min, x_max,
1144 yPlane, yPlaneN, layer2Dtop ? zPlaneN : zPlane, zPlaneN,
1145 0, (zstate != AXE_DEPTH_DIR));
1146
1147 // minor tick marks
1148 if (do_xminortick)
1149 {
1150 if (tick_along_z)
1151 {
1152 render_tickmarks (xmticks, x_min, x_max, ypTick, ypTick, zpTick, zpTickN,
1153 0., 0., signum(zpTick-zpTickN)*fz*xticklen/2*tickdir,
1154 0, (box && xstate != AXE_ANY_DIR));
1155 }
1156 else
1157 {
1158 render_tickmarks (xmticks, x_min, x_max, ypTick, ypTickN, zpTick, zpTick,
1159 0., signum(ypTick-ypTickN)*fy*xticklen/2*tickdir, 0.,
1160 0, (box && xstate != AXE_ANY_DIR));
1161 }
1162 }
1163
1164 text::properties& xlabel_props =
1165 reinterpret_cast<text::properties&> (gh_manager::get_object (props.get_xlabel ()).get_properties ());
1166
1167 xlabel_props.set_visible ("on");
1168
1169 if (! xlabel_props.get_string ().empty ())
1170 {
1171 if (xlabel_props.horizontalalignmentmode_is("auto"))
1172 {
1173 xlabel_props.set_horizontalalignment (xstate > AXE_DEPTH_DIR ? "center" : (xyzSym ? "left" : "right"));
1174 xlabel_props.set_horizontalalignmentmode("auto");
1175 }
1176 if (xlabel_props.verticalalignmentmode_is("auto"))
1177 {
1178 xlabel_props.set_verticalalignment (xstate == AXE_VERT_DIR || x2Dtop ? "bottom" : "top");
1179 xlabel_props.set_verticalalignmentmode("auto");
1180 }
1181
1182 if (xlabel_props.positionmode_is("auto") || xlabel_props.rotationmode_is("auto"))
1183 {
1184 double angle = 0;
1185 ColumnVector p = graphics_xform::xform_vector ((x_min+x_max)/2, ypTick, zpTick);
1186
1187 if (tick_along_z)
1188 p(2) += (signum(zpTick-zpTickN)*fz*xtickoffset);
1189 else
1190 p(1) += (signum(ypTick-ypTickN)*fy*xtickoffset);
1191 p = xform.transform (p(0), p(1), p(2), false);
1192 switch (xstate)
1193 {
1194 case AXE_ANY_DIR:
1195 p(0) += (xyzSym ? wmax : -wmax);
1196 p(1) += hmax;
1197 break;
1198 case AXE_VERT_DIR:
1199 p(0) -= wmax;
1200 angle = 90;
1201 break;
1202 case AXE_HORZ_DIR:
1203 p(1) += (x2Dtop ? -hmax : hmax);
1204 break;
1205 }
1206 if (xlabel_props.positionmode_is("auto"))
1207 {
1208 p = xform.untransform (p(0), p(1), p(2), true);
1209 xlabel_props.set_position (p.extract_n (0, 3).transpose ());
1210 xlabel_props.set_positionmode ("auto");
1211 }
1212 if (xlabel_props.rotationmode_is("auto"))
1213 {
1214 xlabel_props.set_rotation (angle);
1215 xlabel_props.set_rotationmode ("auto");
1216 }
1217 }
1218 }
1219 }
1220 else
1221 {
1222 gh_manager::get_object (props.get_xlabel ()).set ("visible", "off");
1223 }
1224
1225 // Y grid
1226
1227 if (ystate != AXE_DEPTH_DIR && visible)
1228 {
1229 bool do_ygrid = (props.is_ygrid () && (gridstyle != "none"));
1230 bool do_yminorgrid = (props.is_yminorgrid () && (minorgridstyle != "none"));
1231 bool do_yminortick = props.is_yminortick ();
1232 Matrix yticks = xform.yscale (props.get_ytick ().matrix_value ());
1233 Matrix ymticks = xform.yscale (props.get_ymtick ().matrix_value ());
1234 string_vector yticklabels = props.get_yticklabel ().all_strings ();
1235 int wmax = 0, hmax = 0;
1236 bool tick_along_z = nearhoriz || xisinf (fx);
1237
1238 set_color (props.get_ycolor_rgb ());
1239
1240 // grid lines
1241 if (do_ygrid)
1242 render_grid (gridstyle, yticks, y_min, y_max,
1243 xPlane, xPlaneN, layer2Dtop ? zPlaneN : zPlane, zPlaneN,
1244 1, (zstate != AXE_DEPTH_DIR));
1245
1246 // tick marks
1247 if (tick_along_z)
1248 {
1249 render_tickmarks (yticks, y_min, y_max, xpTick, xpTick, zpTick, zpTickN,
1250 0., 0., signum(zpTick-zpTickN)*fz*yticklen*tickdir,
1251 1, (box && ystate != AXE_ANY_DIR));
1252 }
1253 else
1254 {
1255 render_tickmarks (yticks, y_min, y_max, xpTick, xpTickN, zpTick, zpTick,
1256 signum(xPlaneN-xPlane)*fx*yticklen*tickdir, 0., 0.,
1257 1, (box && ystate != AXE_ANY_DIR));
1258 }
1259
1260 // tick texts
1261 if (yticklabels.numel () > 0)
1262 {
1263 int halign = (ystate == AXE_HORZ_DIR ? 1 : (!xyzSym || y2Dright ? 0 : 2));
1264 int valign = (ystate == AXE_VERT_DIR ? 1 : 2);
1265
1266 if (tick_along_z)
1267 {
1268 render_ticktexts (yticks, yticklabels, y_min, y_max,
1269 xpTick, zpTick+signum(zpTick-zpTickN)*fz*ytickoffset,
1270 1, halign, valign, wmax, hmax);
1271 }
1272 else
1273 {
1274 render_ticktexts (yticks, yticklabels, y_min, y_max,
1275 xpTick+signum(xpTick-xpTickN)*fx*ytickoffset, zpTick,
1276 1, halign, valign, wmax, hmax);
1277 }
1278 }
1279
1280 // minor grid lines
1281 if (do_yminorgrid)
1282 render_grid (minorgridstyle, ymticks, y_min, y_max,
1283 xPlane, xPlaneN, layer2Dtop ? zPlaneN : zPlane, zPlaneN,
1284 1, (zstate != AXE_DEPTH_DIR));
1285
1286 // minor tick marks
1287 if (do_yminortick)
1288 {
1289 if (tick_along_z)
1290 {
1291 render_tickmarks (ymticks, y_min, y_max, xpTick, xpTick, zpTick, zpTickN,
1292 0., 0., signum(zpTick-zpTickN)*fz*yticklen/2*tickdir,
1293 1, (box && ystate != AXE_ANY_DIR));
1294 }
1295 else
1296 {
1297 render_tickmarks (ymticks, y_min, y_max, xpTick, xpTickN, zpTick, zpTick,
1298 signum(xpTick-xpTickN)*fx*yticklen/2*tickdir, 0., 0.,
1299 1, (box && ystate != AXE_ANY_DIR));
1300 }
1301 }
1302
1303 text::properties& ylabel_props =
1304 reinterpret_cast<text::properties&> (gh_manager::get_object (props.get_ylabel ()).get_properties ());
1305
1306 ylabel_props.set_visible ("on");
1307
1308 if (! ylabel_props.get_string ().empty ())
1309 {
1310 if (ylabel_props.horizontalalignmentmode_is("auto"))
1311 {
1312 ylabel_props.set_horizontalalignment (ystate > AXE_DEPTH_DIR ? "center" : (!xyzSym ? "left" : "right"));
1313 ylabel_props.set_horizontalalignmentmode("auto");
1314 }
1315 if (ylabel_props.verticalalignmentmode_is("auto"))
1316 {
1317 ylabel_props.set_verticalalignment (ystate == AXE_VERT_DIR && !y2Dright ? "bottom" : "top");
1318 ylabel_props.set_verticalalignmentmode("auto");
1319 }
1320
1321 if (ylabel_props.positionmode_is("auto") || ylabel_props.rotationmode_is("auto"))
1322 {
1323 double angle = 0;
1324 ColumnVector p = graphics_xform::xform_vector (xpTick, (y_min+y_max)/2, zpTick);
1325
1326 if (tick_along_z)
1327 p(2) += (signum(zpTick-zpTickN)*fz*ytickoffset);
1328 else
1329 p(0) += (signum(xpTick-xpTickN)*fx*ytickoffset);
1330 p = xform.transform (p(0), p(1), p(2), false);
1331 switch (ystate)
1332 {
1333 case AXE_ANY_DIR:
1334 p(0) += (!xyzSym ? wmax : -wmax);
1335 p(1) += hmax;
1336 break;
1337 case AXE_VERT_DIR:
1338 p(0) += (y2Dright ? wmax : -wmax);
1339 angle = 90;
1340 break;
1341 case AXE_HORZ_DIR:
1342 p(1) += hmax;
1343 break;
1344 }
1345 if (ylabel_props.positionmode_is("auto"))
1346 {
1347 p = xform.untransform (p(0), p(1), p(2), true);
1348 ylabel_props.set_position (p.extract_n (0, 3).transpose ());
1349 ylabel_props.set_positionmode ("auto");
1350 }
1351 if (ylabel_props.rotationmode_is("auto"))
1352 {
1353 ylabel_props.set_rotation (angle);
1354 ylabel_props.set_rotationmode ("auto");
1355 }
1356 }
1357 }
1358 }
1359 else
1360 {
1361 gh_manager::get_object (props.get_ylabel ()).set ("visible", "off");
1362 }
1363
1364 // Z Grid
1365
1366 if (zstate != AXE_DEPTH_DIR && visible)
1367 {
1368 bool do_zgrid = (props.is_zgrid () && (gridstyle != "none"));
1369 bool do_zminorgrid = (props.is_zminorgrid () && (minorgridstyle != "none"));
1370 bool do_zminortick = props.is_zminortick ();
1371 Matrix zticks = xform.zscale (props.get_ztick ().matrix_value ());
1372 Matrix zmticks = xform.zscale (props.get_zmtick ().matrix_value ());
1373 string_vector zticklabels = props.get_zticklabel ().all_strings ();
1374 int wmax = 0, hmax = 0;
1375
1376 set_color (props.get_zcolor_rgb ());
1377
1378 // grid lines
1379 if (do_zgrid)
1380 render_grid (gridstyle, zticks, z_min, z_max,
1381 xPlane, xPlaneN, yPlane, yPlaneN, 2, true);
1382
1383 // tick marks
1384 if (xySym)
1385 {
1386 if (xisinf (fy))
1387 {
1388 render_tickmarks( zticks, z_min, z_max, xPlaneN, xPlane, yPlane, yPlane,
1389 signum(xPlaneN-xPlane)*fx*zticklen*tickdir, 0., 0.,
1390 2, (box && zstate != AXE_ANY_DIR));
1391 }
1392 else
1393 {
1394 render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlaneN, yPlane, yPlane,
1395 0., signum(yPlane-yPlaneN)*fy*zticklen*tickdir, 0.,
1396 2, false);
1397 }
1398 }
1399 else
1400 {
1401 if (xisinf (fx))
1402 {
1403 render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlane, yPlaneN, yPlane,
1404 0., signum(yPlaneN-yPlane)*fy*zticklen*tickdir, 0.,
1405 2, (box && zstate != AXE_ANY_DIR));
1406 }
1407 else
1408 {
1409 render_tickmarks (zticks, z_min, z_max, xPlane, xPlane, yPlaneN, yPlane,
1410 signum(xPlane-xPlaneN)*fx*zticklen*tickdir, 0., 0.,
1411 2, false);
1412 }
1413 }
1414
1415 // FIXME: tick texts
1416 if (zticklabels.numel () > 0)
1417 {
1418 int halign = 2;
1419 int valign = (zstate == AXE_VERT_DIR ? 1 : (zSign ? 3 : 2));
1420
1421 if (xySym)
1422 {
1423 if (xisinf (fy))
1424 {
1425 render_ticktexts (zticks, zticklabels, z_min, z_max,
1426 xPlaneN+signum(xPlaneN-xPlane)*fx*ztickoffset, yPlane,
1427 2, halign, valign, wmax, hmax);
1428 }
1429 else
1430 {
1431 render_ticktexts (zticks, zticklabels, z_min, z_max,
1432 xPlaneN, yPlane+signum(yPlane-yPlaneN)*fy*ztickoffset,
1433 2, halign, valign, wmax, hmax);
1434 }
1435 }
1436 else
1437 {
1438 if (xisinf (fx))
1439 {
1440 render_ticktexts (zticks, zticklabels, z_min, z_max,
1441 xPlane, yPlaneN+signum(yPlaneN-yPlane)*fy*ztickoffset,
1442 2, halign, valign, wmax, hmax);
1443 }
1444 else
1445 {
1446 render_ticktexts (zticks, zticklabels, z_min, z_max,
1447 xPlane+signum(xPlane-xPlaneN)*fx*ztickoffset, yPlaneN,
1448 2, halign, valign, wmax, hmax);
1449 }
1450 }
1451 }
1452
1453 // minor grid lines
1454 if (do_zminorgrid)
1455 render_grid (minorgridstyle, zmticks, z_min, z_max,
1456 xPlane, xPlaneN, yPlane, yPlaneN, 2, true);
1457
1458 // minor tick marks
1459 if (do_zminortick)
1460 {
1461 if (xySym)
1462 {
1463 if (xisinf (fy))
1464 {
1465 render_tickmarks( zmticks, z_min, z_max, xPlaneN, xPlane, yPlane, yPlane,
1466 signum(xPlaneN-xPlane)*fx*zticklen/2*tickdir, 0., 0.,
1467 2, (box && zstate != AXE_ANY_DIR));
1468 }
1469 else
1470 {
1471 render_tickmarks (zmticks, z_min, z_max, xPlaneN, xPlaneN, yPlane, yPlane,
1472 0., signum(yPlane-yPlaneN)*fy*zticklen/2*tickdir, 0.,
1473 2, false);
1474 }
1475 }
1476 else
1477 {
1478 if (xisinf (fx))
1479 {
1480 render_tickmarks (zmticks, z_min, z_max, xPlane, xPlane, yPlaneN, yPlane,
1481 0., signum(yPlaneN-yPlane)*fy*zticklen/2*tickdir, 0.,
1482 2, (box && zstate != AXE_ANY_DIR));
1483 }
1484 else
1485 {
1486 render_tickmarks (zmticks, z_min, z_max, xPlane, xPlane, yPlaneN, yPlaneN,
1487 signum(xPlane-xPlaneN)*fx*zticklen/2*tickdir, 0., 0.,
1488 2, false);
1489 }
1490 }
1491 }
1492
1493 text::properties& zlabel_props =
1494 reinterpret_cast<text::properties&> (gh_manager::get_object (props.get_zlabel ()).get_properties ());
1495
1496 zlabel_props.set_visible ("on");
1497
1498 if (! zlabel_props.get_string ().empty ())
1499 {
1500 bool camAuto = props.cameraupvectormode_is ("auto");
1501
1502 if (zlabel_props.horizontalalignmentmode_is("auto"))
1503 {
1504 zlabel_props.set_horizontalalignment ((zstate > AXE_DEPTH_DIR || camAuto) ? "center" : "right");
1505 zlabel_props.set_horizontalalignmentmode("auto");
1506 }
1507 if (zlabel_props.verticalalignmentmode_is("auto"))
1508 {
1509 zlabel_props.set_verticalalignment(zstate == AXE_VERT_DIR ? "bottom" : ((zSign || camAuto) ? "bottom" : "top"));
1510 zlabel_props.set_verticalalignmentmode("auto");
1511 }
1512
1513 if (zlabel_props.positionmode_is("auto") || zlabel_props.rotationmode_is("auto"))
1514 {
1515 double angle = 0;
1516 ColumnVector p;
1517
1518 if (xySym)
1519 {
1520 p = graphics_xform::xform_vector (xPlaneN, yPlane, (z_min+z_max)/2);
1521 if (xisinf (fy))
1522 p(0) += (signum(xPlaneN-xPlane)*fx*ztickoffset);
1523 else
1524 p(1) += (signum(yPlane-yPlaneN)*fy*ztickoffset);
1525 }
1526 else
1527 {
1528 p = graphics_xform::xform_vector (xPlane, yPlaneN, (z_min+z_max)/2);
1529 if (xisinf (fx))
1530 p(1) += (signum(yPlaneN-yPlane)*fy*ztickoffset);
1531 else
1532 p(0) += (signum(xPlane-xPlaneN)*fx*ztickoffset);
1533 }
1534 p = xform.transform (p(0), p(1), p(2), false);
1535 switch (zstate)
1536 {
1537 case AXE_ANY_DIR:
1538 if (camAuto)
1539 {
1540 p(0) -= wmax;
1541 angle = 90;
1542 }
1543 /* FIXME: what's the correct offset?
1544 p[0] += (!xySym ? wmax : -wmax);
1545 p[1] += (zSign ? hmax : -hmax);
1546 */
1547 break;
1548 case AXE_VERT_DIR:
1549 p(0) -= wmax;
1550 angle = 90;
1551 break;
1552 case AXE_HORZ_DIR:
1553 p(1) += hmax;
1554 break;
1555 }
1556 if (zlabel_props.positionmode_is("auto"))
1557 {
1558 p = xform.untransform (p(0), p(1), p(2), true);
1559 zlabel_props.set_position (p.extract_n (0, 3).transpose ());
1560 zlabel_props.set_positionmode ("auto");
1561 }
1562 if (zlabel_props.rotationmode_is("auto"))
1563 {
1564 zlabel_props.set_rotation (angle);
1565 zlabel_props.set_rotationmode ("auto");
1566 }
1567 }
1568 }
1569 }
1570 else
1571 {
1572 gh_manager::get_object (props.get_zlabel ()).set ("visible", "off");
1573 }
1574 1800
1575 set_linestyle ("-"); 1801 set_linestyle ("-");
1576 1802
1577 // Title 1803 draw_axes_title (props, xlim(0), xlim(1), ylim(0), ylim(1),
1578 1804 zlim(0), zlim(1));
1579 text::properties& title_props = 1805
1580 reinterpret_cast<text::properties&> (gh_manager::get_object (props.get_title ()).get_properties ()); 1806 draw_axes_children (props);
1581
1582 if (! title_props.get_string ().empty () && title_props.positionmode_is("auto"))
1583 {
1584 ColumnVector p = xform.untransform (bbox(0)+bbox(2)/2, (bbox(1)-10),
1585 (x_zlim(0)+x_zlim(1))/2, true);
1586 title_props.set_position (p.extract_n(0, 3).transpose ());
1587 title_props.set_positionmode ("auto");
1588 }
1589
1590 set_clipbox (x_min, x_max, y_min, y_max, z_min, z_max);
1591
1592 // Children
1593
1594 if (antialias == GL_TRUE)
1595 glEnable (GL_LINE_SMOOTH);
1596
1597 Matrix children = props.get_all_children ();
1598 std::list<graphics_object> obj_list;
1599 std::list<graphics_object>::iterator it;
1600
1601 // 1st pass: draw light objects
1602
1603 // Start with the last element of the array of child objects to
1604 // display them in the oder they were added to the array.
1605
1606 for (octave_idx_type i = children.numel () - 1; i >= 0; i--)
1607 {
1608 graphics_object go = gh_manager::get_object (children (i));
1609
1610 if (go.get_properties ().is_visible ())
1611 {
1612 if (go.isa ("light"))
1613 draw (go);
1614 else
1615 obj_list.push_back (go);
1616 }
1617 }
1618
1619 // 2nd pass: draw other objects (with units set to "data")
1620
1621 it = obj_list.begin ();
1622 while (it != obj_list.end ())
1623 {
1624 graphics_object go = (*it);
1625
1626 // FIXME: check whether object has "units" property and it is set to "data"
1627 if (! go.isa ("text") || go.get ("units").string_value () == "data")
1628 {
1629 set_clipping (go.get_properties ().is_clipping ());
1630 draw (go);
1631
1632 it = obj_list.erase (it);
1633 }
1634 else
1635 it++;
1636 }
1637
1638 // 3rd pass: draw remaining objects
1639
1640 glDisable (GL_DEPTH_TEST);
1641 for (it = obj_list.begin (); it != obj_list.end (); it++)
1642 {
1643 graphics_object go = (*it);
1644
1645 set_clipping (go.get_properties ().is_clipping ());
1646 draw (go);
1647 }
1648 glEnable (GL_DEPTH_TEST);
1649
1650 set_clipping (false);
1651 // FIXME: finalize rendering (transparency processing)
1652 // FIXME: draw zoom box, if needed
1653 } 1807 }
1654 1808
1655 void 1809 void
1656 opengl_renderer::draw_line (const line::properties& props) 1810 opengl_renderer::draw_line (const line::properties& props)
1657 { 1811 {