mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-04-19 06:50:18 +02:00
[N-Gage] Preserve source textures and optimize rotation with DDA
- Add temporary render bitmap to avoid destroying source texture data - Implement incremental DDA algorithm for rotation - Replaces per-pixel FixMul operations with simple additions and preserves textures for reuse.
This commit is contained in:
@@ -160,7 +160,7 @@ CRenderer *CRenderer::NewL()
|
||||
return self;
|
||||
}
|
||||
|
||||
CRenderer::CRenderer() : iRenderer(0), iDirectScreen(0), iScreenGc(0), iWsSession(), iWsWindowGroup(), iWsWindowGroupID(0), iWsWindow(), iWsScreen(0), iWsEventStatus(), iWsEvent(), iShowFPS(EFalse), iFPS(0), iFont(0), iWorkBuffer1(0), iWorkBuffer2(0), iWorkBufferSize(0) {}
|
||||
CRenderer::CRenderer() : iRenderer(0), iDirectScreen(0), iScreenGc(0), iWsSession(), iWsWindowGroup(), iWsWindowGroupID(0), iWsWindow(), iWsScreen(0), iWsEventStatus(), iWsEvent(), iShowFPS(EFalse), iFPS(0), iFont(0), iWorkBuffer1(0), iWorkBuffer2(0), iWorkBufferSize(0), iTempRenderBitmap(0), iTempRenderBitmapWidth(0), iTempRenderBitmapHeight(0) {}
|
||||
|
||||
CRenderer::~CRenderer()
|
||||
{
|
||||
@@ -173,6 +173,12 @@ CRenderer::~CRenderer()
|
||||
iWorkBuffer1 = 0;
|
||||
iWorkBuffer2 = 0;
|
||||
iWorkBufferSize = 0;
|
||||
|
||||
// Free temp render bitmap.
|
||||
delete iTempRenderBitmap;
|
||||
iTempRenderBitmap = 0;
|
||||
iTempRenderBitmapWidth = 0;
|
||||
iTempRenderBitmapHeight = 0;
|
||||
}
|
||||
|
||||
void CRenderer::ConstructL()
|
||||
@@ -321,6 +327,40 @@ bool CRenderer::EnsureWorkBufferCapacity(TInt aRequiredSize)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CRenderer::EnsureTempBitmapCapacity(TInt aWidth, TInt aHeight)
|
||||
{
|
||||
if (iTempRenderBitmap &&
|
||||
iTempRenderBitmapWidth >= aWidth &&
|
||||
iTempRenderBitmapHeight >= aHeight) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Delete old bitmap.
|
||||
delete iTempRenderBitmap;
|
||||
iTempRenderBitmap = 0;
|
||||
|
||||
// Create new bitmap.
|
||||
iTempRenderBitmap = new CFbsBitmap();
|
||||
if (!iTempRenderBitmap) {
|
||||
iTempRenderBitmapWidth = 0;
|
||||
iTempRenderBitmapHeight = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
TInt error = iTempRenderBitmap->Create(TSize(aWidth, aHeight), EColor4K);
|
||||
if (error != KErrNone) {
|
||||
delete iTempRenderBitmap;
|
||||
iTempRenderBitmap = 0;
|
||||
iTempRenderBitmapWidth = 0;
|
||||
iTempRenderBitmapHeight = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
iTempRenderBitmapWidth = aWidth;
|
||||
iTempRenderBitmapHeight = aHeight;
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -421,14 +461,18 @@ bool CRenderer::Copy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rec
|
||||
useBuffer1 = !useBuffer1;
|
||||
}
|
||||
|
||||
// Render directly from work buffer without copying back to bitmap.
|
||||
// Note: We need a temporary bitmap for rendering the transformed data.
|
||||
// For now, copy to original bitmap (this could be further optimized with a render target).
|
||||
Mem::Copy(phdata->cachedDataAddress, source, pitch * h);
|
||||
// Use temp bitmap to avoid destroying source texture.
|
||||
if (!EnsureTempBitmapCapacity(w, h)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy transformed data to temp bitmap.
|
||||
Mem::Copy(iTempRenderBitmap->DataAddress(), source, pitch * h);
|
||||
|
||||
// Render from temp bitmap, preserving original texture.
|
||||
TRect aSource(TPoint(srcrect->x, srcrect->y), TSize(srcrect->w, srcrect->h));
|
||||
TPoint aDest(dstrect->x, dstrect->y);
|
||||
iRenderer->Gc()->BitBlt(aDest, phdata->bitmap, aSource);
|
||||
iRenderer->Gc()->BitBlt(aDest, iTempRenderBitmap, aSource);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -500,14 +544,18 @@ bool CRenderer::CopyEx(SDL_Renderer *renderer, SDL_Texture *texture, const NGAGE
|
||||
useBuffer1 = !useBuffer1;
|
||||
}
|
||||
|
||||
// Render directly from work buffer without copying back to bitmap.
|
||||
// Note: We need a temporary bitmap for rendering the transformed data.
|
||||
// For now, copy to original bitmap (this could be further optimized with a render target).
|
||||
Mem::Copy(phdata->cachedDataAddress, source, pitch * h);
|
||||
// Use temp bitmap to avoid destroying source texture.
|
||||
if (!EnsureTempBitmapCapacity(w, h)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy transformed data to temp bitmap.
|
||||
Mem::Copy(iTempRenderBitmap->DataAddress(), source, pitch * h);
|
||||
|
||||
// Render from temp bitmap, preserving original texture.
|
||||
TRect aSource(TPoint(copydata->srcrect.x, copydata->srcrect.y), TSize(copydata->srcrect.w, copydata->srcrect.h));
|
||||
TPoint aDest(copydata->dstrect.x, copydata->dstrect.y);
|
||||
iRenderer->Gc()->BitBlt(aDest, phdata->bitmap, aSource);
|
||||
iRenderer->Gc()->BitBlt(aDest, iTempRenderBitmap, aSource);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -92,8 +92,14 @@ class CRenderer : public MDirectScreenAccess
|
||||
void *iWorkBuffer2;
|
||||
TInt iWorkBufferSize;
|
||||
|
||||
// Helper method to ensure work buffers have sufficient capacity.
|
||||
// Temporary render bitmap to avoid destroying source textures.
|
||||
CFbsBitmap *iTempRenderBitmap;
|
||||
TInt iTempRenderBitmapWidth;
|
||||
TInt iTempRenderBitmapHeight;
|
||||
|
||||
// Helper methods.
|
||||
bool EnsureWorkBufferCapacity(TInt aRequiredSize);
|
||||
bool EnsureTempBitmapCapacity(TInt aWidth, TInt aHeight);
|
||||
};
|
||||
|
||||
#endif // ngage_video_render_ngage_c_hpp
|
||||
|
||||
@@ -87,26 +87,42 @@ void ApplyRotation(void *dest, void *source, int pitch, int width, int height, T
|
||||
FixSinCos(angle, sin_angle, cos_angle);
|
||||
}
|
||||
|
||||
// Pre-calculate pitch in pixels to avoid repeated division.
|
||||
const TInt pitchPixels = pitch >> 1;
|
||||
|
||||
// Incremental DDA: Calculate per-pixel increments.
|
||||
// As we move right (x+1), the rotated position changes by (cos, -sin).
|
||||
TFixed dx_cos = cos_angle;
|
||||
TFixed dx_sin = -sin_angle;
|
||||
|
||||
for (int y = 0; y < height; ++y) {
|
||||
// Calculate destination row offset once per row.
|
||||
TInt dstRowOffset = y * pitchPixels;
|
||||
|
||||
// Calculate starting position for this row.
|
||||
TFixed translated_y = Int2Fix(y) - center_y;
|
||||
TFixed row_start_x = FixMul(translated_y, sin_angle) + center_x;
|
||||
TFixed row_start_y = FixMul(translated_y, cos_angle) + center_y;
|
||||
|
||||
// For first pixel in row, account for x=0 translation.
|
||||
TFixed src_x = row_start_x - FixMul(center_x, cos_angle);
|
||||
TFixed src_y = row_start_y + FixMul(center_x, sin_angle);
|
||||
|
||||
for (int x = 0; x < width; ++x) {
|
||||
// Translate point to origin.
|
||||
TFixed translated_x = Int2Fix(x) - center_x;
|
||||
TFixed translated_y = Int2Fix(y) - center_y;
|
||||
|
||||
// Rotate point (clockwise).
|
||||
TFixed rotated_x = FixMul(translated_x, cos_angle) + FixMul(translated_y, sin_angle);
|
||||
TFixed rotated_y = FixMul(translated_y, cos_angle) - FixMul(translated_x, sin_angle);
|
||||
|
||||
// Translate point back.
|
||||
int final_x = Fix2Int(rotated_x + center_x);
|
||||
int final_y = Fix2Int(rotated_y + center_y);
|
||||
// Convert to integer coordinates.
|
||||
int final_x = Fix2Int(src_x);
|
||||
int final_y = Fix2Int(src_y);
|
||||
|
||||
// Check bounds.
|
||||
if (final_x >= 0 && final_x < width && final_y >= 0 && final_y < height) {
|
||||
dst_pixels[y * pitch / 2 + x] = src_pixels[final_y * pitch / 2 + final_x];
|
||||
dst_pixels[dstRowOffset + x] = src_pixels[final_y * pitchPixels + final_x];
|
||||
} else {
|
||||
dst_pixels[y * pitch / 2 + x] = 0;
|
||||
dst_pixels[dstRowOffset + x] = 0;
|
||||
}
|
||||
|
||||
// Incremental step: move to next pixel (just additions, no multiplications!).
|
||||
src_x += dx_cos;
|
||||
src_y += dx_sin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user