1 /* $NoKeywords: $ */
2 /*
3 //
4 // Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved.
5 // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
6 // McNeel & Associates.
7 //
8 // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
9 // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
10 // MERCHANTABILITY ARE HEREBY DISCLAIMED.
11 //
12 // For complete openNURBS copyright information see <http://www.opennurbs.org>.
13 //
14 ////////////////////////////////////////////////////////////////
15 */
16 
17 ////////////////////////////////////////////////////////////////
18 //
19 //   defines ON_TextureMapping
20 //
21 ////////////////////////////////////////////////////////////////
22 
23 #if !defined(OPENNURBS_TEXTURE_MAPPING_INC_)
24 #define OPENNURBS_TEXTURE_MAPPING_INC_
25 
26 ///////////////////////////////////////////////////////////////////////////////
27 //
28 // Class ON_TextureMapping
29 //
30 class ON_Line;
31 class ON_BrepFace;
32 class ON_3dPoint;
33 
34 typedef int  ( *TEXMAP_INTERSECT_LINE_SURFACE )( const ON_Line*, const ON_BrepFace*, ON_SimpleArray<ON_X_EVENT>& );
35 typedef bool ( *TEXMAP_BREP_FACE_CLOSEST_POINT )( const ON_BrepFace*, const ON_3dPoint*, ON_3dPoint& );
36 
37 class ON_CLASS ON_TextureMapping : public ON_Object
38 {
39 public:
40 	ON_OBJECT_DECLARE(ON_TextureMapping);
41 
42 	ON_TextureMapping();
43 	~ON_TextureMapping();
44 
45 	// The copy constructor and operator= overrides are needed
46   // to ensure m_geometry is properly copied.
47 	ON_TextureMapping(const ON_TextureMapping& src);
48 	ON_TextureMapping& operator=(const ON_TextureMapping& src);
49 
50   // overrides virtual ON_Object::IsValid
51   ON_BOOL32 IsValid( ON_TextLog* text_log = NULL ) const;
52 
53   // overrides virtual ON_Object::Dump
54   void Dump( ON_TextLog& ) const;
55 
56   // overrides virtual ON_Object::SizeOf
57   unsigned int SizeOf() const;
58 
59   // overrides virtual ON_Object::Write
60   ON_BOOL32 Write(
61          ON_BinaryArchive& binary_archive
62        ) const;
63 
64   // overrides virtual ON_Object::Read
65   ON_BOOL32 Read(
66          ON_BinaryArchive& binary_archive
67        );
68 
69   void Default();
70 
71   virtual
72   ON_UUID ModelObjectId() const;
73 
74 	/*
75 	Determines whether the mapping, as currently set up, requires vertex normals to be present on the
76 	mesh in order to evaluate the mapping correctly.
77 		*/
78 	bool RequiresVertexNormals() const;
79 	bool IsPeriodic(void) const;
80 
81   /*
82   Description:
83 	  Create a mapping that will convert surface parameters into
84     normalized (0,1)x(0,1) texture coordinates.
85 	*/
86 	bool SetSurfaceParameterMapping(void);
87 
88   /*
89   Description:
90     Create a planar projection texture mapping.
91   Parameters:
92     plane - [in]
93     dx - [in]  portion of the plane's x axis that is mapped to [0,1]
94                (can be a decreasing interval)
95     dy - [in]  portion of the plane's x axis that is mapped to [0,1]
96                (can be a decreasing interval)
97     dz - [in]  portion of the plane's x axis that is mapped to [0,1]
98                (can be a decreasing interval)
99     projection_method - [in]
100         1: Closest point mapping.
101           A target point P is mapped to the point on the plane
102           that is closest to P.  The target normal is ignored.
103         2: Target line mapping.  A target point-vector pair
104           (P, N), are mapped to the point on the plane
105           where the line through P, parallel to N, intersects
106           the plane.  If the line is parallel to the plane,
107           the closest point mapping is used.
108   Example:
109     Create a mapping that maps the world axis aligned rectangle in
110     the world yz plane with corners at (0,3,5) and (0,7,19) to the
111     texture coordinate unit square.
112 
113           ON_3dVector plane_xaxis(0.0,1.0,0.0);
114           ON_3dVector plane_yaxis(0.0,0,0,1.0);
115           ON_3dPoint plane_origin(0.0,2.0,4.0);
116           ON_Plane plane(plane_origin,plane_xaxis,plane_yaxis);
117           ON_Interval dx( 0.0, 7.0 - 3.0);
118           ON_Interval dy( 0.0, 19.0 - 5.0);
119           ON_Interval dz( 0.0, 1.0 );
120           ON_TextureMapping mapping;
121           mapping.CreatePlaneMapping(plane,dx,dy,dz);
122 
123   Returns:
124     True if input is valid.
125   */
126   bool SetPlaneMapping(
127             const ON_Plane& plane,
128             const ON_Interval& dx,
129             const ON_Interval& dy,
130             const ON_Interval& dz
131             );
132 
133   /*
134   Description:
135     Create a cylindrical projection texture mapping.
136   Parameters:
137     cylinder - [in]
138         cylinder in world space used to define a cylindrical
139         coordinate system.  The angular parameter maps (0,2pi)
140         to texture "u" (0,1), The height parameter maps
141         (height[0],height[1]) to texture "v" (0,1), and
142         the radial parameter maps (0,r) to texture "w" (0,1).
143     bIsCapped - [in]
144         If true, the cylinder is treated as a finite
145         capped cylinder.
146   Returns:
147     True if input is valid.
148   Remarks:
149     When the cylinder is capped and m_texture_space = divided,
150     the cylinder is mapped to texture space as follows:
151       The side is mapped to 0 <= "u" <= 2/3.
152       The bottom is mapped to 2/3 <= "u" <= 5/6.
153       The top is mapped to 5/6 <= "u" <= 5/6.
154     This is the same convention box mapping uses.
155   */
156 	bool SetCylinderMapping(
157 		 const ON_Cylinder& cylinder,
158 		 bool bIsCapped
159 	);
160 
161   /*
162   Description:
163     Create a spherical projection texture mapping.
164   Parameters:
165     sphere - [in]
166         sphere in world space used to define a spherical
167         coordinate system. The longitude parameter maps
168         (0,2pi) to texture "u" (0,1).  The latitude paramter
169         maps (-pi/2,+pi/2) to texture "v" (0,1).
170         The radial parameter maps (0,r) to texture "w" (0,1).
171   Returns:
172     True if input is valid.
173   */
174 	bool SetSphereMapping(
175 		 const ON_Sphere& sphere
176 	);
177 
178   /*
179   Description:
180     Create a box projection texture mapping.
181   Parameters:
182     plane - [in]
183         The sides of the box the box are parallel to the
184         plane's coordinate planes.  The dx, dy, dz intervals
185         determine the location of the sides.
186     dx - [in]
187        Determines the location of the front and back planes.
188        The vector plane.xaxis is perpendicular to these planes
189        and they pass through plane.PointAt(dx[0],0,0) and
190        plane.PointAt(dx[1],0,0), respectivly.
191     dy - [in]
192        Determines the location of the left and right planes.
193        The vector plane.yaxis is perpendicular to these planes
194        and they pass through plane.PointAt(0,dy[0],0) and
195        plane.PointAt(0,dy[1],0), respectivly.
196     dz - [in]
197        Determines the location of the top and bottom planes.
198        The vector plane.zaxis is perpendicular to these planes
199        and they pass through plane.PointAt(0,0,dz[0]) and
200        plane.PointAt(0,0,dz[1]), respectivly.
201     bIsCapped - [in]
202         If true, the box is treated as a finite
203         capped box.
204   Returns:
205     True if input is valid.
206   Remarks:
207     When m_texture_space = divided, the box is mapped to texture
208     space as follows:
209 
210     If the box is not capped, then each side maps to 1/4 of the texture map.
211 
212           v=1+---------+---------+---------+---------+
213              | x=dx[1] | y=dy[1] | x=dx[0] | y=dy[0] |
214              | Front   | Right   | Back    | Left    |
215              | --y->   | <-x--   | <-y--   | --x->   |
216           v=0+---------+---------+---------+---------+
217             0/4 <=u<= 1/4 <=u<= 2/4 <=u<= 3/4 <=u<= 4/4
218 
219     If the box is capped, then each side and cap gets 1/6 of the texture map.
220 
221           v=1+---------+---------+---------+---------+---------+---------+
222              | x=dx[1] | y=dy[1] | x=dx[0] | y=dy[0] | z=dx[1] | z=dz[0] |
223              | Front   | Right   | Back    | Left    | Top     |  Bottom |
224              | --y->   | <-x--   | <-y--   | --x->   | --x->   | --x->   |
225           v=0+---------+---------+---------+---------+---------+---------+
226             0/6 <=u<= 1/6 <=u<= 2/6 <=u<= 3/6 <=u<= 4/6 <=u<= 5/6 <=u<= 6/6
227   */
228 	bool SetBoxMapping(
229 		 const ON_Plane& plane,
230 		 ON_Interval dx,
231 		 ON_Interval dy,
232 		 ON_Interval dz,
233      bool bIsCapped
234 	);
235 
236 	/*
237   Description:
238     Get plane mapping parameters from this texture mapping.
239   Parameters:
240     plane - [out]
241     dx - [out]
242       Portion of the plane's x axis that is mapped to [0,1]
243     dy - [out]
244       Portion of the plane's y axis that is mapped to [0,1]
245     dz - [out]
246       Portion of the plane's z axis that is mapped to [0,1]
247   Returns:
248 	  True if valid plane mapping parameters were returned.
249   Remarks:
250     NOTE WELL:
251       Generally, GetMappingPlane will not return the same
252       parameters passed to SetPlaneMapping.  However, the
253       location of the plane will be the same.
254 	*/
255 	bool GetMappingPlane(
256 		 ON_Plane& plane,
257 		 ON_Interval& dx,
258 		 ON_Interval& dy,
259 		 ON_Interval& dz
260 	   ) const;
261 
262 	/*
263   Description:
264 	  Get a cylindrical projection parameters from this texture mapping.
265 	Parameters:
266 	  cylinder - [out]
267   Returns:
268 	  True if a valid cylinder is returned.
269   Remarks:
270     Generally, GetMappingCylinder will not return the same
271     parameters passed to SetCylinderMapping.  However, the
272     location of the cylinder will be the same.
273     If this mapping is not cylindrical, the cylinder will
274     approximate the actual mapping primitive.
275 	*/
276 	bool GetMappingCylinder(
277 		 ON_Cylinder& cylinder
278 	) const;
279 
280 	/*
281   Description:
282 	  Get a spherical projection parameters from this texture mapping.
283 	Parameters:
284 	  sphere - [out]
285   Returns:
286 	  True if a valid sphere is returned.
287   Remarks:
288     Generally, GetMappingShere will not return the same
289     parameters passed to SetSphereMapping.  However, the
290     location of the sphere will be the same.
291     If this mapping is not cylindrical, the cylinder will
292     approximate the actual mapping primitive.
293 	*/
294 	bool GetMappingSphere(
295 		 ON_Sphere& sphere
296 	) const;
297 
298 	/*
299 	Get a box projection from the texture mapping.
300 	Parameters:
301 	plane - [out]
302 		The center of the box is at plane.origin and the sides
303 		of the box are parallel to the plane's coordinate planes.
304 	dx - [out]
305 	   The "front" and "back" sides of the box are in spanned
306 	   by the vectors plane.yaxis and plane.zaxis.  The back
307 	   plane contains the point plane.PointAt(dx[0],0,0) and
308 	   the front plane contains the point plane.PointAt(dx[1],0,0).
309 	dy - [out]
310 	   The "left" and "right" sides of the box are in spanned
311 	   by the vectors plane.zaxis and plane.xaxis.  The left
312 	   plane contains the point plane.PointAt(0,dx[0],0) and
313 	   the back plane contains the point plane.PointAt(0,dy[1],0).
314 	dz - [out]
315 	   The "top" and "bottom" sides of the box are in spanned
316 	   by the vectors plane.xaxis and plane.yaxis.  The bottom
317 	   plane contains the point plane.PointAt(0,0,dz[0]) and
318 	   the top plane contains the point plane.PointAt(0,0,dz[1]).
319   Returns:
320 	  True if a valid box is returned.
321   Remarks:
322     Generally, GetMappingBox will not return the same
323     parameters passed to SetBoxMapping.  However, the
324     location of the box will be the same.
325 	*/
326 	bool GetMappingBox(
327 		 ON_Plane& plane,
328 		 ON_Interval& dx,
329 		 ON_Interval& dy,
330 		 ON_Interval& dz
331 	) const;
332 
333 
334   /*
335   Description:
336     Reverses the texture in the specified direction.
337   Parameters:
338     dir - [in] 0 = reverse "u", 1 = reverse "v", 2 = reverse "w".
339   Remarks:
340     Modies m_uvw so that the spedified direction transforms
341     the texture coordinate t to 1-t.
342   Returns:
343     True if input is valid.
344   */
345   bool ReverseTextureCoordinate( int dir );
346 
347   /*
348   Description:
349     Swaps the specified texture coordinates.
350   Parameters:
351     i - [in]
352     j - [in]
353   Remarks:
354     Modifies m_uvw so that the specified texture coordinates are swapped.
355   Returns:
356     True if input is valid.
357   */
358   bool SwapTextureCoordinate( int i, int j );
359 
360   /*
361   Description:
362     Tiles the specified texture coordinates.
363   Parameters:
364     dir - [in] 0 =  "u", 1 = "v", 2 = "w".
365     count - [in] number of tiles
366     offset - [in] offset of the tile
367   Remarks:
368     Modies m_uvw so that the specified texture coordinate is
369     tiled.
370   Returns:
371     True if input is valid.
372   */
373   bool TileTextureCoordinate( int dir, double count, double offset );
374 
375   /*
376   Description:
377     Evaluate the mapping to get a texture coordinate.
378   Parameters:
379     P - [in] Vertex location
380     N - [in] If the mapping projection is ray_projection,
381              then this is the vertex unit normal.  Otherwise
382              N is ignored.
383     T - [out] Texture coordinate (u,v,w)
384 
385     P_xform -[in]
386       Transformation to be applied to P before performing
387       the mapping calculation.
388     N_xform - [in]
389       Transformation to be applied to N before performing
390       the mapping calculation.  One way to calculate N_xform
391       is to use the call P_xform::GetVectorTransform(N_xform).
392 
393   Returns:
394     Nonzero if evaluation is successful.  When the mapping
395     is a box or capped cylinder mapping, the value indicates
396     which side was evaluated.
397 
398       Cylinder mapping:
399         1 = cylinder wall, 2 = bottom cap, 3 = top cap
400       Box mapping:
401         1 = front
402         2 = right
403         3 = back
404         4 = left
405         5 = bottom
406         6 = top
407 
408   See Also:
409     ON_TextureMapping::GetTextureCoordinates
410     ON_Mesh::SetTextureCoordinates
411   */
412   virtual
413   int Evaluate(
414     const ON_3dPoint& P,
415     const ON_3dVector& N,
416     ON_3dPoint* T
417     ) const;
418 
419   virtual
420   int Evaluate(
421     const ON_3dPoint& P,
422     const ON_3dVector& N,
423     ON_3dPoint* T,
424 	  const ON_Xform& P_xform,
425     const ON_Xform& N_xform
426     ) const;
427 
428   int EvaluatePlaneMapping(
429     const ON_3dPoint& P,
430     const ON_3dVector& N,
431     ON_3dPoint* T
432     ) const;
433 
434   int EvaluateSphereMapping(
435     const ON_3dPoint& P,
436     const ON_3dVector& N,
437     ON_3dPoint* T
438     ) const;
439 
440   int EvaluateCylinderMapping(
441     const ON_3dPoint& P,
442     const ON_3dVector& N,
443     ON_3dPoint* T
444     ) const;
445 
446   int EvaluateBoxMapping(
447     const ON_3dPoint& P,
448     const ON_3dVector& N,
449     ON_3dPoint* T
450     ) const;
451 
452   /*
453   Description:
454     Quickly check to see if a mesh or tag has texture coordinates
455     set by this mapping.
456   Parameters:
457     mesh - [in]
458     tag - [in]
459     object_xform - [in] (optional)
460       If this transform is not NULL, then true will be
461       returned only if the mapping function is the same and
462       the tag's m_mesh_xform field is the same as mesh_xform.
463       This parameter is typically NULL or the value of
464       ON_MappingRef::m_object_xform.
465   Returns:
466     True if the meshes texture coordinates were set by this
467     mapping.
468   */
469   bool HasMatchingTextureCoordinates(
470          const ON_Mesh& mesh,
471          const ON_Xform* object_xform = 0
472          ) const;
473   bool HasMatchingTextureCoordinates(
474          const class ON_MappingTag& tag,
475          const ON_Xform* object_xform = 0
476          ) const;
477 
478   /*
479   Description:
480     Get texture coordinates.  This calculation is
481     expensive.  When possible, use a MappingMatch()
482     query to avoid unnecessary calculations.
483   Parameters:
484     mesh - [in]
485     T - [out] Texture coordinates returned here.
486     mesh_xform - [in] (optional)
487       If the mesh has been transformed since the texture mapping was set
488       up, pass the transformation here.  Typically this is the value
489       of ON_Mesh::m_mapping_xform or ON_MappingRef::m_object_xform
490     bLazy - [in]
491       If true and the mesh.m_T[] values were calculated using
492       this mapping, they are simply copied to the T[] array
493       and no calculations are performed.  If you are calling
494       the 3d point version and you care about the z-coordinate,
495       then do not use the lazy option (meshes only store
496       2d texture coordinates).
497     Tside - [out]
498       In the case of divided textures, side information is returned
499       here if a lazy mapping is not done.  Otherwise Tside->Count()
500       will be zero.
501       Cylinder mapping:
502         1 = cylinder wall, 2 = bottom cap, 3 = top cap
503       Box mapping:
504         1 = front
505         2 = right
506         3 = back
507         4 = left
508         5 = bottom
509         6 = top
510   Example:
511 
512           ON_TextureMapping mapping = ...;
513           const ON_Mesh* mesh = ...;
514           bool bLazy = true;
515           ON_SimpleArray<ON_3dPoint> T(mesh->VertexCount());
516           T.SetCount(mesh->m_VertexCount());
517           if ( !mapping.GetTextureCoordinates(mesh,3,3,&T[0].x,bLazy) )
518             T.SetCount(0).
519 
520   Returns:
521     True if successful.
522   */
523   bool GetTextureCoordinates(
524     const ON_Mesh& mesh,
525     ON_SimpleArray<ON_3fPoint>& T,
526 		const ON_Xform* mesh_xform = 0,
527     bool bLazy = false,
528     ON_SimpleArray<int>* Tside = 0
529     ) const;
530 
531   bool GetTextureCoordinates(
532     const ON_Mesh& mesh,
533     ON_SimpleArray<ON_2fPoint>& T,
534 		const ON_Xform* mesh_xform = 0,
535     bool bLazy = false,
536     ON_SimpleArray<int>* Tside = 0
537     ) const;
538 
539 public:
540   // The only reliable and persistent way to reference texture
541   // mappings is by the mapping_id.  If the mapping id is
542   // set to m_srfp_mapping_id, then all other mapping settings
543   // are ignored.
544   ON_UUID m_mapping_id;
545 
546   // Runtime texture mapping table index.
547   // This value is NOT SAVED IN 3DM FILES.
548   // This value is constant for each runtime instance of Rhino,
549   // but can change each time a model is loaded or saved.
550   // Once a texture mapping is in the CRhinoDoc material table,
551   // its id and index never change in that instance of Rhino.
552   int m_mapping_index;
553 
554   // The texture mapping name is for UI and user comfort.
555   // Duplicates are permitted.
556   ON_wString m_mapping_name;
557 
558   //////////////////////////////////////////////////////////
559   //
560   // Mapping types:
561   //
562   //   You can either calculate texture coordinates based on
563   //   the parameterization of the surface used to create a mesh,
564   //   or project the natural parameterization from a mapping
565   //   primitive, like a plane, sphere, box, or cylinder.
566   //
567 	// Do not change TYPE enum values - they are saved in 3dm files.
568   //
569   enum TYPE
570   {
571     no_mapping       = 0,
572 
573     srfp_mapping     = 1, // u,v = linear transform of surface params,w = 0
574     plane_mapping    = 2, // u,v,w = 3d coordinates wrt frame
575     cylinder_mapping = 3, // u,v,w = logitude, height, radius
576     sphere_mapping   = 4, // (u,v,w) = longitude,latitude,radius
577     box_mapping      = 5,
578     mesh_mapping_primitive = 6, // m_mapping_primitive is an ON_Mesh
579     srf_mapping_primitive  = 7, // m_mapping_primitive is an ON_Surface
580     brep_mapping_primitive = 8, // m_mapping_primitive is an ON_Brep
581 
582     force_32bit_mapping_type = 0xFFFFFFFF
583   };
584 
585 	TYPE m_type;
586 
587   //////////////////////////////////////////////////////////
588   //
589   // Projection:
590   //
591   //   When a mapping primitive, like a plane, sphere, box,
592   //   or cylinder, is used, there are two projection options.
593   //
594   //  clspt_projection: world xyz maps to the point on the
595   //                    mapping primitive that is closest to xyz.
596   //                    In this case, ON_TextureMapping::Evaluate
597   //                    ignores the vector argument.
598   //
599   //  ray_projection:   world xyz + world vector defines a world line.
600   //                    The world line is intersected with the mapping
601   //                    primitive and the intersection point that is
602   //                    closest to the world xyz point is used to
603   //                    calculate the mapping parameters.
604   //
605   //  The value of m_projection can be changed as needed.
606   //
607   //  If m_type = srfp_mapping, then m_projection is ignored.
608   //
609   enum PROJECTION
610   {
611     no_projection    = 0,
612     clspt_projection = 1,
613     ray_projection   = 2,
614     force_32bit_mapping_projection = 0xFFFFFFFF
615   };
616 
617   PROJECTION m_projection;
618 
619   //////////////////////////////////////////////////////////
620   //
621   // Texture space
622   //
623   //   When a mapping primitive is a box or a capped cylinder,
624   //   there are two options for the mapping.  Either the sides
625   //   all map to (0,1)x(0,1) (so the either texture map appears
626   //   on each side, or the sides map to distinct regions of the
627   //   texture space.
628   //
629   enum TEXTURE_SPACE
630   {
631     single  = 0, // sides and caps map to same texture space
632     divided = 1, // sides and caps map to distinct vertical
633                  // regions of texture space.
634                  // (0, 1/4, 2/4, 3/4, 1) for uncapped boxes.
635                  // (0, 1/6, 2/6, 3/6, 4/6, 5/6, 1) for capped boxes.
636                  // (0, 4/6, 5/6, 1) for capped cylinders.
637     force_32bit_texture_space = 0xFFFFFFFF
638   };
639 
640   TEXTURE_SPACE m_texture_space;
641 
642   // The m_bCapped applies to planar, cylinder and box mappings.
643   // If m_bCapped is false, the cylinder or box is "infinite", if m_bCapped is true, they are finite.
644   // In planar mappings, m_bCapped=false means "the Z texture coordinate will always be 0.0"
645   // this is now the default behaviour in Rhino 5.0 - it's what users expect apparently.
646   bool m_bCapped;
647 
648   //////////////////////////////////////////////////////////
649   //
650   // For primitive based mappings, these transformations are
651   // used to map the world coordinate (x,y,z) point P and
652   // surface normal N before it is projected to the normalized
653   // mapping primitive. The surface normal transformation,
654   // m_Nxyz, is always calculated from m_Pxyz.  It is a
655   // runtime setting that is not saved in 3dm files.
656   // If m_type is srfp_mapping, then m_Pxyz and m_Nxyz are
657   // ignored.
658   ON_Xform m_Pxyz;
659   ON_Xform m_Nxyz;
660 
661   // Transform applied to mapping coordinate (u,v,w) to
662   // convert it into a texture coordinate.
663   ON_Xform m_uvw;
664 
665   // Custom mapping primitive.
666   ON_Object* m_mapping_primitive;
667 
668   static TYPE TypeFromInt( int i );
669   static PROJECTION ProjectionFromInt( int i );
670   static TEXTURE_SPACE TextureSpaceFromInt( int i);
671 
672   ON__UINT32 MappingCRC() const;
673 };
674 
675 #if defined(ON_DLL_TEMPLATE)
676 // This stuff is here because of a limitation in the way Microsoft
677 // handles templates and DLLs.  See Microsoft's knowledge base
678 // article ID Q168958 for details.
679 #pragma warning( push )
680 #pragma warning( disable : 4231 )
681 ON_DLL_TEMPLATE template class ON_CLASS ON_ClassArray<ON_TextureMapping>;
682 ON_DLL_TEMPLATE template class ON_CLASS ON_ObjectArray<ON_TextureMapping>;
683 #pragma warning( pop )
684 #endif
685 
686 
687 #endif
688 
689