diff --git a/src/Agent.h b/src/Agent.h index 1d6d756b8..11dc6edb4 100644 --- a/src/Agent.h +++ b/src/Agent.h @@ -218,6 +218,14 @@ class Agent : public std::enable_shared_from_this { int thrt = 0; int size = 0; + // drawing + uint8_t alpha = 255; + bool draw_mirrored = false; + float scle = 1.0; // Sea-Monkeys only + bool strc = false; // Sea-Monkeys only + unsigned int strc_width; // Sea-Monkeys only + unsigned int strc_height; // Sea-Monkeys only + Agent(unsigned char f, unsigned char g, unsigned short s, unsigned int p); virtual ~Agent(); diff --git a/src/Backend.h b/src/Backend.h index e6b62f595..c67e60dce 100644 --- a/src/Backend.h +++ b/src/Backend.h @@ -32,10 +32,22 @@ using std::shared_ptr; class creaturesImage; +struct RenderOptions { + uint8_t alpha = 255; + bool mirror = false; + float scale = 1.0; + bool override_drawsize = false; + int overridden_drawwidth; + int overridden_drawheight; +}; + class RenderTarget { public: - virtual void renderCreaturesImage(creaturesImage& tex, unsigned int frame, int x, int y, uint8_t transparency = 0, bool mirror = false) = 0; - virtual void renderCreaturesImage(const std::shared_ptr& tex, unsigned int frame, int x, int y, uint8_t transparency = 0, bool mirror = false) = 0; + virtual void renderCreaturesImage(creaturesImage& tex, unsigned int frame, int x, int y, RenderOptions options = {}) = 0; + void renderCreaturesImage(const std::shared_ptr& tex, unsigned int frame, int x, int y, RenderOptions options = {}) { + assert(tex.get() != nullptr); + renderCreaturesImage(*tex.get(), frame, x, y, options); + } virtual void renderLine(int x1, int y1, int x2, int y2, unsigned int colour) = 0; virtual void blitRenderTarget(RenderTarget* src, int x, int y, int w, int h) = 0; virtual unsigned int getWidth() const = 0; diff --git a/src/CompoundPart.cpp b/src/CompoundPart.cpp index 465e465de..e21a1cca6 100644 --- a/src/CompoundPart.cpp +++ b/src/CompoundPart.cpp @@ -86,8 +86,6 @@ CompoundPart::CompoundPart(Agent* p, unsigned int _id, int _x, int _y, int _z) addZOrder(); x = _x; y = _y; - - has_alpha = false; } CompoundPart::~CompoundPart() { diff --git a/src/CompoundPart.h b/src/CompoundPart.h index 8da685c59..b15a6bd43 100644 --- a/src/CompoundPart.h +++ b/src/CompoundPart.h @@ -42,9 +42,6 @@ class CompoundPart : public renderable { unsigned int zorder, id; unsigned int part_sequence_number; - bool has_alpha; - unsigned char alpha; - virtual void render(class RenderTarget* renderer, int xoffset, int yoffset); virtual void partRender(class RenderTarget* renderer, int xoffset, int yoffset) = 0; virtual void tick() {} diff --git a/src/SpritePart.cpp b/src/SpritePart.cpp index b13bdb304..afab883ac 100644 --- a/src/SpritePart.cpp +++ b/src/SpritePart.cpp @@ -22,7 +22,6 @@ SpritePart::SpritePart(Agent* p, unsigned int _id, std::string spritefile, unsig is_transparent = (engine.version > 2); framerate = 1; framedelay = 0; - draw_mirrored = false; if (sprite->numframes() <= firstimg) { if (engine.gametype == "cv") { @@ -54,7 +53,16 @@ void SpritePart::partRender(RenderTarget* renderer, int xoffset, int yoffset) { } } assert(getCurrentSprite() < getSprite()->numframes()); - renderer->renderCreaturesImage(getSprite(), getCurrentSprite(), xoffset + x, yoffset + y, has_alpha ? alpha : 0, draw_mirrored); + RenderOptions render_opts; + render_opts.alpha = parent->alpha; + render_opts.mirror = parent->draw_mirrored; + render_opts.scale = parent->scle; + if (parent->strc) { + render_opts.override_drawsize = true; + render_opts.overridden_drawwidth = parent->strc_width; + render_opts.overridden_drawheight = parent->strc_height; + } + renderer->renderCreaturesImage(getSprite(), getCurrentSprite(), xoffset + x, yoffset + y, render_opts); } void SpritePart::setFrameNo(unsigned int f) { diff --git a/src/SpritePart.h b/src/SpritePart.h index 6e7c035f9..d3bc5cf80 100644 --- a/src/SpritePart.h +++ b/src/SpritePart.h @@ -11,7 +11,6 @@ class SpritePart : public AnimatablePart { public: bool is_transparent; - bool draw_mirrored; unsigned char framerate; unsigned int framedelay; std::shared_ptr getSprite() { return sprite; } diff --git a/src/TextEntryPart.cpp b/src/TextEntryPart.cpp index b1cb8427b..d826e4101 100644 --- a/src/TextEntryPart.cpp +++ b/src/TextEntryPart.cpp @@ -98,7 +98,9 @@ void TextEntryPart::partRender(RenderTarget* renderer, int xoffset, int yoffset) void TextEntryPart::renderCaret(RenderTarget* renderer, int xoffset, int yoffset) { // TODO: fudge xoffset/yoffset as required - renderer->renderCreaturesImage(caretsprite, caretpose, xoffset, yoffset, has_alpha ? alpha : 0); + RenderOptions render_opts; + render_opts.alpha = parent->alpha; + renderer->renderCreaturesImage(caretsprite, caretpose, xoffset, yoffset, render_opts); } void TextEntryPart::tick() { diff --git a/src/TextPart.cpp b/src/TextPart.cpp index 981e82d45..6675e2e4c 100644 --- a/src/TextPart.cpp +++ b/src/TextPart.cpp @@ -1,5 +1,6 @@ #include "TextPart.h" +#include "Agent.h" #include "Backend.h" #include "Engine.h" #include "TextEntryPart.h" @@ -262,7 +263,9 @@ void TextPart::partRender(RenderTarget* renderer, int xoffset, int yoffset, Text if (((unsigned char)lines[i].text[x]) < 32) continue; // TODO: replace with space or similar? int spriteid = ((unsigned char)lines[i].text[x]) - 32; - renderer->renderCreaturesImage(sprite_to_use, spriteid, somex + currentx, yoff + currenty, has_alpha ? alpha : 0); + RenderOptions render_opts; + render_opts.alpha = parent->alpha; + renderer->renderCreaturesImage(sprite_to_use, spriteid, somex + currentx, yoff + currenty, render_opts); if ((caretdata) && (caretdata->caretpos == lines[i].offset + x)) caretdata->renderCaret(renderer, somex + currentx, yoff + currenty); currentx += textsprite->width(spriteid) + charspacing; diff --git a/src/backends/NullBackend.h b/src/backends/NullBackend.h index 864dace54..4327158ec 100644 --- a/src/backends/NullBackend.h +++ b/src/backends/NullBackend.h @@ -26,8 +26,7 @@ class NullRenderTarget : public RenderTarget { public: - virtual void renderCreaturesImage(creaturesImage&, unsigned int, int, int, uint8_t, bool) {} - virtual void renderCreaturesImage(const std::shared_ptr&, unsigned int, int, int, uint8_t, bool) {} + virtual void renderCreaturesImage(creaturesImage&, unsigned int, int, int, RenderOptions) {} virtual void renderLine(int, int, int, int, unsigned int) {} virtual void blitRenderTarget(RenderTarget*, int, int, int, int) {} virtual unsigned int getWidth() const { return 800; } diff --git a/src/backends/SDLBackend.cpp b/src/backends/SDLBackend.cpp index 4b5959903..b07c3fb3e 100644 --- a/src/backends/SDLBackend.cpp +++ b/src/backends/SDLBackend.cpp @@ -309,7 +309,7 @@ unsigned int SDLRenderTarget::getHeight() const { return drawableheight / scale - viewport_offset_top - viewport_offset_bottom; } -void SDLRenderTarget::renderCreaturesImage(creaturesImage& img, unsigned int frame, int x, int y, uint8_t transparency, bool mirror) { +void SDLRenderTarget::renderCreaturesImage(creaturesImage& img, unsigned int frame, int x, int y, RenderOptions options) { if ((x + img.width(frame) <= 0 || x >= (int)getWidth()) && (y + img.height(frame) <= 0 || y >= (int)getHeight())) { return; } @@ -321,8 +321,8 @@ void SDLRenderTarget::renderCreaturesImage(creaturesImage& img, unsigned int fra SDL_Texture* tex = img.getTextureForFrame(frame).as(); assert(tex); - SDL_SetTextureAlphaMod(tex, 255 - transparency); - SDL_RendererFlip flip = mirror ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE; + SDL_SetTextureAlphaMod(tex, options.alpha); + SDL_RendererFlip flip = options.mirror ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE; SDL_Rect srcrect; srcrect.x = img.getXOffsetForFrame(frame); @@ -333,18 +333,13 @@ void SDLRenderTarget::renderCreaturesImage(creaturesImage& img, unsigned int fra SDL_Rect destrect; destrect.x = x; destrect.y = y + viewport_offset_top; - destrect.w = srcrect.w; - destrect.h = srcrect.h; + destrect.w = (options.override_drawsize ? options.overridden_drawwidth : srcrect.w) * options.scale; + destrect.h = (options.override_drawsize ? options.overridden_drawheight : srcrect.h) * options.scale; SDL_SetRenderTarget(parent->renderer, texture); SDL_RenderCopyEx(parent->renderer, tex, &srcrect, &destrect, 0, nullptr, flip); } -void SDLRenderTarget::renderCreaturesImage(const std::shared_ptr& img, unsigned int frame, int x, int y, uint8_t transparency, bool mirror) { - assert(img.get() != nullptr); - renderCreaturesImage(*img.get(), frame, x, y, transparency, mirror); -} - void SDLRenderTarget::renderClear() { SDL_SetRenderDrawColor(parent->renderer, 0, 0, 0, 255); SDL_SetRenderTarget(parent->renderer, texture); diff --git a/src/backends/SDLBackend.h b/src/backends/SDLBackend.h index 0232b6151..e6e3e4041 100644 --- a/src/backends/SDLBackend.h +++ b/src/backends/SDLBackend.h @@ -40,8 +40,7 @@ class SDLRenderTarget : public RenderTarget { SDLRenderTarget(SDLBackend* p) { parent = p; } public: - void renderCreaturesImage(creaturesImage& tex, unsigned int frame, int x, int y, uint8_t transparency = 0, bool mirror = false); - void renderCreaturesImage(const std::shared_ptr& tex, unsigned int frame, int x, int y, uint8_t transparency = 0, bool mirror = false); + void renderCreaturesImage(creaturesImage& tex, unsigned int frame, int x, int y, RenderOptions options = {}); void renderLine(int x1, int y1, int x2, int y2, unsigned int colour); void blitRenderTarget(RenderTarget* src, int x, int y, int w, int h); unsigned int getWidth() const; diff --git a/src/caos/caosVM_agent.cpp b/src/caos/caosVM_agent.cpp index 22380eb30..9e8f01268 100644 --- a/src/caos/caosVM_agent.cpp +++ b/src/caos/caosVM_agent.cpp @@ -1464,6 +1464,20 @@ void c_DCOR(caosVM* vm) { vm->targ->displaycore = core_on; } +/** + MIRA (command) mirror_on (integer) + %status maybe + + Turns mirroring of the TARG agent's current sprite on or off (0 or 1). +*/ +void c_MIRA(caosVM* vm) { + VM_PARAM_INTEGER(mirror_on) + + valid_agent(vm->targ); + caos_assert(mirror_on == 0 || mirror_on == 1); + vm->targ->draw_mirrored = mirror_on; +} + /** MIRA (integer) %status maybe @@ -1472,31 +1486,61 @@ void c_DCOR(caosVM* vm) { */ void v_MIRA(caosVM* vm) { valid_agent(vm->targ); + vm->result.setInt(vm->targ->draw_mirrored); +} - // TODO: correct? - SpritePart* p = vm->getCurrentSpritePart(); - caos_assert(p); +/** + FLIP (command) onoroff (integer) + %status stub + %variants sm - vm->result.setInt(p->draw_mirrored); + Tell the agent to draw the current sprite vertically flipped. +*/ +void c_FLIP(caosVM* vm) { + VM_PARAM_INTEGER(onoroff); + valid_agent(vm->targ); + caos_assert(onoroff == 0 || onoroff == 1); + // TODO (this isn't actually used anywhere, afaict) } /** - MIRA (command) mirror_on (integer) - %status maybe + FLIP (integer) + %status stub + %variants sm - Turns mirroring of the TARG agent's current sprite on or off (0 or 1). + Is the current sprite for this agent vertically flipped? */ -void c_MIRA(caosVM* vm) { - VM_PARAM_INTEGER(mirror_on) +void v_FLIP(caosVM* vm) { + valid_agent(vm->targ); + // TODO (this isn't actually used anywhere, afaict) + vm->result.setInt(0); +} + +/** + ROTA (command) angle (integer) + %status stub + %variants sm + + Tell the agent to draw the current sprite rotated clockwise by the given angle a value between 0 and 360. +*/ +void c_ROTA(caosVM* vm) { + VM_PARAM_INTEGER(angle) valid_agent(vm->targ); + caos_assert(angle >= 0 && angle <= 360); + // TODO: doesn't actually do anything in original engine? +} - // TODO: what does 'current sprite' mean? - // TODO: correct? - SpritePart* p = vm->getCurrentSpritePart(); - caos_assert(p); +/** + ROTA (integer) + %status stub + %variants sm - p->draw_mirrored = mirror_on; + By what angle is the current sprite for this agent rotated returns angle between 0 and 360. +*/ +void v_ROTA(caosVM* vm) { + valid_agent(vm->targ); + vm->result.setInt(0); } /** @@ -1518,7 +1562,7 @@ void v_DISQ(caosVM* vm) { } /** - ALPH (command) alpha_value (integer) enable (integer) + ALPH (command) transparency (integer) enable (integer) %status maybe Sets the degree of alpha blending on the TARG agent, to a value from 0 (solid) to 256 @@ -1526,27 +1570,16 @@ void v_DISQ(caosVM* vm) { */ void c_ALPH(caosVM* vm) { VM_PARAM_INTEGER(enable) - VM_PARAM_INTEGER(alpha_value) + VM_PARAM_INTEGER(transparency) - if (alpha_value < 0) - alpha_value = 0; - else if (alpha_value > 255) - alpha_value = 255; + caos_assert(transparency >= 0 && transparency <= 256); + if (transparency == 256) { + transparency = 255; + } + caos_assert(enable == 0 || enable == 1); valid_agent(vm->targ); - - CompoundAgent* c = dynamic_cast(vm->targ.get()); - if (c && vm->part == -1) { - for (auto& part : c->parts) { - part->has_alpha = enable; - part->alpha = alpha_value; - } - } else { - CompoundPart* p = vm->targ->part(vm->part); - caos_assert(p); - p->has_alpha = enable; - p->alpha = alpha_value; - } + vm->targ->alpha = enable ? 255 - transparency : 255; } /** @@ -2042,23 +2075,42 @@ void v_XIST(caosVM* vm) { } /** - SCLE (command) pose (integer) scaleby (integer) + SCLE (command) scaleby (float) yesorno (integer) + %status done + %variants sm +*/ +void c_SCLE_sm(caosVM* vm) { + VM_PARAM_INTEGER(yesorno) + VM_PARAM_FLOAT(scaleby) + + valid_agent(vm->targ); + + caos_assert(yesorno == 0 || yesorno == 1); + vm->targ->scle = yesorno ? scaleby : 1.0; +} + +/** + SCLE (command) pose(integer) scaleby (float) %status stub + %variants cv */ -void c_SCLE(caosVM* vm) { - VM_PARAM_INTEGER(scaleby) +void c_SCLE_cv(caosVM* vm) { + VM_PARAM_FLOAT(scaleby) VM_PARAM_INTEGER(pose) valid_agent(vm->targ); + caos_assert(pose == 1 || pose == -1); + // TODO } /** STRC (command) width (integer) height (integer) enable (integer) %status stub + %variants sm - Draw the current agent (or part? don't know) with the given width/height (ie, stretch the sprite). Set enable to 1 to enable, or 0 to disable. + Draw the current agent with the given width/height (ie, stretch the sprite). Set enable to 1 to enable, or 0 to disable. */ void c_STRC(caosVM* vm) { VM_PARAM_INTEGER(enable) @@ -2066,8 +2118,11 @@ void c_STRC(caosVM* vm) { VM_PARAM_INTEGER(width) valid_agent(vm->targ); - - // TODO + caos_assert(enable == 0 || enable == 1); + // TODO: does this affect agent's width/height? + vm->targ->strc = enable; + vm->targ->strc_width = width; + vm->targ->strc_height = height; } /** @@ -2178,7 +2233,9 @@ void c_SHAD(caosVM* vm) { valid_agent(vm->targ); - // TODO + // TODO: only used by clams in Sea-Monkeys. + // Intensity doesn't map directly to alpha 0.0–1.0, maybe 0–0.5? + // Needs to either only be on primary part, or all shadows rendered before all parts } /** diff --git a/src/creatures/SkeletalCreature.cpp b/src/creatures/SkeletalCreature.cpp index 4e1d23876..1ab540372 100644 --- a/src/creatures/SkeletalCreature.cpp +++ b/src/creatures/SkeletalCreature.cpp @@ -300,7 +300,9 @@ void SkeletalCreature::render(RenderTarget* renderer, int xoffset, int yoffset) assert(images[i]); - renderer->renderCreaturesImage(images[i], ourpose, partx[i] + adjustx + xoffset, party[i] + adjusty + yoffset, 0, mirror); + RenderOptions render_opts; + render_opts.mirror = mirror; + renderer->renderCreaturesImage(images[i], ourpose, partx[i] + adjustx + xoffset, party[i] + adjusty + yoffset, render_opts); if (displaycore) { // TODO: we draw a lot of points twice here :)