Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendrawprim.c
Go to the documentation of this file.
00001 /* 00002 * WINED3D draw functions 00003 * 00004 * Copyright 2002-2004 Jason Edmeades 00005 * Copyright 2002-2004 Raphael Junqueira 00006 * Copyright 2004 Christian Costa 00007 * Copyright 2005 Oliver Stieber 00008 * Copyright 2006, 2008 Henri Verbeet 00009 * Copyright 2007-2008 Stefan Dösinger for CodeWeavers 00010 * Copyright 2009 Henri Verbeet for CodeWeavers 00011 * 00012 * This library is free software; you can redistribute it and/or 00013 * modify it under the terms of the GNU Lesser General Public 00014 * License as published by the Free Software Foundation; either 00015 * version 2.1 of the License, or (at your option) any later version. 00016 * 00017 * This library is distributed in the hope that it will be useful, 00018 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00020 * Lesser General Public License for more details. 00021 * 00022 * You should have received a copy of the GNU Lesser General Public 00023 * License along with this library; if not, write to the Free Software 00024 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00025 */ 00026 00027 #include "config.h" 00028 #include "wined3d_private.h" 00029 00030 WINE_DEFAULT_DEBUG_CHANNEL(d3d_draw); 00031 00032 #include <stdio.h> 00033 #include <math.h> 00034 00035 /* GL locking is done by the caller */ 00036 static void drawStridedFast(const struct wined3d_gl_info *gl_info, GLenum primitive_type, UINT count, UINT idx_size, 00037 const void *idx_data, UINT start_idx, INT base_vertex_index) 00038 { 00039 if (idx_size) 00040 { 00041 GLenum idxtype = idx_size == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT; 00042 if (gl_info->supported[ARB_DRAW_ELEMENTS_BASE_VERTEX]) 00043 { 00044 GL_EXTCALL(glDrawElementsBaseVertex(primitive_type, count, idxtype, 00045 (const char *)idx_data + (idx_size * start_idx), base_vertex_index)); 00046 checkGLcall("glDrawElementsBaseVertex"); 00047 } 00048 else 00049 { 00050 glDrawElements(primitive_type, count, 00051 idxtype, (const char *)idx_data + (idx_size * start_idx)); 00052 checkGLcall("glDrawElements"); 00053 } 00054 } 00055 else 00056 { 00057 glDrawArrays(primitive_type, start_idx, count); 00058 checkGLcall("glDrawArrays"); 00059 } 00060 } 00061 00062 /* 00063 * Actually draw using the supplied information. 00064 * Slower GL version which extracts info about each vertex in turn 00065 */ 00066 00067 /* GL locking is done by the caller */ 00068 static void drawStridedSlow(const struct wined3d_device *device, const struct wined3d_context *context, 00069 const struct wined3d_stream_info *si, UINT NumVertexes, GLenum glPrimType, 00070 const void *idxData, UINT idxSize, UINT startIdx) 00071 { 00072 unsigned int textureNo = 0; 00073 const WORD *pIdxBufS = NULL; 00074 const DWORD *pIdxBufL = NULL; 00075 UINT vx_index; 00076 const struct wined3d_state *state = &device->stateBlock->state; 00077 LONG SkipnStrides = startIdx; 00078 BOOL pixelShader = use_ps(state); 00079 BOOL specular_fog = FALSE; 00080 const BYTE *texCoords[WINED3DDP_MAXTEXCOORD]; 00081 const BYTE *diffuse = NULL, *specular = NULL, *normal = NULL, *position = NULL; 00082 const struct wined3d_gl_info *gl_info = context->gl_info; 00083 UINT texture_stages = gl_info->limits.texture_stages; 00084 const struct wined3d_stream_info_element *element; 00085 UINT num_untracked_materials; 00086 DWORD tex_mask = 0; 00087 00088 TRACE("Using slow vertex array code\n"); 00089 00090 /* Variable Initialization */ 00091 if (idxSize) 00092 { 00093 /* Immediate mode drawing can't make use of indices in a vbo - get the 00094 * data from the index buffer. If the index buffer has no vbo (not 00095 * supported or other reason), or with user pointer drawing idxData 00096 * will be non-NULL. */ 00097 if (!idxData) 00098 idxData = buffer_get_sysmem(state->index_buffer, gl_info); 00099 00100 if (idxSize == 2) pIdxBufS = idxData; 00101 else pIdxBufL = idxData; 00102 } else if (idxData) { 00103 ERR("non-NULL idxData with 0 idxSize, this should never happen\n"); 00104 return; 00105 } 00106 00107 /* Start drawing in GL */ 00108 glBegin(glPrimType); 00109 00110 if (si->use_map & (1 << WINED3D_FFP_POSITION)) 00111 { 00112 element = &si->elements[WINED3D_FFP_POSITION]; 00113 position = element->data.addr; 00114 } 00115 00116 if (si->use_map & (1 << WINED3D_FFP_NORMAL)) 00117 { 00118 element = &si->elements[WINED3D_FFP_NORMAL]; 00119 normal = element->data.addr; 00120 } 00121 else 00122 { 00123 glNormal3f(0, 0, 0); 00124 } 00125 00126 num_untracked_materials = context->num_untracked_materials; 00127 if (si->use_map & (1 << WINED3D_FFP_DIFFUSE)) 00128 { 00129 element = &si->elements[WINED3D_FFP_DIFFUSE]; 00130 diffuse = element->data.addr; 00131 00132 if (num_untracked_materials && element->format->id != WINED3DFMT_B8G8R8A8_UNORM) 00133 FIXME("Implement diffuse color tracking from %s\n", debug_d3dformat(element->format->id)); 00134 } 00135 else 00136 { 00137 glColor4f(1.0f, 1.0f, 1.0f, 1.0f); 00138 } 00139 00140 if (si->use_map & (1 << WINED3D_FFP_SPECULAR)) 00141 { 00142 element = &si->elements[WINED3D_FFP_SPECULAR]; 00143 specular = element->data.addr; 00144 00145 /* special case where the fog density is stored in the specular alpha channel */ 00146 if (state->render_states[WINED3D_RS_FOGENABLE] 00147 && (state->render_states[WINED3D_RS_FOGVERTEXMODE] == WINED3D_FOG_NONE 00148 || si->elements[WINED3D_FFP_POSITION].format->id == WINED3DFMT_R32G32B32A32_FLOAT) 00149 && state->render_states[WINED3D_RS_FOGTABLEMODE] == WINED3D_FOG_NONE) 00150 { 00151 if (gl_info->supported[EXT_FOG_COORD]) 00152 { 00153 if (element->format->id == WINED3DFMT_B8G8R8A8_UNORM) specular_fog = TRUE; 00154 else FIXME("Implement fog coordinates from %s\n", debug_d3dformat(element->format->id)); 00155 } 00156 else 00157 { 00158 static BOOL warned; 00159 00160 if (!warned) 00161 { 00162 /* TODO: Use the fog table code from old ddraw */ 00163 FIXME("Implement fog for transformed vertices in software\n"); 00164 warned = TRUE; 00165 } 00166 } 00167 } 00168 } 00169 else if (gl_info->supported[EXT_SECONDARY_COLOR]) 00170 { 00171 GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0); 00172 } 00173 00174 for (textureNo = 0; textureNo < texture_stages; ++textureNo) 00175 { 00176 int coordIdx = state->texture_states[textureNo][WINED3D_TSS_TEXCOORD_INDEX]; 00177 DWORD texture_idx = device->texUnitMap[textureNo]; 00178 00179 if (!gl_info->supported[ARB_MULTITEXTURE] && textureNo > 0) 00180 { 00181 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n"); 00182 continue; 00183 } 00184 00185 if (!pixelShader && !state->textures[textureNo]) continue; 00186 00187 if (texture_idx == WINED3D_UNMAPPED_STAGE) continue; 00188 00189 if (coordIdx > 7) 00190 { 00191 TRACE("tex: %d - Skip tex coords, as being system generated\n", textureNo); 00192 continue; 00193 } 00194 else if (coordIdx < 0) 00195 { 00196 FIXME("tex: %d - Coord index %d is less than zero, expect a crash.\n", textureNo, coordIdx); 00197 continue; 00198 } 00199 00200 if (si->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + coordIdx))) 00201 { 00202 element = &si->elements[WINED3D_FFP_TEXCOORD0 + coordIdx]; 00203 texCoords[coordIdx] = element->data.addr; 00204 tex_mask |= (1 << textureNo); 00205 } 00206 else 00207 { 00208 TRACE("tex: %d - Skipping tex coords, as no data supplied\n", textureNo); 00209 if (gl_info->supported[ARB_MULTITEXTURE]) 00210 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + texture_idx, 0, 0, 0, 1)); 00211 else 00212 glTexCoord4f(0, 0, 0, 1); 00213 } 00214 } 00215 00216 /* We shouldn't start this function if any VBO is involved. Should I put a safety check here? 00217 * Guess it's not necessary(we crash then anyway) and would only eat CPU time 00218 */ 00219 00220 /* For each primitive */ 00221 for (vx_index = 0; vx_index < NumVertexes; ++vx_index) { 00222 UINT texture, tmp_tex_mask; 00223 /* Blending data and Point sizes are not supported by this function. They are not supported by the fixed 00224 * function pipeline at all. A Fixme for them is printed after decoding the vertex declaration 00225 */ 00226 00227 /* For indexed data, we need to go a few more strides in */ 00228 if (idxData) 00229 { 00230 /* Indexed so work out the number of strides to skip */ 00231 if (idxSize == 2) 00232 SkipnStrides = pIdxBufS[startIdx + vx_index] + state->base_vertex_index; 00233 else 00234 SkipnStrides = pIdxBufL[startIdx + vx_index] + state->base_vertex_index; 00235 } 00236 00237 tmp_tex_mask = tex_mask; 00238 for (texture = 0; tmp_tex_mask; tmp_tex_mask >>= 1, ++texture) 00239 { 00240 int coord_idx; 00241 const void *ptr; 00242 DWORD texture_idx; 00243 00244 if (!(tmp_tex_mask & 1)) continue; 00245 00246 coord_idx = state->texture_states[texture][WINED3D_TSS_TEXCOORD_INDEX]; 00247 ptr = texCoords[coord_idx] + (SkipnStrides * si->elements[WINED3D_FFP_TEXCOORD0 + coord_idx].stride); 00248 00249 texture_idx = device->texUnitMap[texture]; 00250 multi_texcoord_funcs[si->elements[WINED3D_FFP_TEXCOORD0 + coord_idx].format->emit_idx]( 00251 GL_TEXTURE0_ARB + texture_idx, ptr); 00252 } 00253 00254 /* Diffuse -------------------------------- */ 00255 if (diffuse) { 00256 const void *ptrToCoords = diffuse + SkipnStrides * si->elements[WINED3D_FFP_DIFFUSE].stride; 00257 00258 diffuse_funcs[si->elements[WINED3D_FFP_DIFFUSE].format->emit_idx](ptrToCoords); 00259 if (num_untracked_materials) 00260 { 00261 DWORD diffuseColor = ((const DWORD *)ptrToCoords)[0]; 00262 unsigned char i; 00263 float color[4]; 00264 00265 color[0] = D3DCOLOR_B_R(diffuseColor) / 255.0f; 00266 color[1] = D3DCOLOR_B_G(diffuseColor) / 255.0f; 00267 color[2] = D3DCOLOR_B_B(diffuseColor) / 255.0f; 00268 color[3] = D3DCOLOR_B_A(diffuseColor) / 255.0f; 00269 00270 for (i = 0; i < num_untracked_materials; ++i) 00271 { 00272 glMaterialfv(GL_FRONT_AND_BACK, context->untracked_materials[i], color); 00273 } 00274 } 00275 } 00276 00277 /* Specular ------------------------------- */ 00278 if (specular) { 00279 const void *ptrToCoords = specular + SkipnStrides * si->elements[WINED3D_FFP_SPECULAR].stride; 00280 00281 specular_funcs[si->elements[WINED3D_FFP_SPECULAR].format->emit_idx](ptrToCoords); 00282 00283 if (specular_fog) 00284 { 00285 DWORD specularColor = *(const DWORD *)ptrToCoords; 00286 GL_EXTCALL(glFogCoordfEXT((float) (specularColor >> 24))); 00287 } 00288 } 00289 00290 /* Normal -------------------------------- */ 00291 if (normal) 00292 { 00293 const void *ptrToCoords = normal + SkipnStrides * si->elements[WINED3D_FFP_NORMAL].stride; 00294 normal_funcs[si->elements[WINED3D_FFP_NORMAL].format->emit_idx](ptrToCoords); 00295 } 00296 00297 /* Position -------------------------------- */ 00298 if (position) { 00299 const void *ptrToCoords = position + SkipnStrides * si->elements[WINED3D_FFP_POSITION].stride; 00300 position_funcs[si->elements[WINED3D_FFP_POSITION].format->emit_idx](ptrToCoords); 00301 } 00302 00303 /* For non indexed mode, step onto next parts */ 00304 if (!idxData) ++SkipnStrides; 00305 } 00306 00307 glEnd(); 00308 checkGLcall("glEnd and previous calls"); 00309 } 00310 00311 /* GL locking is done by the caller */ 00312 static inline void send_attribute(const struct wined3d_gl_info *gl_info, 00313 enum wined3d_format_id format, const UINT index, const void *ptr) 00314 { 00315 switch(format) 00316 { 00317 case WINED3DFMT_R32_FLOAT: 00318 GL_EXTCALL(glVertexAttrib1fvARB(index, ptr)); 00319 break; 00320 case WINED3DFMT_R32G32_FLOAT: 00321 GL_EXTCALL(glVertexAttrib2fvARB(index, ptr)); 00322 break; 00323 case WINED3DFMT_R32G32B32_FLOAT: 00324 GL_EXTCALL(glVertexAttrib3fvARB(index, ptr)); 00325 break; 00326 case WINED3DFMT_R32G32B32A32_FLOAT: 00327 GL_EXTCALL(glVertexAttrib4fvARB(index, ptr)); 00328 break; 00329 00330 case WINED3DFMT_R8G8B8A8_UINT: 00331 GL_EXTCALL(glVertexAttrib4ubvARB(index, ptr)); 00332 break; 00333 case WINED3DFMT_B8G8R8A8_UNORM: 00334 if (gl_info->supported[ARB_VERTEX_ARRAY_BGRA]) 00335 { 00336 const DWORD *src = ptr; 00337 DWORD c = *src & 0xff00ff00; 00338 c |= (*src & 0xff0000) >> 16; 00339 c |= (*src & 0xff) << 16; 00340 GL_EXTCALL(glVertexAttrib4NubvARB(index, (GLubyte *)&c)); 00341 break; 00342 } 00343 /* else fallthrough */ 00344 case WINED3DFMT_R8G8B8A8_UNORM: 00345 GL_EXTCALL(glVertexAttrib4NubvARB(index, ptr)); 00346 break; 00347 00348 case WINED3DFMT_R16G16_SINT: 00349 GL_EXTCALL(glVertexAttrib4svARB(index, ptr)); 00350 break; 00351 case WINED3DFMT_R16G16B16A16_SINT: 00352 GL_EXTCALL(glVertexAttrib4svARB(index, ptr)); 00353 break; 00354 00355 case WINED3DFMT_R16G16_SNORM: 00356 { 00357 GLshort s[4] = {((const GLshort *)ptr)[0], ((const GLshort *)ptr)[1], 0, 1}; 00358 GL_EXTCALL(glVertexAttrib4NsvARB(index, s)); 00359 break; 00360 } 00361 case WINED3DFMT_R16G16_UNORM: 00362 { 00363 GLushort s[4] = {((const GLushort *)ptr)[0], ((const GLushort *)ptr)[1], 0, 1}; 00364 GL_EXTCALL(glVertexAttrib4NusvARB(index, s)); 00365 break; 00366 } 00367 case WINED3DFMT_R16G16B16A16_SNORM: 00368 GL_EXTCALL(glVertexAttrib4NsvARB(index, ptr)); 00369 break; 00370 case WINED3DFMT_R16G16B16A16_UNORM: 00371 GL_EXTCALL(glVertexAttrib4NusvARB(index, ptr)); 00372 break; 00373 00374 case WINED3DFMT_R10G10B10A2_UINT: 00375 FIXME("Unsure about WINED3DDECLTYPE_UDEC3\n"); 00376 /*glVertexAttrib3usvARB(instancedData[j], (GLushort *) ptr); Does not exist */ 00377 break; 00378 case WINED3DFMT_R10G10B10A2_SNORM: 00379 FIXME("Unsure about WINED3DDECLTYPE_DEC3N\n"); 00380 /*glVertexAttrib3NusvARB(instancedData[j], (GLushort *) ptr); Does not exist */ 00381 break; 00382 00383 case WINED3DFMT_R16G16_FLOAT: 00384 /* Are those 16 bit floats. C doesn't have a 16 bit float type. I could read the single bits and calculate a 4 00385 * byte float according to the IEEE standard 00386 */ 00387 if (gl_info->supported[NV_HALF_FLOAT] && gl_info->supported[NV_VERTEX_PROGRAM]) 00388 { 00389 /* Not supported by GL_ARB_half_float_vertex */ 00390 GL_EXTCALL(glVertexAttrib2hvNV(index, ptr)); 00391 } 00392 else 00393 { 00394 float x = float_16_to_32(((const unsigned short *)ptr) + 0); 00395 float y = float_16_to_32(((const unsigned short *)ptr) + 1); 00396 GL_EXTCALL(glVertexAttrib2fARB(index, x, y)); 00397 } 00398 break; 00399 case WINED3DFMT_R16G16B16A16_FLOAT: 00400 if (gl_info->supported[NV_HALF_FLOAT] && gl_info->supported[NV_VERTEX_PROGRAM]) 00401 { 00402 /* Not supported by GL_ARB_half_float_vertex */ 00403 GL_EXTCALL(glVertexAttrib4hvNV(index, ptr)); 00404 } 00405 else 00406 { 00407 float x = float_16_to_32(((const unsigned short *)ptr) + 0); 00408 float y = float_16_to_32(((const unsigned short *)ptr) + 1); 00409 float z = float_16_to_32(((const unsigned short *)ptr) + 2); 00410 float w = float_16_to_32(((const unsigned short *)ptr) + 3); 00411 GL_EXTCALL(glVertexAttrib4fARB(index, x, y, z, w)); 00412 } 00413 break; 00414 00415 default: 00416 ERR("Unexpected attribute format: %s\n", debug_d3dformat(format)); 00417 break; 00418 } 00419 } 00420 00421 /* GL locking is done by the caller */ 00422 static void drawStridedSlowVs(const struct wined3d_gl_info *gl_info, const struct wined3d_state *state, 00423 const struct wined3d_stream_info *si, UINT numberOfVertices, GLenum glPrimitiveType, 00424 const void *idxData, UINT idxSize, UINT startIdx) 00425 { 00426 LONG SkipnStrides = startIdx + state->load_base_vertex_index; 00427 const DWORD *pIdxBufL = NULL; 00428 const WORD *pIdxBufS = NULL; 00429 UINT vx_index; 00430 int i; 00431 const BYTE *ptr; 00432 00433 if (idxSize) 00434 { 00435 /* Immediate mode drawing can't make use of indices in a vbo - get the 00436 * data from the index buffer. If the index buffer has no vbo (not 00437 * supported or other reason), or with user pointer drawing idxData 00438 * will be non-NULL. */ 00439 if (!idxData) 00440 idxData = buffer_get_sysmem(state->index_buffer, gl_info); 00441 00442 if (idxSize == 2) pIdxBufS = idxData; 00443 else pIdxBufL = idxData; 00444 } else if (idxData) { 00445 ERR("non-NULL idxData with 0 idxSize, this should never happen\n"); 00446 return; 00447 } 00448 00449 /* Start drawing in GL */ 00450 glBegin(glPrimitiveType); 00451 00452 for (vx_index = 0; vx_index < numberOfVertices; ++vx_index) 00453 { 00454 if (idxData) 00455 { 00456 /* Indexed so work out the number of strides to skip */ 00457 if (idxSize == 2) 00458 SkipnStrides = pIdxBufS[startIdx + vx_index] + state->load_base_vertex_index; 00459 else 00460 SkipnStrides = pIdxBufL[startIdx + vx_index] + state->load_base_vertex_index; 00461 } 00462 00463 for (i = MAX_ATTRIBS - 1; i >= 0; i--) 00464 { 00465 if (!(si->use_map & (1 << i))) continue; 00466 00467 ptr = si->elements[i].data.addr + si->elements[i].stride * SkipnStrides; 00468 00469 send_attribute(gl_info, si->elements[i].format->id, i, ptr); 00470 } 00471 SkipnStrides++; 00472 } 00473 00474 glEnd(); 00475 } 00476 00477 /* GL locking is done by the caller */ 00478 static void drawStridedInstanced(const struct wined3d_gl_info *gl_info, const struct wined3d_state *state, 00479 const struct wined3d_stream_info *si, UINT numberOfVertices, GLenum glPrimitiveType, 00480 const void *idxData, UINT idxSize, UINT startIdx, UINT base_vertex_index) 00481 { 00482 UINT numInstances = 0, i; 00483 int numInstancedAttribs = 0, j; 00484 UINT instancedData[sizeof(si->elements) / sizeof(*si->elements) /* 16 */]; 00485 GLenum idxtype = idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT; 00486 00487 if (!idxSize) 00488 { 00489 /* This is a nasty thing. MSDN says no hardware supports that and apps have to use software vertex processing. 00490 * We don't support this for now 00491 * 00492 * Shouldn't be too hard to support with opengl, in theory just call glDrawArrays instead of drawElements. 00493 * But the StreamSourceFreq value has a different meaning in that situation. 00494 */ 00495 FIXME("Non-indexed instanced drawing is not supported\n"); 00496 return; 00497 } 00498 00499 /* First, figure out how many instances we have to draw */ 00500 for (i = 0; i < MAX_STREAMS; ++i) 00501 { 00502 /* Look at the streams and take the first one which matches */ 00503 if (state->streams[i].buffer 00504 && ((state->streams[i].flags & WINED3DSTREAMSOURCE_INSTANCEDATA) 00505 || (state->streams[i].flags & WINED3DSTREAMSOURCE_INDEXEDDATA))) 00506 { 00507 /* Use the specified number of instances from the first matched 00508 * stream. A streamFreq of 0 (with INSTANCEDATA or INDEXEDDATA) 00509 * is handled as 1. See d3d9/tests/visual.c-> stream_test(). */ 00510 numInstances = state->streams[i].frequency ? state->streams[i].frequency : 1; 00511 break; 00512 } 00513 } 00514 00515 for (i = 0; i < sizeof(si->elements) / sizeof(*si->elements); ++i) 00516 { 00517 if (!(si->use_map & (1 << i))) continue; 00518 00519 if (state->streams[si->elements[i].stream_idx].flags & WINED3DSTREAMSOURCE_INSTANCEDATA) 00520 { 00521 instancedData[numInstancedAttribs] = i; 00522 numInstancedAttribs++; 00523 } 00524 } 00525 00526 /* now draw numInstances instances :-) */ 00527 for(i = 0; i < numInstances; i++) { 00528 /* Specify the instanced attributes using immediate mode calls */ 00529 for(j = 0; j < numInstancedAttribs; j++) { 00530 const BYTE *ptr = si->elements[instancedData[j]].data.addr 00531 + si->elements[instancedData[j]].stride * i; 00532 if (si->elements[instancedData[j]].data.buffer_object) 00533 { 00534 struct wined3d_buffer *vb = state->streams[si->elements[instancedData[j]].stream_idx].buffer; 00535 ptr += (ULONG_PTR)buffer_get_sysmem(vb, gl_info); 00536 } 00537 00538 send_attribute(gl_info, si->elements[instancedData[j]].format->id, instancedData[j], ptr); 00539 } 00540 00541 if (gl_info->supported[ARB_DRAW_ELEMENTS_BASE_VERTEX]) 00542 { 00543 GL_EXTCALL(glDrawElementsBaseVertex(glPrimitiveType, numberOfVertices, idxtype, 00544 (const char *)idxData+(idxSize * startIdx), base_vertex_index)); 00545 checkGLcall("glDrawElementsBaseVertex"); 00546 } 00547 else 00548 { 00549 glDrawElements(glPrimitiveType, numberOfVertices, idxtype, 00550 (const char *)idxData+(idxSize * startIdx)); 00551 checkGLcall("glDrawElements"); 00552 } 00553 } 00554 } 00555 00556 static void remove_vbos(const struct wined3d_gl_info *gl_info, 00557 const struct wined3d_state *state, struct wined3d_stream_info *s) 00558 { 00559 unsigned int i; 00560 00561 for (i = 0; i < (sizeof(s->elements) / sizeof(*s->elements)); ++i) 00562 { 00563 struct wined3d_stream_info_element *e; 00564 00565 if (!(s->use_map & (1 << i))) continue; 00566 00567 e = &s->elements[i]; 00568 if (e->data.buffer_object) 00569 { 00570 struct wined3d_buffer *vb = state->streams[e->stream_idx].buffer; 00571 e->data.buffer_object = 0; 00572 e->data.addr = (BYTE *)((ULONG_PTR)e->data.addr + (ULONG_PTR)buffer_get_sysmem(vb, gl_info)); 00573 } 00574 } 00575 } 00576 00577 /* Routine common to the draw primitive and draw indexed primitive routines */ 00578 void drawPrimitive(struct wined3d_device *device, UINT index_count, UINT StartIdx, UINT idxSize, const void *idxData) 00579 { 00580 const struct wined3d_state *state = &device->stateBlock->state; 00581 struct wined3d_context *context; 00582 unsigned int i; 00583 00584 if (!index_count) return; 00585 00586 if (state->render_states[WINED3D_RS_COLORWRITEENABLE]) 00587 { 00588 /* Invalidate the back buffer memory so LockRect will read it the next time */ 00589 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i) 00590 { 00591 struct wined3d_surface *target = device->fb.render_targets[i]; 00592 if (target) 00593 { 00594 surface_load_location(target, target->draw_binding, NULL); 00595 surface_modify_location(target, target->draw_binding, TRUE); 00596 } 00597 } 00598 } 00599 00600 /* Signals other modules that a drawing is in progress and the stateblock finalized */ 00601 device->isInDraw = TRUE; 00602 00603 context = context_acquire(device, device->fb.render_targets[0]); 00604 if (!context->valid) 00605 { 00606 context_release(context); 00607 WARN("Invalid context, skipping draw.\n"); 00608 return; 00609 } 00610 00611 if (device->fb.depth_stencil) 00612 { 00613 /* Note that this depends on the context_acquire() call above to set 00614 * context->render_offscreen properly. We don't currently take the 00615 * Z-compare function into account, but we could skip loading the 00616 * depthstencil for D3DCMP_NEVER and D3DCMP_ALWAYS as well. Also note 00617 * that we never copy the stencil data.*/ 00618 DWORD location = context->render_offscreen ? device->fb.depth_stencil->draw_binding : SFLAG_INDRAWABLE; 00619 if (state->render_states[WINED3D_RS_ZWRITEENABLE] || state->render_states[WINED3D_RS_ZENABLE]) 00620 { 00621 struct wined3d_surface *ds = device->fb.depth_stencil; 00622 RECT current_rect, draw_rect, r; 00623 00624 if (!context->render_offscreen && ds != device->onscreen_depth_stencil) 00625 device_switch_onscreen_ds(device, context, ds); 00626 00627 if (ds->flags & location) 00628 SetRect(¤t_rect, 0, 0, ds->ds_current_size.cx, ds->ds_current_size.cy); 00629 else 00630 SetRectEmpty(¤t_rect); 00631 00632 wined3d_get_draw_rect(state, &draw_rect); 00633 00634 IntersectRect(&r, &draw_rect, ¤t_rect); 00635 if (!EqualRect(&r, &draw_rect)) 00636 surface_load_ds_location(ds, context, location); 00637 } 00638 } 00639 00640 if (!context_apply_draw_state(context, device)) 00641 { 00642 context_release(context); 00643 WARN("Unable to apply draw state, skipping draw.\n"); 00644 return; 00645 } 00646 00647 if (device->fb.depth_stencil && state->render_states[WINED3D_RS_ZWRITEENABLE]) 00648 { 00649 struct wined3d_surface *ds = device->fb.depth_stencil; 00650 DWORD location = context->render_offscreen ? ds->draw_binding : SFLAG_INDRAWABLE; 00651 00652 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy); 00653 } 00654 00655 if ((!context->gl_info->supported[WINED3D_GL_VERSION_2_0] 00656 || (!glPointParameteri && !context->gl_info->supported[NV_POINT_SPRITE])) 00657 && context->render_offscreen 00658 && state->render_states[WINED3D_RS_POINTSPRITEENABLE] 00659 && state->gl_primitive_type == GL_POINTS) 00660 { 00661 FIXME("Point sprite coordinate origin switching not supported.\n"); 00662 } 00663 00664 /* Ok, we will be updating the screen from here onwards so grab the lock */ 00665 ENTER_GL(); 00666 { 00667 GLenum glPrimType = state->gl_primitive_type; 00668 INT base_vertex_index = state->base_vertex_index; 00669 BOOL emulation = FALSE; 00670 const struct wined3d_stream_info *stream_info = &device->strided_streams; 00671 struct wined3d_stream_info stridedlcl; 00672 00673 if (!use_vs(state)) 00674 { 00675 if (!stream_info->position_transformed && context->num_untracked_materials 00676 && state->render_states[WINED3D_RS_LIGHTING]) 00677 { 00678 static BOOL warned; 00679 if (!warned) { 00680 FIXME("Using software emulation because not all material properties could be tracked\n"); 00681 warned = TRUE; 00682 } else { 00683 TRACE("Using software emulation because not all material properties could be tracked\n"); 00684 } 00685 emulation = TRUE; 00686 } 00687 else if (context->fog_coord && state->render_states[WINED3D_RS_FOGENABLE]) 00688 { 00689 /* Either write a pipeline replacement shader or convert the specular alpha from unsigned byte 00690 * to a float in the vertex buffer 00691 */ 00692 static BOOL warned; 00693 if (!warned) { 00694 FIXME("Using software emulation because manual fog coordinates are provided\n"); 00695 warned = TRUE; 00696 } else { 00697 TRACE("Using software emulation because manual fog coordinates are provided\n"); 00698 } 00699 emulation = TRUE; 00700 } 00701 00702 if(emulation) { 00703 stream_info = &stridedlcl; 00704 memcpy(&stridedlcl, &device->strided_streams, sizeof(stridedlcl)); 00705 remove_vbos(context->gl_info, state, &stridedlcl); 00706 } 00707 } 00708 00709 if (device->useDrawStridedSlow || emulation) 00710 { 00711 /* Immediate mode drawing */ 00712 if (use_vs(state)) 00713 { 00714 static BOOL warned; 00715 if (!warned) { 00716 FIXME("Using immediate mode with vertex shaders for half float emulation\n"); 00717 warned = TRUE; 00718 } else { 00719 TRACE("Using immediate mode with vertex shaders for half float emulation\n"); 00720 } 00721 drawStridedSlowVs(context->gl_info, state, stream_info, 00722 index_count, glPrimType, idxData, idxSize, StartIdx); 00723 } 00724 else 00725 { 00726 drawStridedSlow(device, context, stream_info, index_count, 00727 glPrimType, idxData, idxSize, StartIdx); 00728 } 00729 } 00730 else if (device->instancedDraw) 00731 { 00732 /* Instancing emulation with mixing immediate mode and arrays */ 00733 drawStridedInstanced(context->gl_info, state, stream_info, 00734 index_count, glPrimType, idxData, idxSize, StartIdx, base_vertex_index); 00735 } 00736 else 00737 { 00738 drawStridedFast(context->gl_info, glPrimType, index_count, idxSize, idxData, StartIdx, base_vertex_index); 00739 } 00740 } 00741 00742 /* Finished updating the screen, restore lock */ 00743 LEAVE_GL(); 00744 00745 for(i = 0; i < device->num_buffer_queries; ++i) 00746 { 00747 wined3d_event_query_issue(device->buffer_queries[i], device); 00748 } 00749 00750 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */ 00751 00752 context_release(context); 00753 00754 TRACE("Done all gl drawing\n"); 00755 00756 /* Control goes back to the device, stateblock values may change again */ 00757 device->isInDraw = FALSE; 00758 } 00759 00760 static void normalize_normal(float *n) { 00761 float length = n[0] * n[0] + n[1] * n[1] + n[2] * n[2]; 00762 if (length == 0.0f) return; 00763 length = sqrtf(length); 00764 n[0] = n[0] / length; 00765 n[1] = n[1] / length; 00766 n[2] = n[2] / length; 00767 } 00768 00769 /* Tesselates a high order rectangular patch into single triangles using gl evaluators 00770 * 00771 * The problem is that OpenGL does not offer a direct way to return the tesselated primitives, 00772 * and they can't be sent off for rendering directly either. Tesselating is slow, so we want 00773 * to cache the patches in a vertex buffer. But more importantly, gl can't bind generated 00774 * attributes to numbered shader attributes, so we have to store them and rebind them as needed 00775 * in drawprim. 00776 * 00777 * To read back, the opengl feedback mode is used. This creates a problem because we want 00778 * untransformed, unlit vertices, but feedback runs everything through transform and lighting. 00779 * Thus disable lighting and set identity matrices to get unmodified colors and positions. 00780 * To overcome clipping find the biggest x, y and z values of the vertices in the patch and scale 00781 * them to [-1.0;+1.0] and set the viewport up to scale them back. 00782 * 00783 * Normals are more tricky: Draw white vertices with 3 directional lights, and calculate the 00784 * resulting colors back to the normals. 00785 * 00786 * NOTE: This function activates a context for blitting, modifies matrices & viewport, but 00787 * does not restore it because normally a draw follows immediately afterwards. The caller is 00788 * responsible of taking care that either the gl states are restored, or the context activated 00789 * for drawing to reset the lastWasBlit flag. 00790 */ 00791 HRESULT tesselate_rectpatch(struct wined3d_device *This, struct WineD3DRectPatch *patch) 00792 { 00793 unsigned int i, j, num_quads, out_vertex_size, buffer_size, d3d_out_vertex_size; 00794 const struct wined3d_rect_patch_info *info = &patch->rect_patch_info; 00795 float max_x = 0.0f, max_y = 0.0f, max_z = 0.0f, neg_z = 0.0f; 00796 struct wined3d_state *state = &This->stateBlock->state; 00797 struct wined3d_stream_info stream_info; 00798 struct wined3d_stream_info_element *e; 00799 struct wined3d_context *context; 00800 struct wined3d_shader *vs; 00801 const BYTE *data; 00802 DWORD vtxStride; 00803 GLenum feedback_type; 00804 GLfloat *feedbuffer; 00805 00806 /* Simply activate the context for blitting. This disables all the things we don't want and 00807 * takes care of dirtifying. Dirtifying is preferred over pushing / popping, since drawing the 00808 * patch (as opposed to normal draws) will most likely need different changes anyway. */ 00809 context = context_acquire(This, NULL); 00810 context_apply_blit_state(context, This); 00811 00812 /* First, locate the position data. This is provided in a vertex buffer in 00813 * the stateblock. Beware of VBOs. */ 00814 vs = state->vertex_shader; 00815 state->vertex_shader = NULL; 00816 device_stream_info_from_declaration(This, &stream_info, NULL); 00817 state->vertex_shader = vs; 00818 00819 e = &stream_info.elements[WINED3D_FFP_POSITION]; 00820 if (e->data.buffer_object) 00821 { 00822 struct wined3d_buffer *vb = state->streams[e->stream_idx].buffer; 00823 e->data.addr = (BYTE *)((ULONG_PTR)e->data.addr + (ULONG_PTR)buffer_get_sysmem(vb, context->gl_info)); 00824 } 00825 vtxStride = e->stride; 00826 data = e->data.addr 00827 + vtxStride * info->stride * info->start_vertex_offset_height 00828 + vtxStride * info->start_vertex_offset_width; 00829 00830 /* Not entirely sure about what happens with transformed vertices */ 00831 if (stream_info.position_transformed) FIXME("Transformed position in rectpatch generation\n"); 00832 00833 if(vtxStride % sizeof(GLfloat)) { 00834 /* glMap2f reads vertex sizes in GLfloats, the d3d stride is in bytes. 00835 * I don't see how the stride could not be a multiple of 4, but make sure 00836 * to check it 00837 */ 00838 ERR("Vertex stride is not a multiple of sizeof(GLfloat)\n"); 00839 } 00840 if (info->basis != WINED3D_BASIS_BEZIER) 00841 FIXME("Basis is %s, how to handle this?\n", debug_d3dbasis(info->basis)); 00842 if (info->degree != WINED3D_DEGREE_CUBIC) 00843 FIXME("Degree is %s, how to handle this?\n", debug_d3ddegree(info->degree)); 00844 00845 /* First, get the boundary cube of the input data */ 00846 for (j = 0; j < info->height; ++j) 00847 { 00848 for (i = 0; i < info->width; ++i) 00849 { 00850 const float *v = (const float *)(data + vtxStride * i + vtxStride * info->stride * j); 00851 if(fabs(v[0]) > max_x) max_x = fabsf(v[0]); 00852 if(fabs(v[1]) > max_y) max_y = fabsf(v[1]); 00853 if(fabs(v[2]) > max_z) max_z = fabsf(v[2]); 00854 if(v[2] < neg_z) neg_z = v[2]; 00855 } 00856 } 00857 00858 /* This needs some improvements in the vertex decl code */ 00859 FIXME("Cannot find data to generate. Only generating position and normals\n"); 00860 patch->has_normals = TRUE; 00861 patch->has_texcoords = FALSE; 00862 00863 ENTER_GL(); 00864 00865 glMatrixMode(GL_PROJECTION); 00866 checkGLcall("glMatrixMode(GL_PROJECTION)"); 00867 glLoadIdentity(); 00868 checkGLcall("glLoadIdentity()"); 00869 glScalef(1.0f / (max_x), 1.0f / (max_y), max_z == 0.0f ? 1.0f : 1.0f / (2.0f * max_z)); 00870 glTranslatef(0.0f, 0.0f, 0.5f); 00871 checkGLcall("glScalef"); 00872 glViewport(-max_x, -max_y, 2 * (max_x), 2 * (max_y)); 00873 checkGLcall("glViewport"); 00874 00875 /* Some states to take care of. If we're in wireframe opengl will produce lines, and confuse 00876 * our feedback buffer parser 00877 */ 00878 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 00879 checkGLcall("glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)"); 00880 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_FILLMODE)); 00881 if (patch->has_normals) 00882 { 00883 static const GLfloat black[] = {0.0f, 0.0f, 0.0f, 0.0f}; 00884 static const GLfloat red[] = {1.0f, 0.0f, 0.0f, 0.0f}; 00885 static const GLfloat green[] = {0.0f, 1.0f, 0.0f, 0.0f}; 00886 static const GLfloat blue[] = {0.0f, 0.0f, 1.0f, 0.0f}; 00887 static const GLfloat white[] = {1.0f, 1.0f, 1.0f, 1.0f}; 00888 glEnable(GL_LIGHTING); 00889 checkGLcall("glEnable(GL_LIGHTING)"); 00890 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, black); 00891 checkGLcall("glLightModel for MODEL_AMBIENT"); 00892 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_AMBIENT)); 00893 00894 for (i = 3; i < context->gl_info->limits.lights; ++i) 00895 { 00896 glDisable(GL_LIGHT0 + i); 00897 checkGLcall("glDisable(GL_LIGHT0 + i)"); 00898 context_invalidate_state(context, STATE_ACTIVELIGHT(i)); 00899 } 00900 00901 context_invalidate_state(context, STATE_ACTIVELIGHT(0)); 00902 glLightfv(GL_LIGHT0, GL_DIFFUSE, red); 00903 glLightfv(GL_LIGHT0, GL_SPECULAR, black); 00904 glLightfv(GL_LIGHT0, GL_AMBIENT, black); 00905 glLightfv(GL_LIGHT0, GL_POSITION, red); 00906 glEnable(GL_LIGHT0); 00907 checkGLcall("Setting up light 1"); 00908 context_invalidate_state(context, STATE_ACTIVELIGHT(1)); 00909 glLightfv(GL_LIGHT1, GL_DIFFUSE, green); 00910 glLightfv(GL_LIGHT1, GL_SPECULAR, black); 00911 glLightfv(GL_LIGHT1, GL_AMBIENT, black); 00912 glLightfv(GL_LIGHT1, GL_POSITION, green); 00913 glEnable(GL_LIGHT1); 00914 checkGLcall("Setting up light 2"); 00915 context_invalidate_state(context, STATE_ACTIVELIGHT(2)); 00916 glLightfv(GL_LIGHT2, GL_DIFFUSE, blue); 00917 glLightfv(GL_LIGHT2, GL_SPECULAR, black); 00918 glLightfv(GL_LIGHT2, GL_AMBIENT, black); 00919 glLightfv(GL_LIGHT2, GL_POSITION, blue); 00920 glEnable(GL_LIGHT2); 00921 checkGLcall("Setting up light 3"); 00922 00923 context_invalidate_state(context, STATE_MATERIAL); 00924 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORVERTEX)); 00925 glDisable(GL_COLOR_MATERIAL); 00926 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, black); 00927 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black); 00928 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, white); 00929 checkGLcall("Setting up materials"); 00930 } 00931 00932 /* Enable the needed maps. 00933 * GL_MAP2_VERTEX_3 is needed for positional data. 00934 * GL_AUTO_NORMAL to generate normals from the position. Do not use GL_MAP2_NORMAL. 00935 * GL_MAP2_TEXTURE_COORD_4 for texture coords 00936 */ 00937 num_quads = ceilf(patch->numSegs[0]) * ceilf(patch->numSegs[1]); 00938 out_vertex_size = 3 /* position */; 00939 d3d_out_vertex_size = 3; 00940 glEnable(GL_MAP2_VERTEX_3); 00941 if(patch->has_normals && patch->has_texcoords) { 00942 FIXME("Texcoords not handled yet\n"); 00943 feedback_type = GL_3D_COLOR_TEXTURE; 00944 out_vertex_size += 8; 00945 d3d_out_vertex_size += 7; 00946 glEnable(GL_AUTO_NORMAL); 00947 glEnable(GL_MAP2_TEXTURE_COORD_4); 00948 } else if(patch->has_texcoords) { 00949 FIXME("Texcoords not handled yet\n"); 00950 feedback_type = GL_3D_COLOR_TEXTURE; 00951 out_vertex_size += 7; 00952 d3d_out_vertex_size += 4; 00953 glEnable(GL_MAP2_TEXTURE_COORD_4); 00954 } else if(patch->has_normals) { 00955 feedback_type = GL_3D_COLOR; 00956 out_vertex_size += 4; 00957 d3d_out_vertex_size += 3; 00958 glEnable(GL_AUTO_NORMAL); 00959 } else { 00960 feedback_type = GL_3D; 00961 } 00962 checkGLcall("glEnable vertex attrib generation"); 00963 00964 buffer_size = num_quads * out_vertex_size * 2 /* triangle list */ * 3 /* verts per tri */ 00965 + 4 * num_quads /* 2 triangle markers per quad + num verts in tri */; 00966 feedbuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_size * sizeof(float) * 8); 00967 00968 glMap2f(GL_MAP2_VERTEX_3, 00969 0.0f, 1.0f, vtxStride / sizeof(float), info->width, 00970 0.0f, 1.0f, info->stride * vtxStride / sizeof(float), info->height, 00971 (const GLfloat *)data); 00972 checkGLcall("glMap2f"); 00973 if (patch->has_texcoords) 00974 { 00975 glMap2f(GL_MAP2_TEXTURE_COORD_4, 00976 0.0f, 1.0f, vtxStride / sizeof(float), info->width, 00977 0.0f, 1.0f, info->stride * vtxStride / sizeof(float), info->height, 00978 (const GLfloat *)data); 00979 checkGLcall("glMap2f"); 00980 } 00981 glMapGrid2f(ceilf(patch->numSegs[0]), 0.0f, 1.0f, ceilf(patch->numSegs[1]), 0.0f, 1.0f); 00982 checkGLcall("glMapGrid2f"); 00983 00984 glFeedbackBuffer(buffer_size * 2, feedback_type, feedbuffer); 00985 checkGLcall("glFeedbackBuffer"); 00986 glRenderMode(GL_FEEDBACK); 00987 00988 glEvalMesh2(GL_FILL, 0, ceilf(patch->numSegs[0]), 0, ceilf(patch->numSegs[1])); 00989 checkGLcall("glEvalMesh2"); 00990 00991 i = glRenderMode(GL_RENDER); 00992 if(i == -1) { 00993 LEAVE_GL(); 00994 ERR("Feedback failed. Expected %d elements back\n", buffer_size); 00995 HeapFree(GetProcessHeap(), 0, feedbuffer); 00996 context_release(context); 00997 return WINED3DERR_DRIVERINTERNALERROR; 00998 } else if(i != buffer_size) { 00999 LEAVE_GL(); 01000 ERR("Unexpected amount of elements returned. Expected %d, got %d\n", buffer_size, i); 01001 HeapFree(GetProcessHeap(), 0, feedbuffer); 01002 context_release(context); 01003 return WINED3DERR_DRIVERINTERNALERROR; 01004 } else { 01005 TRACE("Got %d elements as expected\n", i); 01006 } 01007 01008 HeapFree(GetProcessHeap(), 0, patch->mem); 01009 patch->mem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, num_quads * 6 * d3d_out_vertex_size * sizeof(float) * 8); 01010 i = 0; 01011 for(j = 0; j < buffer_size; j += (3 /* num verts */ * out_vertex_size + 2 /* tri marker */)) { 01012 if(feedbuffer[j] != GL_POLYGON_TOKEN) { 01013 ERR("Unexpected token: %f\n", feedbuffer[j]); 01014 continue; 01015 } 01016 if(feedbuffer[j + 1] != 3) { 01017 ERR("Unexpected polygon: %f corners\n", feedbuffer[j + 1]); 01018 continue; 01019 } 01020 /* Somehow there are different ideas about back / front facing, so fix up the 01021 * vertex order 01022 */ 01023 patch->mem[i + 0] = feedbuffer[j + out_vertex_size * 2 + 2]; /* x, triangle 2 */ 01024 patch->mem[i + 1] = feedbuffer[j + out_vertex_size * 2 + 3]; /* y, triangle 2 */ 01025 patch->mem[i + 2] = (feedbuffer[j + out_vertex_size * 2 + 4] - 0.5f) * 4.0f * max_z; /* z, triangle 3 */ 01026 if(patch->has_normals) { 01027 patch->mem[i + 3] = feedbuffer[j + out_vertex_size * 2 + 5]; 01028 patch->mem[i + 4] = feedbuffer[j + out_vertex_size * 2 + 6]; 01029 patch->mem[i + 5] = feedbuffer[j + out_vertex_size * 2 + 7]; 01030 } 01031 i += d3d_out_vertex_size; 01032 01033 patch->mem[i + 0] = feedbuffer[j + out_vertex_size * 1 + 2]; /* x, triangle 2 */ 01034 patch->mem[i + 1] = feedbuffer[j + out_vertex_size * 1 + 3]; /* y, triangle 2 */ 01035 patch->mem[i + 2] = (feedbuffer[j + out_vertex_size * 1 + 4] - 0.5f) * 4.0f * max_z; /* z, triangle 2 */ 01036 if(patch->has_normals) { 01037 patch->mem[i + 3] = feedbuffer[j + out_vertex_size * 1 + 5]; 01038 patch->mem[i + 4] = feedbuffer[j + out_vertex_size * 1 + 6]; 01039 patch->mem[i + 5] = feedbuffer[j + out_vertex_size * 1 + 7]; 01040 } 01041 i += d3d_out_vertex_size; 01042 01043 patch->mem[i + 0] = feedbuffer[j + out_vertex_size * 0 + 2]; /* x, triangle 1 */ 01044 patch->mem[i + 1] = feedbuffer[j + out_vertex_size * 0 + 3]; /* y, triangle 1 */ 01045 patch->mem[i + 2] = (feedbuffer[j + out_vertex_size * 0 + 4] - 0.5f) * 4.0f * max_z; /* z, triangle 1 */ 01046 if(patch->has_normals) { 01047 patch->mem[i + 3] = feedbuffer[j + out_vertex_size * 0 + 5]; 01048 patch->mem[i + 4] = feedbuffer[j + out_vertex_size * 0 + 6]; 01049 patch->mem[i + 5] = feedbuffer[j + out_vertex_size * 0 + 7]; 01050 } 01051 i += d3d_out_vertex_size; 01052 } 01053 01054 if(patch->has_normals) { 01055 /* Now do the same with reverse light directions */ 01056 static const GLfloat x[] = {-1.0f, 0.0f, 0.0f, 0.0f}; 01057 static const GLfloat y[] = { 0.0f, -1.0f, 0.0f, 0.0f}; 01058 static const GLfloat z[] = { 0.0f, 0.0f, -1.0f, 0.0f}; 01059 glLightfv(GL_LIGHT0, GL_POSITION, x); 01060 glLightfv(GL_LIGHT1, GL_POSITION, y); 01061 glLightfv(GL_LIGHT2, GL_POSITION, z); 01062 checkGLcall("Setting up reverse light directions"); 01063 01064 glRenderMode(GL_FEEDBACK); 01065 checkGLcall("glRenderMode(GL_FEEDBACK)"); 01066 glEvalMesh2(GL_FILL, 0, ceilf(patch->numSegs[0]), 0, ceilf(patch->numSegs[1])); 01067 checkGLcall("glEvalMesh2"); 01068 i = glRenderMode(GL_RENDER); 01069 checkGLcall("glRenderMode(GL_RENDER)"); 01070 01071 i = 0; 01072 for(j = 0; j < buffer_size; j += (3 /* num verts */ * out_vertex_size + 2 /* tri marker */)) { 01073 if(feedbuffer[j] != GL_POLYGON_TOKEN) { 01074 ERR("Unexpected token: %f\n", feedbuffer[j]); 01075 continue; 01076 } 01077 if(feedbuffer[j + 1] != 3) { 01078 ERR("Unexpected polygon: %f corners\n", feedbuffer[j + 1]); 01079 continue; 01080 } 01081 if(patch->mem[i + 3] == 0.0f) 01082 patch->mem[i + 3] = -feedbuffer[j + out_vertex_size * 2 + 5]; 01083 if(patch->mem[i + 4] == 0.0f) 01084 patch->mem[i + 4] = -feedbuffer[j + out_vertex_size * 2 + 6]; 01085 if(patch->mem[i + 5] == 0.0f) 01086 patch->mem[i + 5] = -feedbuffer[j + out_vertex_size * 2 + 7]; 01087 normalize_normal(patch->mem + i + 3); 01088 i += d3d_out_vertex_size; 01089 01090 if(patch->mem[i + 3] == 0.0f) 01091 patch->mem[i + 3] = -feedbuffer[j + out_vertex_size * 1 + 5]; 01092 if(patch->mem[i + 4] == 0.0f) 01093 patch->mem[i + 4] = -feedbuffer[j + out_vertex_size * 1 + 6]; 01094 if(patch->mem[i + 5] == 0.0f) 01095 patch->mem[i + 5] = -feedbuffer[j + out_vertex_size * 1 + 7]; 01096 normalize_normal(patch->mem + i + 3); 01097 i += d3d_out_vertex_size; 01098 01099 if(patch->mem[i + 3] == 0.0f) 01100 patch->mem[i + 3] = -feedbuffer[j + out_vertex_size * 0 + 5]; 01101 if(patch->mem[i + 4] == 0.0f) 01102 patch->mem[i + 4] = -feedbuffer[j + out_vertex_size * 0 + 6]; 01103 if(patch->mem[i + 5] == 0.0f) 01104 patch->mem[i + 5] = -feedbuffer[j + out_vertex_size * 0 + 7]; 01105 normalize_normal(patch->mem + i + 3); 01106 i += d3d_out_vertex_size; 01107 } 01108 } 01109 01110 glDisable(GL_MAP2_VERTEX_3); 01111 glDisable(GL_AUTO_NORMAL); 01112 glDisable(GL_MAP2_NORMAL); 01113 glDisable(GL_MAP2_TEXTURE_COORD_4); 01114 checkGLcall("glDisable vertex attrib generation"); 01115 LEAVE_GL(); 01116 01117 context_release(context); 01118 01119 HeapFree(GetProcessHeap(), 0, feedbuffer); 01120 01121 vtxStride = 3 * sizeof(float); 01122 if(patch->has_normals) { 01123 vtxStride += 3 * sizeof(float); 01124 } 01125 if(patch->has_texcoords) { 01126 vtxStride += 4 * sizeof(float); 01127 } 01128 memset(&patch->strided, 0, sizeof(patch->strided)); 01129 patch->strided.position.format = WINED3DFMT_R32G32B32_FLOAT; 01130 patch->strided.position.data = (BYTE *)patch->mem; 01131 patch->strided.position.stride = vtxStride; 01132 01133 if (patch->has_normals) 01134 { 01135 patch->strided.normal.format = WINED3DFMT_R32G32B32_FLOAT; 01136 patch->strided.normal.data = (BYTE *)patch->mem + 3 * sizeof(float) /* pos */; 01137 patch->strided.normal.stride = vtxStride; 01138 } 01139 if (patch->has_texcoords) 01140 { 01141 patch->strided.tex_coords[0].format = WINED3DFMT_R32G32B32A32_FLOAT; 01142 patch->strided.tex_coords[0].data = (BYTE *)patch->mem + 3 * sizeof(float) /* pos */; 01143 if (patch->has_normals) 01144 patch->strided.tex_coords[0].data += 3 * sizeof(float); 01145 patch->strided.tex_coords[0].stride = vtxStride; 01146 } 01147 01148 return WINED3D_OK; 01149 } Generated on Thu May 24 2012 04:22:33 for ReactOS by
1.7.6.1
|