00001
00002 #include "Core/precomp.h"
00003 #include <windows.h>
00004 #include "blit_dx.h"
00005 #include <API/Display/Display/surfaceprovider.h>
00006 #include "../Generic/colormap.h"
00007 #include "../Generic/blit_alphamask_rle.h"
00008 #include "../Generic/pixeldata.h"
00009
00010 std::list<CL_Blit_DX*> CL_Blit_DX::m_loaded_surfaces;
00011
00012 CL_Blit_DX::CL_Blit_DX(
00013 CL_DisplayCard_DirectDraw *target,
00014 CL_SurfaceProvider *provider)
00015 {
00016 m_target = target;
00017 m_provider = provider;
00018 m_surface = NULL;
00019 m_alphablitter = NULL;
00020 }
00021
00022 CL_Blit_DX::~CL_Blit_DX()
00023 {
00024 if (m_surface != NULL)
00025 {
00026 m_surface->Release();
00027 m_loaded_surfaces.remove(this);
00028 }
00029 if (m_alphablitter != NULL) delete m_alphablitter;
00030 }
00031
00032 bool CL_Blit_DX::init_surface(CL_Blitters *blitters)
00033 {
00034 if (!reload(false, true)) return false;
00035
00036 blitters->set_clip(this);
00037 blitters->set_noclip(this);
00038 blitters->set_scale_noclip(this);
00039 blitters->set_scale_clip(this);
00040
00041 m_loaded_surfaces.push_back(this);
00042
00043 return true;
00044 }
00045
00046 void CL_Blit_DX::blt_noclip(
00047 CL_Target *target,
00048 int x,
00049 int y,
00050 int spr_no)
00051 {
00052 DWORD flags = DDBLTFAST_WAIT;
00053 if (m_transparent)
00054 {
00055 flags|=DDBLTFAST_SRCCOLORKEY;
00056 }
00057 else
00058 {
00059 flags|=DDBLTFAST_NOCOLORKEY;
00060 }
00061
00062 RECT source;
00063 int delta = spr_no*m_height;
00064
00065 source.left=0;
00066 source.top=delta;
00067 source.right=m_width;
00068 source.bottom=m_height+delta;
00069
00070 m_target->get_back_buffer()->get_surface()->BltFast(x, y, m_surface, &source, flags);
00071
00072 if (m_alphablitter != NULL) m_alphablitter->blt_noclip(target, x, y, spr_no);
00073 }
00074
00075 void CL_Blit_DX::blt_clip(
00076 CL_Target *target,
00077 int x,
00078 int y,
00079 int spr_no,
00080 const CL_ClipRect &clip)
00081 {
00082 DDBLTFX ddbltfx;
00083 ddbltfx.dwSize = sizeof(ddbltfx);
00084
00085 DWORD flags = DDBLT_WAIT;
00086 if (m_transparent)
00087 {
00088 flags|=DDBLT_KEYSRC;
00089 }
00090
00091 RECT dest, source;
00092 source.left=0;
00093 source.top=0;
00094 source.right=m_width;
00095 source.bottom=m_height;
00096
00097 dest.left = x;
00098 dest.top = y;
00099 dest.right = dest.left + m_width;
00100 dest.bottom = dest.top + m_height;
00101
00102 if (dest.left < clip.m_x1)
00103 {
00104 source.left = clip.m_x1-dest.left;
00105 dest.left = clip.m_x1;
00106 }
00107
00108 if (dest.top < clip.m_y1)
00109 {
00110 source.top = clip.m_y1-dest.top;
00111 dest.top = clip.m_y1;
00112 }
00113
00114 if (dest.right > clip.m_x2)
00115 {
00116 source.right -= dest.right-clip.m_x2;
00117 dest.right = clip.m_x2;
00118 }
00119
00120 if (dest.bottom > clip.m_y2)
00121 {
00122 source.bottom -= dest.bottom-clip.m_y2;
00123 dest.bottom = clip.m_y2;
00124 }
00125
00126 if (dest.right<dest.left || dest.bottom<dest.top) return;
00127
00128 int delta = spr_no*m_height;
00129 source.top += delta;
00130 source.bottom += delta;
00131
00132 m_target->get_back_buffer()->get_surface()->Blt(&dest, m_surface, &source, flags, &ddbltfx);
00133 if (m_alphablitter != NULL) m_alphablitter->blt_clip(target, x, y, spr_no, clip);
00134 }
00135
00136 void CL_Blit_DX::blt_scale_noclip(
00137 CL_Target *target,
00138 int x,
00139 int y,
00140 int dest_width,
00141 int dest_height,
00142 int spr_no)
00143 {
00144 DDBLTFX ddbltfx;
00145 ddbltfx.dwSize = sizeof(ddbltfx);
00146
00147 DWORD flags = DDBLT_WAIT;
00148 if (m_transparent)
00149 {
00150 flags|=DDBLT_KEYSRC;
00151 }
00152
00153 RECT dest, source;
00154 source.left=0;
00155 source.top=0;
00156 source.right=m_width;
00157 source.bottom=m_height;
00158
00159 dest.left = x;
00160 dest.top = y;
00161 dest.right = dest.left + dest_width;
00162 dest.bottom = dest.top + dest_height;
00163
00164 int delta = spr_no*m_height;
00165 source.top += delta;
00166 source.bottom += delta;
00167
00168 m_target->get_back_buffer()->get_surface()->Blt(&dest, m_surface, &source, flags, &ddbltfx);
00169 if (m_alphablitter != NULL) m_alphablitter->blt_scale_noclip(target, x, y, dest_width, dest_height, spr_no);
00170 }
00171
00172 void CL_Blit_DX::blt_scale_clip(
00173 CL_Target *target,
00174 int x,
00175 int y,
00176 int dest_width,
00177 int dest_height,
00178 int spr_no,
00179 const CL_ClipRect &clip)
00180 {
00181 DDBLTFX ddbltfx;
00182 ddbltfx.dwSize = sizeof(ddbltfx);
00183
00184 DWORD flags = DDBLT_WAIT;
00185 if (m_transparent)
00186 {
00187 flags|=DDBLT_KEYSRC;
00188 }
00189
00190 RECT dest, source;
00191 source.left=0;
00192 source.top=0;
00193 source.right=m_width;
00194 source.bottom=m_height;
00195
00196 dest.left = x;
00197 dest.top = y;
00198 dest.right = dest.left + dest_width;
00199 dest.bottom = dest.top + dest_height;
00200
00201 float dx = float(m_width)/dest_width;
00202 float dy = float(m_height)/dest_height;
00203
00204 if (dest.left < clip.m_x1)
00205 {
00206 source.left = int((clip.m_x1-dest.left)*dx+0.5);
00207 dest.left = clip.m_x1;
00208 }
00209
00210 if (dest.top < clip.m_y1)
00211 {
00212 source.top = int((clip.m_y1-dest.top)*dy+0.5);
00213 dest.top = clip.m_y1;
00214 }
00215
00216 if (dest.right > clip.m_x2)
00217 {
00218 source.right -= int((dest.right-clip.m_x2)*dx+0.5);
00219 dest.right = clip.m_x2;
00220 }
00221
00222 if (dest.bottom > clip.m_y2)
00223 {
00224 source.bottom -= int((dest.bottom-clip.m_y2)*dy+0.5);
00225 dest.bottom = clip.m_y2;
00226 }
00227
00228 if (dest.right<dest.left || dest.bottom<dest.top) return;
00229
00230 int delta = spr_no*m_height;
00231 source.top += delta;
00232 source.bottom += delta;
00233
00234 m_target->get_back_buffer()->get_surface()->Blt(&dest, m_surface, &source, flags, &ddbltfx);
00235 if (m_alphablitter != NULL) m_alphablitter->blt_scale_clip(target, x, y, dest_width, dest_height, spr_no, clip);
00236 }
00237
00238 bool CL_Blit_DX::reload(bool lock_provider, bool create_surface)
00239 {
00240 unsigned int y;
00241
00242 if (lock_provider) m_provider->lock();
00243
00244 unsigned int num_lines = m_provider->get_height()*m_provider->get_num_frames();
00245
00246 CL_PixelData alpha(
00247 0,
00248 0,
00249 0,
00250 255,
00251 m_provider,
00252 1);
00253
00254 int bytes_pr_line = alpha.get_bytes_pr_line();
00255 unsigned char *alpha_data = new unsigned char[num_lines*bytes_pr_line];
00256
00257 bool has_alpha = false;
00258 m_transparent = false;
00259
00260 int alpha_width = alpha.get_width();
00261 for (y=0;y<num_lines;y++)
00262 {
00263 unsigned char *l = &alpha_data[y*bytes_pr_line];
00264 alpha.get_line_pixel_to_dest(y, l);
00265
00266 for (int x=0;x<alpha_width;x++)
00267 {
00268 if (l[x] == 0) m_transparent = true;
00269 if (l[x] != 0 && l[x] != 255)
00270 {
00271 m_transparent = true;
00272 has_alpha = true;
00273 break;
00274 }
00275 }
00276 }
00277
00278 CL_PixelData input(
00279 m_target->get_target()->get_red_mask(),
00280 m_target->get_target()->get_green_mask(),
00281 m_target->get_target()->get_blue_mask(),
00282 m_target->get_target()->get_alpha_mask(),
00283 m_provider,
00284 (m_target->get_target()->get_depth()+7)/8);
00285
00286 m_width = m_provider->get_width();
00287 m_height = m_provider->get_height();
00288
00289 if (create_surface)
00290 {
00291 DDSURFACEDESC sur_desc;
00292 sur_desc.dwSize = sizeof(DDSURFACEDESC);
00293 sur_desc.dwFlags=DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH;
00294 sur_desc.dwWidth=m_width;
00295 sur_desc.dwHeight=m_height*m_provider->get_num_frames();
00296 sur_desc.ddsCaps.dwCaps=DDSCAPS_OFFSCREENPLAIN;
00297
00298
00299
00300
00301
00302
00303 {
00304 sur_desc.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
00305 }
00306
00307 HRESULT err;
00308 err = m_target->get_directdraw()->CreateSurface(&sur_desc, &m_surface, NULL);
00309 if (err != DD_OK)
00310 {
00311 delete[] alpha_data;
00312 return false;
00313 }
00314 }
00315 else
00316 {
00317 m_surface->Restore();
00318 }
00319
00320 DDSURFACEDESC surface_desc;
00321 memset(&surface_desc, 0, sizeof(DDSURFACEDESC));
00322 surface_desc.dwSize = sizeof(DDSURFACEDESC);
00323
00324 HRESULT err = m_surface->Lock(
00325 NULL,
00326 &surface_desc,
00327 DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,
00328 NULL);
00329 if (err != DD_OK)
00330 {
00331 delete[] alpha_data;
00332 m_surface->Release();
00333 m_surface = NULL;
00334 return false;
00335 }
00336
00337 CL_ColorMap color_map(m_target->get_target());
00338 unsigned int fill_color = color_map.calc_color(1, 0, 1, 0);
00339
00340 unsigned char *surface_data = (unsigned char *) surface_desc.lpSurface;
00341
00342 if (m_transparent)
00343 {
00344 int input_bytes_pr_line = input.get_bytes_pr_line();
00345 unsigned char *image_data = new unsigned char[num_lines*input_bytes_pr_line];
00346
00347 switch ((m_target->get_target()->get_depth()+7)/8)
00348 {
00349 case 1:
00350 {
00351 unsigned char col = (unsigned char) fill_color;
00352
00353 for (y=0;y<num_lines;y++)
00354 {
00355 unsigned char *input_data = &image_data[y*input_bytes_pr_line];
00356 input.get_line_pixel_to_dest(y, input_data);
00357
00358 unsigned char *a = &alpha_data[y*bytes_pr_line];
00359 for (unsigned int x=0;x<m_width;x++)
00360 {
00361 if (a[x] == 255)
00362 {
00363 surface_data[x] = input_data[x];
00364 }
00365 else
00366 {
00367 surface_data[x] = col;
00368 }
00369 }
00370 surface_data += surface_desc.lPitch;
00371 }
00372
00373 }
00374 break;
00375 case 2:
00376 {
00377 unsigned short col = (unsigned short) fill_color;
00378
00379 for (y=0;y<num_lines;y++)
00380 {
00381 unsigned char *input_data = &image_data[y*input_bytes_pr_line];
00382 input.get_line_pixel_to_dest(y, input_data);
00383 unsigned char *a = &alpha_data[y*bytes_pr_line];
00384
00385 for (unsigned int x=0;x<m_width;x++)
00386 {
00387 if (a[x] == 255)
00388 {
00389 ((unsigned short *) surface_data)[x] = ((unsigned short *) input_data)[x];
00390 }
00391 else
00392 {
00393 ((unsigned short *) surface_data)[x] = col;
00394 }
00395 }
00396 surface_data += surface_desc.lPitch;
00397 }
00398 if (has_alpha) m_alphablitter = new CL_Blit_AlphaMask_RLE(
00399 m_target,
00400 m_provider,
00401 image_data,
00402 input_bytes_pr_line,
00403 alpha_data,
00404 bytes_pr_line);
00405 }
00406 break;
00407 case 3:
00408 {
00409
00410 cl_assert(false);
00411 }
00412 break;
00413 case 4:
00414 {
00415 for (y=0;y<num_lines;y++)
00416 {
00417 unsigned char *input_data = &image_data[y*input_bytes_pr_line];
00418 input.get_line_pixel_to_dest(y, input_data);
00419 unsigned char *a = &alpha_data[y*bytes_pr_line];
00420
00421 for (unsigned int x=0;x<m_width;x++)
00422 {
00423 if (a[x] == 255)
00424 {
00425 ((unsigned int *) surface_data)[x] = ((unsigned int *) input_data)[x];
00426 }
00427 else
00428 {
00429 ((unsigned int *) surface_data)[x] = fill_color;
00430 }
00431 }
00432 surface_data += surface_desc.lPitch;
00433 }
00434 if (has_alpha) m_alphablitter = new CL_Blit_AlphaMask_RLE(
00435 m_target,
00436 m_provider,
00437 image_data,
00438 input_bytes_pr_line,
00439 alpha_data,
00440 bytes_pr_line);
00441 }
00442 break;
00443 }
00444 delete[] image_data;
00445 }
00446 else
00447 {
00448 int bytes_per_line = input.get_bytes_per_pixel()*input.get_width();
00449 for (unsigned int y=0;y<num_lines;y++)
00450 {
00451 memcpy(
00452 &surface_data[y*surface_desc.lPitch],
00453 input.get_line_pixel(y),
00454 bytes_per_line);
00455 }
00456 }
00457
00458 err = m_surface->Unlock(surface_data);
00459 cl_assert(err == DD_OK);
00460
00461 if (m_transparent)
00462 {
00463 DDCOLORKEY key;
00464 key.dwColorSpaceLowValue = fill_color;
00465 key.dwColorSpaceHighValue = fill_color;
00466
00467 err = m_surface->SetColorKey(DDCKEY_SRCBLT, &key);
00468 cl_assert(err == DD_OK);
00469 }
00470
00471 if (lock_provider) m_provider->unlock();
00472 delete[] alpha_data;
00473
00474 return true;
00475 }
00476
00477 void CL_Blit_DX::reload_all_surfaces()
00478 {
00479 for (
00480 std::list<CL_Blit_DX*>::iterator counter = m_loaded_surfaces.begin();
00481 counter != m_loaded_surfaces.end();
00482 counter++)
00483 {
00484 (*counter)->reload(true, false);
00485 }
00486 }
00487
00488 void CL_Blit_DX::release_all_surfaces()
00489 {
00490 for (
00491 std::list<CL_Blit_DX*>::iterator counter = m_loaded_surfaces.begin();
00492 counter != m_loaded_surfaces.end();
00493 counter++)
00494 {
00495 (*counter)->m_surface->Release();
00496 (*counter)->m_surface = NULL;
00497 }
00498 }
00499
00500 void CL_Blit_DX::create_all_surfaces()
00501 {
00502 for (
00503 std::list<CL_Blit_DX*>::iterator counter = m_loaded_surfaces.begin();
00504 counter != m_loaded_surfaces.end();
00505 counter++)
00506 {
00507 (*counter)->reload(true, true);
00508 }
00509 }