Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygens_texstore.c
Go to the documentation of this file.
00001 /* 00002 * Mesa 3-D graphics library 00003 * Version: 6.5.2 00004 * 00005 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 00006 * 00007 * Permission is hereby granted, free of charge, to any person obtaining a 00008 * copy of this software and associated documentation files (the "Software"), 00009 * to deal in the Software without restriction, including without limitation 00010 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 00011 * and/or sell copies of the Software, and to permit persons to whom the 00012 * Software is furnished to do so, subject to the following conditions: 00013 * 00014 * The above copyright notice and this permission notice shall be included 00015 * in all copies or substantial portions of the Software. 00016 * 00017 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00018 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00019 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 00020 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 00021 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 00022 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00023 */ 00024 00025 /* 00026 * Authors: 00027 * Brian Paul 00028 */ 00029 00030 00031 /* 00032 * The functions in this file are mostly related to software texture fallbacks. 00033 * This includes texture image transfer/packing and texel fetching. 00034 * Hardware drivers will likely override most of this. 00035 */ 00036 00037 00038 00039 #include "main/glheader.h" 00040 #include "main/imports.h" 00041 #include "main/colormac.h" 00042 #include "main/context.h" 00043 #include "main/convolve.h" 00044 #include "main/image.h" 00045 #include "main/macros.h" 00046 #include "main/mipmap.h" 00047 #include "main/texformat.h" 00048 #include "main/teximage.h" 00049 #include "main/texstore.h" 00050 00051 #include "s_context.h" 00052 #include "s_depth.h" 00053 #include "s_span.h" 00054 00055 00066 static GLvoid * 00067 read_color_image( GLcontext *ctx, GLint x, GLint y, GLenum type, 00068 GLsizei width, GLsizei height ) 00069 { 00070 SWcontext *swrast = SWRAST_CONTEXT(ctx); 00071 struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; 00072 const GLint pixelSize = _mesa_bytes_per_pixel(GL_RGBA, type); 00073 const GLint stride = width * pixelSize; 00074 GLint row; 00075 GLubyte *image, *dst; 00076 00077 image = (GLubyte *) _mesa_malloc(width * height * pixelSize); 00078 if (!image) 00079 return NULL; 00080 00081 RENDER_START(swrast, ctx); 00082 00083 dst = image; 00084 for (row = 0; row < height; row++) { 00085 _swrast_read_rgba_span(ctx, rb, width, x, y + row, type, dst); 00086 dst += stride; 00087 } 00088 00089 RENDER_FINISH(swrast, ctx); 00090 00091 return image; 00092 } 00093 00094 00099 static GLuint * 00100 read_depth_image( GLcontext *ctx, GLint x, GLint y, 00101 GLsizei width, GLsizei height ) 00102 { 00103 struct gl_renderbuffer *rb = ctx->ReadBuffer->_DepthBuffer; 00104 SWcontext *swrast = SWRAST_CONTEXT(ctx); 00105 GLuint *image, *dst; 00106 GLint i; 00107 00108 image = (GLuint *) _mesa_malloc(width * height * sizeof(GLuint)); 00109 if (!image) 00110 return NULL; 00111 00112 RENDER_START(swrast, ctx); 00113 00114 dst = image; 00115 for (i = 0; i < height; i++) { 00116 _swrast_read_depth_span_uint(ctx, rb, width, x, y + i, dst); 00117 dst += width; 00118 } 00119 00120 RENDER_FINISH(swrast, ctx); 00121 00122 return image; 00123 } 00124 00125 00129 static GLuint * 00130 read_depth_stencil_image(GLcontext *ctx, GLint x, GLint y, 00131 GLsizei width, GLsizei height) 00132 { 00133 struct gl_renderbuffer *depthRb = ctx->ReadBuffer->_DepthBuffer; 00134 struct gl_renderbuffer *stencilRb = ctx->ReadBuffer->_StencilBuffer; 00135 SWcontext *swrast = SWRAST_CONTEXT(ctx); 00136 GLuint *image, *dst; 00137 GLint i; 00138 00139 ASSERT(depthRb); 00140 ASSERT(stencilRb); 00141 00142 image = (GLuint *) _mesa_malloc(width * height * sizeof(GLuint)); 00143 if (!image) 00144 return NULL; 00145 00146 RENDER_START(swrast, ctx); 00147 00148 /* read from depth buffer */ 00149 dst = image; 00150 if (depthRb->DataType == GL_UNSIGNED_INT) { 00151 for (i = 0; i < height; i++) { 00152 _swrast_get_row(ctx, depthRb, width, x, y + i, dst, sizeof(GLuint)); 00153 dst += width; 00154 } 00155 } 00156 else { 00157 GLushort z16[MAX_WIDTH]; 00158 ASSERT(depthRb->DataType == GL_UNSIGNED_SHORT); 00159 for (i = 0; i < height; i++) { 00160 GLint j; 00161 _swrast_get_row(ctx, depthRb, width, x, y + i, z16, sizeof(GLushort)); 00162 /* convert GLushorts to GLuints */ 00163 for (j = 0; j < width; j++) { 00164 dst[j] = z16[j]; 00165 } 00166 dst += width; 00167 } 00168 } 00169 00170 /* put depth values into bits 0xffffff00 */ 00171 if (ctx->ReadBuffer->Visual.depthBits == 24) { 00172 GLint j; 00173 for (j = 0; j < width * height; j++) { 00174 image[j] <<= 8; 00175 } 00176 } 00177 else if (ctx->ReadBuffer->Visual.depthBits == 16) { 00178 GLint j; 00179 for (j = 0; j < width * height; j++) { 00180 image[j] = (image[j] << 16) | (image[j] & 0xff00); 00181 } 00182 } 00183 else { 00184 /* this handles arbitrary depthBits >= 12 */ 00185 const GLint rShift = ctx->ReadBuffer->Visual.depthBits; 00186 const GLint lShift = 32 - rShift; 00187 GLint j; 00188 for (j = 0; j < width * height; j++) { 00189 GLuint z = (image[j] << lShift); 00190 image[j] = z | (z >> rShift); 00191 } 00192 } 00193 00194 /* read stencil values and interleave into image array */ 00195 dst = image; 00196 for (i = 0; i < height; i++) { 00197 GLstencil stencil[MAX_WIDTH]; 00198 GLint j; 00199 ASSERT(8 * sizeof(GLstencil) == stencilRb->StencilBits); 00200 _swrast_get_row(ctx, stencilRb, width, x, y + i, 00201 stencil, sizeof(GLstencil)); 00202 for (j = 0; j < width; j++) { 00203 dst[j] = (dst[j] & 0xffffff00) | (stencil[j] & 0xff); 00204 } 00205 dst += width; 00206 } 00207 00208 RENDER_FINISH(swrast, ctx); 00209 00210 return image; 00211 } 00212 00213 00214 static GLboolean 00215 is_depth_format(GLenum format) 00216 { 00217 switch (format) { 00218 case GL_DEPTH_COMPONENT: 00219 case GL_DEPTH_COMPONENT16: 00220 case GL_DEPTH_COMPONENT24: 00221 case GL_DEPTH_COMPONENT32: 00222 return GL_TRUE; 00223 default: 00224 return GL_FALSE; 00225 } 00226 } 00227 00228 00229 static GLboolean 00230 is_depth_stencil_format(GLenum format) 00231 { 00232 switch (format) { 00233 case GL_DEPTH_STENCIL_EXT: 00234 case GL_DEPTH24_STENCIL8_EXT: 00235 return GL_TRUE; 00236 default: 00237 return GL_FALSE; 00238 } 00239 } 00240 00241 00242 /* 00243 * Fallback for Driver.CopyTexImage1D(). 00244 */ 00245 void 00246 _swrast_copy_teximage1d( GLcontext *ctx, GLenum target, GLint level, 00247 GLenum internalFormat, 00248 GLint x, GLint y, GLsizei width, GLint border ) 00249 { 00250 struct gl_texture_unit *texUnit; 00251 struct gl_texture_object *texObj; 00252 struct gl_texture_image *texImage; 00253 00254 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; 00255 texObj = _mesa_select_tex_object(ctx, texUnit, target); 00256 ASSERT(texObj); 00257 texImage = _mesa_select_tex_image(ctx, texObj, target, level); 00258 ASSERT(texImage); 00259 00260 ASSERT(ctx->Driver.TexImage1D); 00261 00262 if (is_depth_format(internalFormat)) { 00263 /* read depth image from framebuffer */ 00264 GLuint *image = read_depth_image(ctx, x, y, width, 1); 00265 if (!image) { 00266 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage1D"); 00267 return; 00268 } 00269 /* call glTexImage1D to redefine the texture */ 00270 ctx->Driver.TexImage1D(ctx, target, level, internalFormat, 00271 width, border, 00272 GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, image, 00273 &ctx->DefaultPacking, texObj, texImage); 00274 _mesa_free(image); 00275 } 00276 else if (is_depth_stencil_format(internalFormat)) { 00277 /* read depth/stencil image from framebuffer */ 00278 GLuint *image = read_depth_stencil_image(ctx, x, y, width, 1); 00279 if (!image) { 00280 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage1D"); 00281 return; 00282 } 00283 /* call glTexImage1D to redefine the texture */ 00284 ctx->Driver.TexImage1D(ctx, target, level, internalFormat, 00285 width, border, 00286 GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, 00287 image, &ctx->DefaultPacking, texObj, texImage); 00288 _mesa_free(image); 00289 } 00290 else { 00291 /* read RGBA image from framebuffer */ 00292 const GLenum format = GL_RGBA; 00293 const GLenum type = ctx->ReadBuffer->_ColorReadBuffer->DataType; 00294 GLvoid *image = read_color_image(ctx, x, y, type, width, 1); 00295 if (!image) { 00296 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage1D"); 00297 return; 00298 } 00299 /* call glTexImage1D to redefine the texture */ 00300 ctx->Driver.TexImage1D(ctx, target, level, internalFormat, 00301 width, border, format, type, image, 00302 &ctx->DefaultPacking, texObj, texImage); 00303 _mesa_free(image); 00304 } 00305 00306 /* GL_SGIS_generate_mipmap */ 00307 if (level == texObj->BaseLevel && texObj->GenerateMipmap) { 00308 ctx->Driver.GenerateMipmap(ctx, target, texObj); 00309 } 00310 } 00311 00312 00321 void 00322 _swrast_copy_teximage2d( GLcontext *ctx, GLenum target, GLint level, 00323 GLenum internalFormat, 00324 GLint x, GLint y, GLsizei width, GLsizei height, 00325 GLint border ) 00326 { 00327 struct gl_texture_unit *texUnit; 00328 struct gl_texture_object *texObj; 00329 struct gl_texture_image *texImage; 00330 00331 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; 00332 texObj = _mesa_select_tex_object(ctx, texUnit, target); 00333 ASSERT(texObj); 00334 texImage = _mesa_select_tex_image(ctx, texObj, target, level); 00335 ASSERT(texImage); 00336 00337 ASSERT(ctx->Driver.TexImage2D); 00338 00339 if (is_depth_format(internalFormat)) { 00340 /* read depth image from framebuffer */ 00341 GLuint *image = read_depth_image(ctx, x, y, width, height); 00342 if (!image) { 00343 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage2D"); 00344 return; 00345 } 00346 /* call glTexImage2D to redefine the texture */ 00347 ctx->Driver.TexImage2D(ctx, target, level, internalFormat, 00348 width, height, border, 00349 GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, image, 00350 &ctx->DefaultPacking, texObj, texImage); 00351 _mesa_free(image); 00352 } 00353 else if (is_depth_stencil_format(internalFormat)) { 00354 GLuint *image = read_depth_stencil_image(ctx, x, y, width, height); 00355 if (!image) { 00356 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage2D"); 00357 return; 00358 } 00359 /* call glTexImage2D to redefine the texture */ 00360 ctx->Driver.TexImage2D(ctx, target, level, internalFormat, 00361 width, height, border, 00362 GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, 00363 image, &ctx->DefaultPacking, texObj, texImage); 00364 _mesa_free(image); 00365 } 00366 else { 00367 /* read RGBA image from framebuffer */ 00368 const GLenum format = GL_RGBA; 00369 const GLenum type = ctx->ReadBuffer->_ColorReadBuffer->DataType; 00370 GLvoid *image = read_color_image(ctx, x, y, type, width, height); 00371 if (!image) { 00372 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage2D"); 00373 return; 00374 } 00375 /* call glTexImage2D to redefine the texture */ 00376 ctx->Driver.TexImage2D(ctx, target, level, internalFormat, 00377 width, height, border, format, type, image, 00378 &ctx->DefaultPacking, texObj, texImage); 00379 _mesa_free(image); 00380 } 00381 00382 /* GL_SGIS_generate_mipmap */ 00383 if (level == texObj->BaseLevel && texObj->GenerateMipmap) { 00384 ctx->Driver.GenerateMipmap(ctx, target, texObj); 00385 } 00386 } 00387 00388 00389 /* 00390 * Fallback for Driver.CopyTexSubImage1D(). 00391 */ 00392 void 00393 _swrast_copy_texsubimage1d( GLcontext *ctx, GLenum target, GLint level, 00394 GLint xoffset, GLint x, GLint y, GLsizei width ) 00395 { 00396 struct gl_texture_unit *texUnit; 00397 struct gl_texture_object *texObj; 00398 struct gl_texture_image *texImage; 00399 00400 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; 00401 texObj = _mesa_select_tex_object(ctx, texUnit, target); 00402 ASSERT(texObj); 00403 texImage = _mesa_select_tex_image(ctx, texObj, target, level); 00404 ASSERT(texImage); 00405 00406 ASSERT(ctx->Driver.TexImage1D); 00407 00408 if (texImage->_BaseFormat == GL_DEPTH_COMPONENT) { 00409 /* read depth image from framebuffer */ 00410 GLuint *image = read_depth_image(ctx, x, y, width, 1); 00411 if (!image) { 00412 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage1D"); 00413 return; 00414 } 00415 00416 /* call glTexSubImage1D to redefine the texture */ 00417 ctx->Driver.TexSubImage1D(ctx, target, level, xoffset, width, 00418 GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, image, 00419 &ctx->DefaultPacking, texObj, texImage); 00420 _mesa_free(image); 00421 } 00422 else if (texImage->_BaseFormat == GL_DEPTH_STENCIL_EXT) { 00423 /* read depth/stencil image from framebuffer */ 00424 GLuint *image = read_depth_stencil_image(ctx, x, y, width, 1); 00425 if (!image) { 00426 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage1D"); 00427 return; 00428 } 00429 /* call glTexImage1D to redefine the texture */ 00430 ctx->Driver.TexSubImage1D(ctx, target, level, xoffset, width, 00431 GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, 00432 image, &ctx->DefaultPacking, texObj, texImage); 00433 _mesa_free(image); 00434 } 00435 else { 00436 /* read RGBA image from framebuffer */ 00437 const GLenum format = GL_RGBA; 00438 const GLenum type = ctx->ReadBuffer->_ColorReadBuffer->DataType; 00439 GLvoid *image = read_color_image(ctx, x, y, type, width, 1); 00440 if (!image) { 00441 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage1D" ); 00442 return; 00443 } 00444 /* now call glTexSubImage1D to do the real work */ 00445 ctx->Driver.TexSubImage1D(ctx, target, level, xoffset, width, 00446 format, type, image, 00447 &ctx->DefaultPacking, texObj, texImage); 00448 _mesa_free(image); 00449 } 00450 00451 /* GL_SGIS_generate_mipmap */ 00452 if (level == texObj->BaseLevel && texObj->GenerateMipmap) { 00453 ctx->Driver.GenerateMipmap(ctx, target, texObj); 00454 } 00455 } 00456 00457 00464 void 00465 _swrast_copy_texsubimage2d( GLcontext *ctx, 00466 GLenum target, GLint level, 00467 GLint xoffset, GLint yoffset, 00468 GLint x, GLint y, GLsizei width, GLsizei height ) 00469 { 00470 struct gl_texture_unit *texUnit; 00471 struct gl_texture_object *texObj; 00472 struct gl_texture_image *texImage; 00473 00474 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; 00475 texObj = _mesa_select_tex_object(ctx, texUnit, target); 00476 ASSERT(texObj); 00477 texImage = _mesa_select_tex_image(ctx, texObj, target, level); 00478 ASSERT(texImage); 00479 00480 ASSERT(ctx->Driver.TexImage2D); 00481 00482 if (texImage->_BaseFormat == GL_DEPTH_COMPONENT) { 00483 /* read depth image from framebuffer */ 00484 GLuint *image = read_depth_image(ctx, x, y, width, height); 00485 if (!image) { 00486 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage2D"); 00487 return; 00488 } 00489 /* call glTexImage2D to redefine the texture */ 00490 ctx->Driver.TexSubImage2D(ctx, target, level, 00491 xoffset, yoffset, width, height, 00492 GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, image, 00493 &ctx->DefaultPacking, texObj, texImage); 00494 _mesa_free(image); 00495 } 00496 else if (texImage->_BaseFormat == GL_DEPTH_STENCIL_EXT) { 00497 /* read depth/stencil image from framebuffer */ 00498 GLuint *image = read_depth_stencil_image(ctx, x, y, width, height); 00499 if (!image) { 00500 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage2D"); 00501 return; 00502 } 00503 /* call glTexImage2D to redefine the texture */ 00504 ctx->Driver.TexSubImage2D(ctx, target, level, 00505 xoffset, yoffset, width, height, 00506 GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, 00507 image, &ctx->DefaultPacking, texObj, texImage); 00508 _mesa_free(image); 00509 } 00510 else { 00511 /* read RGBA image from framebuffer */ 00512 const GLenum format = GL_RGBA; 00513 const GLenum type = ctx->ReadBuffer->_ColorReadBuffer->DataType; 00514 GLvoid *image = read_color_image(ctx, x, y, type, width, height); 00515 if (!image) { 00516 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage2D" ); 00517 return; 00518 } 00519 /* now call glTexSubImage2D to do the real work */ 00520 ctx->Driver.TexSubImage2D(ctx, target, level, 00521 xoffset, yoffset, width, height, 00522 format, type, image, 00523 &ctx->DefaultPacking, texObj, texImage); 00524 _mesa_free(image); 00525 } 00526 00527 /* GL_SGIS_generate_mipmap */ 00528 if (level == texObj->BaseLevel && texObj->GenerateMipmap) { 00529 ctx->Driver.GenerateMipmap(ctx, target, texObj); 00530 } 00531 } 00532 00533 00534 /* 00535 * Fallback for Driver.CopyTexSubImage3D(). 00536 */ 00537 void 00538 _swrast_copy_texsubimage3d( GLcontext *ctx, 00539 GLenum target, GLint level, 00540 GLint xoffset, GLint yoffset, GLint zoffset, 00541 GLint x, GLint y, GLsizei width, GLsizei height ) 00542 { 00543 struct gl_texture_unit *texUnit; 00544 struct gl_texture_object *texObj; 00545 struct gl_texture_image *texImage; 00546 00547 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; 00548 texObj = _mesa_select_tex_object(ctx, texUnit, target); 00549 ASSERT(texObj); 00550 texImage = _mesa_select_tex_image(ctx, texObj, target, level); 00551 ASSERT(texImage); 00552 00553 ASSERT(ctx->Driver.TexImage3D); 00554 00555 if (texImage->_BaseFormat == GL_DEPTH_COMPONENT) { 00556 /* read depth image from framebuffer */ 00557 GLuint *image = read_depth_image(ctx, x, y, width, height); 00558 if (!image) { 00559 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage3D"); 00560 return; 00561 } 00562 /* call glTexImage3D to redefine the texture */ 00563 ctx->Driver.TexSubImage3D(ctx, target, level, 00564 xoffset, yoffset, zoffset, width, height, 1, 00565 GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, image, 00566 &ctx->DefaultPacking, texObj, texImage); 00567 _mesa_free(image); 00568 } 00569 else if (texImage->_BaseFormat == GL_DEPTH_STENCIL_EXT) { 00570 /* read depth/stencil image from framebuffer */ 00571 GLuint *image = read_depth_stencil_image(ctx, x, y, width, height); 00572 if (!image) { 00573 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage3D"); 00574 return; 00575 } 00576 /* call glTexImage3D to redefine the texture */ 00577 ctx->Driver.TexSubImage3D(ctx, target, level, 00578 xoffset, yoffset, zoffset, width, height, 1, 00579 GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, 00580 image, &ctx->DefaultPacking, texObj, texImage); 00581 _mesa_free(image); 00582 } 00583 else { 00584 /* read RGBA image from framebuffer */ 00585 const GLenum format = GL_RGBA; 00586 const GLenum type = ctx->ReadBuffer->_ColorReadBuffer->DataType; 00587 GLvoid *image = read_color_image(ctx, x, y, type, width, height); 00588 if (!image) { 00589 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage3D" ); 00590 return; 00591 } 00592 /* now call glTexSubImage3D to do the real work */ 00593 ctx->Driver.TexSubImage3D(ctx, target, level, 00594 xoffset, yoffset, zoffset, width, height, 1, 00595 format, type, image, 00596 &ctx->DefaultPacking, texObj, texImage); 00597 _mesa_free(image); 00598 } 00599 00600 /* GL_SGIS_generate_mipmap */ 00601 if (level == texObj->BaseLevel && texObj->GenerateMipmap) { 00602 ctx->Driver.GenerateMipmap(ctx, target, texObj); 00603 } 00604 } Generated on Sun May 27 2012 04:20:45 for ReactOS by
1.7.6.1
|