2
* Copyright (C) 2002-2004 by the Widelands Development Team
4
* This program is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU General Public License
6
* as published by the Free Software Foundation; either version 2
7
* of the License, or (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
Management classes and functions of the 16-bit software renderer.
23
#include <SDL_image.h>
25
#include "editor_game_base.h"
27
#include "filesystem.h"
30
#include "sw16_graphic.h"
32
#include "overlay_manager.h"
33
#include "filesystem.h"
36
* Names of road terrains
38
#define ROAD_NORMAL_PIC "pics/roadt_normal.png"
39
#define ROAD_BUSY_PIC "pics/roadt_busy.png"
41
namespace Renderer_Software16
49
Helper function wraps around SDL_image. Returns the given image file as a
51
Cannot return 0, throws an exception on error.
54
SDL_Surface* LoadImage(std::string filename)
59
fr.Open(g_fs, filename);
61
surf = IMG_Load_RW(SDL_RWFromMem(fr.Data(0), fr.GetSize()), 1);
63
throw wexception("%s", IMG_GetError());
70
==============================================================================
72
RenderTargetImpl -- wrapper around a Bitmap that can be rendered into
74
==============================================================================
79
RenderTargetImpl::RenderTargetImpl
81
Build a render target for the given bitmap.
82
Note that the bitmap will not be owned by the renderer, i.e. it won't be
83
deleted by the destructor.
86
RenderTargetImpl::RenderTargetImpl(Bitmap* bmp)
96
RenderTargetImpl::~RenderTargetImpl
99
RenderTargetImpl::~RenderTargetImpl()
105
RenderTargetImpl::reset
107
Called every time before the render target is handed out by the Graphic
108
implementation to start in a neutral state.
111
void RenderTargetImpl::reset()
113
m_rect.x = m_rect.y = 0;
114
m_rect.w = m_bitmap->w;
115
m_rect.h = m_bitmap->h;
117
m_offset.x = m_offset.y = 0;
123
RenderTargetImpl::get_window [const]
125
Retrieve the current window setting.
128
void RenderTargetImpl::get_window(Rect* rc, Point* ofs) const
137
RenderTargetImpl::set_window
139
Sets an arbitrary drawing window.
142
void RenderTargetImpl::set_window(const Rect& rc, const Point& ofs)
147
// safeguards clipping against the bitmap itself
149
m_offset.x += m_rect.x;
150
m_rect.w += m_rect.x;
153
if (m_rect.x + m_rect.w > m_bitmap->w)
154
m_rect.w = m_bitmap->w - m_rect.x;
159
m_offset.y += m_rect.y;
160
m_rect.h += m_rect.y;
163
if (m_rect.y + m_rect.h > m_bitmap->h)
164
m_rect.h = m_bitmap->h - m_rect.y;
172
RenderTargetImpl::enter_window
174
Builds a subwindow. rc is relative to the current drawing window. The subwindow
175
will be clipped appropriately.
176
The previous window state is returned in previous and prevofs.
178
Returns false if the subwindow is invisible. In that case, the window state is
179
not changed at all. Otherwise, the function returns true.
182
bool RenderTargetImpl::enter_window(const Rect& rc, Rect* previous, Point* prevofs)
187
newrect.x = rc.x + m_offset.x;
188
newrect.y = rc.y + m_offset.y;
194
newofs.x = newrect.x;
195
newrect.w += newrect.x;
198
if (newrect.x + newrect.w > m_rect.w)
199
newrect.w = m_rect.w - newrect.x;
204
newofs.y = newrect.y;
205
newrect.h += newrect.y;
208
if (newrect.y + newrect.h > m_rect.h)
209
newrect.h = m_rect.h - newrect.y;
213
newrect.x += m_rect.x;
214
newrect.y += m_rect.y;
231
RenderTargetImpl::get_w [const]
232
RenderTargetImpl::get_h [const]
234
Returns the true size of the render target (ignoring the window settings).
237
int RenderTargetImpl::get_w() const
242
int RenderTargetImpl::get_h() const
248
* Render Target: draw line
250
* This functions draws a (not horizontal or vertical)
251
* line in the target, using Bresenham's algorithm
253
* This function is still quite slow, since it draws
254
* every pixel as a rectangle. So use it with care
256
void RenderTargetImpl::draw_line(int x1, int y1, int x2, int y2, RGBColor color)
258
int dx=x2-x1; /* the horizontal distance of the line */
259
int dy=y2-y1; /* the vertical distance of the line */
262
int sdx= dx < 0 ? -1 : 1;
263
int sdy= dy < 0 ? -1 : 1;
269
draw_rect(px,py,1,1,color);
271
if (dxabs>=dyabs) /* the line is more horizontal than vertical */
273
for(int i=0;i<dxabs;i++)
282
draw_rect(px,py,1,1,color);
285
else /* the line is more vertical than horizontal */
287
for(int i=0;i<dyabs;i++)
296
draw_rect(px,py,1,1,color);
302
RenderTargetImpl::draw_rect
303
RenderTargetImpl::fill_rect
304
RenderTargetImpl::brighten_rect
305
RenderTargetImpl::clear
307
Clip against window and pass those primitives along to the bitmap.
310
void RenderTargetImpl::draw_rect(int x, int y, int w, int h, RGBColor clr)
319
if (x + w > m_rect.w)
328
if (y + h > m_rect.h)
333
m_bitmap->draw_rect(Rect(x + m_rect.x, y + m_rect.y, w, h), clr);
336
void RenderTargetImpl::fill_rect(int x, int y, int w, int h, RGBColor clr)
345
if (x + w > m_rect.w)
354
if (y + h > m_rect.h)
359
m_bitmap->fill_rect(Rect(x + m_rect.x, y + m_rect.y, w, h), clr);
362
void RenderTargetImpl::brighten_rect(int x, int y, int w, int h, int factor)
371
if (x + w > m_rect.w)
380
if (y + h > m_rect.h)
385
m_bitmap->brighten_rect(Rect(x + m_rect.x, y + m_rect.y, w, h), factor);
388
void RenderTargetImpl::clear(void)
390
if (!m_rect.x && !m_rect.y && m_rect.w == m_bitmap->w && m_rect.h == m_bitmap->h)
393
m_bitmap->fill_rect(Rect(m_rect.x, m_rect.y, m_rect.w, m_rect.h), RGBColor(0,0,0));
399
RenderTargetImpl::doblit
401
Clip against window and source bitmap, then call the Bitmap blit routine.
404
void RenderTargetImpl::doblit(Point dst, Bitmap* src, Rect srcrc)
420
if (dst.x + srcrc.w > m_rect.w)
421
srcrc.w = m_rect.w - dst.x;
435
if (dst.y + srcrc.h > m_rect.h)
436
srcrc.h = m_rect.h - dst.y;
441
m_bitmap->blit(Point(dst.x + m_rect.x, dst.y + m_rect.y), src, srcrc);
447
RenderTargetImpl::blit
448
RenderTargetImpl::blitrect
450
Blits a blitsource into this bitmap
453
void RenderTargetImpl::blit(int dstx, int dsty, uint picture)
455
GraphicImpl* gfx = get_graphicimpl();
456
Bitmap* src = gfx->get_picture_bitmap(picture);
459
doblit(Point(dstx, dsty), src, Rect(0, 0, src->w, src->h));
462
void RenderTargetImpl::blitrect(int dstx, int dsty, uint picture,
463
int srcx, int srcy, int w, int h)
465
GraphicImpl* gfx = get_graphicimpl();
466
Bitmap* src = gfx->get_picture_bitmap(picture);
469
doblit(Point(dstx, dsty), src, Rect(srcx, srcy, w, h));
475
RenderTargetImpl::tile
477
Fill the given rectangle with the given picture.
478
The pixel from (ofsx/ofsy) inside picture is placed at the top-left corner of
479
the filled rectangle.
482
void RenderTargetImpl::tile(int x, int y, int w, int h, uint picture, int ofsx, int ofsy)
484
GraphicImpl* gfx = get_graphicimpl();
485
Bitmap* src = gfx->get_picture_bitmap(picture);
488
log("RenderTargetImpl::tile: bad picture %u\n", picture);
500
if (x + w > m_rect.w)
509
if (y + h > m_rect.h)
514
// Make sure the offset is within bounds
515
ofsx = ofsx % src->w;
519
ofsy = ofsy % src->h;
523
// Blit the picture into the rectangle
533
srcrc.h = src->h - ofsy;
534
if (ty + srcrc.h > h)
540
srcrc.w = src->w - tofsx;
541
if (tx + srcrc.w > w)
544
m_bitmap->blit(Point(m_rect.x + x + tx, m_rect.y + y + ty), src, srcrc);
559
Draw build help, frontier and registered overlays
562
static void draw_overlays(RenderTargetImpl* dst, Editor_Game_Base* egbase, const std::vector<bool>* visibility, FCoords fc, Point pos,
563
FCoords fcr, Point posr, FCoords fcbl, Point posbl, FCoords fcbr, Point posbr)
567
if((player=egbase->get_map()->get_overlay_manager()->is_frontier_field(fc))) {
568
Player *ownerplayer = egbase->get_player(player);
569
uint anim = ownerplayer->get_tribe()->get_frontier_anim();
570
const RGBColor* playercolors = ownerplayer->get_playercolor();
572
dst->drawanim(pos.x, pos.y, anim, 0, playercolors);
574
// check to the right
575
if(egbase->get_map()->get_overlay_manager()->draw_border_to_right(fc))
576
dst->drawanim((pos.x+posr.x)/2, (pos.y+posr.y)/2, anim, 0, playercolors);
577
// check to the bottom left
578
if(egbase->get_map()->get_overlay_manager()->draw_border_to_bottom_left(fc))
579
dst->drawanim((pos.x+posbl.x)/2, (pos.y+posbl.y)/2, anim, 0, playercolors);
580
// check to the bottom right
581
if(egbase->get_map()->get_overlay_manager()->draw_border_to_right(fcbl))
582
dst->drawanim((pos.x+posbr.x)/2, (pos.y+posbr.y)/2, anim, 0, playercolors);
585
// Draw normal buildhelp
586
Overlay_Manager::Overlay_Info overlay_info[MAX_OVERLAYS_PER_FIELD];
587
int num_overlays=egbase->get_map()->get_overlay_manager()->get_overlays(fc, overlay_info);
590
for(i=0; i<num_overlays; i++) {
591
int x = pos.x - overlay_info[i].hotspot_x;
592
int y = pos.y - overlay_info[i].hotspot_y;
594
dst->blit(x,y,overlay_info[i].picid);
601
RenderTargetImpl::rendermap
603
Render the map into the current drawing window.
604
viewofs is the offset of the upper left corner of the window into the map,
608
void RenderTargetImpl::rendermap(Editor_Game_Base* egbase, const std::vector<bool>* visibility, Point viewofs)
612
viewofs.x -= m_offset.x;
613
viewofs.y -= m_offset.y;
615
dst.pixels = &m_bitmap->pixels[m_rect.y * m_bitmap->pitch + m_rect.x];
616
dst.pitch = m_bitmap->pitch;
619
dst.hasclrkey = false; // should be irrelevant
621
// Completely clear the window
624
// Actually draw the map. Loop through fields row by row
625
// For each field, draw ground textures, then roads, then immovables
626
// (and borders), then bobs, then overlay stuff (build icons etc...)
627
//Player *player = m_player->get_player();
628
Map* map = egbase->get_map();
629
int mapwidth = map->get_width();
633
minfx = (viewofs.x + (FIELD_WIDTH>>1)) / FIELD_WIDTH - 1; // hack to prevent negative numbers
634
minfy = viewofs.y / (FIELD_HEIGHT>>1);
635
maxfx = (viewofs.x + (FIELD_WIDTH>>1) + dst.w) / FIELD_WIDTH;
636
maxfy = (viewofs.y + dst.h) / (FIELD_HEIGHT>>1);
637
maxfx += 1; // because of big buildings
638
maxfy += 10; // necessary because of heights
640
//log("%i %i -> %i %i\n", minfx, minfy, maxfx, maxfy);
641
int dx = maxfx - minfx + 1;
642
int dy = maxfy - minfy + 1;
643
int linear_fy = minfy;
646
int linear_fx = minfx;
652
// Use linear (non-wrapped) coordinates to calculate on-screen pos
653
map->get_basepix(Coords(linear_fx, linear_fy), &posx, &posy);
657
// Get linear bottom-left coordinate
659
bl.x = linear_fx - (bl.y&1);
661
map->get_basepix(bl, &blposx, &bposy);
665
// Get linear top-left coordinates
667
tl.x = linear_fx - (tl.y&1);
669
map->get_basepix(tl, &tlposx, &tposy);
673
// Calculate safe (bounded) field coordinates and get field pointers
676
map->normalize_coords(&f);
677
map->normalize_coords(&bl);
678
map->normalize_coords(&tl);
680
f.field = map->get_field(f);
681
bl.field = map->get_field(bl);
682
tl.field = map->get_field(tl);
686
FCoords br, r, l, tr;
687
int rposx, brposx, lposx, trposx;
692
rposx = posx + FIELD_WIDTH;
695
lposx = posx - FIELD_WIDTH;
697
map->get_rn(bl, &br);
698
brposx = blposx + FIELD_WIDTH;
700
map->get_rn(tl, &tr);
701
trposx = tlposx + FIELD_WIDTH;
704
if (!(*visibility)[f.y*mapwidth + f.x] ||
705
!(*visibility)[br.y*mapwidth + br.x]) {
709
if(!(*visibility)[bl.y*mapwidth + bl.x])
711
if(!(*visibility)[r.y*mapwidth + r.x])
716
// Render stuff that belongs to ground triangles
717
if (render_b || render_r) {
718
uchar roads = f.field->get_roads();
720
roads |= egbase->get_map()->get_overlay_manager()->get_road_overlay(f);
722
dst.draw_field(f.field, r.field, bl.field, br.field, l.field, tr.field,
723
posx, rposx, posy, blposx, brposx, bposy, roads, render_r, render_b);
726
// Render stuff that belongs to the field node
727
if (!visibility || (*visibility)[f.y*mapwidth + f.x])
729
Point wh_pos(posx, posy - MULTIPLY_WITH_HEIGHT_FACTOR(f.field->get_height()));
732
// TODO - rendering order?
733
// This must be defined somewho. some bobs have a higher priority than others
734
// ^-- maybe this priority is a moving vs. non-moving bobs thing?
735
// draw_ground implies that this doesn't render map objects.
736
// are there any overdraw issues with the current rendering order?
738
// Draw Map_Objects hooked to this field
739
BaseImmovable *imm = f.field->get_immovable();
744
imm->draw(egbase, this, f, wh_pos);
746
Bob *bob = f.field->get_first_bob();
748
bob->draw(egbase, this, wh_pos);
749
bob = bob->get_next_bob();
752
// Draw buildhelp, road buildhelp
753
draw_overlays(this, egbase, visibility, f, wh_pos,
754
r, Point(rposx, posy-MULTIPLY_WITH_HEIGHT_FACTOR(r.field->get_height())),
755
bl, Point(blposx, bposy-MULTIPLY_WITH_HEIGHT_FACTOR(bl.field->get_height())),
756
br, Point(brposx, bposy-MULTIPLY_WITH_HEIGHT_FACTOR(br.field->get_height())));
760
// Advance to next field in row
778
RenderTargetImpl::renderminimap
780
Renders a minimap into the current window.
781
The field at viewpt will be in the top-left corner of the window.
782
flags specifies what information to display (see Minimap_XXX enums).
785
void RenderTargetImpl::renderminimap(Editor_Game_Base* egbase, const std::vector<bool>* visibility, Coords viewpt, uint flags)
789
// The entire clipping rect will be used for drawing
792
// Calculate the field at the top-left corner of the clipping rect
793
viewpt.x -= m_offset.x;
794
viewpt.y -= m_offset.y;
796
m_bitmap->draw_minimap(egbase, visibility, rc, viewpt, flags);
802
RenderTargetImpl::drawanim
804
Draws a frame of an animation at the given location
807
void RenderTargetImpl::drawanim(int dstx, int dsty, uint animation, uint time, const RGBColor* plrclrs)
809
const AnimationData* data = g_anim.get_animation(animation);
810
const AnimationGfx* gfx = get_graphicimpl()->get_animation(animation);
811
const AnimFrame* frame;
815
log("WARNING: Animation %i doesn't exist\n", animation);
819
// Get the frame and its data
820
frame = gfx->get_frame((time / data->frametime) % gfx->get_nrframes());
824
dstx -= frame->hotspot.x;
825
dsty -= frame->hotspot.y;
830
rc.h = frame->height;
839
if (dstx + rc.w > m_rect.w)
840
rc.w = m_rect.w - dstx;
849
if (dsty + rc.h > m_rect.h)
850
rc.h = m_rect.h - dsty;
856
m_bitmap->draw_animframe(Point(dstx + m_rect.x, dsty + m_rect.y), frame, rc, plrclrs);
862
RenderTargetImpl::drawanimrect
864
Draws a part of a frame of an animation at the given location
867
void RenderTargetImpl::drawanimrect(int dstx, int dsty, uint animation, uint time, const RGBColor* plrclrs,
868
int srcx, int srcy, int w, int h)
870
const AnimationData* data = g_anim.get_animation(animation);
871
const AnimationGfx* gfx = get_graphicimpl()->get_animation(animation);
872
const AnimFrame* frame;
876
log("WARNING: Animation %i doesn't exist\n", animation);
880
// Get the frame and its data
881
frame = gfx->get_frame((time / data->frametime) % gfx->get_nrframes());
885
dstx -= frame->hotspot.x;
886
dsty -= frame->hotspot.y;
893
rc.w = w; //frame->width;
894
rc.h = h; //frame->height;
896
// Clipping against source
902
if (rc.x + rc.w > frame->width)
903
rc.w = frame->width - rc.x;
912
if (rc.y + rc.h > frame->height)
913
rc.h = frame->height - rc.y;
917
// Clipping against destination
923
if (dstx + rc.w > m_rect.w)
924
rc.w = m_rect.w - dstx;
933
if (dsty + rc.h > m_rect.h)
934
rc.h = m_rect.h - dsty;
940
m_bitmap->draw_animframe(Point(dstx + m_rect.x, dsty + m_rect.y), frame, rc, plrclrs);
945
===============================================================================
947
GraphicImpl -- 16 bit software implementation of main graphics interface
949
===============================================================================
954
GraphicImpl::GraphicImpl
956
Initialize the SDL video mode.
959
GraphicImpl::GraphicImpl(int w, int h, bool fullscreen)
961
m_nr_update_rects = 0;
962
m_update_fullscreen = false;
965
// Set video mode using SDL
966
int flags = SDL_SWSURFACE;
969
flags |= SDL_FULLSCREEN;
971
m_sdlsurface = SDL_SetVideoMode(w, h, 16, flags);
973
throw wexception("Couldn't set video mode: %s", SDL_GetError());
975
SDL_WM_SetCaption("Widelands " VERSION, "Widelands");
977
m_screen.w = m_sdlsurface->w;
978
m_screen.h = m_sdlsurface->h;
979
m_screen.pitch = m_sdlsurface->pitch / sizeof(ushort);
980
m_screen_pixels_size_in_bytes=m_screen.pitch*h*sizeof(ushort);
981
m_lock_sdl_surface=SDL_MUSTLOCK(m_sdlsurface);
982
if(m_lock_sdl_surface) {
983
m_screen.pixels = (ushort*)malloc(m_screen.pitch*h*sizeof(ushort));
985
m_screen.pixels = (ushort*)m_sdlsurface->pixels;
987
m_rendertarget = new RenderTargetImpl(&m_screen);
992
GraphicImpl::~GraphicImpl
997
GraphicImpl::~GraphicImpl()
999
if(m_lock_sdl_surface)
1000
free(m_screen.pixels);
1004
if(m_roadtextures) {
1005
delete m_roadtextures;
1009
delete m_rendertarget;
1010
SDL_FreeSurface(m_sdlsurface);
1015
GraphicImpl::get_xres
1016
GraphicImpl::get_yres
1018
Return the screen resolution
1021
int GraphicImpl::get_xres()
1023
return m_sdlsurface->w;
1026
int GraphicImpl::get_yres()
1028
return m_sdlsurface->h;
1033
GraphicImpl::get_render_target
1035
Return a pointer to the RenderTarget representing the screen
1038
RenderTarget* GraphicImpl::get_render_target()
1040
m_rendertarget->reset();
1042
return m_rendertarget;
1047
GraphicImpl::update_fullscreen
1049
Mark the entire screen for refreshing
1052
void GraphicImpl::update_fullscreen()
1054
m_update_fullscreen = true;
1059
GraphicImpl::update_rectangle
1061
Mark a rectangle for refreshing
1064
void GraphicImpl::update_rectangle(int x, int y, int w, int h)
1066
if (m_nr_update_rects >= MAX_RECTS)
1068
m_update_fullscreen = true;
1072
m_update_rects[m_nr_update_rects].x = x;
1073
m_update_rects[m_nr_update_rects].y = y;
1074
m_update_rects[m_nr_update_rects].w = w;
1075
m_update_rects[m_nr_update_rects].h = h;
1076
++m_nr_update_rects;
1081
GraphicImpl::need_update
1083
Returns true if parts of the screen have been marked for refreshing.
1086
bool GraphicImpl::need_update()
1088
return m_nr_update_rects || m_update_fullscreen;
1093
GraphicImpl::refresh
1095
Bring the screen uptodate.
1098
void GraphicImpl::refresh()
1100
// if (m_update_fullscreen)
1101
if(m_lock_sdl_surface) {
1102
if(SDL_LockSurface(m_sdlsurface)) // When lock failed, do not draw this frame
1104
memcpy(m_sdlsurface->pixels, m_screen.pixels, m_screen_pixels_size_in_bytes);
1105
SDL_UnlockSurface(m_sdlsurface);
1108
SDL_UpdateRect(m_sdlsurface, 0, 0, 0, 0);
1111
// SDL_UpdateRects(m_sdlsurface, m_nr_update_rects, m_update_rects);
1114
m_update_fullscreen = false;
1115
m_nr_update_rects = 0;
1123
Remove all resources (currently pictures) from the given modules.
1124
If mod is 0, all pictures are flushed.
1127
void GraphicImpl::flush(int mod)
1132
for(i = 0; i < m_pictures.size(); i++) {
1133
Picture* pic = &m_pictures[i];
1135
// NoLog("Flushing picture: %i while flushing all!\n", i);
1142
log("LEAK: SW16: flush(0): non-picture %i left.\n", i+1);
1146
pic->mod &= ~mod; // unmask the mods that should be flushed
1148
// Once the picture is no longer in any mods, free it
1152
m_picturemap.erase(pic->u.fname);
1155
if(pic->bitmap.pixels)
1156
free(pic->bitmap.pixels);
1161
if (!mod || mod & PicMod_Game) {
1162
for(i = 0; i < m_maptextures.size(); i++)
1163
delete m_maptextures[i];
1164
m_maptextures.resize(0);
1166
for(i = 0; i < m_animations.size(); i++)
1167
delete m_animations[i];
1168
m_animations.resize(0);
1170
if( m_roadtextures ) {
1171
delete m_roadtextures;
1180
GraphicImpl::get_picture
1182
Retrieves the picture ID of the picture with the given filename.
1183
If the picture has already been loaded, the old ID is reused.
1184
The picture is placed into the module(s) given by mod.
1186
Returns 0 (a null-picture) if the picture cannot be loaded.
1189
uint GraphicImpl::get_picture(int mod, const char* fname, bool buse_clrkey)
1193
// Check if the picture's already loaded
1194
picmap_t::iterator it = m_picturemap.find(fname);
1196
if (it != m_picturemap.end())
1206
bmp = LoadImage(fname);
1208
catch(std::exception& e)
1210
log("WARNING: Couldn't open %s: %s\n", fname, e.what());
1214
SDL_Surface* cv = SDL_ConvertSurface(bmp, m_sdlsurface->format, 0);
1216
// Fill in a free slot in the pictures array
1219
id = find_free_picture();
1220
pic = &m_pictures[id];
1222
pic->mod = 0; // will be filled in by caller
1223
pic->u.fname = strdup(fname);
1224
pic->bitmap.pixels = (ushort*)malloc(cv->w*cv->h*2);
1225
pic->bitmap.w = cv->w;
1226
pic->bitmap.h = cv->h;
1227
pic->bitmap.pitch = cv->w;
1228
pic->bitmap.hasclrkey = false;
1230
SDL_LockSurface(cv); // paranoia
1231
for(int y = 0; y < cv->h; y++)
1232
memcpy(pic->bitmap.pixels + y*cv->w, (Uint8*)cv->pixels + y*cv->pitch, cv->w*2);
1233
SDL_UnlockSurface(cv);
1235
SDL_FreeSurface(cv);
1236
SDL_FreeSurface(bmp);
1238
m_picturemap[pic->u.fname] = id;
1241
m_pictures[id].mod |= mod;
1242
use_clrkey(id,buse_clrkey);
1247
void GraphicImpl::use_clrkey(uint id, bool t) {
1248
if (id >= m_pictures.size() || !m_pictures[id].mod)
1249
throw wexception("get_picture_size(%i): picture doesn't exist", id);
1250
m_pictures[id].bitmap.clrkey = *m_pictures[id].bitmap.pixels;
1251
m_pictures[id].bitmap.hasclrkey = t;
1254
bool GraphicImpl::has_clrkey(uint id) {
1255
if (id >= m_pictures.size() || !m_pictures[id].mod)
1256
throw wexception("get_picture_size(%i): picture doesn't exist", id);
1257
return m_pictures[id].bitmap.hasclrkey;
1262
// TODO: get rid of this function (needs change of font format)
1263
uint GraphicImpl::get_picture(int mod, int w, int h, const ushort* data, RGBColor clrkey)
1265
uint id = find_free_picture();
1266
Picture* pic = &m_pictures[id];
1270
pic->bitmap.pixels = (ushort*)malloc(w*h*2);
1273
pic->bitmap.pitch = w;
1274
pic->bitmap.hasclrkey = true;
1275
pic->bitmap.clrkey = clrkey.pack16();
1277
memcpy(pic->bitmap.pixels, data, w*h*2);
1285
GraphicImpl::get_picture_size
1287
Stores the picture size in pw and ph.
1288
Throws an exception if the picture doesn't exist.
1291
void GraphicImpl::get_picture_size(uint pic, int* pw, int* ph)
1293
if (pic >= m_pictures.size() || !m_pictures[pic].mod)
1294
throw wexception("get_picture_size(%i): picture doesn't exist", pic);
1296
Bitmap* bmp = &m_pictures[pic].bitmap;
1305
GraphicImpl::create_surface
1307
Create an offscreen surface that can be used both as target and as source for
1308
rendering operations. The surface is put into a normal slot in the picture
1309
array so the surface can be used in normal blit() operations.
1310
A RenderTarget for the surface can be obtained using get_surface_renderer().
1311
Note that surfaces do not belong to a module and must be freed explicitly.
1314
uint GraphicImpl::create_surface(int w, int h)
1316
uint id = find_free_picture();
1317
Picture* pic = &m_pictures[id];
1319
pic->mod = -1; // mark as surface
1320
pic->bitmap.pixels = (ushort*)malloc(w*h*sizeof(ushort));
1323
pic->bitmap.pitch = w;
1324
pic->bitmap.hasclrkey = false;
1325
pic->u.rendertarget = new RenderTargetImpl(&pic->bitmap);
1330
uint GraphicImpl::create_surface(int w, int h, RGBColor clrkey)
1332
uint id = create_surface(w, h);
1333
Picture* pic = &m_pictures[id];
1335
pic->bitmap.hasclrkey = true;
1336
pic->bitmap.clrkey = clrkey.pack16();
1344
GraphicImpl::free_surface
1346
Free the given surface.
1347
Unlike normal pictures, surfaces are not freed by flush().
1350
void GraphicImpl::free_surface(uint picid)
1352
assert(picid < m_pictures.size() && m_pictures[picid].mod == -1);
1354
Picture* pic = &m_pictures[picid];
1356
delete pic->u.rendertarget;
1357
free(pic->bitmap.pixels);
1364
GraphicImpl::get_surface_renderer
1366
Returns the RenderTarget for the given surface
1369
RenderTarget* GraphicImpl::get_surface_renderer(uint pic)
1371
assert(pic < m_pictures.size() && m_pictures[pic].mod == -1);
1373
RenderTargetImpl* rt = m_pictures[pic].u.rendertarget;
1383
GraphicImpl::get_picture_bitmap
1385
Returns the bitmap that belongs to the given picture ID.
1386
May return 0 if the given picture does not exist.
1389
Bitmap* GraphicImpl::get_picture_bitmap(uint id)
1391
if (id >= m_pictures.size())
1394
if (!m_pictures[id].mod)
1397
return &m_pictures[id].bitmap;
1403
GraphicImpl::get_maptexture
1405
Creates a terrain texture.
1406
fnametempl is a filename with possible wildcard characters '?'. The function
1407
fills the wildcards with decimal numbers to get the different frames of a
1408
texture animation. For example, if fnametempl is "foo_??.bmp", it tries
1409
"foo_00.bmp", "foo_01.bmp" etc...
1410
frametime is in milliseconds.
1412
Returns 0 if the texture couldn't be loaded.
1414
Note: Terrain textures are not reused, even if fnametempl matches.
1415
These textures are freed when PicMod_Game is flushed.
1418
uint GraphicImpl::get_maptexture(const char* fnametempl, uint frametime)
1421
Texture* tex = new Texture(fnametempl, frametime);
1423
m_maptextures.push_back(tex);
1425
return m_maptextures.size(); // ID 1 is at m_maptextures[0]
1426
} catch(std::exception& e) {
1427
log("Failed to load maptexture %s: %s\n", fnametempl, e.what());
1435
GraphicImpl::animate_maptextures
1437
Advance frames for animated textures
1440
void GraphicImpl::animate_maptextures(uint time)
1442
for(uint i = 0; i < m_maptextures.size(); i++)
1443
m_maptextures[i]->animate(time);
1449
GraphicImpl::get_maptexture_data
1451
Return the actual texture data associated with the given ID.
1454
Texture* GraphicImpl::get_maptexture_data(uint id)
1456
id--; // ID 1 is at m_maptextures[0]
1458
if (id < m_maptextures.size())
1459
return m_maptextures[id];
1466
GraphicImp::get_road_textures
1468
returns the road textures
1471
Bitmap* GraphicImpl::get_road_texture( int roadtex) {
1472
if(! m_roadtextures ) {
1473
// Load the road textures
1474
m_roadtextures = new Road_Textures();
1475
m_roadtextures->pic_road_normal = get_picture(PicMod_Game, ROAD_NORMAL_PIC, 0);
1476
m_roadtextures->pic_road_busy = get_picture(PicMod_Game, ROAD_BUSY_PIC , 0);
1478
if(roadtex == Road_Normal)
1479
return get_picture_bitmap(m_roadtextures->pic_road_normal);
1481
return get_picture_bitmap(m_roadtextures->pic_road_busy);
1486
GraphicImp::get_texture_picture
1488
Return Filename of texture of given ID.
1491
const char* GraphicImpl::get_maptexture_picture(uint id) {
1492
Texture* tex = get_maptexture_data(id);
1494
return tex->get_texture_picture();
1502
GraphicImpl::load_animations
1504
Load all animations that are registered with the AnimationManager
1507
void GraphicImpl::load_animations()
1509
assert(!m_animations.size());
1511
for(uint id = 1; id <= g_anim.get_nranimations(); id++)
1512
m_animations.push_back(new AnimationGfx(g_anim.get_animation(id)));
1518
GraphicImpl::get_animation
1520
Retrieve the animation graphics
1523
AnimationGfx* GraphicImpl::get_animation(uint anim)
1525
if (!anim || anim > m_animations.size())
1528
return m_animations[anim-1];
1532
* Return the number of frames in this animation
1534
int GraphicImpl::get_animation_nr_frames(uint anim) {
1535
AnimationGfx* gfx=get_animation(anim);
1536
return gfx->get_nrframes();
1541
GraphicImpl::get_animation_size
1543
Return the size of the animation at the given time.
1546
void GraphicImpl::get_animation_size(uint anim, uint time, int* pw, int* ph)
1548
const AnimationData* data = g_anim.get_animation(anim);
1549
const AnimationGfx* gfx = get_graphicimpl()->get_animation(anim);
1550
const AnimFrame* frame;
1555
log("WARNING: Animation %i doesn't exist\n", anim);
1560
// Get the frame and its data
1561
frame = gfx->get_frame((time / data->frametime) % gfx->get_nrframes());
1578
GraphicImpl::screenshot
1580
Save a screenshot in the given file.
1583
void GraphicImpl::screenshot(const char* fname)
1585
// TODO: this is incorrect; it bypasses the files code
1586
SDL_SaveBMP(m_sdlsurface, fname);
1593
GraphicImpl::find_free_picture
1595
Find a free picture slot and return it.
1598
uint GraphicImpl::find_free_picture()
1602
for(id = 1; id < m_pictures.size(); id++)
1603
if (!m_pictures[id].mod)
1606
m_pictures.resize(id+1);
1612
* GraphicImpl::flush_picture(int)
1614
void GraphicImpl::flush_picture(uint pic_index) {
1615
Picture* pic = &m_pictures[pic_index];
1619
m_picturemap.erase(pic->u.fname);
1623
free(pic->bitmap.pixels);
1624
pic->bitmap.pixels=0;
1628
* Save and load pictures
1630
#define PICTURE_VERSION 1
1631
void GraphicImpl::save_pic_to_file(uint pic_index, FileWrite* fw) {
1632
Picture* pic = &m_pictures[pic_index];
1634
// First the version
1635
fw->Unsigned16(PICTURE_VERSION);
1638
fw->Unsigned8(pic->bitmap.hasclrkey);
1640
// Now width and height
1641
fw->Unsigned16(pic->bitmap.w);
1642
fw->Unsigned16(pic->bitmap.h);
1644
// now all the data as RGB values
1645
for(int h=0; h<pic->bitmap.h; h++) {
1646
for(int w=0; w<pic->bitmap.w; w++) {
1647
ushort clr=pic->bitmap.pixels[h*pic->bitmap.pitch+w];
1649
unpack_rgb(clr, &r,&g,&b);
1657
uint GraphicImpl::load_pic_from_file(FileRead* fr, int mod) {
1658
// First the version
1659
int version=fr->Unsigned16();
1660
if(version<=PICTURE_VERSION) {
1661
bool has_clrkey=fr->Unsigned8();
1662
// NoLog("Load picture:\n has clrkey: %i\n", has_clrkey);
1663
int g_w=fr->Unsigned16();
1664
int g_h=fr->Unsigned16();
1665
// NoLog(" Width: %i, Height: %i\n", g_w, g_h);
1667
ushort* pixels=(ushort*)malloc(sizeof(ushort)*g_w*g_h);
1668
for(int h=0; h<g_h; h++) {
1669
for(int w=0; w<g_w; w++) {
1670
ushort* clr=&pixels[h*g_w+w];
1675
// NoLog(" Pixel: (%i,%i) has color RGB(%i,%i,%i)\n", w, h, r, g, b);
1676
*clr=pack_rgb(r,g,b);
1680
uint id = find_free_picture();
1681
// NoLog(" Got Free id: %i\n", id);
1682
Picture* pic = &m_pictures[id];
1686
pic->bitmap.pixels = pixels;
1687
pic->bitmap.w = g_w;
1688
pic->bitmap.h = g_h;
1689
pic->bitmap.pitch = g_w;
1690
pic->bitmap.hasclrkey = has_clrkey;
1691
pic->bitmap.clrkey = *pixels; // Upper left pixel
1695
throw wexception("Unknown picture version %i in file!\n", version);
1698
} // namespace Renderer_Software16
1705
Factory function called by System code
1708
Graphic* SW16_CreateGraphics(int w, int h, bool fullscreen)
1710
return new Renderer_Software16::GraphicImpl(w, h, fullscreen);