|
1 /*------------------------------------------------------------------------ |
|
2 * |
|
3 * VGU library for OpenVG 1.1 Reference Implementation |
|
4 * --------------------------------------------------- |
|
5 * |
|
6 * Copyright (c) 2007 The Khronos Group Inc. |
|
7 * Portions copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
8 * |
|
9 * Permission is hereby granted, free of charge, to any person obtaining a |
|
10 * copy of this software and /or associated documentation files |
|
11 * (the "Materials "), to deal in the Materials without restriction, |
|
12 * including without limitation the rights to use, copy, modify, merge, |
|
13 * publish, distribute, sublicense, and/or sell copies of the Materials, |
|
14 * and to permit persons to whom the Materials are furnished to do so, |
|
15 * subject to the following conditions: |
|
16 * |
|
17 * The above copyright notice and this permission notice shall be included |
|
18 * in all copies or substantial portions of the Materials. |
|
19 * |
|
20 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
|
23 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
|
24 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
25 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR |
|
26 * THE USE OR OTHER DEALINGS IN THE MATERIALS. |
|
27 * |
|
28 *//** |
|
29 * \file |
|
30 * \brief Implementation of the VGU utility library for OpenVG |
|
31 *//*-------------------------------------------------------------------*/ |
|
32 |
|
33 #include "vgu.h" |
|
34 #include "openvg.h" |
|
35 #include "riMath.h" |
|
36 |
|
37 using namespace OpenVGRI; |
|
38 |
|
39 /*-------------------------------------------------------------------*//*! |
|
40 * \brief |
|
41 * \param |
|
42 * \return |
|
43 * \note |
|
44 *//*-------------------------------------------------------------------*/ |
|
45 |
|
46 static void append(VGPath path, int numSegments, const VGubyte* segments, int numCoordinates, const VGfloat* coordinates) |
|
47 { |
|
48 RI_ASSERT(numCoordinates <= 26); |
|
49 |
|
50 VGPathDatatype datatype = (VGPathDatatype)vgGetParameteri(path, VG_PATH_DATATYPE); |
|
51 VGfloat scale = vgGetParameterf(path, VG_PATH_SCALE); |
|
52 VGfloat bias = vgGetParameterf(path, VG_PATH_BIAS); |
|
53 |
|
54 switch(datatype) |
|
55 { |
|
56 case VG_PATH_DATATYPE_S_8: |
|
57 { |
|
58 RIint8 data[26]; |
|
59 for(int i=0;i<numCoordinates;i++) |
|
60 data[i] = (RIint8)floor((coordinates[i] - bias) / scale + 0.5f); //add 0.5 for correct rounding |
|
61 vgAppendPathData(path, numSegments, segments, data); |
|
62 break; |
|
63 } |
|
64 |
|
65 case VG_PATH_DATATYPE_S_16: |
|
66 { |
|
67 RIint16 data[26]; |
|
68 for(int i=0;i<numCoordinates;i++) |
|
69 data[i] = (RIint16)floor((coordinates[i] - bias) / scale + 0.5f); //add 0.5 for correct rounding |
|
70 vgAppendPathData(path, numSegments, segments, data); |
|
71 break; |
|
72 } |
|
73 |
|
74 case VG_PATH_DATATYPE_S_32: |
|
75 { |
|
76 RIint32 data[26]; |
|
77 for(int i=0;i<numCoordinates;i++) |
|
78 data[i] = (RIint32)floor((coordinates[i] - bias) / scale + 0.5f); //add 0.5 for correct rounding |
|
79 vgAppendPathData(path, numSegments, segments, data); |
|
80 break; |
|
81 } |
|
82 |
|
83 default: |
|
84 { |
|
85 RI_ASSERT(datatype == VG_PATH_DATATYPE_F); |
|
86 RIfloat32 data[26]; |
|
87 for(int i=0;i<numCoordinates;i++) |
|
88 data[i] = (RIfloat32)((coordinates[i] - bias) / scale); |
|
89 vgAppendPathData(path, numSegments, segments, data); |
|
90 break; |
|
91 } |
|
92 } |
|
93 } |
|
94 |
|
95 /*-------------------------------------------------------------------*//*! |
|
96 * \brief |
|
97 * \param |
|
98 * \return |
|
99 * \note |
|
100 *//*-------------------------------------------------------------------*/ |
|
101 |
|
102 VGUErrorCode RI_APIENTRY vguLine(VGPath path, VGfloat x0, VGfloat y0, VGfloat x1, VGfloat y1) |
|
103 { |
|
104 VGErrorCode error = vgGetError(); //clear the error state |
|
105 static const VGubyte segments[2] = {VG_MOVE_TO | VG_ABSOLUTE, VG_LINE_TO | VG_ABSOLUTE}; |
|
106 const VGfloat data[4] = {x0, y0, x1, y1}; |
|
107 append(path, 2, segments, 4, data); |
|
108 |
|
109 error = vgGetError(); |
|
110 if(error == VG_BAD_HANDLE_ERROR) |
|
111 return VGU_BAD_HANDLE_ERROR; |
|
112 else if(error == VG_PATH_CAPABILITY_ERROR) |
|
113 return VGU_PATH_CAPABILITY_ERROR; |
|
114 return VGU_NO_ERROR; |
|
115 } |
|
116 |
|
117 /*-------------------------------------------------------------------*//*! |
|
118 * \brief |
|
119 * \param |
|
120 * \return |
|
121 * \note |
|
122 *//*-------------------------------------------------------------------*/ |
|
123 |
|
124 VGUErrorCode RI_APIENTRY vguPolygon(VGPath path, const VGfloat * points, VGint count, VGboolean closed) |
|
125 { |
|
126 VGErrorCode error = vgGetError(); //clear the error state |
|
127 if(!points || (((RIuintptr)points) & 3) || count <= 0) |
|
128 return VGU_ILLEGAL_ARGUMENT_ERROR; |
|
129 |
|
130 VGubyte segments[1] = {VG_MOVE_TO | VG_ABSOLUTE}; |
|
131 VGfloat data[2]; |
|
132 for(int i=0;i<count;i++) |
|
133 { |
|
134 data[0] = points[i*2+0]; |
|
135 data[1] = points[i*2+1]; |
|
136 append(path, 1, segments, 2, data); |
|
137 segments[0] = VG_LINE_TO | VG_ABSOLUTE; |
|
138 } |
|
139 if(closed) |
|
140 { |
|
141 segments[0] = VG_CLOSE_PATH; |
|
142 append(path, 1, segments, 0, data); |
|
143 } |
|
144 |
|
145 error = vgGetError(); |
|
146 if(error == VG_BAD_HANDLE_ERROR) |
|
147 return VGU_BAD_HANDLE_ERROR; |
|
148 else if(error == VG_PATH_CAPABILITY_ERROR) |
|
149 return VGU_PATH_CAPABILITY_ERROR; |
|
150 return VGU_NO_ERROR; |
|
151 } |
|
152 |
|
153 /*-------------------------------------------------------------------*//*! |
|
154 * \brief |
|
155 * \param |
|
156 * \return |
|
157 * \note |
|
158 *//*-------------------------------------------------------------------*/ |
|
159 |
|
160 VGUErrorCode RI_APIENTRY vguRect(VGPath path, VGfloat x, VGfloat y, VGfloat width, VGfloat height) |
|
161 { |
|
162 VGErrorCode error = vgGetError(); //clear the error state |
|
163 if(width <= 0 || height <= 0) |
|
164 return VGU_ILLEGAL_ARGUMENT_ERROR; |
|
165 |
|
166 static const VGubyte segments[5] = {VG_MOVE_TO | VG_ABSOLUTE, |
|
167 VG_HLINE_TO | VG_ABSOLUTE, |
|
168 VG_VLINE_TO | VG_ABSOLUTE, |
|
169 VG_HLINE_TO | VG_ABSOLUTE, |
|
170 VG_CLOSE_PATH}; |
|
171 const VGfloat data[5] = {x, y, x + width, y + height, x}; |
|
172 append(path, 5, segments, 5, data); |
|
173 |
|
174 error = vgGetError(); |
|
175 if(error == VG_BAD_HANDLE_ERROR) |
|
176 return VGU_BAD_HANDLE_ERROR; |
|
177 else if(error == VG_PATH_CAPABILITY_ERROR) |
|
178 return VGU_PATH_CAPABILITY_ERROR; |
|
179 return VGU_NO_ERROR; |
|
180 } |
|
181 |
|
182 /*-------------------------------------------------------------------*//*! |
|
183 * \brief |
|
184 * \param |
|
185 * \return |
|
186 * \note |
|
187 *//*-------------------------------------------------------------------*/ |
|
188 |
|
189 VGUErrorCode RI_APIENTRY vguRoundRect(VGPath path, VGfloat x, VGfloat y, VGfloat width, VGfloat height, VGfloat arcWidth, VGfloat arcHeight) |
|
190 { |
|
191 VGErrorCode error = vgGetError(); //clear the error state |
|
192 if(width <= 0 || height <= 0) |
|
193 return VGU_ILLEGAL_ARGUMENT_ERROR; |
|
194 |
|
195 arcWidth = RI_CLAMP(arcWidth, 0.0f, width); |
|
196 arcHeight = RI_CLAMP(arcHeight, 0.0f, height); |
|
197 |
|
198 static const VGubyte segments[10] = {VG_MOVE_TO | VG_ABSOLUTE, |
|
199 VG_HLINE_TO | VG_ABSOLUTE, |
|
200 VG_SCCWARC_TO | VG_ABSOLUTE, |
|
201 VG_VLINE_TO | VG_ABSOLUTE, |
|
202 VG_SCCWARC_TO | VG_ABSOLUTE, |
|
203 VG_HLINE_TO | VG_ABSOLUTE, |
|
204 VG_SCCWARC_TO | VG_ABSOLUTE, |
|
205 VG_VLINE_TO | VG_ABSOLUTE, |
|
206 VG_SCCWARC_TO | VG_ABSOLUTE, |
|
207 VG_CLOSE_PATH}; |
|
208 const VGfloat data[26] = {x + arcWidth/2, y, |
|
209 x + width - arcWidth/2, |
|
210 arcWidth/2, arcHeight/2, 0, x + width, y + arcHeight/2, |
|
211 y + height - arcHeight/2, |
|
212 arcWidth/2, arcHeight/2, 0, x + width - arcWidth/2, y + height, |
|
213 x + arcWidth/2, |
|
214 arcWidth/2, arcHeight/2, 0, x, y + height - arcHeight/2, |
|
215 y + arcHeight/2, |
|
216 arcWidth/2, arcHeight/2, 0, x + arcWidth/2, y}; |
|
217 append(path, 10, segments, 26, data); |
|
218 |
|
219 error = vgGetError(); |
|
220 if(error == VG_BAD_HANDLE_ERROR) |
|
221 return VGU_BAD_HANDLE_ERROR; |
|
222 else if(error == VG_PATH_CAPABILITY_ERROR) |
|
223 return VGU_PATH_CAPABILITY_ERROR; |
|
224 return VGU_NO_ERROR; |
|
225 } |
|
226 |
|
227 /*-------------------------------------------------------------------*//*! |
|
228 * \brief |
|
229 * \param |
|
230 * \return |
|
231 * \note |
|
232 *//*-------------------------------------------------------------------*/ |
|
233 |
|
234 VGUErrorCode RI_APIENTRY vguEllipse(VGPath path, VGfloat cx, VGfloat cy, VGfloat width, VGfloat height) |
|
235 { |
|
236 VGErrorCode error = vgGetError(); //clear the error state |
|
237 if(width <= 0 || height <= 0) |
|
238 return VGU_ILLEGAL_ARGUMENT_ERROR; |
|
239 |
|
240 static const VGubyte segments[4] = {VG_MOVE_TO | VG_ABSOLUTE, |
|
241 VG_SCCWARC_TO | VG_ABSOLUTE, |
|
242 VG_SCCWARC_TO | VG_ABSOLUTE, |
|
243 VG_CLOSE_PATH}; |
|
244 const VGfloat data[12] = {cx + width/2, cy, |
|
245 width/2, height/2, 0, cx - width/2, cy, |
|
246 width/2, height/2, 0, cx + width/2, cy}; |
|
247 append(path, 4, segments, 12, data); |
|
248 |
|
249 error = vgGetError(); |
|
250 if(error == VG_BAD_HANDLE_ERROR) |
|
251 return VGU_BAD_HANDLE_ERROR; |
|
252 else if(error == VG_PATH_CAPABILITY_ERROR) |
|
253 return VGU_PATH_CAPABILITY_ERROR; |
|
254 return VGU_NO_ERROR; |
|
255 } |
|
256 |
|
257 /*-------------------------------------------------------------------*//*! |
|
258 * \brief |
|
259 * \param |
|
260 * \return |
|
261 * \note |
|
262 *//*-------------------------------------------------------------------*/ |
|
263 |
|
264 VGUErrorCode RI_APIENTRY vguArc(VGPath path, VGfloat x, VGfloat y, VGfloat width, VGfloat height, VGfloat startAngle, VGfloat angleExtent, VGUArcType arcType) |
|
265 { |
|
266 VGErrorCode error = vgGetError(); //clear the error state |
|
267 if((arcType != VGU_ARC_OPEN && arcType != VGU_ARC_CHORD && arcType != VGU_ARC_PIE) || width <= 0.0f || height <= 0.0f) |
|
268 return VGU_ILLEGAL_ARGUMENT_ERROR; |
|
269 |
|
270 startAngle = RI_DEG_TO_RAD(startAngle); |
|
271 angleExtent = RI_DEG_TO_RAD(angleExtent); |
|
272 |
|
273 VGfloat w = width/2.0f; |
|
274 VGfloat h = height/2.0f; |
|
275 |
|
276 VGubyte segments[1]; |
|
277 VGfloat data[5]; |
|
278 |
|
279 segments[0] = VG_MOVE_TO | VG_ABSOLUTE; |
|
280 data[0] = x + w * (VGfloat)cos(startAngle); |
|
281 data[1] = y + h * (VGfloat)sin(startAngle); |
|
282 append(path, 1, segments, 2, data); |
|
283 |
|
284 data[0] = w; |
|
285 data[1] = h; |
|
286 data[2] = 0.0f; |
|
287 VGfloat endAngle = startAngle + angleExtent; |
|
288 if(angleExtent >= 0.0f) |
|
289 { |
|
290 segments[0] = VG_SCCWARC_TO | VG_ABSOLUTE; |
|
291 for(VGfloat a = startAngle + RI_PI;a < endAngle; a += RI_PI) |
|
292 { |
|
293 if ((a + RI_PI) == a) |
|
294 return VGU_ILLEGAL_ARGUMENT_ERROR; |
|
295 |
|
296 data[3] = x + w * (VGfloat)cos(a); |
|
297 data[4] = y + h * (VGfloat)sin(a); |
|
298 append(path, 1, segments, 5, data); |
|
299 } |
|
300 } |
|
301 else |
|
302 { |
|
303 segments[0] = VG_SCWARC_TO | VG_ABSOLUTE; |
|
304 for(VGfloat a = startAngle - RI_PI;a > endAngle; a -= RI_PI) |
|
305 { |
|
306 if ((a - RI_PI) == a) |
|
307 return VGU_ILLEGAL_ARGUMENT_ERROR; |
|
308 |
|
309 data[3] = x + w * (VGfloat)cos(a); |
|
310 data[4] = y + h * (VGfloat)sin(a); |
|
311 append(path, 1, segments, 5, data); |
|
312 } |
|
313 } |
|
314 data[3] = x + w * (VGfloat)cos(endAngle); |
|
315 data[4] = y + h * (VGfloat)sin(endAngle); |
|
316 append(path, 1, segments, 5, data); |
|
317 |
|
318 if(arcType == VGU_ARC_CHORD) |
|
319 { |
|
320 segments[0] = VG_CLOSE_PATH; |
|
321 append(path, 1, segments, 0, data); |
|
322 } |
|
323 else if(arcType == VGU_ARC_PIE) |
|
324 { |
|
325 segments[0] = VG_LINE_TO | VG_ABSOLUTE; |
|
326 data[0] = x; |
|
327 data[1] = y; |
|
328 append(path, 1, segments, 2, data); |
|
329 segments[0] = VG_CLOSE_PATH; |
|
330 append(path, 1, segments, 0, data); |
|
331 } |
|
332 |
|
333 error = vgGetError(); |
|
334 if(error == VG_BAD_HANDLE_ERROR) |
|
335 return VGU_BAD_HANDLE_ERROR; |
|
336 else if(error == VG_PATH_CAPABILITY_ERROR) |
|
337 return VGU_PATH_CAPABILITY_ERROR; |
|
338 return VGU_NO_ERROR; |
|
339 } |
|
340 |
|
341 /*-------------------------------------------------------------------*//*! |
|
342 * \brief |
|
343 * \param |
|
344 * \return |
|
345 * \note |
|
346 *//*-------------------------------------------------------------------*/ |
|
347 |
|
348 VGUErrorCode RI_APIENTRY vguComputeWarpQuadToSquare(VGfloat sx0, VGfloat sy0, VGfloat sx1, VGfloat sy1, VGfloat sx2, VGfloat sy2, VGfloat sx3, VGfloat sy3, VGfloat * matrix) |
|
349 { |
|
350 if(!matrix || ((RIuintptr)matrix) & 3) |
|
351 return VGU_ILLEGAL_ARGUMENT_ERROR; |
|
352 |
|
353 VGfloat mat[9]; |
|
354 VGUErrorCode ret = vguComputeWarpSquareToQuad(sx0, sy0, sx1, sy1, sx2, sy2, sx3, sy3, mat); |
|
355 if(ret == VGU_BAD_WARP_ERROR) |
|
356 return VGU_BAD_WARP_ERROR; |
|
357 Matrix3x3 m(mat[0], mat[3], mat[6], |
|
358 mat[1], mat[4], mat[7], |
|
359 mat[2], mat[5], mat[8]); |
|
360 bool nonsingular = m.invert(); |
|
361 if(!nonsingular) |
|
362 return VGU_BAD_WARP_ERROR; |
|
363 matrix[0] = m[0][0]; |
|
364 matrix[1] = m[1][0]; |
|
365 matrix[2] = m[2][0]; |
|
366 matrix[3] = m[0][1]; |
|
367 matrix[4] = m[1][1]; |
|
368 matrix[5] = m[2][1]; |
|
369 matrix[6] = m[0][2]; |
|
370 matrix[7] = m[1][2]; |
|
371 matrix[8] = m[2][2]; |
|
372 return VGU_NO_ERROR; |
|
373 } |
|
374 |
|
375 /*-------------------------------------------------------------------*//*! |
|
376 * \brief |
|
377 * \param |
|
378 * \return |
|
379 * \note |
|
380 *//*-------------------------------------------------------------------*/ |
|
381 |
|
382 VGUErrorCode RI_APIENTRY vguComputeWarpSquareToQuad(VGfloat dx0, VGfloat dy0, VGfloat dx1, VGfloat dy1, VGfloat dx2, VGfloat dy2, VGfloat dx3, VGfloat dy3, VGfloat * matrix) |
|
383 { |
|
384 if(!matrix || ((RIuintptr)matrix) & 3) |
|
385 return VGU_ILLEGAL_ARGUMENT_ERROR; |
|
386 |
|
387 //from Heckbert:Fundamentals of Texture Mapping and Image Warping |
|
388 //Note that his mapping of vertices is different from OpenVG's |
|
389 //(0,0) => (dx0,dy0) |
|
390 //(1,0) => (dx1,dy1) |
|
391 //(0,1) => (dx2,dy2) |
|
392 //(1,1) => (dx3,dy3) |
|
393 |
|
394 VGfloat diffx1 = dx1 - dx3; |
|
395 VGfloat diffy1 = dy1 - dy3; |
|
396 VGfloat diffx2 = dx2 - dx3; |
|
397 VGfloat diffy2 = dy2 - dy3; |
|
398 |
|
399 VGfloat det = diffx1*diffy2 - diffx2*diffy1; |
|
400 if(det == 0.0f) |
|
401 return VGU_BAD_WARP_ERROR; |
|
402 |
|
403 VGfloat sumx = dx0 - dx1 + dx3 - dx2; |
|
404 VGfloat sumy = dy0 - dy1 + dy3 - dy2; |
|
405 |
|
406 if(sumx == 0.0f && sumy == 0.0f) |
|
407 { //affine mapping |
|
408 matrix[0] = dx1 - dx0; |
|
409 matrix[1] = dy1 - dy0; |
|
410 matrix[2] = 0.0f; |
|
411 matrix[3] = dx3 - dx1; |
|
412 matrix[4] = dy3 - dy1; |
|
413 matrix[5] = 0.0f; |
|
414 matrix[6] = dx0; |
|
415 matrix[7] = dy0; |
|
416 matrix[8] = 1.0f; |
|
417 return VGU_NO_ERROR; |
|
418 } |
|
419 |
|
420 VGfloat oodet = 1.0f / det; |
|
421 VGfloat g = (sumx*diffy2 - diffx2*sumy) * oodet; |
|
422 VGfloat h = (diffx1*sumy - sumx*diffy1) * oodet; |
|
423 |
|
424 matrix[0] = dx1-dx0+g*dx1; |
|
425 matrix[1] = dy1-dy0+g*dy1; |
|
426 matrix[2] = g; |
|
427 matrix[3] = dx2-dx0+h*dx2; |
|
428 matrix[4] = dy2-dy0+h*dy2; |
|
429 matrix[5] = h; |
|
430 matrix[6] = dx0; |
|
431 matrix[7] = dy0; |
|
432 matrix[8] = 1.0f; |
|
433 return VGU_NO_ERROR; |
|
434 } |
|
435 |
|
436 /*-------------------------------------------------------------------*//*! |
|
437 * \brief |
|
438 * \param |
|
439 * \return |
|
440 * \note |
|
441 *//*-------------------------------------------------------------------*/ |
|
442 |
|
443 VGUErrorCode RI_APIENTRY vguComputeWarpQuadToQuad(VGfloat dx0, VGfloat dy0, VGfloat dx1, VGfloat dy1, VGfloat dx2, VGfloat dy2, VGfloat dx3, VGfloat dy3, VGfloat sx0, VGfloat sy0, VGfloat sx1, VGfloat sy1, VGfloat sx2, VGfloat sy2, VGfloat sx3, VGfloat sy3, VGfloat * matrix) |
|
444 { |
|
445 if(!matrix || ((RIuintptr)matrix) & 3) |
|
446 return VGU_ILLEGAL_ARGUMENT_ERROR; |
|
447 |
|
448 VGfloat qtos[9]; |
|
449 VGUErrorCode ret1 = vguComputeWarpQuadToSquare(sx0, sy0, sx1, sy1, sx2, sy2, sx3, sy3, qtos); |
|
450 if(ret1 == VGU_BAD_WARP_ERROR) |
|
451 return VGU_BAD_WARP_ERROR; |
|
452 |
|
453 VGfloat stoq[9]; |
|
454 VGUErrorCode ret2 = vguComputeWarpSquareToQuad(dx0, dy0, dx1, dy1, dx2, dy2, dx3, dy3, stoq); |
|
455 if(ret2 == VGU_BAD_WARP_ERROR) |
|
456 return VGU_BAD_WARP_ERROR; |
|
457 |
|
458 Matrix3x3 m1(qtos[0], qtos[3], qtos[6], |
|
459 qtos[1], qtos[4], qtos[7], |
|
460 qtos[2], qtos[5], qtos[8]); |
|
461 Matrix3x3 m2(stoq[0], stoq[3], stoq[6], |
|
462 stoq[1], stoq[4], stoq[7], |
|
463 stoq[2], stoq[5], stoq[8]); |
|
464 Matrix3x3 r = m2 * m1; |
|
465 |
|
466 matrix[0] = r[0][0]; |
|
467 matrix[1] = r[1][0]; |
|
468 matrix[2] = r[2][0]; |
|
469 matrix[3] = r[0][1]; |
|
470 matrix[4] = r[1][1]; |
|
471 matrix[5] = r[2][1]; |
|
472 matrix[6] = r[0][2]; |
|
473 matrix[7] = r[1][2]; |
|
474 matrix[8] = r[2][2]; |
|
475 return VGU_NO_ERROR; |
|
476 } |