Panda3D
|
00001 // Filename: tinyOsxGraphicsPipe.cxx 00002 // Created by: drose (12May08) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "pandabase.h" 00016 00017 #if defined(IS_OSX) && !defined(BUILD_IPHONE) 00018 00019 #include "tinyOsxGraphicsPipe.h" 00020 #include "config_tinydisplay.h" 00021 #include "tinyOsxGraphicsWindow.h" 00022 #include "tinyGraphicsBuffer.h" 00023 #include "pnmImage.h" 00024 #include "subprocessWindow.h" 00025 #include "nativeWindowHandle.h" 00026 00027 TypeHandle TinyOsxGraphicsPipe::_type_handle; 00028 00029 //////////////////////////////////////////////////////////////////// 00030 // Function: TinyOsxGraphicsPipe::Constructor 00031 // Access: Public 00032 // Description: 00033 //////////////////////////////////////////////////////////////////// 00034 TinyOsxGraphicsPipe:: 00035 TinyOsxGraphicsPipe() { 00036 CGRect display_bounds = CGDisplayBounds(kCGDirectMainDisplay); 00037 _display_width = CGRectGetWidth(display_bounds); 00038 _display_height = CGRectGetHeight(display_bounds); 00039 } 00040 00041 //////////////////////////////////////////////////////////////////// 00042 // Function: TinyOsxGraphicsPipe::Destructor 00043 // Access: Public, Virtual 00044 // Description: 00045 //////////////////////////////////////////////////////////////////// 00046 TinyOsxGraphicsPipe:: 00047 ~TinyOsxGraphicsPipe() { 00048 } 00049 00050 //////////////////////////////////////////////////////////////////// 00051 // Function: TinyOsxGraphicsPipe::get_interface_name 00052 // Access: Published, Virtual 00053 // Description: Returns the name of the rendering interface 00054 // associated with this GraphicsPipe. This is used to 00055 // present to the user to allow him/her to choose 00056 // between several possible GraphicsPipes available on a 00057 // particular platform, so the name should be meaningful 00058 // and unique for a given platform. 00059 //////////////////////////////////////////////////////////////////// 00060 string TinyOsxGraphicsPipe:: 00061 get_interface_name() const { 00062 return "TinyPanda"; 00063 } 00064 00065 //////////////////////////////////////////////////////////////////// 00066 // Function: TinyOsxGraphicsPipe::pipe_constructor 00067 // Access: Public, Static 00068 // Description: This function is passed to the GraphicsPipeSelection 00069 // object to allow the user to make a default 00070 // TinyOsxGraphicsPipe. 00071 //////////////////////////////////////////////////////////////////// 00072 PT(GraphicsPipe) TinyOsxGraphicsPipe:: 00073 pipe_constructor() { 00074 return new TinyOsxGraphicsPipe; 00075 } 00076 00077 //////////////////////////////////////////////////////////////////// 00078 // Function: TinyOsxGraphicsPipe::create_cg_image 00079 // Access: Public, Static 00080 // Description: Creates a new Quartz bitmap image with the data in 00081 // the indicated PNMImage. The caller should eventually 00082 // free this image via CGImageRelease. 00083 //////////////////////////////////////////////////////////////////// 00084 CGImageRef TinyOsxGraphicsPipe:: 00085 create_cg_image(const PNMImage &pnm_image) { 00086 size_t width = pnm_image.get_x_size(); 00087 size_t height = pnm_image.get_y_size(); 00088 00089 #ifdef PGM_BIGGRAYS 00090 size_t bytes_per_component = 2; 00091 #else 00092 size_t bytes_per_component = 1; 00093 #endif 00094 size_t bits_per_component = bytes_per_component * 8; 00095 size_t num_components = pnm_image.get_num_channels(); 00096 00097 size_t bits_per_pixel = num_components * bits_per_component; 00098 size_t bytes_per_row = num_components * bytes_per_component * width; 00099 00100 size_t num_bytes = bytes_per_row * height; 00101 bool has_alpha; 00102 bool is_grayscale; 00103 00104 CFStringRef color_space_name = NULL; 00105 switch (pnm_image.get_color_type()) { 00106 case PNMImage::CT_grayscale: 00107 color_space_name = kCGColorSpaceGenericGray; 00108 has_alpha = false; 00109 is_grayscale = true; 00110 break; 00111 00112 case PNMImage::CT_two_channel: 00113 color_space_name = kCGColorSpaceGenericGray; 00114 has_alpha = true; 00115 is_grayscale = true; 00116 break; 00117 00118 case PNMImage::CT_color: 00119 color_space_name = kCGColorSpaceGenericRGB; 00120 has_alpha = false; 00121 is_grayscale = false; 00122 break; 00123 00124 case PNMImage::CT_four_channel: 00125 color_space_name = kCGColorSpaceGenericRGB; 00126 has_alpha = true; 00127 is_grayscale = false; 00128 break; 00129 00130 case PNMImage::CT_invalid: 00131 // Shouldn't get here. 00132 nassertr(false, NULL); 00133 break; 00134 } 00135 nassertr(color_space_name != NULL, NULL); 00136 00137 CGColorSpaceRef color_space = CGColorSpaceCreateWithName(color_space_name); 00138 nassertr(color_space != NULL, NULL); 00139 00140 CGBitmapInfo bitmap_info = 0; 00141 #ifdef PGM_BIGGRAYS 00142 bitmap_info |= kCGBitmapByteOrder16Host; 00143 #endif 00144 if (has_alpha) { 00145 bitmap_info |= kCGImageAlphaLast; 00146 } 00147 00148 // Now convert the pixel data to a format friendly to 00149 // CGImageCreate(). 00150 char *char_array = (char *)PANDA_MALLOC_ARRAY(num_bytes); 00151 00152 xelval *dp = (xelval *)char_array; 00153 for (size_t yi = 0; yi < height; ++yi) { 00154 for (size_t xi = 0; xi < width; ++xi) { 00155 if (is_grayscale) { 00156 *dp++ = (xelval)(pnm_image.get_gray(xi, yi) * PGM_MAXMAXVAL); 00157 } else { 00158 *dp++ = (xelval)(pnm_image.get_red(xi, yi) * PGM_MAXMAXVAL); 00159 *dp++ = (xelval)(pnm_image.get_green(xi, yi) * PGM_MAXMAXVAL); 00160 *dp++ = (xelval)(pnm_image.get_blue(xi, yi) * PGM_MAXMAXVAL); 00161 } 00162 if (has_alpha) { 00163 *dp++ = (xelval)(pnm_image.get_alpha(xi, yi) * PGM_MAXMAXVAL); 00164 } 00165 } 00166 } 00167 nassertr((void *)dp == (void *)(char_array + num_bytes), NULL); 00168 00169 CGDataProviderRef provider = 00170 CGDataProviderCreateWithData(NULL, char_array, num_bytes, release_data); 00171 nassertr(provider != NULL, NULL); 00172 00173 CGImageRef image = CGImageCreate 00174 (width, height, bits_per_component, bits_per_pixel, bytes_per_row, 00175 color_space, bitmap_info, provider, 00176 NULL, false, kCGRenderingIntentDefault); 00177 nassertr(image != NULL, NULL); 00178 00179 CGColorSpaceRelease(color_space); 00180 CGDataProviderRelease(provider); 00181 00182 return image; 00183 } 00184 00185 //////////////////////////////////////////////////////////////////// 00186 // Function: TinyOsxGraphicsPipe::release_data 00187 // Access: Private, Static 00188 // Description: This callback is assigned to delete the data array 00189 // allocated within create_cg_image(). 00190 //////////////////////////////////////////////////////////////////// 00191 void TinyOsxGraphicsPipe:: 00192 release_data(void *info, const void *data, size_t size) { 00193 char *char_array = (char *)data; 00194 PANDA_FREE_ARRAY(char_array); 00195 } 00196 00197 //////////////////////////////////////////////////////////////////// 00198 // Function: TinyOsxGraphicsPipe::make_output 00199 // Access: Protected, Virtual 00200 // Description: Creates a new window or buffer on the pipe, if possible. 00201 // This routine is only called from GraphicsEngine::make_output. 00202 //////////////////////////////////////////////////////////////////// 00203 PT(GraphicsOutput) TinyOsxGraphicsPipe:: 00204 make_output(const string &name, 00205 const FrameBufferProperties &fb_prop, 00206 const WindowProperties &win_prop, 00207 int flags, 00208 GraphicsEngine *engine, 00209 GraphicsStateGuardian *gsg, 00210 GraphicsOutput *host, 00211 int retry, 00212 bool &precertify) { 00213 00214 if (!_is_valid) { 00215 return NULL; 00216 } 00217 00218 TinyGraphicsStateGuardian *tinygsg = 0; 00219 if (gsg != 0) { 00220 DCAST_INTO_R(tinygsg, gsg, NULL); 00221 } 00222 00223 // First thing to try: a TinyOsxGraphicsWindow 00224 00225 if (retry == 0) { 00226 if (((flags&BF_require_parasite)!=0)|| 00227 ((flags&BF_refuse_window)!=0)|| 00228 ((flags&BF_resizeable)!=0)|| 00229 ((flags&BF_size_track_host)!=0)|| 00230 ((flags&BF_rtt_cumulative)!=0)|| 00231 ((flags&BF_can_bind_color)!=0)|| 00232 ((flags&BF_can_bind_every)!=0)) { 00233 return NULL; 00234 } 00235 if ((flags & BF_fb_props_optional)==0) { 00236 if ((fb_prop.get_aux_rgba() > 0)|| 00237 (fb_prop.get_aux_hrgba() > 0)|| 00238 (fb_prop.get_aux_float() > 0)) { 00239 return NULL; 00240 } 00241 } 00242 WindowHandle *window_handle = win_prop.get_parent_window(); 00243 if (window_handle != NULL) { 00244 tinydisplay_cat.info() 00245 << "Got parent_window " << *window_handle << "\n"; 00246 #ifdef SUPPORT_SUBPROCESS_WINDOW 00247 WindowHandle::OSHandle *os_handle = window_handle->get_os_handle(); 00248 if (os_handle != NULL && 00249 os_handle->is_of_type(NativeWindowHandle::SubprocessHandle::get_class_type())) { 00250 return new SubprocessWindow(engine, this, name, fb_prop, win_prop, 00251 flags, gsg, host); 00252 } 00253 #endif // SUPPORT_SUBPROCESS_WINDOW 00254 } 00255 return new TinyOsxGraphicsWindow(engine, this, name, fb_prop, win_prop, 00256 flags, gsg, host); 00257 } 00258 00259 // Second thing to try: a TinyGraphicsBuffer 00260 if (retry == 1) { 00261 if (((flags&BF_require_parasite)!=0)|| 00262 ((flags&BF_require_window)!=0)) { 00263 return NULL; 00264 } 00265 return new TinyGraphicsBuffer(engine, this, name, fb_prop, win_prop, flags, gsg, host); 00266 } 00267 00268 // Nothing else left to try. 00269 return NULL; 00270 } 00271 00272 #endif // IS_OSX